#
tokens: 49757/50000 2/128 files (page 6/9)
lines: off (toggle) GitHub
raw markdown copy
This is page 6 of 9. Use http://codebase.md/tejpalvirk/contextmanager?page={x} to view the full context.

# Directory Structure

```
├── .gitattributes
├── .gitignore
├── build-all-domains.sh
├── developer
│   ├── .gitattributes
│   ├── developer_advancedcontext.txt
│   ├── developer_buildcontext.txt
│   ├── developer_deletecontext.txt
│   ├── developer_endsession_examples.txt
│   ├── developer_endsession.txt
│   ├── developer_loadcontext.txt
│   ├── developer_startsession.txt
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── README.md
│   └── tsconfig.json
├── dist
│   ├── developer
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── main
│   │   ├── descriptions
│   │   │   ├── common_advancedcontext.txt
│   │   │   ├── common_buildcontext.txt
│   │   │   ├── common_deletecontext.txt
│   │   │   ├── common_endsession.txt
│   │   │   ├── common_loadcontext.txt
│   │   │   ├── common_startsession.txt
│   │   │   ├── developer_advancedcontext.txt
│   │   │   ├── developer_buildcontext.txt
│   │   │   ├── developer_deletecontext.txt
│   │   │   ├── developer_endsession_examples.txt
│   │   │   ├── developer_endsession.txt
│   │   │   ├── developer_loadcontext.txt
│   │   │   ├── developer_startsession.txt
│   │   │   ├── project_advancedcontext.txt
│   │   │   ├── project_buildcontext.txt
│   │   │   ├── project_deletecontext.txt
│   │   │   ├── project_endsession_examples.txt
│   │   │   ├── project_endsession.txt
│   │   │   ├── project_loadcontext.txt
│   │   │   ├── project_startsession.txt
│   │   │   ├── qualitativeresearch_advancedcontext.txt
│   │   │   ├── qualitativeresearch_buildcontext.txt
│   │   │   ├── qualitativeresearch_deletecontext.txt
│   │   │   ├── qualitativeresearch_endsession_examples.txt
│   │   │   ├── qualitativeresearch_endsession.txt
│   │   │   ├── qualitativeresearch_loadcontext.txt
│   │   │   ├── qualitativeresearch_startsession.txt
│   │   │   ├── quantitativeresearch_advancedcontext.txt
│   │   │   ├── quantitativeresearch_buildcontext.txt
│   │   │   ├── quantitativeresearch_deletecontext.txt
│   │   │   ├── quantitativeresearch_endsession_examples.txt
│   │   │   ├── quantitativeresearch_endsession.txt
│   │   │   ├── quantitativeresearch_loadcontext.txt
│   │   │   ├── quantitativeresearch_startsession.txt
│   │   │   ├── student_advancedcontext.txt
│   │   │   ├── student_buildcontext.txt
│   │   │   ├── student_deletecontext.txt
│   │   │   ├── student_endsession_examples.txt
│   │   │   ├── student_endsession.txt
│   │   │   ├── student_loadcontext.txt
│   │   │   └── student_startsession.txt
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   ├── mcp.d.ts
│   │   └── mcp.js
│   ├── project
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── qualitativeresearch
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── quantitativeresearch
│   │   ├── index.d.ts
│   │   └── index.js
│   └── student
│       ├── index.d.ts
│       └── index.js
├── main
│   ├── descriptions
│   │   ├── common_advancedcontext.txt
│   │   ├── common_buildcontext.txt
│   │   ├── common_deletecontext.txt
│   │   ├── common_endsession.txt
│   │   ├── common_loadcontext.txt
│   │   ├── common_startsession.txt
│   │   ├── developer_advancedcontext.txt
│   │   ├── developer_buildcontext.txt
│   │   ├── developer_deletecontext.txt
│   │   ├── developer_endsession_examples.txt
│   │   ├── developer_endsession.txt
│   │   ├── developer_loadcontext.txt
│   │   ├── developer_startsession.txt
│   │   ├── project_advancedcontext.txt
│   │   ├── project_buildcontext.txt
│   │   ├── project_deletecontext.txt
│   │   ├── project_endsession_examples.txt
│   │   ├── project_endsession.txt
│   │   ├── project_loadcontext.txt
│   │   ├── project_startsession.txt
│   │   ├── qualitativeresearch_advancedcontext.txt
│   │   ├── qualitativeresearch_buildcontext.txt
│   │   ├── qualitativeresearch_deletecontext.txt
│   │   ├── qualitativeresearch_endsession_examples.txt
│   │   ├── qualitativeresearch_endsession.txt
│   │   ├── qualitativeresearch_loadcontext.txt
│   │   ├── qualitativeresearch_startsession.txt
│   │   ├── quantitativeresearch_advancedcontext.txt
│   │   ├── quantitativeresearch_buildcontext.txt
│   │   ├── quantitativeresearch_deletecontext.txt
│   │   ├── quantitativeresearch_endsession_examples.txt
│   │   ├── quantitativeresearch_endsession.txt
│   │   ├── quantitativeresearch_loadcontext.txt
│   │   ├── quantitativeresearch_startsession.txt
│   │   ├── student_advancedcontext.txt
│   │   ├── student_buildcontext.txt
│   │   ├── student_deletecontext.txt
│   │   ├── student_endsession_examples.txt
│   │   ├── student_endsession.txt
│   │   ├── student_loadcontext.txt
│   │   └── student_startsession.txt
│   ├── index.js
│   ├── index.ts
│   ├── mcp.ts
│   ├── package.json
│   ├── README.md
│   └── tsconfig.json
├── package-lock.json
├── package.json
├── project
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── project_advancedcontext.txt
│   ├── project_buildcontext.txt
│   ├── project_deletecontext.txt
│   ├── project_endsession_examples.txt
│   ├── project_endsession.txt
│   ├── project_loadcontext.txt
│   ├── project_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── qualitativeresearch
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── qualitativeresearch_advancedcontext.txt
│   ├── qualitativeresearch_buildcontext.txt
│   ├── qualitativeresearch_deletecontext.txt
│   ├── qualitativeresearch_endsession_examples.txt
│   ├── qualitativeresearch_endsession.txt
│   ├── qualitativeresearch_loadcontext.txt
│   ├── qualitativeresearch_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── quantitativeresearch
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── quantitativeresearch_advancedcontext.txt
│   ├── quantitativeresearch_buildcontext.txt
│   ├── quantitativeresearch_deletecontext.txt
│   ├── quantitativeresearch_endsession_examples.txt
│   ├── quantitativeresearch_endsession.txt
│   ├── quantitativeresearch_loadcontext.txt
│   ├── quantitativeresearch_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── README.md
├── student
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── README.md
│   ├── student_advancedcontext.txt
│   ├── student_buildcontext.txt
│   ├── student_deletecontext.txt
│   ├── student_endsession_examples.txt
│   ├── student_endsession.txt
│   ├── student_loadcontext.txt
│   ├── student_startsession.txt
│   └── tsconfig.json
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/qualitativeresearch/index.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { z } from "zod";
import { readFileSync, existsSync } from "fs";
// Define memory file path using environment variable with fallback
const parentPath = path.dirname(fileURLToPath(import.meta.url));
const defaultMemoryPath = path.join(parentPath, 'memory.json');
const defaultSessionsPath = path.join(parentPath, 'sessions.json');
// Properly handle absolute and relative paths for MEMORY_FILE_PATH
const MEMORY_FILE_PATH = process.env.MEMORY_FILE_PATH
    ? path.isAbsolute(process.env.MEMORY_FILE_PATH)
        ? process.env.MEMORY_FILE_PATH // Use absolute path as is
        : path.join(process.cwd(), process.env.MEMORY_FILE_PATH) // Relative to current working directory
    : defaultMemoryPath; // Default fallback
// Properly handle absolute and relative paths for SESSIONS_FILE_PATH
const SESSIONS_FILE_PATH = process.env.SESSIONS_FILE_PATH
    ? path.isAbsolute(process.env.SESSIONS_FILE_PATH)
        ? process.env.SESSIONS_FILE_PATH // Use absolute path as is
        : path.join(process.cwd(), process.env.SESSIONS_FILE_PATH) // Relative to current working directory
    : defaultSessionsPath; // Default fallback
// Qualitative Research specific entity types
const VALID_ENTITY_TYPES = [
    'project', // Overall research study
    'participant', // Research subjects
    'interview', // Formal conversation with participants
    'observation', // Field notes from observational research
    'document', // External materials being analyzed
    'code', // Labels applied to data segments
    'codeGroup', // Categories or families of related codes
    'memo', // Researcher's analytical notes
    'theme', // Emergent patterns across data
    'quote', // Notable excerpts from data sources
    'literature', // Academic sources
    'researchQuestion', // Formal questions guiding the study
    'finding', // Results or conclusions
    'status', // Status entity type
    'priority' // Priority entity type
];
// Qualitative Research specific relation types
const VALID_RELATION_TYPES = [
    'participated_in', // Links participants to interviews/observations
    'codes', // Shows which codes apply to which data
    'contains', // Hierarchical relationship (e.g., codegroup contains codes)
    'supports', // Data supporting a theme or finding
    'contradicts', // Data contradicting a theme or finding
    'answers', // Data addressing a research question
    'cites', // References to literature
    'followed_by', // Temporal sequence
    'related_to', // General connection
    'reflects_on', // Memo reflecting on data/code/theme
    'compares', // Comparative relationship
    'conducted_by', // Person who conducted data collection
    'transcribed_by', // Person who transcribed data
    'part_of', // Entity is part of another entity
    'derived_from', // Entity is derived from another entity
    'collected_on', // Data collection date
    'analyzes', // Analysis relationship
    'triangulates_with', // Triangulation between data sources
    'has_status', // Entity has a specific status
    'has_priority', // Entity has a specific priority
    'precedes' // Entity comes before another entity in sequence
];
// Status values for different entity types in qualitative research
const STATUS_VALUES = {
    project: ['planning', 'data_collection', 'analysis', 'writing', 'complete'],
    interview: ['scheduled', 'conducted', 'transcribed', 'coded', 'analyzed'],
    observation: ['planned', 'conducted', 'documented', 'coded', 'analyzed'],
    code: ['initial', 'revised', 'final'],
    theme: ['emerging', 'developing', 'established'],
    finding: ['preliminary', 'draft', 'final']
};
// Define valid status values for all entity types
const VALID_STATUS_VALUES = [
    'planning', 'data_collection', 'analysis', 'writing', 'complete',
    'scheduled', 'conducted', 'transcribed', 'coded', 'analyzed',
    'planned', 'documented',
    'initial', 'revised', 'final',
    'emerging', 'developing', 'established',
    'preliminary', 'draft',
    'active', 'in_progress', 'not_started'
];
// Define valid priority values
const VALID_PRIORITY_VALUES = [
    'high', 'low'
];
// Basic validation functions
function validateEntityType(entityType) {
    return VALID_ENTITY_TYPES.includes(entityType);
}
function validateRelationType(relationType) {
    return VALID_RELATION_TYPES.includes(relationType);
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Collect tool descriptions from text files
const toolDescriptions = {
    'startsession': '',
    'loadcontext': '',
    'deletecontext': '',
    'buildcontext': '',
    'advancedcontext': '',
    'endsession': '',
};
for (const tool of Object.keys(toolDescriptions)) {
    const descriptionFilePath = path.resolve(__dirname, `qualitativeresearch_${tool}.txt`);
    if (existsSync(descriptionFilePath)) {
        toolDescriptions[tool] = readFileSync(descriptionFilePath, 'utf-8');
    }
}
// Session management functions
async function loadSessionStates() {
    try {
        const fileContent = await fs.readFile(SESSIONS_FILE_PATH, 'utf-8');
        const sessions = JSON.parse(fileContent);
        // Convert from object to Map
        const sessionsMap = new Map();
        for (const [key, value] of Object.entries(sessions)) {
            sessionsMap.set(key, value);
        }
        return sessionsMap;
    }
    catch (error) {
        if (error instanceof Error && 'code' in error && error.code === "ENOENT") {
            return new Map();
        }
        throw error;
    }
}
async function saveSessionStates(sessionsMap) {
    // Convert from Map to object
    const sessions = {};
    for (const [key, value] of sessionsMap.entries()) {
        sessions[key] = value;
    }
    await fs.writeFile(SESSIONS_FILE_PATH, JSON.stringify(sessions, null, 2), 'utf-8');
}
// Generate a unique session ID
function generateSessionId() {
    return `qual_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
}
// The KnowledgeGraphManager class contains all operations to interact with the knowledge graph
class KnowledgeGraphManager {
    async loadGraph() {
        try {
            const fileContent = await fs.readFile(MEMORY_FILE_PATH, 'utf-8');
            return JSON.parse(fileContent);
        }
        catch (error) {
            // If the file doesn't exist, return an empty graph
            return {
                entities: [],
                relations: []
            };
        }
    }
    async saveGraph(graph) {
        await fs.writeFile(MEMORY_FILE_PATH, JSON.stringify(graph, null, 2), 'utf-8');
    }
    // Initialize status and priority entities
    async initializeStatusAndPriority() {
        const graph = await this.loadGraph();
        // Create status entities if they don't exist
        for (const statusValue of VALID_STATUS_VALUES) {
            const statusName = `status:${statusValue}`;
            if (!graph.entities.some(e => e.name === statusName && e.entityType === 'status')) {
                graph.entities.push({
                    name: statusName,
                    entityType: 'status',
                    observations: [`A ${statusValue} status value`]
                });
            }
        }
        // Create priority entities if they don't exist
        for (const priorityValue of VALID_PRIORITY_VALUES) {
            const priorityName = `priority:${priorityValue}`;
            if (!graph.entities.some(e => e.name === priorityName && e.entityType === 'priority')) {
                graph.entities.push({
                    name: priorityName,
                    entityType: 'priority',
                    observations: [`A ${priorityValue} priority value`]
                });
            }
        }
        await this.saveGraph(graph);
    }
    // Helper method to get status of an entity
    async getEntityStatus(entityName) {
        const graph = await this.loadGraph();
        // Find status relation for this entity
        const statusRelation = graph.relations.find(r => r.from === entityName &&
            r.relationType === 'has_status');
        if (statusRelation) {
            // Extract status value from the status entity name (status:value)
            return statusRelation.to.split(':')[1];
        }
        return null;
    }
    // Helper method to get priority of an entity
    async getEntityPriority(entityName) {
        const graph = await this.loadGraph();
        // Find priority relation for this entity
        const priorityRelation = graph.relations.find(r => r.from === entityName &&
            r.relationType === 'has_priority');
        if (priorityRelation) {
            // Extract priority value from the priority entity name (priority:value)
            return priorityRelation.to.split(':')[1];
        }
        return null;
    }
    // Helper method to set status of an entity
    async setEntityStatus(entityName, statusValue) {
        if (!VALID_STATUS_VALUES.includes(statusValue)) {
            throw new Error(`Invalid status value: ${statusValue}. Valid values are: ${VALID_STATUS_VALUES.join(', ')}`);
        }
        const graph = await this.loadGraph();
        // Remove any existing status relations for this entity
        graph.relations = graph.relations.filter(r => !(r.from === entityName && r.relationType === 'has_status'));
        // Add new status relation
        graph.relations.push({
            from: entityName,
            to: `status:${statusValue}`,
            relationType: 'has_status'
        });
        await this.saveGraph(graph);
    }
    // Helper method to set priority of an entity
    async setEntityPriority(entityName, priorityValue) {
        if (!VALID_PRIORITY_VALUES.includes(priorityValue)) {
            throw new Error(`Invalid priority value: ${priorityValue}. Valid values are: ${VALID_PRIORITY_VALUES.join(', ')}`);
        }
        const graph = await this.loadGraph();
        // Remove any existing priority relations for this entity
        graph.relations = graph.relations.filter(r => !(r.from === entityName && r.relationType === 'has_priority'));
        // Add new priority relation
        graph.relations.push({
            from: entityName,
            to: `priority:${priorityValue}`,
            relationType: 'has_priority'
        });
        await this.saveGraph(graph);
    }
    async createEntities(entities) {
        const graph = await this.loadGraph();
        const existingEntityNames = new Set(graph.entities.map(e => e.name));
        // Validate entity types
        entities.forEach(entity => {
            if (!validateEntityType(entity.entityType)) {
                throw new Error(`Invalid entity type: ${entity.entityType}. Valid types are: ${VALID_ENTITY_TYPES.join(', ')}`);
            }
        });
        const newEntities = entities.filter(entity => !existingEntityNames.has(entity.name));
        graph.entities.push(...newEntities);
        await this.saveGraph(graph);
        return newEntities;
    }
    async createRelations(relations) {
        const graph = await this.loadGraph();
        const existingEntityNames = new Set(graph.entities.map(e => e.name));
        // Check that entities exist and validate relation types
        relations.forEach(relation => {
            if (!existingEntityNames.has(relation.from)) {
                throw new Error(`Entity '${relation.from}' not found`);
            }
            if (!existingEntityNames.has(relation.to)) {
                throw new Error(`Entity '${relation.to}' not found`);
            }
            if (!validateRelationType(relation.relationType)) {
                throw new Error(`Invalid relation type: ${relation.relationType}. Valid types are: ${VALID_RELATION_TYPES.join(', ')}`);
            }
        });
        // Filter out duplicate relations
        const existingRelations = new Set(graph.relations.map(r => `${r.from}:${r.to}:${r.relationType}`));
        const newRelations = relations.filter(r => !existingRelations.has(`${r.from}:${r.to}:${r.relationType}`));
        graph.relations.push(...newRelations);
        await this.saveGraph(graph);
        return newRelations;
    }
    async addObservations(observations) {
        const graph = await this.loadGraph();
        const results = [];
        for (const observation of observations) {
            const entity = graph.entities.find(e => e.name === observation.entityName);
            if (!entity) {
                throw new Error(`Entity '${observation.entityName}' not found`);
            }
            // Filter out duplicate observations
            const existingObservations = new Set(entity.observations);
            const newObservations = observation.contents.filter(o => !existingObservations.has(o));
            entity.observations.push(...newObservations);
            results.push({
                entityName: observation.entityName,
                addedObservations: newObservations
            });
        }
        await this.saveGraph(graph);
        return results;
    }
    async deleteEntities(entityNames) {
        const graph = await this.loadGraph();
        // Remove the entities
        graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
        // Remove relations that involve the deleted entities
        graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
        await this.saveGraph(graph);
    }
    async deleteObservations(deletions) {
        const graph = await this.loadGraph();
        for (const deletion of deletions) {
            const entity = graph.entities.find(e => e.name === deletion.entityName);
            if (entity) {
                // Remove the specified observations
                entity.observations = entity.observations.filter(o => !deletion.observations.includes(o));
            }
        }
        await this.saveGraph(graph);
    }
    async deleteRelations(relations) {
        const graph = await this.loadGraph();
        // Remove specified relations
        graph.relations = graph.relations.filter(r => !relations.some(toDelete => r.from === toDelete.from &&
            r.to === toDelete.to &&
            r.relationType === toDelete.relationType));
        await this.saveGraph(graph);
    }
    async readGraph() {
        return this.loadGraph();
    }
    async searchNodes(query) {
        const graph = await this.loadGraph();
        // Split query into search terms
        const terms = query.toLowerCase().split(/\s+/);
        // Find matching entities
        const matchingEntityNames = new Set();
        for (const entity of graph.entities) {
            // Check if all terms match
            const matchesAllTerms = terms.every(term => {
                // Check entity name
                if (entity.name.toLowerCase().includes(term)) {
                    return true;
                }
                // Check entity type
                if (entity.entityType.toLowerCase().includes(term)) {
                    return true;
                }
                // Check observations
                for (const observation of entity.observations) {
                    if (observation.toLowerCase().includes(term)) {
                        return true;
                    }
                }
                return false;
            });
            if (matchesAllTerms) {
                matchingEntityNames.add(entity.name);
            }
        }
        // Find relations between matching entities
        const matchingRelations = graph.relations.filter(r => matchingEntityNames.has(r.from) && matchingEntityNames.has(r.to));
        // Return matching entities and their relations
        return {
            entities: graph.entities.filter(e => matchingEntityNames.has(e.name)),
            relations: matchingRelations
        };
    }
    async openNodes(names) {
        const graph = await this.loadGraph();
        // Find the specified entities
        const entities = graph.entities.filter(e => names.includes(e.name));
        // Find relations between the specified entities
        const relations = graph.relations.filter(r => names.includes(r.from) && names.includes(r.to));
        return {
            entities,
            relations
        };
    }
    // Get project overview including research questions, methodology, participants, data sources
    async getProjectOverview(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find research questions
        const researchQuestions = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const question = graph.entities.find(e => e.name === relation.from && e.entityType === 'researchQuestion');
                if (question) {
                    researchQuestions.push(question);
                }
            }
        }
        // Find participants
        const participants = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const participant = graph.entities.find(e => e.name === relation.from && e.entityType === 'participant');
                if (participant) {
                    participants.push(participant);
                }
            }
        }
        // Find data sources (interviews, observations, documents)
        const interviews = [];
        const observations = [];
        const documents = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const entity = graph.entities.find(e => e.name === relation.from);
                if (entity) {
                    if (entity.entityType === 'interview') {
                        interviews.push(entity);
                    }
                    else if (entity.entityType === 'observation') {
                        observations.push(entity);
                    }
                    else if (entity.entityType === 'document') {
                        documents.push(entity);
                    }
                }
            }
        }
        // Find findings
        const findings = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const finding = graph.entities.find(e => e.name === relation.from && e.entityType === 'finding');
                if (finding) {
                    findings.push(finding);
                }
            }
        }
        // Find themes
        const themes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const theme = graph.entities.find(e => e.name === relation.from && e.entityType === 'theme');
                if (theme) {
                    themes.push(theme);
                }
            }
        }
        // Get methodology info from project observations
        const methodologyObs = project.observations.filter(o => o.toLowerCase().includes('method') || o.toLowerCase().includes('approach'));
        return {
            project,
            researchQuestions,
            methodology: methodologyObs,
            dataCollection: {
                participants: participants.length,
                interviews: interviews.length,
                observations: observations.length,
                documents: documents.length,
                participantsList: participants,
                interviewsList: interviews,
                observationsList: observations,
                documentsList: documents
            },
            analysis: {
                themes: themes.length,
                themesList: themes
            },
            findings
        };
    }
    // Get all data related to a specific participant
    async getParticipantProfile(participantName) {
        const graph = await this.loadGraph();
        // Find the participant
        const participant = graph.entities.find(e => e.name === participantName && e.entityType === 'participant');
        if (!participant) {
            throw new Error(`Participant '${participantName}' not found`);
        }
        // Find interviews with this participant
        const interviews = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'participated_in' && relation.from === participantName) {
                const interview = graph.entities.find(e => e.name === relation.to && e.entityType === 'interview');
                if (interview) {
                    interviews.push(interview);
                }
            }
        }
        // Find observations including this participant
        const observations = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'participated_in' && relation.from === participantName) {
                const observation = graph.entities.find(e => e.name === relation.to && e.entityType === 'observation');
                if (observation) {
                    observations.push(observation);
                }
            }
        }
        // Find quotes from this participant
        const quotes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'contains' && relation.to === participantName) {
                const quote = graph.entities.find(e => e.name === relation.from && e.entityType === 'quote');
                if (quote) {
                    quotes.push(quote);
                }
            }
        }
        // Find any memos about this participant
        const memos = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'reflects_on' && relation.to === participantName) {
                const memo = graph.entities.find(e => e.name === relation.from && e.entityType === 'memo');
                if (memo) {
                    memos.push(memo);
                }
            }
        }
        // Extract demographic information from observations
        const demographicObs = participant.observations.filter(o => o.toLowerCase().includes('age') ||
            o.toLowerCase().includes('gender') ||
            o.toLowerCase().includes('occupation') ||
            o.toLowerCase().includes('education'));
        return {
            participant,
            demographics: demographicObs,
            interviews,
            observations,
            quotes,
            memos
        };
    }
    // Get themes with supporting codes and data
    async getThematicAnalysis(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find all themes related to this project
        const themes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const theme = graph.entities.find(e => e.name === relation.from && e.entityType === 'theme');
                if (theme) {
                    themes.push(theme);
                }
            }
        }
        // For each theme, find supporting data
        const thematicAnalysis = themes.map(theme => {
            // Find codes supporting this theme
            const supportingCodes = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'supports' && relation.to === theme.name) {
                    const code = graph.entities.find(e => e.name === relation.from && e.entityType === 'code');
                    if (code) {
                        supportingCodes.push(code);
                    }
                }
            }
            // For each code, find supporting quotes
            const codeData = supportingCodes.map(code => {
                const quotes = [];
                for (const relation of graph.relations) {
                    if (relation.relationType === 'codes' && relation.from === code.name) {
                        const quote = graph.entities.find(e => e.name === relation.to && e.entityType === 'quote');
                        if (quote) {
                            quotes.push(quote);
                        }
                    }
                }
                return {
                    code,
                    quotes
                };
            });
            // Find any memos reflecting on this theme
            const memos = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'reflects_on' && relation.to === theme.name) {
                    const memo = graph.entities.find(e => e.name === relation.from && e.entityType === 'memo');
                    if (memo) {
                        memos.push(memo);
                    }
                }
            }
            // Find status of the theme
            const statusObs = theme.observations.find(o => o.startsWith('Status:'));
            const status = statusObs ? statusObs.split(':')[1].trim() : 'unknown';
            return {
                theme,
                status,
                supportingData: codeData,
                codes: supportingCodes,
                memos
            };
        });
        return {
            project,
            themes: thematicAnalysis
        };
    }
    // Get all data segments tagged with a specific code
    async getCodedData(codeName) {
        const graph = await this.loadGraph();
        // Find the code
        const code = graph.entities.find(e => e.name === codeName && e.entityType === 'code');
        if (!code) {
            throw new Error(`Code '${codeName}' not found`);
        }
        // Find which code group this code belongs to, if any
        const codeGroups = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'contains' && relation.to === codeName) {
                const codeGroup = graph.entities.find(e => e.name === relation.from && e.entityType === 'codeGroup');
                if (codeGroup) {
                    codeGroups.push(codeGroup);
                }
            }
        }
        // Find all quotes tagged with this code
        const quotes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'codes' && relation.from === codeName) {
                const quote = graph.entities.find(e => e.name === relation.to && e.entityType === 'quote');
                if (quote) {
                    quotes.push(quote);
                }
            }
        }
        // Find which sources (interviews, observations, documents) these quotes come from
        const sources = new Map();
        for (const quote of quotes) {
            for (const relation of graph.relations) {
                if (relation.relationType === 'contains' && relation.from !== codeName && relation.to === quote.name) {
                    const source = graph.entities.find(e => e.name === relation.from);
                    if (source) {
                        sources.set(source.name, source);
                    }
                }
            }
        }
        // Find themes this code supports
        const themes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'supports' && relation.from === codeName) {
                const theme = graph.entities.find(e => e.name === relation.to && e.entityType === 'theme');
                if (theme) {
                    themes.push(theme);
                }
            }
        }
        // Find any memos reflecting on this code
        const memos = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'reflects_on' && relation.to === codeName) {
                const memo = graph.entities.find(e => e.name === relation.from && e.entityType === 'memo');
                if (memo) {
                    memos.push(memo);
                }
            }
        }
        return {
            code,
            codeGroups,
            quotes,
            sourceCount: sources.size,
            sources: Array.from(sources.values()),
            themes,
            memos
        };
    }
    // Shows data organized by research questions with findings
    async getResearchQuestionAnalysis(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find all research questions for this project
        const researchQuestions = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const question = graph.entities.find(e => e.name === relation.from && e.entityType === 'researchQuestion');
                if (question) {
                    researchQuestions.push(question);
                }
            }
        }
        // For each research question, find related data
        const questionAnalysis = researchQuestions.map(question => {
            // Find findings that answer this question
            const findings = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'answers' && relation.to === question.name) {
                    const finding = graph.entities.find(e => e.name === relation.from && e.entityType === 'finding');
                    if (finding) {
                        findings.push(finding);
                    }
                }
            }
            // Find themes related to this question
            const themes = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'answers' && relation.to === question.name) {
                    const theme = graph.entities.find(e => e.name === relation.from && e.entityType === 'theme');
                    if (theme) {
                        themes.push(theme);
                    }
                }
            }
            // Find data directly addressing this question
            const quotes = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'answers' && relation.to === question.name) {
                    const quote = graph.entities.find(e => e.name === relation.from && e.entityType === 'quote');
                    if (quote) {
                        quotes.push(quote);
                    }
                }
            }
            return {
                question,
                findings,
                themes,
                quotes
            };
        });
        return {
            project,
            researchQuestions: questionAnalysis
        };
    }
    // Returns data in temporal sequence
    async getChronologicalData(projectName, dataType) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find all data collection entities for this project
        let dataEntities = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                let entity;
                // Filter by data type if specified
                if (dataType) {
                    entity = graph.entities.find(e => e.name === relation.from && e.entityType === dataType);
                }
                else {
                    entity = graph.entities.find(e => e.name === relation.from &&
                        (e.entityType === 'interview' ||
                            e.entityType === 'observation' ||
                            e.entityType === 'document'));
                }
                if (entity) {
                    dataEntities.push(entity);
                }
            }
        }
        // Extract date information for each entity
        const dataWithDates = dataEntities.map(entity => {
            const dateObs = entity.observations.find(o => o.startsWith('Date:') || o.startsWith('Collected on:') || o.startsWith('Created:'));
            let date = new Date(0);
            if (dateObs) {
                // Extract date string and try to parse it
                const dateString = dateObs.split(':')[1].trim();
                const parsedDate = new Date(dateString);
                if (!isNaN(parsedDate.getTime())) {
                    date = parsedDate;
                }
            }
            return {
                entity,
                date
            };
        });
        // Sort by date
        dataWithDates.sort((a, b) => a.date.getTime() - b.date.getTime());
        // Create a timeline of data
        const timeline = dataWithDates.map(item => {
            // For each entity, find related quotes
            const quotes = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'contains' && relation.from === item.entity.name) {
                    const quote = graph.entities.find(e => e.name === relation.to && e.entityType === 'quote');
                    if (quote) {
                        quotes.push(quote);
                    }
                }
            }
            return {
                date: item.date,
                entity: item.entity,
                quotes
            };
        });
        return {
            project,
            timeline
        };
    }
    // Finds where multiple codes appear together
    async getCodeCooccurrence(codeName) {
        const graph = await this.loadGraph();
        // Find the code
        const code = graph.entities.find(e => e.name === codeName && e.entityType === 'code');
        if (!code) {
            throw new Error(`Code '${codeName}' not found`);
        }
        // Find all quotes tagged with this code
        const quotes = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'codes' && relation.from === codeName) {
                const quote = graph.entities.find(e => e.name === relation.to && e.entityType === 'quote');
                if (quote) {
                    quotes.push(quote);
                }
            }
        }
        // For each quote, find other codes that also tag it
        const codeOccurrences = new Map();
        for (const quote of quotes) {
            for (const relation of graph.relations) {
                if (relation.relationType === 'codes' && relation.from !== codeName && relation.to === quote.name) {
                    const otherCode = graph.entities.find(e => e.name === relation.from && e.entityType === 'code');
                    if (otherCode) {
                        if (codeOccurrences.has(otherCode.name)) {
                            const occurrence = codeOccurrences.get(otherCode.name);
                            occurrence.count++;
                            occurrence.quotes.push(quote);
                        }
                        else {
                            codeOccurrences.set(otherCode.name, {
                                code: otherCode,
                                count: 1,
                                quotes: [quote]
                            });
                        }
                    }
                }
            }
        }
        // Sort codes by co-occurrence frequency
        const cooccurringCodes = Array.from(codeOccurrences.values())
            .sort((a, b) => b.count - a.count);
        return {
            code,
            quotesCount: quotes.length,
            cooccurringCodes
        };
    }
    // Gets all memos related to a specific entity
    async getMemosByFocus(entityName) {
        const graph = await this.loadGraph();
        // Find the entity
        const entity = graph.entities.find(e => e.name === entityName);
        if (!entity) {
            throw new Error(`Entity '${entityName}' not found`);
        }
        // Find all memos reflecting on this entity
        const memos = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'reflects_on' && relation.to === entityName) {
                const memo = graph.entities.find(e => e.name === relation.from && e.entityType === 'memo');
                if (memo) {
                    memos.push(memo);
                }
            }
        }
        // Sort memos by date if possible
        const memosWithDates = memos.map(memo => {
            const dateObs = memo.observations.find(o => o.startsWith('Date:') || o.startsWith('Created:'));
            let date = new Date(0);
            if (dateObs) {
                const dateString = dateObs.split(':')[1].trim();
                const parsedDate = new Date(dateString);
                if (!isNaN(parsedDate.getTime())) {
                    date = parsedDate;
                }
            }
            return {
                memo,
                date
            };
        });
        // Sort by date, most recent first
        memosWithDates.sort((a, b) => b.date.getTime() - a.date.getTime());
        return {
            entity,
            memos: memosWithDates.map(m => m.memo)
        };
    }
    // Returns information about methods, sampling, analysis approach
    async getMethodologyDetails(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Extract methodology information from project observations
        const methodologyObs = project.observations.filter(o => o.toLowerCase().includes('method') ||
            o.toLowerCase().includes('approach') ||
            o.toLowerCase().includes('sampling') ||
            o.toLowerCase().includes('analysis') ||
            o.toLowerCase().includes('validity') ||
            o.toLowerCase().includes('reliability'));
        // Find methodology-related memos
        const memos = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'reflects_on' && relation.to === projectName) {
                const memo = graph.entities.find(e => e.name === relation.from && e.entityType === 'memo');
                if (memo && memo.observations.some(o => o.toLowerCase().includes('method') ||
                    o.toLowerCase().includes('approach') ||
                    o.toLowerCase().includes('sampling') ||
                    o.toLowerCase().includes('analysis'))) {
                    memos.push(memo);
                }
            }
        }
        // Calculate data collection statistics
        // 1. Get all interviews
        const interviews = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const interview = graph.entities.find(e => e.name === relation.from && e.entityType === 'interview');
                if (interview) {
                    interviews.push(interview);
                }
            }
        }
        // 2. Get all observations
        const observations = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const observation = graph.entities.find(e => e.name === relation.from && e.entityType === 'observation');
                if (observation) {
                    observations.push(observation);
                }
            }
        }
        // 3. Get all documents
        const documents = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const document = graph.entities.find(e => e.name === relation.from && e.entityType === 'document');
                if (document) {
                    documents.push(document);
                }
            }
        }
        // 4. Get all participants
        const participants = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const participant = graph.entities.find(e => e.name === relation.from && e.entityType === 'participant');
                if (participant) {
                    participants.push(participant);
                }
            }
        }
        // Find literature cited in this project
        const literature = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'cites' && relation.from === projectName) {
                const source = graph.entities.find(e => e.name === relation.to && e.entityType === 'literature');
                if (source) {
                    literature.push(source);
                }
            }
        }
        return {
            project,
            methodology: methodologyObs,
            dataCollection: {
                participants: participants.length,
                interviews: interviews.length,
                observations: observations.length,
                documents: documents.length
            },
            memos,
            literature
        };
    }
    // First, let's add the missing getRelatedEntities method to the KnowledgeGraphManager class
    // Add this before the async main() function
    async getRelatedEntities(entityName, relationTypes) {
        const graph = await this.loadGraph();
        // Find the entity
        const entity = graph.entities.find(e => e.name === entityName);
        if (!entity) {
            throw new Error(`Entity '${entityName}' not found`);
        }
        // Find all relations involving this entity
        let relevantRelations = graph.relations.filter(r => r.from === entityName || r.to === entityName);
        // Filter by relation types if specified
        if (relationTypes && relationTypes.length > 0) {
            relevantRelations = relevantRelations.filter(r => relationTypes.includes(r.relationType));
        }
        // Get all related entities grouped by relation type
        const related = {};
        for (const relation of relevantRelations) {
            const relationType = relation.relationType;
            if (!related[relationType]) {
                related[relationType] = [];
            }
            if (relation.from === entityName) {
                const target = graph.entities.find(e => e.name === relation.to);
                if (target) {
                    related[relationType].push(target);
                }
            }
            else {
                const source = graph.entities.find(e => e.name === relation.from);
                if (source) {
                    related[relationType].push(source);
                }
            }
        }
        return {
            entity,
            related
        };
    }
}
// Main function to set up the MCP server
async function main() {
    try {
        const knowledgeGraphManager = new KnowledgeGraphManager();
        // Initialize status and priority entities
        await knowledgeGraphManager.initializeStatusAndPriority();
        // Create the MCP server with a name and version
        const server = new McpServer({
            name: "Context Manager",
            version: "1.0.0"
        });
        // Define a resource that exposes the entire graph
        server.resource("graph", "graph://researcher/qualitative", async (uri) => ({
            contents: [{
                    uri: uri.href,
                    text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2)
                }]
        }));
        // Define tools using zod for parameter validation
        /**
         * Load context for a specific entity
         */
        server.tool("loadcontext", toolDescriptions["loadcontext"], {
            entityName: z.string(),
            entityType: z.string().optional(),
            sessionId: z.string().optional() // Optional to maintain backward compatibility
        }, async ({ entityName, entityType = "project", sessionId }) => {
            try {
                // Validate session if ID is provided
                if (sessionId) {
                    const sessionStates = await loadSessionStates();
                    if (!sessionStates.has(sessionId)) {
                        console.warn(`Warning: Session ${sessionId} not found, but proceeding with context load`);
                        // Initialize it anyway for more robustness
                        sessionStates.set(sessionId, []);
                        await saveSessionStates(sessionStates);
                    }
                    // Track that this entity was loaded in this session
                    const sessionState = sessionStates.get(sessionId) || [];
                    const loadEvent = {
                        type: 'context_loaded',
                        timestamp: new Date().toISOString(),
                        entityName,
                        entityType
                    };
                    sessionState.push(loadEvent);
                    sessionStates.set(sessionId, sessionState);
                    await saveSessionStates(sessionStates);
                }
                // Get the entity
                // Changed from using 'name:' prefix to directly searching by the entity name
                const entityGraph = await knowledgeGraphManager.searchNodes(entityName);
                if (entityGraph.entities.length === 0) {
                    throw new Error(`Entity ${entityName} not found`);
                }
                // Find the exact entity by name (case-sensitive match)
                const entity = entityGraph.entities.find(e => e.name === entityName);
                if (!entity) {
                    throw new Error(`Entity ${entityName} not found`);
                }
                // Different context loading based on entity type
                let contextMessage = "";
                if (entityType === "project") {
                    // Get project overview
                    const projectOverview = await knowledgeGraphManager.getProjectOverview(entityName);
                    // Get thematic analysis
                    let thematicAnalysis;
                    try {
                        thematicAnalysis = await knowledgeGraphManager.getThematicAnalysis(entityName);
                    }
                    catch (error) {
                        thematicAnalysis = { themes: [] };
                    }
                    // Get research question analysis
                    let researchQuestions;
                    try {
                        researchQuestions = await knowledgeGraphManager.getResearchQuestionAnalysis(entityName);
                    }
                    catch (error) {
                        researchQuestions = { researchQuestions: [] };
                    }
                    // Get methodology details
                    let methodology;
                    try {
                        methodology = await knowledgeGraphManager.getMethodologyDetails(entityName);
                    }
                    catch (error) {
                        methodology = { methodology: [] };
                    }
                    // Get status and priority using the relation-based approach
                    const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(entityName);
                    const priorityText = priority ? `- **Priority**: ${priority}` : "";
                    // Format observations
                    const observationsList = entity.observations.length > 0
                        ? entity.observations.map(obs => `- ${obs}`).join("\n")
                        : "No observations";
                    // Extract methodology information
                    const methodologyText = methodology.methodology?.map((m) => `- ${m}`).join("\n") || "No methodology details available";
                    // Extract research questions
                    const questionsText = researchQuestions.researchQuestions?.map((q) => {
                        const findings = q.findings?.map((f) => `  - ${f.name}`).join("\n") || "  - No findings yet";
                        return `- **${q.question.name}**\n${findings}`;
                    }).join("\n") || "No research questions found";
                    // Format data collection stats
                    const participantCount = projectOverview.dataCollection?.participants || 0;
                    const interviewCount = projectOverview.dataCollection?.interviews || 0;
                    const observationCount = projectOverview.dataCollection?.observations || 0;
                    const documentCount = projectOverview.dataCollection?.documents || 0;
                    // Format theme analysis
                    const themesText = thematicAnalysis.themes?.map(async (t) => {
                        const codeCount = t.supportingData?.length || 0;
                        const themeStatus = await knowledgeGraphManager.getEntityStatus(t.theme.name) || "unknown";
                        return `- **${t.theme.name}** (Status: ${themeStatus}): ${codeCount} codes`;
                    });
                    const resolvedThemesText = themesText ?
                        await Promise.all(themesText).then(texts => texts.join("\n")) :
                        "No themes identified yet";
                    // Get recent data collection - without date references
                    const recentInterviews = projectOverview.dataCollection?.interviewsList?.slice(0, 5).map(async (i) => {
                        const participant = i.observations.find(o => o.startsWith("participant:"))?.substring(12) || "Unknown";
                        const interviewStatus = await knowledgeGraphManager.getEntityStatus(i.name) || "unknown";
                        return `- **${i.name}** with ${participant} (Status: ${interviewStatus})`;
                    });
                    const resolvedInterviewsText = recentInterviews ?
                        await Promise.all(recentInterviews).then(texts => texts.join("\n")) :
                        "No recent interviews";
                    // Get findings with status from relations
                    const findingsText = projectOverview.findings?.map(async (f) => {
                        const findingStatus = await knowledgeGraphManager.getEntityStatus(f.name) || "preliminary";
                        const findingObs = f.observations.length > 0 ? f.observations[0] : "No description";
                        return `- **${f.name}** (Status: ${findingStatus}): ${findingObs}`;
                    });
                    const resolvedFindingsText = findingsText ?
                        await Promise.all(findingsText).then(texts => texts.join("\n")) :
                        "No findings recorded yet";
                    contextMessage = `# Qualitative Research Project Context: ${entityName}

## Project Details
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Research Design
${methodologyText}

## Research Questions
${questionsText}

## Data Collection Stats
- **Participants**: ${participantCount}
- **Interviews**: ${interviewCount}
- **Observations**: ${observationCount}
- **Documents**: ${documentCount}

## Recent Interviews
${resolvedInterviewsText}

## Analysis Progress
### Themes
${resolvedThemesText}

## Findings
${resolvedFindingsText}`;
                }
                else if (entityType === "participant") {
                    // Get participant profile
                    const participantProfile = await knowledgeGraphManager.getParticipantProfile(entityName);
                    // Get status and priority using the relation-based approach
                    const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(entityName);
                    const priorityText = priority ? `- **Priority**: ${priority}` : "";
                    // Format observations
                    const observationsList = entity.observations.length > 0
                        ? entity.observations.map(obs => `- ${obs}`).join("\n")
                        : "No observations";
                    // Format demographics without relying on patterns
                    const demographics = participantProfile.demographics?.map((d) => `- ${d}`).join("\n") || "No demographic information available";
                    // Format interviews with status from relations
                    const interviewsText = participantProfile.interviews?.map(async (i) => {
                        const interviewStatus = await knowledgeGraphManager.getEntityStatus(i.name) || "unknown";
                        return `- **${i.name}** (Status: ${interviewStatus})`;
                    });
                    const resolvedInterviewsText = interviewsText ?
                        await Promise.all(interviewsText).then(texts => texts.join("\n")) :
                        "No interviews recorded";
                    // Format observations with status from relations
                    const observationsText = participantProfile.observations?.map(async (o) => {
                        const observationStatus = await knowledgeGraphManager.getEntityStatus(o.name) || "unknown";
                        return `- **${o.name}** (Status: ${observationStatus})`;
                    });
                    const resolvedObservationsText = observationsText ?
                        await Promise.all(observationsText).then(texts => texts.join("\n")) :
                        "No observations recorded";
                    // Format quotes
                    const quotesText = participantProfile.quotes?.map((q) => {
                        // Show the full quote
                        const quote = q.observations.find(o => !o.startsWith("source:") && !o.startsWith("context:"));
                        const source = q.observations.find(o => o.startsWith("source:"))?.substring(7) || "Unknown source";
                        return `- "${quote || "No text available"}" (Source: ${source})`;
                    }).join("\n") || "No quotes recorded";
                    // Format memos
                    const memosText = participantProfile.memos?.map(async (m) => {
                        const memoStatus = await knowledgeGraphManager.getEntityStatus(m.name) || "unknown";
                        const topic = m.observations.find(o => o.startsWith("topic:"))?.substring(6) || "Untitled";
                        return `- **${topic}** (Status: ${memoStatus})`;
                    });
                    const resolvedMemosText = memosText ?
                        await Promise.all(memosText).then(texts => texts.join("\n")) :
                        "No memos about this participant";
                    contextMessage = `# Participant Context: ${entityName}

## Status and Priority
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Demographics
${demographics}

## Interviews
${resolvedInterviewsText}

## Observations
${resolvedObservationsText}

## Quotes
${quotesText}

## Research Memos
${resolvedMemosText}`;
                }
                else if (entityType === "interview") {
                    // Find which project this interview belongs to
                    let projectName = 'Unknown project';
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'part_of' && relation.from === entityName) {
                            const project = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                            if (project) {
                                projectName = project.name;
                                break;
                            }
                        }
                    }
                    // Get status and priority using the relation-based approach
                    const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(entityName);
                    const priorityText = priority ? `- **Priority**: ${priority}` : "";
                    // Format observations
                    const observationsList = entity.observations.length > 0
                        ? entity.observations.map(obs => `- ${obs}`).join("\n")
                        : "No observations";
                    // Get interview details without parsing date
                    const participant = entity.observations.find(o => o.startsWith("participant:"))?.substring(12) || "Unknown";
                    // Find codes applied to this interview and include their status
                    const codesWithStatus = [];
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'codes' && relation.to === entityName) {
                            const code = entityGraph.entities.find(e => e.name === relation.from && e.entityType === 'code');
                            if (code) {
                                const codeStatus = await knowledgeGraphManager.getEntityStatus(code.name) || "unknown";
                                codesWithStatus.push({
                                    code,
                                    status: codeStatus
                                });
                            }
                        }
                    }
                    const codesText = codesWithStatus.map(c => `- **${c.code.name}** (Status: ${c.status}): ${c.code.observations[0] || "No description"}`).join("\n") || "No codes applied yet";
                    // Find quotes from this interview
                    const quotes = [];
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'contains' && relation.from === entityName) {
                            const quote = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'quote');
                            if (quote) {
                                quotes.push(quote);
                            }
                        }
                    }
                    const quotesText = quotes.map(q => {
                        // Get the full quote text
                        const quoteText = q.observations.find(o => !o.startsWith("context:") && !o.startsWith("speaker:")) || "No text";
                        return `- "${quoteText}"`;
                    }).join("\n") || "No notable quotes recorded";
                    contextMessage = `# Interview Context: ${entityName}

## Overview
- **Project**: ${projectName}
- **Participant**: ${participant}
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Applied Codes
${codesText}

## Notable Quotes
${quotesText}`;
                }
                else if (entityType === "code") {
                    // Get coded data for this code
                    const codedData = await knowledgeGraphManager.getCodedData(entityName);
                    // Format code context
                    const definition = entity.observations.find(o => !o.startsWith("status:") && !o.startsWith("created:"));
                    const created = entity.observations.find(o => o.startsWith("created:"))?.substring(8) || "Unknown";
                    const status = entity.observations.find(o => o.startsWith("status:"))?.substring(7) || "active";
                    // Format code groups
                    const codeGroupsText = codedData.codeGroups?.map((group) => {
                        const description = group.observations.find(o => !o.startsWith("created:"));
                        return `- **${group.name}**: ${description || "No description"}`;
                    }).join("\n") || "Not part of any code groups";
                    // Format quotes
                    const quotesText = codedData.quotes?.map((quote) => {
                        const source = quote.observations.find(o => o.startsWith("source:"))?.substring(7) || "Unknown source";
                        const text = quote.observations.find(o => !o.startsWith("source:") && !o.startsWith("context:"));
                        return `- "${text || "No text"}" (Source: ${source})`;
                    }).join("\n") || "No quotes tagged with this code";
                    // Format sources
                    const sourcesText = codedData.sources?.map((source) => {
                        return `- **${source.name}** (${source.entityType})`;
                    }).join("\n") || "No sources found";
                    // Format themes
                    const themesText = codedData.themes?.map((theme) => {
                        const description = theme.observations.find(o => !o.startsWith("status:") && !o.startsWith("created:"));
                        return `- **${theme.name}**: ${description || "No description"}`;
                    }).join("\n") || "Not associated with any themes";
                    // Get co-occurrence data
                    let cooccurrenceData;
                    try {
                        cooccurrenceData = await knowledgeGraphManager.getCodeCooccurrence(entityName);
                        // Format co-occurrence
                        const cooccurrenceText = cooccurrenceData.cooccurringCodes?.map((c) => {
                            return `- **${c.code.name}** (${c.count} co-occurrences)`;
                        }).slice(0, 5).join("\n") || "No code co-occurrence data";
                        contextMessage = `# Code Context: ${entityName}

## Code Details
- **Definition**: ${definition || "No definition provided"}
- **Created**: ${created}
- **Status**: ${status}
- **Items Coded**: ${codedData.quotes?.length || 0}

## Part of Code Groups
${codeGroupsText}

## Supporting Themes
${themesText}

## Top Co-occurring Codes
${cooccurrenceText}

## Example Quotes
${quotesText}

## Used in These Sources
${sourcesText}`;
                    }
                    catch (error) {
                        contextMessage = `# Code Context: ${entityName}

## Code Details
- **Definition**: ${definition || "No definition provided"}
- **Created**: ${created}
- **Status**: ${status}
- **Items Coded**: ${codedData.quotes?.length || 0}

## Part of Code Groups
${codeGroupsText}

## Supporting Themes
${themesText}

## Example Quotes
${quotesText}

## Used in These Sources
${sourcesText}`;
                    }
                }
                else if (entityType === "theme") {
                    // Get thematic analysis data
                    let projectName = "";
                    // Find which project this theme belongs to
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'part_of' && relation.from === entityName) {
                            const project = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                            if (project) {
                                projectName = project.name;
                                break;
                            }
                        }
                    }
                    let thematicAnalysis;
                    try {
                        thematicAnalysis = await knowledgeGraphManager.getThematicAnalysis(projectName);
                        // Find this theme in the analysis
                        const themeAnalysis = thematicAnalysis.themes?.find((t) => t.theme.name === entityName);
                        if (themeAnalysis) {
                            const description = entity.observations.find(o => !o.startsWith("created:") && !o.startsWith("status:"));
                            const status = entity.observations.find(o => o.startsWith("status:"))?.substring(7) || "emerging";
                            const created = entity.observations.find(o => o.startsWith("created:"))?.substring(8) || "Unknown";
                            // Format codes
                            const codesText = themeAnalysis.codes?.map((code) => {
                                const definition = code.observations.find(o => !o.startsWith("status:") && !o.startsWith("created:"));
                                return `- **${code.name}**: ${definition || "No definition"}`;
                            }).join("\n") || "No supporting codes";
                            // Format supporting quotes
                            const quotesText = themeAnalysis.supportingData?.flatMap((codeData) => codeData.quotes.map((quote) => {
                                const text = quote.observations.find(o => !o.startsWith("source:") && !o.startsWith("context:"));
                                return `- "${text || "No text"}" [Code: ${codeData.code.name}]`;
                            })).slice(0, 10).join("\n") || "No supporting quotes";
                            // Format memos
                            const memosText = themeAnalysis.memos?.map((memo) => {
                                const date = memo.observations.find(o => o.startsWith("date:"))?.substring(5) || "Unknown date";
                                const topic = memo.observations.find(o => o.startsWith("topic:"))?.substring(6) || "Untitled";
                                const content = memo.observations.find(o => !o.startsWith("date:") && !o.startsWith("topic:"));
                                return `- **${topic}** (${date}): ${content ? (content.length > 100 ? content.substring(0, 100) + "..." : content) : "No content"}`;
                            }).join("\n") || "No analytical memos about this theme";
                            contextMessage = `# Theme Context: ${entityName}

## Theme Details
- **Description**: ${description || "No description provided"}
- **Status**: ${status}
- **Created**: ${created}
- **Project**: ${projectName || "Not associated with a specific project"}

## Supporting Codes
${codesText}

## Example Supporting Quotes
${quotesText}

## Analytical Memos
${memosText}`;
                        }
                        else {
                            const description = entity.observations.find(o => !o.startsWith("created:") && !o.startsWith("status:"));
                            const status = entity.observations.find(o => o.startsWith("status:"))?.substring(7) || "emerging";
                            contextMessage = `# Theme Context: ${entityName}

## Theme Details
- **Description**: ${description || "No description provided"}
- **Status**: ${status}
- **Project**: ${projectName || "Not associated with a specific project"}

No detailed analysis available for this theme.`;
                        }
                    }
                    catch (error) {
                        const description = entity.observations.find(o => !o.startsWith("created:") && !o.startsWith("status:"));
                        const status = entity.observations.find(o => o.startsWith("status:"))?.substring(7) || "emerging";
                        contextMessage = `# Theme Context: ${entityName}

## Theme Details
- **Description**: ${description || "No description provided"}
- **Status**: ${status}
- **Project**: ${projectName || "Not associated with a specific project"}

No detailed analysis available for this theme.`;
                    }
                }
                else if (entityType === "memo") {
                    // Get memo details
                    const topic = entity.observations.find(o => o.startsWith("topic:"))?.substring(6) || "Untitled";
                    const date = entity.observations.find(o => o.startsWith("date:"))?.substring(5) || "Unknown date";
                    const content = entity.observations.find(o => !o.startsWith("topic:") && !o.startsWith("date:"));
                    // Find what this memo reflects on
                    const relatedEntities = [];
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'reflects_on' && relation.from === entityName) {
                            const relatedEntity = entityGraph.entities.find(e => e.name === relation.to);
                            if (relatedEntity) {
                                relatedEntities.push(relatedEntity);
                            }
                        }
                    }
                    // Find which project this memo belongs to
                    let projectName = 'Unknown project';
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'part_of' && relation.from === entityName) {
                            const project = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                            if (project) {
                                projectName = project.name;
                                break;
                            }
                        }
                    }
                    // Format related entities
                    const relatedText = relatedEntities.map((e) => `- **${e.name}** (${e.entityType})`).join("\n") || "Not specifically linked to any entities";
                    contextMessage = `# Memo Context: ${entityName}

## Memo Details
- **Topic**: ${topic}
- **Date**: ${date}
- **Project**: ${projectName}

## Content
${content || "No content available"}

## Related Entities
${relatedText}`;
                }
                else if (entityType === "researchQuestion") {
                    // Find which project this research question belongs to
                    let projectName = 'Unknown project';
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'part_of' && relation.from === entityName) {
                            const project = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                            if (project) {
                                projectName = project.name;
                                break;
                            }
                        }
                    }
                    // Get research question analysis
                    let analysisData;
                    try {
                        analysisData = await knowledgeGraphManager.getResearchQuestionAnalysis(projectName);
                        // Find this question in the analysis
                        const questionAnalysis = analysisData.researchQuestions?.find((q) => q.question.name === entityName);
                        if (questionAnalysis) {
                            // Format findings
                            const findingsText = questionAnalysis.findings?.map((finding) => {
                                const status = finding.observations.find(o => o.startsWith("status:"))?.substring(7) || "preliminary";
                                const description = finding.observations.find(o => !o.startsWith("status:") && !o.startsWith("created:"));
                                return `- **${finding.name}** (${status}): ${description || "No description"}`;
                            }).join("\n") || "No findings recorded yet";
                            // Format themes
                            const themesText = questionAnalysis.themes?.map((theme) => {
                                const description = theme.observations.find(o => !o.startsWith("status:") && !o.startsWith("created:"));
                                return `- **${theme.name}**: ${description || "No description"}`;
                            }).join("\n") || "No themes associated with this question";
                            // Format quotes
                            const quotesText = questionAnalysis.quotes?.map((quote) => {
                                const source = quote.observations.find(o => o.startsWith("source:"))?.substring(7) || "Unknown source";
                                const text = quote.observations.find(o => !o.startsWith("source:") && !o.startsWith("context:"));
                                return `- "${text || "No text"}" (Source: ${source})`;
                            }).slice(0, 5).join("\n") || "No direct quotes addressing this question";
                            contextMessage = `# Research Question Context: ${entityName}

## Question
${entity.observations.find(o => !o.startsWith("created:")) || entityName}

## Project
${projectName}

## Findings
${findingsText}

## Related Themes
${themesText}

## Supporting Quotes
${quotesText}`;
                        }
                        else {
                            contextMessage = `# Research Question Context: ${entityName}

## Question
${entity.observations.find(o => !o.startsWith("created:")) || entityName}

## Project
${projectName}

No analysis data available for this research question.`;
                        }
                    }
                    catch (error) {
                        contextMessage = `# Research Question Context: ${entityName}

## Question
${entity.observations.find(o => !o.startsWith("created:")) || entityName}

## Project
${projectName}

No analysis data available for this research question.`;
                    }
                }
                else {
                    // Generic entity context for other entity types
                    // Get related entities
                    const relatedEntitiesData = await knowledgeGraphManager.getRelatedEntities(entityName);
                    // Format observations
                    const observationsText = entity.observations.map((obs) => `- ${obs}`).join("\n") || "No observations";
                    // Format related entities
                    const relatedText = Object.entries(relatedEntitiesData.related || {}).map(([relation, entities]) => {
                        const entitiesList = entities.map(e => `- **${e.name}** (${e.entityType})`).join("\n");
                        return `### ${relation} (${entities.length})\n${entitiesList}`;
                    }).join("\n\n") || "No related entities found";
                    contextMessage = `# Entity Context: ${entityName} (${entityType})

## Observations
${observationsText}

## Related Entities
${relatedText}`;
                }
                return {
                    content: [{
                            type: "text",
                            text: contextMessage
                        }]
                };
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        // Helper function to process each stage of endsession
        async function processStage(params, previousStages) {
            // Process based on the stage
            switch (params.stage) {
                case "summary":
                    // Process summary stage
                    return {
                        stage: "summary",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || {
                            summary: "",
                            duration: "",
                            project: ""
                        },
                        completed: !params.nextStageNeeded
                    };
                case "interviewData":
                    // Process interview data stage
                    return {
                        stage: "interviewData",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { interviews: [] },
                        completed: !params.nextStageNeeded
                    };
                case "memos":
                    // Process memos stage
                    return {
                        stage: "memos",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { memos: [] },
                        completed: !params.nextStageNeeded
                    };
                case "codingActivity":
                    // Process coding activity stage
                    return {
                        stage: "codingActivity",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { codes: [] },
                        completed: !params.nextStageNeeded
                    };
                case "themes":
                    // Process themes stage
                    return {
                        stage: "themes",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { themes: [] },
                        completed: !params.nextStageNeeded
                    };
                case "projectStatus":
                    // Process project status stage
                    return {
                        stage: "projectStatus",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || {
                            projectStatus: "",
                            projectObservation: ""
                        },
                        completed: !params.nextStageNeeded
                    };
                case "assembly":
                    // Final assembly stage - compile all arguments for end-session
                    return {
                        stage: "assembly",
                        stageNumber: params.stageNumber,
                        analysis: "Final assembly of end-session arguments",
                        stageData: assembleEndSessionArgs(previousStages),
                        completed: true
                    };
                default:
                    throw new Error(`Unknown stage: ${params.stage}`);
            }
        }
        // Helper function to assemble the final end-session arguments
        function assembleEndSessionArgs(stages) {
            const summaryStage = stages.find(s => s.stage === "summary");
            const interviewDataStage = stages.find(s => s.stage === "interviewData");
            const memosStage = stages.find(s => s.stage === "memos");
            const codingActivityStage = stages.find(s => s.stage === "codingActivity");
            const themesStage = stages.find(s => s.stage === "themes");
            const projectStatusStage = stages.find(s => s.stage === "projectStatus");
            return {
                summary: summaryStage?.stageData?.summary || "",
                duration: summaryStage?.stageData?.duration || "unknown",
                project: summaryStage?.stageData?.project || "",
                interviewData: JSON.stringify(interviewDataStage?.stageData?.interviews || []),
                newMemos: JSON.stringify(memosStage?.stageData?.memos || []),
                codingActivity: JSON.stringify(codingActivityStage?.stageData?.codes || []),
                newThemes: JSON.stringify(themesStage?.stageData?.themes || []),
                projectStatus: projectStatusStage?.stageData?.projectStatus || "",
                projectObservation: projectStatusStage?.stageData?.projectObservation || ""
            };
        }
        /**
         * End session by processing all stages and recording the final results.
         * Only use this tool if the user asks for it.
         *
         * Usage examples:
         *
         * 1. Starting the end session process with the summary stage:
         * {
         *   "sessionId": "qual_1234567890_abc123",  // From startsession
         *   "stage": "summary",
         *   "stageNumber": 1,
         *   "totalStages": 6,
         *   "analysis": "Analyzed progress on the interview data coding",
         *   "stageData": {
         *     "summary": "Completed initial coding of participant interviews",
         *     "duration": "3 hours",
         *     "project": "Health Behavior Study"  // Project name
         *   },
         *   "nextStageNeeded": true,  // More stages coming
         *   "isRevision": false
         * }
         *
         * 2. Middle stage for themes:
         * {
         *   "sessionId": "qual_1234567890_abc123",
         *   "stage": "themes",
         *   "stageNumber": 2,
         *   "totalStages": 6,
         *   "analysis": "Identified emerging themes",
         *   "stageData": {
         *     "themes": [
         *       { "name": "Perceived Barriers", "codes": ["time_constraints", "financial_concerns"], "description": "Factors preventing healthy behaviors" },
         *       { "name": "Social Support", "codes": ["family_influence", "peer_encouragement"], "description": "External motivation from relationships" }
         *     ]
         *   },
         *   "nextStageNeeded": true,
         *   "isRevision": false
         * }
         *
         * 3. Final assembly stage:
         * {
         *   "sessionId": "qual_1234567890_abc123",
         *   "stage": "assembly",
         *   "stageNumber": 6,
         *   "totalStages": 6,
         *   "nextStageNeeded": false,  // This completes the session
         *   "isRevision": false
         * }
         */
        server.tool("endsession", toolDescriptions["endsession"], {
            sessionId: z.string().describe("The unique session identifier obtained from startsession"),
            stage: z.string().describe("Current stage of analysis: 'summary', 'themes', 'codes', 'memos', 'participantInsights', or 'assembly'"),
            stageNumber: z.number().int().positive().describe("The sequence number of the current stage (starts at 1)"),
            totalStages: z.number().int().positive().describe("Total number of stages in the workflow (typically 6 for standard workflow)"),
            analysis: z.string().optional().describe("Text analysis or observations for the current stage"),
            stageData: z.record(z.string(), z.any()).optional().describe(`Stage-specific data structure - format depends on the stage type:
        - For 'summary' stage: { summary: "Session summary text", duration: "3 hours", project: "Project Name" }
        - For 'themes' stage: { themes: [{ name: "Theme1", codes: ["code1", "code2"], description: "Theme description" }] }
        - For 'codes' stage: { codes: [{ name: "Code1", description: "Code meaning", quotes: ["Quote text"] }] }
        - For 'memos' stage: { memos: [{ title: "Memo title", content: "Detailed memo text", tags: ["tag1", "tag2"] }] }
        - For 'participantInsights' stage: { insights: [{ participant: "P1", observation: "Key insight about participant" }] }
        - For 'assembly' stage: no stageData needed - automatic assembly of previous stages`),
            nextStageNeeded: z.boolean().describe("Whether additional stages are needed after this one (false for final stage)"),
            isRevision: z.boolean().optional().describe("Whether this is revising a previous stage"),
            revisesStage: z.number().int().positive().optional().describe("If revising, which stage number is being revised")
        }, async (params) => {
            try {
                // Load session states from persistent storage
                const sessionStates = await loadSessionStates();
                // Validate session ID
                if (!sessionStates.has(params.sessionId)) {
                    return {
                        content: [{
                                type: "text",
                                text: JSON.stringify({
                                    success: false,
                                    error: `Session with ID ${params.sessionId} not found. Please start a new session with startsession.`
                                }, null, 2)
                            }]
                    };
                }
                // Get or initialize session state
                let sessionState = sessionStates.get(params.sessionId) || [];
                // Process the current stage
                const stageResult = await processStage(params, sessionState);
                // Store updated state
                if (params.isRevision && params.revisesStage) {
                    // Find the analysis stages in the session state
                    const analysisStages = sessionState.filter(item => item.type === 'analysis_stage') || [];
                    if (params.revisesStage <= analysisStages.length) {
                        // Replace the revised stage
                        analysisStages[params.revisesStage - 1] = {
                            type: 'analysis_stage',
                            ...stageResult
                        };
                    }
                    else {
                        // Add as a new stage
                        analysisStages.push({
                            type: 'analysis_stage',
                            ...stageResult
                        });
                    }
                    // Update the session state with the modified analysis stages
                    sessionState = [
                        ...sessionState.filter(item => item.type !== 'analysis_stage'),
                        ...analysisStages
                    ];
                }
                else {
                    // Add new stage
                    sessionState.push({
                        type: 'analysis_stage',
                        ...stageResult
                    });
                }
                // Update in persistent storage
                sessionStates.set(params.sessionId, sessionState);
                await saveSessionStates(sessionStates);
                // Check if this is the final assembly stage and no more stages are needed
                if (params.stage === "assembly" && !params.nextStageNeeded) {
                    // Get the assembled arguments
                    const args = stageResult.stageData;
                    try {
                        // Parse arguments
                        const summary = args.summary;
                        const duration = args.duration;
                        const project = args.project;
                        const interviewData = args.interviewData ? JSON.parse(args.interviewData) : [];
                        const newMemos = args.newMemos ? JSON.parse(args.newMemos) : [];
                        const codingActivity = args.codingActivity ? JSON.parse(args.codingActivity) : [];
                        const newThemes = args.newThemes ? JSON.parse(args.newThemes) : [];
                        const projectStatus = args.projectStatus;
                        const projectObservation = args.projectObservation;
                        // Update project status using the relation-based approach
                        try {
                            // Set the project status using our helper method
                            if (projectStatus) {
                                await knowledgeGraphManager.setEntityStatus(project, projectStatus);
                            }
                            // Add observation if provided
                            if (projectObservation) {
                                await knowledgeGraphManager.addObservations([{
                                        entityName: project,
                                        contents: [projectObservation]
                                    }]);
                            }
                        }
                        catch (error) {
                            console.error(`Error updating status for project ${project}:`, error);
                        }
                        // Record session completion in persistent storage
                        sessionState.push({
                            type: 'session_completed',
                            timestamp: new Date().toISOString(),
                            project
                        });
                        sessionStates.set(params.sessionId, sessionState);
                        await saveSessionStates(sessionStates);
                        // Prepare the summary message
                        const summaryMessage = `# Qualitative Research Session Recorded

I've recorded your research session focusing on the ${project} project.

## Session Summary
${summary}

${interviewData.length > 0 ? `## Interviews Conducted
${interviewData.map((i) => `- Interview with ${i.participant}`).join('\n')}` : "No interviews were recorded."}

${newMemos.length > 0 ? `## Research Memos Created
${newMemos.map((m) => `- ${m.topic}`).join('\n')}` : "No memos were created."}

${codingActivity.length > 0 ? `## Coding Activity
${codingActivity.map((c) => `- Coded ${c.dataItem} with "${c.code}"${c.note ? `: ${c.note}` : ''}`).join('\n')}` : "No coding was performed."}

${newThemes.length > 0 ? `## Themes Identified
${newThemes.map((t) => `- ${t.name}: ${t.description}`).join('\n')}` : "No themes were identified."}

## Project Status
Project ${project} has been updated to: ${projectStatus}

Would you like me to perform any additional updates to your qualitative research knowledge graph?`;
                        // Return the final result with the session recorded message
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({
                                        success: true,
                                        stageCompleted: params.stage,
                                        nextStageNeeded: false,
                                        stageResult: stageResult,
                                        sessionRecorded: true,
                                        summaryMessage: summaryMessage
                                    }, null, 2)
                                }]
                        };
                    }
                    catch (error) {
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({
                                        success: false,
                                        error: `Error assembling end-session arguments: ${error instanceof Error ? error.message : String(error)}`
                                    }, null, 2)
                                }]
                        };
                    }
                }
                else {
                    // This is not the final stage or more stages are needed
                    // Return intermediate result
                    return {
                        content: [{
                                type: "text",
                                text: JSON.stringify({
                                    success: true,
                                    stageCompleted: params.stage,
                                    nextStageNeeded: params.nextStageNeeded,
                                    stageResult: stageResult,
                                    endSessionArgs: params.stage === "assembly" ? stageResult.stageData : null
                                }, null, 2)
                            }]
                    };
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: `Error recording qualitative research session: ${error instanceof Error ? error.message : String(error)}`
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Start a new session for qualitative research. Returns session ID, recent sessions, active projects, sample participants, top codes, and recent memos.
         * The output allows the user to easily choose what to focus on and which specific context to load.
         */
        server.tool("startsession", toolDescriptions["startsession"], {}, async () => {
            try {
                // Generate a unique session ID
                const sessionId = generateSessionId();
                // Get recent sessions from persistent storage
                const sessionStates = await loadSessionStates();
                // Initialize the session state
                sessionStates.set(sessionId, []);
                await saveSessionStates(sessionStates);
                // Convert sessions map to array and retrieve the most recent sessions
                const recentSessions = Array.from(sessionStates.entries())
                    .map(([id, stages]) => {
                    // Extract summary data from the first stage (if it exists)
                    const summaryStage = stages.find(s => s.stage === "summary");
                    return {
                        id,
                        project: summaryStage?.stageData?.project || "Unknown project",
                        summary: summaryStage?.stageData?.summary || "No summary available"
                    };
                })
                    .slice(0, 3); // Default to showing 3 recent sessions
                // Query for all research projects and filter by status
                const projectsQuery = await knowledgeGraphManager.searchNodes("entityType:project");
                const projects = [];
                // Filter for active projects based on has_status relation
                for (const project of projectsQuery.entities) {
                    const status = await knowledgeGraphManager.getEntityStatus(project.name);
                    if (status === "active" || status === "in_progress" || status === "data_collection" || status === "analysis") {
                        projects.push(project);
                    }
                }
                // Query for a sample of participants
                const participantsQuery = await knowledgeGraphManager.searchNodes("entityType:participant");
                const participants = participantsQuery.entities.slice(0, 5); // Limit to 5 participants for initial display
                // Get all codes
                const codesQuery = await knowledgeGraphManager.searchNodes("entityType:code");
                const codes = codesQuery.entities.slice(0, 10); // Top 10 codes
                // Get recent memos
                const memosQuery = await knowledgeGraphManager.searchNodes("entityType:memo");
                const memos = memosQuery.entities.slice(0, 3); // Most recent 3 memos
                // Format the context information using entity-relation approach
                const projectsText = await Promise.all(projects.map(async (p) => {
                    const status = await knowledgeGraphManager.getEntityStatus(p.name) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(p.name);
                    const priorityText = priority ? `, Priority: ${priority}` : "";
                    // Show truncated preview of first observation
                    const preview = p.observations.length > 0
                        ? `${p.observations[0].substring(0, 60)}${p.observations[0].length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${p.name}** (Status: ${status}${priorityText}): ${preview}`;
                }));
                const participantsText = await Promise.all(participants.map(async (p) => {
                    const status = await knowledgeGraphManager.getEntityStatus(p.name) || "Active";
                    // Show truncated preview of first observation for demographics
                    const preview = p.observations.length > 0
                        ? `${p.observations[0].substring(0, 60)}${p.observations[0].length > 60 ? '...' : ''}`
                        : "No demographics";
                    return `- **${p.name}** (Status: ${status}): ${preview}`;
                }));
                const codesText = await Promise.all(codes.map(async (c) => {
                    const status = await knowledgeGraphManager.getEntityStatus(c.name) || "initial";
                    // Show truncated preview of first observation for description
                    const preview = c.observations.length > 0
                        ? `${c.observations[0].substring(0, 60)}${c.observations[0].length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${c.name}** (Status: ${status}): ${preview}`;
                }));
                const memosText = await Promise.all(memos.map(async (m) => {
                    const status = await knowledgeGraphManager.getEntityStatus(m.name) || "draft";
                    // Show truncated preview of first observation for content
                    const preview = m.observations.length > 0
                        ? `${m.observations[0].substring(0, 60)}${m.observations[0].length > 60 ? '...' : ''}`
                        : "No content";
                    return `- **${m.name}** (Status: ${status}): ${preview}`;
                }));
                const sessionsText = recentSessions.map(s => {
                    return `- ${s.project} - ${s.summary.substring(0, 60)}${s.summary.length > 60 ? '...' : ''}`;
                }).join("\n");
                return {
                    content: [{
                            type: "text",
                            text: `# Choose what to focus on in this session

## Session ID
\`${sessionId}\`

## Recent Research Sessions
${sessionsText || "No recent sessions found."}

## Active Research Projects
${projectsText.join("\n") || "No active projects found."}

## Sample Participants
${participantsText.join("\n") || "No participants found."}

## Top Codes
${codesText.join("\n") || "No codes found."}

## Recent Memos
${memosText.join("\n") || "No memos found."}

To load specific context, use the \`loadcontext\` tool with the entity name and session ID - ${sessionId}`
                        }]
                };
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Create new entities, relations, and observations.
         */
        server.tool("buildcontext", toolDescriptions["buildcontext"], {
            type: z.enum(["entities", "relations", "observations"]).describe("Type of creation operation: 'entities', 'relations', or 'observations'"),
            data: z.array(z.any()).describe("Data for the creation operation, structure varies by type but must be an array")
        }, async ({ type, data }) => {
            try {
                let result;
                switch (type) {
                    case "entities":
                        // Validate entity types
                        for (const entity of data) {
                            if (!validateEntityType(entity.entityType)) {
                                throw new Error(`Invalid entity type: ${entity.entityType}`);
                            }
                        }
                        // Ensure entities match the Entity interface
                        const typedEntities = data.map((e) => ({
                            name: e.name,
                            entityType: e.entityType,
                            observations: e.observations
                        }));
                        result = await knowledgeGraphManager.createEntities(typedEntities);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, created: result }, null, 2)
                                }]
                        };
                    case "relations":
                        // Validate relation types
                        for (const relation of data) {
                            if (!validateRelationType(relation.relationType)) {
                                throw new Error(`Invalid relation type: ${relation.relationType}`);
                            }
                        }
                        // Ensure relations match the Relation interface
                        const typedRelations = data.map((r) => ({
                            from: r.from,
                            to: r.to,
                            relationType: r.relationType
                        }));
                        result = await knowledgeGraphManager.createRelations(typedRelations);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, created: result }, null, 2)
                                }]
                        };
                    case "observations":
                        // For qualitative researcher domain, addObservations takes an array
                        // Ensure observations match the required interface
                        const typedObservations = Array.isArray(data) ? data.map((o) => ({
                            entityName: o.entityName,
                            contents: Array.isArray(o.contents) ? o.contents :
                                Array.isArray(o.observations) ? o.observations : []
                        })) : [data];
                        result = await knowledgeGraphManager.addObservations(typedObservations);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, added: result }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Delete entities, relations, or observations.
         */
        server.tool("deletecontext", toolDescriptions["deletecontext"], {
            type: z.enum(["entities", "relations", "observations"]).describe("Type of deletion operation: 'entities', 'relations', or 'observations'"),
            data: z.array(z.any()).describe("Data for the deletion operation, structure varies by type but must be an array")
        }, async ({ type, data }) => {
            try {
                switch (type) {
                    case "entities":
                        await knowledgeGraphManager.deleteEntities(data);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted ${data.length} entities` }, null, 2)
                                }]
                        };
                    case "relations":
                        // Ensure relations match the Relation interface
                        const typedRelations = data.map((r) => ({
                            from: r.from,
                            to: r.to,
                            relationType: r.relationType
                        }));
                        await knowledgeGraphManager.deleteRelations(typedRelations);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted ${data.length} relations` }, null, 2)
                                }]
                        };
                    case "observations":
                        // Ensure deletions match the required interface
                        const typedDeletions = data.map((d) => ({
                            entityName: d.entityName,
                            observations: d.observations
                        }));
                        await knowledgeGraphManager.deleteObservations(typedDeletions);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted observations from ${data.length} entities` }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Get information about the graph, search for nodes, open nodes, get project overview, get participant profile, get codes, get themes, get transcript, get memo, get analysis, get codebook, or get related entities.
         */
        server.tool("advancedcontext", toolDescriptions["advancedcontext"], {
            type: z.enum([
                "graph",
                "search",
                "nodes",
                "project",
                "participant",
                "codes",
                "themes",
                "transcript",
                "memo",
                "analysis",
                "codebook",
                "related"
            ]).describe("Type of get operation"),
            params: z.record(z.string(), z.any()).describe("Parameters for the get operation, structure varies by type")
        }, async ({ type, params }) => {
            try {
                let result;
                switch (type) {
                    case "graph":
                        result = await knowledgeGraphManager.readGraph();
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, graph: result }, null, 2)
                                }]
                        };
                    case "search":
                        result = await knowledgeGraphManager.searchNodes(params.query);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, results: result }, null, 2)
                                }]
                        };
                    case "nodes":
                        result = await knowledgeGraphManager.openNodes(params.names);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, nodes: result }, null, 2)
                                }]
                        };
                    case "project":
                        result = await knowledgeGraphManager.getProjectOverview(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, project: result }, null, 2)
                                }]
                        };
                    case "participant":
                        result = await knowledgeGraphManager.getParticipantProfile(params.participantName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, participant: result }, null, 2)
                                }]
                        };
                    case "codes":
                        // Use searchNodes for codes instead of a specialized method
                        result = await knowledgeGraphManager.searchNodes(`entityType:code ${params.projectName ? `project:${params.projectName}` : ""}`);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, codes: result }, null, 2)
                                }]
                        };
                    case "themes":
                        // Use searchNodes for themes
                        result = await knowledgeGraphManager.searchNodes(`entityType:theme ${params.projectName ? `project:${params.projectName}` : ""}`);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, themes: result }, null, 2)
                                }]
                        };
                    case "transcript":
                        // Use searchNodes to find the transcript
                        const transcriptQuery = await knowledgeGraphManager.searchNodes(`entityType:transcript participant:${params.participantName} ${params.interviewId ? `interview:${params.interviewId}` : ""}`);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, transcript: transcriptQuery }, null, 2)
                                }]
                        };
                    case "memo":
                        // Use openNodes to get the specific memo
                        const memoResult = await knowledgeGraphManager.openNodes([params.memoName]);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, memo: memoResult }, null, 2)
                                }]
                        };
                    case "analysis":
                        // Use searchNodes to get analysis artifacts
                        const analysisQuery = await knowledgeGraphManager.searchNodes(`entityType:analysis project:${params.projectName}`);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, analysis: analysisQuery }, null, 2)
                                }]
                        };
                    case "codebook":
                        // Use searchNodes to get codebook entries
                        const codebookQuery = await knowledgeGraphManager.searchNodes(`entityType:code project:${params.projectName}`);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, codebook: codebookQuery }, null, 2)
                                }]
                        };
                    case "related":
                        // For the related case, we don't have a specialized method in the manager
                        // So we'll use the generic KnowledgeGraph search capabilities
                        const entityGraph = await knowledgeGraphManager.searchNodes(params.entityName);
                        const entity = entityGraph.entities.find(e => e.name === params.entityName);
                        if (!entity) {
                            throw new Error(`Entity "${params.entityName}" not found`);
                        }
                        // Find related entities
                        const relations = entityGraph.relations.filter(r => r.from === params.entityName || r.to === params.entityName);
                        const relatedNames = relations.map(r => r.from === params.entityName ? r.to : r.from);
                        if (relatedNames.length === 0) {
                            return {
                                content: [{
                                        type: "text",
                                        text: JSON.stringify({ success: true, related: { entity, relatedEntities: [] } }, null, 2)
                                    }]
                            };
                        }
                        const relatedEntitiesGraph = await knowledgeGraphManager.openNodes(relatedNames);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({
                                        success: true,
                                        related: {
                                            entity,
                                            relations,
                                            relatedEntities: relatedEntitiesGraph.entities
                                        }
                                    }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be one of the supported get operation types.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        // Connect the server to the transport
        const transport = new StdioServerTransport();
        await server.connect(transport);
    }
    catch (error) {
        console.error("Error starting server:", error);
        process.exit(1);
    }
}
// Run the main function
main().catch(error => {
    console.error("Unhandled error:", error);
    process.exit(1);
});
// Export the KnowledgeGraphManager for testing
export { KnowledgeGraphManager };

```

--------------------------------------------------------------------------------
/quantitativeresearch/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { z } from "zod";
import { readFileSync, existsSync } from "fs";

// Define memory file path using environment variable with fallback
const parentPath = path.dirname(fileURLToPath(import.meta.url));
const defaultMemoryPath = path.join(parentPath, 'memory.json');
const defaultSessionsPath = path.join(parentPath, 'sessions.json');

// Properly handle absolute and relative paths for MEMORY_FILE_PATH
const MEMORY_FILE_PATH = process.env.MEMORY_FILE_PATH
  ? path.isAbsolute(process.env.MEMORY_FILE_PATH)
    ? process.env.MEMORY_FILE_PATH  // Use absolute path as is
    : path.join(process.cwd(), process.env.MEMORY_FILE_PATH)  // Relative to current working directory
  : defaultMemoryPath;  // Default fallback

// Properly handle absolute and relative paths for SESSIONS_FILE_PATH
const SESSIONS_FILE_PATH = process.env.SESSIONS_FILE_PATH
  ? path.isAbsolute(process.env.SESSIONS_FILE_PATH)
    ? process.env.SESSIONS_FILE_PATH  // Use absolute path as is
    : path.join(process.cwd(), process.env.SESSIONS_FILE_PATH)  // Relative to current working directory
  : defaultSessionsPath;  // Default fallback

// Quantitative Research specific entity types
const VALID_ENTITY_TYPES = [
  'project',          // Overall research study
  'dataset',          // Collection of data used for analysis
  'variable',         // Specific measurable attribute in a dataset
  'hypothesis',       // Formal testable statement
  'statisticalTest',  // Analysis method applied to data
  'result',           // Outcome of statistical analysis
  'analysisScript',   // Code used to perform analysis
  'visualization',    // Visual representation of data
  'model',            // Statistical/mathematical model
  'literature',       // Academic sources
  'researchQuestion', // Formal questions guiding the study
  'finding',          // Results or conclusions
  'participant',      // Research subjects
  'status',           // Entity status values
  'priority'          // Entity priority values
];

// Quantitative Research specific relation types
const VALID_RELATION_TYPES = [
  'contains',             // Project contains datasets, variables, etc.
  'derived_from',         // Results derived from datasets or tests
  'analyzes',             // Test analyzes variables
  'produced_by',          // Visualization produced by script
  'supports',             // Result supports hypothesis
  'contradicts',          // Result contradicts hypothesis
  'based_on',             // Model based on dataset
  'cites',                // Finding cites literature
  'addresses',            // Test addresses research question
  'precedes',             // Entity precedes another in a sequence
  'has_status',           // Entity has status relation
  'has_priority'          // Entity has priority relation
];

// Valid status and priority values
const VALID_STATUS_VALUES = ['active', 'completed', 'pending', 'abandoned'];
const VALID_PRIORITY_VALUES = ['high', 'low'];

// Status values for different entity types in quantitative research
const STATUS_VALUES = {
  project: ['planning', 'data_collection', 'analysis', 'writing', 'complete'],
  dataset: ['raw', 'cleaned', 'transformed', 'analyzed'],
  hypothesis: ['proposed', 'tested', 'supported', 'rejected'],
  statisticalTest: ['planned', 'conducted', 'validated'],
  model: ['specified', 'estimated', 'validated', 'applied'],
  result: ['preliminary', 'verified', 'final'],
  variable: ['defined', 'measured', 'analyzed', 'interpreted']
};

// Basic validation functions
function validateEntityType(entityType: string): boolean {
  return VALID_ENTITY_TYPES.includes(entityType);
}

function validateRelationType(relationType: string): boolean {
  return VALID_RELATION_TYPES.includes(relationType);
}

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Collect tool descriptions from text files
const toolDescriptions: Record<string, string> = {
  'startsession': '',
  'loadcontext': '',
  'deletecontext': '',
  'buildcontext': '',
  'advancedcontext': '',
  'endsession': '',
};
for (const tool of Object.keys(toolDescriptions)) {
  const descriptionFilePath = path.resolve(
    __dirname,
    `quantitativeresearch_${tool}.txt`
  );
  if (existsSync(descriptionFilePath)) {
    toolDescriptions[tool] = readFileSync(descriptionFilePath, 'utf-8');
  }
}

// Session management functions
async function loadSessionStates(): Promise<Map<string, any[]>> {
  try {
    const fileContent = await fs.readFile(SESSIONS_FILE_PATH, 'utf-8');
    const sessions = JSON.parse(fileContent);
    // Convert from object to Map
    const sessionsMap = new Map<string, any[]>();
    for (const [key, value] of Object.entries(sessions)) {
      sessionsMap.set(key, value as any[]);
    }
    return sessionsMap;
  } catch (error) {
    if (error instanceof Error && 'code' in error && (error as any).code === "ENOENT") {
      return new Map<string, any[]>();
    }
    throw error;
  }
}

async function saveSessionStates(sessionsMap: Map<string, any[]>): Promise<void> {
  // Convert from Map to object
  const sessions: Record<string, any[]> = {};
  for (const [key, value] of sessionsMap.entries()) {
    sessions[key] = value;
  }
  await fs.writeFile(SESSIONS_FILE_PATH, JSON.stringify(sessions, null, 2), 'utf-8');
}

// Generate a unique session ID
function generateSessionId(): string {
  return `quant_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
}

// We are storing our memory using entities, relations, and observations in a graph structure
interface Entity {
  name: string;
  entityType: string;
  observations: string[];
}

interface Relation {
  from: string;
  to: string;
  relationType: string;
}

interface KnowledgeGraph {
  entities: Entity[];
  relations: Relation[];
}

// The KnowledgeGraphManager class contains all operations to interact with the knowledge graph
class KnowledgeGraphManager {
  private async loadGraph(): Promise<KnowledgeGraph> {
    try {
      const fileContent = await fs.readFile(MEMORY_FILE_PATH, 'utf-8');
      return JSON.parse(fileContent);
    } catch (error) {
      // If the file doesn't exist, return an empty graph
      return {
        entities: [],
        relations: []
      };
    }
  }

  private async saveGraph(graph: KnowledgeGraph): Promise<void> {
    await fs.writeFile(MEMORY_FILE_PATH, JSON.stringify(graph, null, 2), 'utf-8');
  }

  async createEntities(entities: Entity[]): Promise<Entity[]> {
    const graph = await this.loadGraph();
    const existingEntityNames = new Set(graph.entities.map(e => e.name));
    
    // Validate entity types
    entities.forEach(entity => {
      if (!validateEntityType(entity.entityType)) {
        throw new Error(`Invalid entity type: ${entity.entityType}. Valid types are: ${VALID_ENTITY_TYPES.join(', ')}`);
      }
    });
    
    const newEntities = entities.filter(entity => !existingEntityNames.has(entity.name));
    graph.entities.push(...newEntities);
    
    await this.saveGraph(graph);
    return newEntities;
  }

  async createRelations(relations: Relation[]): Promise<Relation[]> {
    const graph = await this.loadGraph();
    const existingEntityNames = new Set(graph.entities.map(e => e.name));
    
    // Check that entities exist and validate relation types
    relations.forEach(relation => {
      if (!existingEntityNames.has(relation.from)) {
        throw new Error(`Entity '${relation.from}' not found`);
      }
      if (!existingEntityNames.has(relation.to)) {
        throw new Error(`Entity '${relation.to}' not found`);
      }
      if (!validateRelationType(relation.relationType)) {
        throw new Error(`Invalid relation type: ${relation.relationType}. Valid types are: ${VALID_RELATION_TYPES.join(', ')}`);
      }
    });
    
    // Filter out duplicate relations
    const existingRelations = new Set(
      graph.relations.map(r => `${r.from}:${r.to}:${r.relationType}`)
    );
    
    const newRelations = relations.filter(
      r => !existingRelations.has(`${r.from}:${r.to}:${r.relationType}`)
    );
    
    graph.relations.push(...newRelations);
    
    await this.saveGraph(graph);
    return newRelations;
  }

  async addObservations(observations: { entityName: string; contents: string[] }[]): Promise<{ entityName: string; addedObservations: string[] }[]> {
    const graph = await this.loadGraph();
    const results: { entityName: string; addedObservations: string[] }[] = [];
    
    for (const observation of observations) {
      const entity = graph.entities.find(e => e.name === observation.entityName);
      if (!entity) {
        throw new Error(`Entity '${observation.entityName}' not found`);
      }
      
      // Filter out duplicate observations
      const existingObservations = new Set(entity.observations);
      const newObservations = observation.contents.filter(o => !existingObservations.has(o));
      
      entity.observations.push(...newObservations);
      results.push({
        entityName: observation.entityName,
        addedObservations: newObservations
      });
    }
    
    await this.saveGraph(graph);
    return results;
  }

  async deleteEntities(entityNames: string[]): Promise<void> {
    const graph = await this.loadGraph();
    
    // Remove the entities
    graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
    
    // Remove relations that involve the deleted entities
    graph.relations = graph.relations.filter(
      r => !entityNames.includes(r.from) && !entityNames.includes(r.to)
    );
    
    await this.saveGraph(graph);
  }

  async deleteObservations(deletions: { entityName: string; observations: string[] }[]): Promise<void> {
    const graph = await this.loadGraph();
    
    for (const deletion of deletions) {
      const entity = graph.entities.find(e => e.name === deletion.entityName);
      if (entity) {
        // Remove the specified observations
        entity.observations = entity.observations.filter(
          o => !deletion.observations.includes(o)
        );
      }
    }
    
    await this.saveGraph(graph);
  }

  async deleteRelations(relations: Relation[]): Promise<void> {
    const graph = await this.loadGraph();
    
    // Remove specified relations
    graph.relations = graph.relations.filter(r => 
      !relations.some(toDelete => 
        r.from === toDelete.from && 
        r.to === toDelete.to && 
        r.relationType === toDelete.relationType
      )
    );
    
    await this.saveGraph(graph);
  }

  async readGraph(): Promise<KnowledgeGraph> {
    return this.loadGraph();
  }

  async searchNodes(query: string): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();
    
    // Split query into search terms
    const terms = query.toLowerCase().split(/\s+/);
    
    // Find matching entities
    const matchingEntityNames = new Set<string>();
    
    for (const entity of graph.entities) {
      // Check if all terms match
      const matchesAllTerms = terms.every(term => {
        // Check entity name
        if (entity.name.toLowerCase().includes(term)) {
          return true;
        }
        
        // Check entity type
        if (entity.entityType.toLowerCase().includes(term)) {
          return true;
        }
        
        // Check observations
        for (const observation of entity.observations) {
          if (observation.toLowerCase().includes(term)) {
            return true;
          }
        }
        
        return false;
      });
      
      if (matchesAllTerms) {
        matchingEntityNames.add(entity.name);
      }
    }
    
    // Find relations between matching entities
    const matchingRelations = graph.relations.filter(r => 
      matchingEntityNames.has(r.from) && matchingEntityNames.has(r.to)
    );
    
    // Return matching entities and their relations
    return {
      entities: graph.entities.filter(e => matchingEntityNames.has(e.name)),
      relations: matchingRelations
    };
  }

  async openNodes(names: string[]): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();
    
    // Find the specified entities
    const entities = graph.entities.filter(e => names.includes(e.name));
    
    // Find relations between the specified entities
    const relations = graph.relations.filter(r => 
      names.includes(r.from) && names.includes(r.to)
    );
    
    return {
      entities,
      relations
    };
  }

  // Get project overview including research questions, methodology, datasets
  async getProjectOverview(projectName: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the project
    const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
    if (!project) {
      throw new Error(`Project '${projectName}' not found`);
    }
    
    // Find research questions
    const researchQuestions: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const question = graph.entities.find(
          e => e.name === relation.from && e.entityType === 'researchQuestion'
        );
        if (question) {
          researchQuestions.push(question);
        }
      }
    }
    
    // Find datasets
    const datasets: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const dataset = graph.entities.find(
          e => e.name === relation.from && e.entityType === 'dataset'
        );
        if (dataset) {
          datasets.push(dataset);
        }
      }
    }
    
    // Find hypotheses
    const hypotheses: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const hypothesis = graph.entities.find(
          e => e.name === relation.from && e.entityType === 'hypothesis'
        );
        if (hypothesis) {
          hypotheses.push(hypothesis);
        }
      }
    }
    
    // Find statistical models
    const models: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const model = graph.entities.find(
          e => e.name === relation.from && e.entityType === 'model'
        );
        if (model) {
          models.push(model);
        }
      }
    }
    
    // Find findings
    const findings: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const finding = graph.entities.find(
          e => e.name === relation.from && e.entityType === 'finding'
        );
        if (finding) {
          findings.push(finding);
        }
      }
    }
    
    // Get methodology info from project observations
    const methodologyObs = project.observations.filter(
      o => o.toLowerCase().includes('method') || 
           o.toLowerCase().includes('approach') ||
           o.toLowerCase().includes('design')
    );
    
    // Get participant information
    const participantInfo = project.observations.filter(
      o => o.toLowerCase().includes('participant') || 
           o.toLowerCase().includes('sample') ||
           o.toLowerCase().includes('subject')
    );
    
    // Count variables across all datasets
    let totalVariables = 0;
    for (const dataset of datasets) {
      const datasetVariables: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'contains' && relation.from === dataset.name) {
          const variable = graph.entities.find(
            e => e.name === relation.to && e.entityType === 'variable'
          );
          if (variable) {
            datasetVariables.push(variable);
          }
        }
      }
      totalVariables += datasetVariables.length;
    }
    
    return {
      project,
      researchQuestions,
      methodology: methodologyObs,
      participants: participantInfo,
      dataCollection: {
        datasets: datasets.length,
        totalVariables,
        datasetList: datasets
      },
      analysis: {
        hypotheses: hypotheses.length,
        models: models.length,
        hypothesisList: hypotheses,
        modelsList: models
      },
      findings
    };
  }

  // Get all variables, descriptive statistics, and analyses for a dataset
  async getDatasetAnalysis(datasetName: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the dataset
    const dataset = graph.entities.find(e => e.name === datasetName && e.entityType === 'dataset');
    if (!dataset) {
      throw new Error(`Dataset '${datasetName}' not found`);
    }
    
    // Find variables in this dataset
    const variables: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'contains' && relation.from === datasetName) {
        const variable = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
        if (variable) {
          variables.push(variable);
        }
      }
    }
    
    // Find statistical tests performed on this dataset
    const statisticalTests: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'analyzes' && relation.to === datasetName) {
        const test = graph.entities.find(e => e.name === relation.from && e.entityType === 'statisticalTest');
        if (test) {
          statisticalTests.push(test);
        }
      }
    }
    
    // Find models that use this dataset
    const models: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'analyzes' && relation.to === datasetName) {
        const model = graph.entities.find(e => e.name === relation.from && e.entityType === 'model');
        if (model) {
          models.push(model);
        }
      }
    }
    
    // Find visualizations of this dataset
    const visualizations: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'visualizes' && relation.to === datasetName) {
        const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
        if (visualization) {
          visualizations.push(visualization);
        }
      }
    }
    
    // Extract dataset metadata
    const sizeObs = dataset.observations.find(o => o.startsWith('Size:') || o.startsWith('n=') || o.startsWith('N='));
    const size = sizeObs ? sizeObs.split(':')[1]?.trim() || sizeObs.split('=')[1]?.trim() : 'unknown';
    
    const sourceObs = dataset.observations.find(o => o.startsWith('Source:'));
    const source = sourceObs ? sourceObs.split(':')[1].trim() : 'unknown';
    
    const dateObs = dataset.observations.find(o => o.startsWith('Date:') || o.startsWith('Collected:'));
    const date = dateObs ? dateObs.split(':')[1].trim() : 'unknown';
    
    const statusObs = dataset.observations.find(o => o.startsWith('Status:'));
    const status = statusObs ? statusObs.split(':')[1].trim() : 'unknown';
    
    // Organize variables by type
    const independentVariables = variables.filter(v => 
      v.observations.some(o => o.toLowerCase().includes('independent') || 
                               o.toLowerCase().includes('predictor') ||
                               o.toLowerCase().includes('iv'))
    );
    
    const dependentVariables = variables.filter(v => 
      v.observations.some(o => o.toLowerCase().includes('dependent') || 
                               o.toLowerCase().includes('outcome') ||
                               o.toLowerCase().includes('dv'))
    );
    
    const controlVariables = variables.filter(v => 
      v.observations.some(o => o.toLowerCase().includes('control') || o.toLowerCase().includes('covariate'))
    );
    
    const otherVariables = variables.filter(v => 
      !independentVariables.includes(v) && !dependentVariables.includes(v) && !controlVariables.includes(v)
    );
    
    return {
      dataset,
      metadata: {
        size,
        source,
        date,
        status
      },
      variables: {
        count: variables.length,
        independent: independentVariables,
        dependent: dependentVariables,
        control: controlVariables,
        other: otherVariables
      },
      analysis: {
        statisticalTests,
        models,
        visualizations
      }
    };
  }

  // Get hypotheses with associated tests and results
  async getHypothesisTests(projectName: string, hypothesisName?: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the project
    const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
    if (!project) {
      throw new Error(`Project '${projectName}' not found`);
    }
    
    // Get all hypotheses for this project, or a specific one if specified
    let hypotheses: Entity[] = [];
    
    if (hypothesisName) {
      // Find the specific hypothesis
      const hypothesis = graph.entities.find(e => e.name === hypothesisName && e.entityType === 'hypothesis');
      if (!hypothesis) {
        throw new Error(`Hypothesis '${hypothesisName}' not found`);
      }
      hypotheses.push(hypothesis);
    } else {
      // Find all hypotheses for this project
      for (const relation of graph.relations) {
        if (relation.relationType === 'part_of' && relation.to === projectName) {
          const hypothesis = graph.entities.find(e => e.name === relation.from && e.entityType === 'hypothesis');
          if (hypothesis) {
            hypotheses.push(hypothesis);
          }
        }
      }
    }
    
    // For each hypothesis, find tests and results
    const hypothesisAnalyses = hypotheses.map(hypothesis => {
      // Find statistical tests for this hypothesis
      const tests: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'tests' && relation.to === hypothesis.name) {
          const test = graph.entities.find(e => e.name === relation.from && e.entityType === 'statisticalTest');
          if (test) {
            tests.push(test);
          }
        }
      }
      
      // For each test, find its results
      const testResults = tests.map(test => {
        const results: Entity[] = [];
        for (const relation of graph.relations) {
          if (relation.relationType === 'produces' && relation.from === test.name) {
            const result = graph.entities.find(e => e.name === relation.to && e.entityType === 'result');
            if (result) {
              results.push(result);
            }
          }
        }
        
        return {
          test,
          results
        };
      });
      
      // Extract hypothesis status from observations
      const statusObs = hypothesis.observations.find(o => o.startsWith('Status:'));
      const status = statusObs ? statusObs.split(':')[1].trim() : 'unknown';
      
      // Determine if hypothesis is supported based on results
      const isSupported = status === 'supported';
      
      return {
        hypothesis,
        status,
        isSupported,
        tests: testResults
      };
    });
    
    return {
      project,
      hypotheses: hypothesisAnalyses
    };
  }

  // Get relationships between variables (correlations, predictions, moderations)
  async getVariableRelationships(variableName: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the variable
    const variable = graph.entities.find(e => e.name === variableName && e.entityType === 'variable');
    if (!variable) {
      throw new Error(`Variable '${variableName}' not found`);
    }
    
    // Find which dataset this variable is part of
    const datasets: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'contains' && relation.to === variableName) {
        const dataset = graph.entities.find(e => e.name === relation.from && e.entityType === 'dataset');
        if (dataset) {
          datasets.push(dataset);
        }
      }
    }
    
    // Find correlations
    const correlations: { variable: Entity; strength: string; direction: string }[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'correlates_with' && 
         (relation.from === variableName || relation.to === variableName)) {
        
        // Get the other variable in the correlation
        const otherVariableName = relation.from === variableName ? relation.to : relation.from;
        const otherVariable = graph.entities.find(e => e.name === otherVariableName && e.entityType === 'variable');
        
        if (otherVariable) {
          // Look for correlation strength and direction in observations
          const strengthObs = otherVariable.observations.find(o => o.includes(`correlation with ${variableName}`));
          let strength = 'unknown';
          let direction = 'unknown';
          
          if (strengthObs) {
            // Try to extract strength (weak, moderate, strong)
            if (strengthObs.toLowerCase().includes('weak')) {
              strength = 'weak';
            } else if (strengthObs.toLowerCase().includes('moderate')) {
              strength = 'moderate';
            } else if (strengthObs.toLowerCase().includes('strong')) {
              strength = 'strong';
            }
            
            // Try to extract direction (positive, negative)
            if (strengthObs.toLowerCase().includes('positive')) {
              direction = 'positive';
            } else if (strengthObs.toLowerCase().includes('negative')) {
              direction = 'negative';
            }
          }
          
          correlations.push({
            variable: otherVariable,
            strength,
            direction
          });
        }
      }
    }
    
    // Find prediction relationships (as predictor)
    const predicts: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'predicts' && relation.from === variableName) {
        const outcome = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
        if (outcome) {
          predicts.push(outcome);
        }
      }
    }
    
    // Find prediction relationships (as outcome)
    const predictedBy: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'predicts' && relation.to === variableName) {
        const predictor = graph.entities.find(e => e.name === relation.from && e.entityType === 'variable');
        if (predictor) {
          predictedBy.push(predictor);
        }
      }
    }
    
    // Find moderation relationships
    const moderates: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'moderates' && relation.from === variableName) {
        const relationship = graph.entities.find(e => e.name === relation.to);
        if (relationship) {
          moderates.push(relationship);
        }
      }
    }
    
    // Find mediation relationships
    const mediates: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'mediates' && relation.from === variableName) {
        const relationship = graph.entities.find(e => e.name === relation.to);
        if (relationship) {
          mediates.push(relationship);
        }
      }
    }
    
    // Find statistical tests involving this variable
    const statisticalTests: Entity[] = [];
    for (const relation of graph.relations) {
      if ((relation.from === variableName || relation.to === variableName) &&
          (relation.relationType === 'analyzes' || relation.relationType === 'tests')) {
        const test = graph.entities.find(e => 
          e.name === (relation.relationType === 'analyzes' ? relation.from : relation.to) && 
          e.entityType === 'statisticalTest'
        );
        if (test) {
          statisticalTests.push(test);
        }
      }
    }
    
    // Get variable metadata
    const typeObs = variable.observations.find(o => o.startsWith('Type:') || o.startsWith('Data Type:'));
    const dataType = typeObs ? typeObs.split(':')[1].trim() : 'unknown';
    
    const roleObs = variable.observations.find(o => o.startsWith('Role:'));
    const role = roleObs ? roleObs.split(':')[1].trim() : 'unknown';
    
    const descriptionObs = variable.observations.find(o => o.startsWith('Description:'));
    const description = descriptionObs ? descriptionObs.split(':')[1].trim() : 'unknown';
    
    return {
      variable,
      datasets,
      metadata: {
        dataType,
        role,
        description
      },
      relationships: {
        correlations,
        predicts,
        predictedBy,
        moderates,
        mediates
      },
      statisticalTests
    };
  }

  // Shows results organized by statistical tests
  async getStatisticalResults(projectName: string, testType?: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the project
    const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
    if (!project) {
      throw new Error(`Project '${projectName}' not found`);
    }
    
    // Find all statistical tests for this project
    let statisticalTests: Entity[] = [];
    
    // First, get all tests directly part of the project
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const test = graph.entities.find(e => e.name === relation.from && e.entityType === 'statisticalTest');
        if (test) {
          statisticalTests.push(test);
        }
      }
    }
    
    // Also include tests associated with project datasets
    const projectDatasets: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.to === projectName) {
        const dataset = graph.entities.find(e => e.name === relation.from && e.entityType === 'dataset');
        if (dataset) {
          projectDatasets.push(dataset);
        }
      }
    }
    
    for (const dataset of projectDatasets) {
      for (const relation of graph.relations) {
        if (relation.relationType === 'analyzes' && relation.to === dataset.name) {
          const test = graph.entities.find(e => e.name === relation.from && e.entityType === 'statisticalTest');
          if (test && !statisticalTests.some(t => t.name === test.name)) {
            statisticalTests.push(test);
          }
        }
      }
    }
    
    // Filter by test type if specified
    if (testType) {
      statisticalTests = statisticalTests.filter(test => 
        test.observations.some(o => o.toLowerCase().includes(testType.toLowerCase()))
      );
    }
    
    // For each test, get its details and results
    const testResults = statisticalTests.map(test => {
      // Find which hypothesis this test is related to, if any
      const hypotheses: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'tests' && relation.from === test.name) {
          const hypothesis = graph.entities.find(e => e.name === relation.to && e.entityType === 'hypothesis');
          if (hypothesis) {
            hypotheses.push(hypothesis);
          }
        }
      }
      
      // Find which dataset this test analyzes
      const datasets: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'analyzes' && relation.from === test.name) {
          const dataset = graph.entities.find(e => e.name === relation.to && e.entityType === 'dataset');
          if (dataset) {
            datasets.push(dataset);
          }
        }
      }
      
      // Find which variables are included in this test
      const variables: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'analyzes' && relation.from === test.name) {
          const variable = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
          if (variable) {
            variables.push(variable);
          }
        }
      }
      
      // Find results produced by this test
      const results: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'produces' && relation.from === test.name) {
          const result = graph.entities.find(e => e.name === relation.to && e.entityType === 'result');
          if (result) {
            results.push(result);
          }
        }
      }
      
      // Extract test metadata
      const typeObs = test.observations.find(o => o.startsWith('Type:'));
      const type = typeObs ? typeObs.split(':')[1].trim() : 'unknown';
      
      const statusObs = test.observations.find(o => o.startsWith('Status:'));
      const status = statusObs ? statusObs.split(':')[1].trim() : 'unknown';
      
      const significanceObs = results.flatMap(r => r.observations).find(o => 
        o.toLowerCase().includes('p value:') || 
        o.toLowerCase().includes('p-value:') || 
        o.toLowerCase().includes('significance:')
      );
      const significance = significanceObs ? significanceObs.split(':')[1].trim() : 'unknown';
      
      // Check if result is significant
      const isSignificant = significance !== 'unknown' && 
                            (significance.toLowerCase().includes('significant') ||
                             (significance.includes('p') && significance.includes('<') && significance.includes('0.05')));
      
      return {
        test,
        type,
        status,
        hypotheses,
        datasets,
        variables,
        results,
        significance,
        isSignificant
      };
    });
    
    // Group tests by type
    const testsByType: { [key: string]: any[] } = {};
    testResults.forEach(result => {
      if (!testsByType[result.type]) {
        testsByType[result.type] = [];
      }
      testsByType[result.type].push(result);
    });
    
    return {
      project,
      testResults,
      testsByType,
      significantResults: testResults.filter(r => r.isSignificant)
    };
  }

  // Returns all visualizations for a project or specific dataset
  async getVisualizationGallery(projectName: string, datasetName?: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the project
    const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
    if (!project) {
      throw new Error(`Project '${projectName}' not found`);
    }
    
    // Find dataset if specified
    let dataset: Entity | undefined;
    if (datasetName) {
      dataset = graph.entities.find(e => e.name === datasetName && e.entityType === 'dataset');
      if (!dataset) {
        throw new Error(`Dataset '${datasetName}' not found`);
      }
    }
    
    // Find visualizations for this project or dataset
    const visualizations: Entity[] = [];
    
    // If dataset is specified, get only visualizations for that dataset
    if (dataset) {
      for (const relation of graph.relations) {
        if (relation.relationType === 'visualizes' && relation.to === datasetName) {
          const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
          if (visualization) {
            visualizations.push(visualization);
          }
        }
      }
    } else {
      // Get visualizations related to any project dataset
      const projectDatasets: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'part_of' && relation.to === projectName) {
          const dataset = graph.entities.find(e => e.name === relation.from && e.entityType === 'dataset');
          if (dataset) {
            projectDatasets.push(dataset);
          }
        }
      }
      
      for (const dataset of projectDatasets) {
        for (const relation of graph.relations) {
          if (relation.relationType === 'visualizes' && relation.to === dataset.name) {
            const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
            if (visualization && !visualizations.some(v => v.name === visualization.name)) {
              visualizations.push(visualization);
            }
          }
        }
      }
      
      // Also include visualizations of model results
      const projectModels: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'part_of' && relation.to === projectName) {
          const model = graph.entities.find(e => e.name === relation.from && e.entityType === 'model');
          if (model) {
            projectModels.push(model);
          }
        }
      }
      
      for (const model of projectModels) {
        for (const relation of graph.relations) {
          if (relation.relationType === 'visualizes' && relation.to === model.name) {
            const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
            if (visualization && !visualizations.some(v => v.name === visualization.name)) {
              visualizations.push(visualization);
            }
          }
        }
      }
    }
    
    // Group visualizations by type
    const visualizationsByType: { [key: string]: Entity[] } = {};
    
    for (const visualization of visualizations) {
      const typeObs = visualization.observations.find(o => o.startsWith('Type:'));
      const type = typeObs ? typeObs.split(':')[1].trim() : 'Other';
      
      if (!visualizationsByType[type]) {
        visualizationsByType[type] = [];
      }
      
      visualizationsByType[type].push(visualization);
    }
    
    // Get information about what variables are visualized
    const visualizationDetails = visualizations.map(visualization => {
      // Find which variables are visualized
      const variables: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'visualizes' && relation.from === visualization.name) {
          const variable = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
          if (variable) {
            variables.push(variable);
          }
        }
      }
      
      // Extract visualization metadata
      const typeObs = visualization.observations.find(o => o.startsWith('Type:'));
      const type = typeObs ? typeObs.split(':')[1].trim() : 'unknown';
      
      const titleObs = visualization.observations.find(o => o.startsWith('Title:'));
      const title = titleObs ? titleObs.split(':')[1].trim() : visualization.name;
      
      const descriptionObs = visualization.observations.find(o => o.startsWith('Description:'));
      const description = descriptionObs ? descriptionObs.split(':')[1].trim() : '';
      
      return {
        visualization,
        type,
        title,
        description,
        variables
      };
    });
    
    return {
      project,
      dataset,
      visualizations: visualizationDetails,
      visualizationsByType,
      count: visualizations.length
    };
  }

  // Returns performance metrics for statistical models
  async getModelPerformance(modelName: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the model
    const model = graph.entities.find(e => e.name === modelName && e.entityType === 'model');
    if (!model) {
      throw new Error(`Model '${modelName}' not found`);
    }
    
    // Find variables included in the model
    const variables: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'includes' && relation.from === modelName) {
        const variable = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
        if (variable) {
          variables.push(variable);
        }
      }
    }
    
    // Find predictors (independent variables)
    const predictors: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'predicts' && relation.from === modelName) {
        const variable = graph.entities.find(e => e.name === relation.to && e.entityType === 'variable');
        if (variable) {
          predictors.push(variable);
        }
      }
    }
    
    // Find outcomes (dependent variables)
    const outcomes: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'contains' && relation.from === modelName) {
        const variable = graph.entities.find(e => 
          e.name === relation.to && 
          e.entityType === 'variable' &&
          e.observations.some(o => 
            o.toLowerCase().includes('dependent') || 
            o.toLowerCase().includes('outcome') ||
            o.toLowerCase().includes('dv')
          )
        );
        
        if (variable) {
          outcomes.push(variable);
        }
      }
    }
    
    // Find datasets this model analyzes
    const datasets: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'analyzes' && relation.from === modelName) {
        const dataset = graph.entities.find(e => e.name === relation.to && e.entityType === 'dataset');
        if (dataset) {
          datasets.push(dataset);
        }
      }
    }
    
    // Find results produced by this model
    const results: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'produces' && relation.from === modelName) {
        const result = graph.entities.find(e => e.name === relation.to && e.entityType === 'result');
        if (result) {
          results.push(result);
        }
      }
    }
    
    // Find visualizations of this model
    const visualizations: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'visualizes' && relation.to === modelName) {
        const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
        if (visualization) {
          visualizations.push(visualization);
        }
      }
    }
    
    // Extract model type and performance metrics
    const typeObs = model.observations.find(o => o.startsWith('Type:'));
    const modelType = typeObs ? typeObs.split(':')[1].trim() : 'unknown';
    
    // Extract performance metrics
    const performanceMetrics = model.observations.filter(o => 
      o.toLowerCase().includes('r²') || 
      o.toLowerCase().includes('r-squared') ||
      o.toLowerCase().includes('mse') ||
      o.toLowerCase().includes('rmse') ||
      o.toLowerCase().includes('mae') ||
      o.toLowerCase().includes('aic') ||
      o.toLowerCase().includes('bic') ||
      o.toLowerCase().includes('accuracy') ||
      o.toLowerCase().includes('precision') ||
      o.toLowerCase().includes('recall') ||
      o.toLowerCase().includes('f1')
    );
    
    // Look for validation information
    const validationObs = model.observations.filter(o => 
      o.toLowerCase().includes('validation') || 
      o.toLowerCase().includes('cross-validation') ||
      o.toLowerCase().includes('test data')
    );
    
    return {
      model,
      modelType,
      variables,
      predictors,
      outcomes,
      datasets,
      results,
      performanceMetrics,
      validation: validationObs,
      visualizations
    };
  }

  // Shows results organized by research questions
  async getResearchQuestionResults(questionName: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the research question
    const question = graph.entities.find(e => e.name === questionName && e.entityType === 'researchQuestion');
    if (!question) {
      throw new Error(`Research question '${questionName}' not found`);
    }
    
    // Find which project this question is part of
    let project: Entity | undefined;
    for (const relation of graph.relations) {
      if (relation.relationType === 'part_of' && relation.from === questionName) {
        project = graph.entities.find(e => e.name === relation.to && e.entityType === 'project');
        if (project) {
          break;
        }
      }
    }
    
    // Find hypotheses related to this question
    const hypotheses: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'related_to' && relation.from === questionName) {
        const hypothesis = graph.entities.find(e => e.name === relation.to && e.entityType === 'hypothesis');
        if (hypothesis) {
          hypotheses.push(hypothesis);
        }
      }
    }
    
    // Find direct results that answer this question
    const directResults: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'answers' && relation.to === questionName) {
        const result = graph.entities.find(e => e.name === relation.from && e.entityType === 'result');
        if (result) {
          directResults.push(result);
        }
      }
    }
    
    // Find findings that answer this question
    const findings: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'answers' && relation.to === questionName) {
        const finding = graph.entities.find(e => e.name === relation.from && e.entityType === 'finding');
        if (finding) {
          findings.push(finding);
        }
      }
    }
    
    // For each hypothesis, find its tests and results
    const hypothesisResults = hypotheses.map(hypothesis => {
      // Find statistical tests for this hypothesis
      const tests: Entity[] = [];
      for (const relation of graph.relations) {
        if (relation.relationType === 'tests' && relation.to === hypothesis.name) {
          const test = graph.entities.find(e => e.name === relation.from && e.entityType === 'statisticalTest');
          if (test) {
            tests.push(test);
          }
        }
      }
      
      // For each test, find its results
      const testResults = tests.map(test => {
        const results: Entity[] = [];
        for (const relation of graph.relations) {
          if (relation.relationType === 'produces' && relation.from === test.name) {
            const result = graph.entities.find(e => e.name === relation.to && e.entityType === 'result');
            if (result) {
              results.push(result);
            }
          }
        }
        
        return {
          test,
          results
        };
      });
      
      // Extract hypothesis status from observations
      const statusObs = hypothesis.observations.find(o => o.startsWith('Status:'));
      const status = statusObs ? statusObs.split(':')[1].trim() : 'unknown';
      
      // Determine if hypothesis is supported based on results
      const isSupported = status === 'supported';
      
      return {
        hypothesis,
        status,
        isSupported,
        tests: testResults
      };
    });
    
    return {
      question,
      project,
      directResults,
      findings,
      hypotheses: hypothesisResults
    };
  }

  // Returns distributional statistics for variables
  async getVariableDistribution(variableName: string, datasetName?: string): Promise<any> {
    const graph = await this.loadGraph();
    
    // Find the variable
    const variable = graph.entities.find(e => e.name === variableName && e.entityType === 'variable');
    if (!variable) {
      throw new Error(`Variable '${variableName}' not found`);
    }
    
    // Find datasets containing this variable
    let datasets: Entity[] = [];
    
    if (datasetName) {
      // If dataset is specified, verify it contains the variable
      const dataset = graph.entities.find(e => e.name === datasetName && e.entityType === 'dataset');
      if (!dataset) {
        throw new Error(`Dataset '${datasetName}' not found`);
      }
      
      const containsRelation = graph.relations.find(r => 
        r.relationType === 'contains' && r.from === datasetName && r.to === variableName
      );
      
      if (!containsRelation) {
        throw new Error(`Dataset '${datasetName}' does not contain variable '${variableName}'`);
      }
      
      datasets.push(dataset);
    } else {
      // Otherwise find all datasets containing this variable
      for (const relation of graph.relations) {
        if (relation.relationType === 'contains' && relation.to === variableName) {
          const dataset = graph.entities.find(e => e.name === relation.from && e.entityType === 'dataset');
          if (dataset) {
            datasets.push(dataset);
          }
        }
      }
    }
    
    // Extract descriptive statistics from variable observations
    const descriptiveStats: {[key: string]: string} = {};
    
    // Common descriptive statistics to look for
    const statKeys = [
      'Mean:', 'Median:', 'Mode:', 'Range:', 'Minimum:', 'Maximum:', 
      'Standard Deviation:', 'Variance:', 'Skewness:', 'Kurtosis:',
      'n=', 'N='
    ];
    
    for (const key of statKeys) {
      const obs = variable.observations.find(o => o.startsWith(key));
      if (obs) {
        const value = obs.split(':')[1]?.trim() || obs.split('=')[1]?.trim();
        if (value) {
          descriptiveStats[key.replace(':', '')] = value;
        }
      }
    }
    
    // Look for normality test information
    const normalityObs = variable.observations.filter(o => 
      o.toLowerCase().includes('normality') || 
      o.toLowerCase().includes('shapiro') ||
      o.toLowerCase().includes('kolmogorov')
    );
    
    // Find visualizations of this variable
    const visualizations: Entity[] = [];
    for (const relation of graph.relations) {
      if (relation.relationType === 'visualizes' && relation.to === variableName) {
        const visualization = graph.entities.find(e => e.name === relation.from && e.entityType === 'visualization');
        if (visualization) {
          visualizations.push(visualization);
        }
      }
    }
    
    // Extract variable metadata
    const typeObs = variable.observations.find(o => o.startsWith('Type:') || o.startsWith('Data Type:'));
    const dataType = typeObs ? typeObs.split(':')[1].trim() : 'unknown';
    
    const roleObs = variable.observations.find(o => o.startsWith('Role:'));
    const role = roleObs ? roleObs.split(':')[1].trim() : 'unknown';
    
    const scaleObs = variable.observations.find(o => o.startsWith('Scale:') || o.startsWith('Measurement Scale:'));
    const scale = scaleObs ? scaleObs.split(':')[1].trim() : 'unknown';
    
    return {
      variable,
      datasets,
      metadata: {
        dataType,
        role,
        scale
      },
      distribution: {
        descriptiveStats,
        normality: normalityObs
      },
      visualizations
    };
  }

  // Initialize status and priority entities
  async initializeStatusAndPriority(): Promise<void> {
    const graph = await this.loadGraph();
    
    // Create status entities if they don't exist
    for (const statusValue of VALID_STATUS_VALUES) {
      const statusName = `status:${statusValue}`;
      if (!graph.entities.some(e => e.name === statusName && e.entityType === 'status')) {
        graph.entities.push({
          name: statusName,
          entityType: 'status',
          observations: [`A ${statusValue} status value`]
        });
      }
    }
    
    // Create priority entities if they don't exist
    for (const priorityValue of VALID_PRIORITY_VALUES) {
      const priorityName = `priority:${priorityValue}`;
      if (!graph.entities.some(e => e.name === priorityName && e.entityType === 'priority')) {
        graph.entities.push({
          name: priorityName,
          entityType: 'priority',
          observations: [`A ${priorityValue} priority value`]
        });
      }
    }
    
    await this.saveGraph(graph);
  }

  // Helper method to get status of an entity
  async getEntityStatus(entityName: string): Promise<string | null> {
    const graph = await this.loadGraph();
    
    // Find status relation for this entity
    const statusRelation = graph.relations.find(r => 
      r.from === entityName && 
      r.relationType === 'has_status'
    );
    
    if (statusRelation) {
      // Extract status value from the status entity name (status:value)
      return statusRelation.to.split(':')[1];
    }
    
    return null;
  }
  
  // Helper method to get priority of an entity
  async getEntityPriority(entityName: string): Promise<string | null> {
    const graph = await this.loadGraph();
    
    // Find priority relation for this entity
    const priorityRelation = graph.relations.find(r => 
      r.from === entityName && 
      r.relationType === 'has_priority'
    );
    
    if (priorityRelation) {
      // Extract priority value from the priority entity name (priority:value)
      return priorityRelation.to.split(':')[1];
    }
    
    return null;
  }
  
  // Helper method to set status of an entity
  async setEntityStatus(entityName: string, statusValue: string): Promise<void> {
    if (!VALID_STATUS_VALUES.includes(statusValue)) {
      throw new Error(`Invalid status value: ${statusValue}. Valid values are: ${VALID_STATUS_VALUES.join(', ')}`);
    }
    
    const graph = await this.loadGraph();
    
    // Remove any existing status relations for this entity
    graph.relations = graph.relations.filter(r => 
      !(r.from === entityName && r.relationType === 'has_status')
    );
    
    // Add new status relation
    graph.relations.push({
      from: entityName,
      to: `status:${statusValue}`,
      relationType: 'has_status'
    });
    
    await this.saveGraph(graph);
  }
  
  // Helper method to set priority of an entity
  async setEntityPriority(entityName: string, priorityValue: string): Promise<void> {
    if (!VALID_PRIORITY_VALUES.includes(priorityValue)) {
      throw new Error(`Invalid priority value: ${priorityValue}. Valid values are: ${VALID_PRIORITY_VALUES.join(', ')}`);
    }
    
    const graph = await this.loadGraph();
    
    // Remove any existing priority relations for this entity
    graph.relations = graph.relations.filter(r => 
      !(r.from === entityName && r.relationType === 'has_priority')
    );
    
    // Add new priority relation
    graph.relations.push({
      from: entityName,
      to: `priority:${priorityValue}`,
      relationType: 'has_priority'
    });
    
    await this.saveGraph(graph);
  }
}

// Main function to set up the MCP server
async function main() {
  try {
    const knowledgeGraphManager = new KnowledgeGraphManager();
    
    // Initialize status and priority entities
    await knowledgeGraphManager.initializeStatusAndPriority();
    
    // Create the MCP server with a name and version
    const server = new McpServer({
      name: "Context Manager",
      version: "1.0.0"
    });
    
    // Define a resource that exposes the entire graph
    server.resource(
      "graph",
      "graph://researcher/quantitative",
      async (uri) => ({
        contents: [{
          uri: uri.href,
          text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2)
        }]
      })
    );
    
    // Define tools using zod for parameter validation

    /**
     * Start a new session for quantitative research. Returns session ID, recent sessions, active projects, datasets, research questions, statistical models, and visualizations.
     */
    server.tool(
      "startsession",
      toolDescriptions["startsession"],
      {},
      async () => {
        try {
          // Generate a unique session ID
          const sessionId = generateSessionId();
          
          // Get recent sessions from persistent storage instead of entities
          const sessionStates = await loadSessionStates();

          // Initialize the session state
          sessionStates.set(sessionId, []);
          await saveSessionStates(sessionStates);
          
          // Convert sessions map to array and retrieve recent sessions
          const recentSessions = Array.from(sessionStates.entries())
            .map(([id, stages]) => {
              // Extract summary data from the first stage (if it exists)
              const summaryStage = stages.find(s => s.stage === "summary");
              return {
                id,
                project: summaryStage?.stageData?.project || "Unknown project",
                summary: summaryStage?.stageData?.summary || "No summary available"
              };
            })
            .slice(0, 3); // Default to showing 3 recent sessions
          
          // Query for all research projects
          const projectsQuery = await knowledgeGraphManager.searchNodes("entityType:project");
          const projects = [];
          
          // Filter for active projects based on has_status relation
          for (const project of projectsQuery.entities) {
            const status = await knowledgeGraphManager.getEntityStatus(project.name);
            if (status === "active") {
              projects.push(project);
            }
          }
          
          // Get a sampling of datasets
          const datasetsQuery = await knowledgeGraphManager.searchNodes("entityType:dataset");
          const datasets = datasetsQuery.entities.slice(0, 5); // Limit to 5 for initial display
          
          // Get research questions
          const questionsQuery = await knowledgeGraphManager.searchNodes("entityType:researchQuestion");
          const questions = questionsQuery.entities.slice(0, 5); // Top 5 research questions
          
          // Get statistical models
          const modelsQuery = await knowledgeGraphManager.searchNodes("entityType:model");
          const models = modelsQuery.entities.slice(0, 3); // Most recent 3 models
            
          // Get visualizations
          const visualizationsQuery = await knowledgeGraphManager.searchNodes("entityType:visualization");
          const visualizations = visualizationsQuery.entities.slice(0, 3); // Most recent 3 visualizations
          
          // Format the data for display with truncated previews
          const projectsText = await Promise.all(projects.map(async p => {
            const status = await knowledgeGraphManager.getEntityStatus(p.name) || "Unknown";
            const priority = await knowledgeGraphManager.getEntityPriority(p.name);
            const priorityText = priority ? `, Priority: ${priority}` : "";
            
            // Show truncated preview of first observation
            const preview = p.observations.length > 0 
              ? `${p.observations[0].substring(0, 60)}${p.observations[0].length > 60 ? '...' : ''}`
              : "No description";
              
            return `- **${p.name}** (Status: ${status}${priorityText}): ${preview}`;
          }));
          
          const datasetsText = await Promise.all(datasets.map(async d => {
            const status = await knowledgeGraphManager.getEntityStatus(d.name) || "Unknown";
            
            // Show truncated preview of first observation
            const preview = d.observations.length > 0 
              ? `${d.observations[0].substring(0, 60)}${d.observations[0].length > 60 ? '...' : ''}`
              : "No description";
              
            return `- **${d.name}** (Status: ${status}): ${preview}`;
          }));
          
          const questionsText = await Promise.all(questions.map(async q => {
            const status = await knowledgeGraphManager.getEntityStatus(q.name) || "Unknown";
            
            // Show truncated preview of first observation
            const preview = q.observations.length > 0 
              ? `${q.observations[0].substring(0, 60)}${q.observations[0].length > 60 ? '...' : ''}`
              : "No description";
              
            return `- **${q.name}** (Status: ${status}): ${preview}`;
          }));
          
          const modelsText = await Promise.all(models.map(async m => {
            const status = await knowledgeGraphManager.getEntityStatus(m.name) || "Unknown";
            const type = m.observations.find(o => o.startsWith("type:"))?.substring(5) || "Unknown";
            
            // Show truncated preview of first non-type observation
            const nonTypeObs = m.observations.find(o => !o.startsWith("type:"));
            const preview = nonTypeObs 
              ? `${nonTypeObs.substring(0, 60)}${nonTypeObs.length > 60 ? '...' : ''}`
              : "No description";
              
            return `- **${m.name}** (${type}, Status: ${status}): ${preview}`;
          }));
          
          const visualizationsText = await Promise.all(visualizations.map(async v => {
            const status = await knowledgeGraphManager.getEntityStatus(v.name) || "Unknown";
            const type = v.observations.find(o => o.startsWith("type:"))?.substring(5) || "Unknown";
            
            // Show truncated preview of first non-type observation
            const nonTypeObs = v.observations.find(o => !o.startsWith("type:"));
            const preview = nonTypeObs 
              ? `${nonTypeObs.substring(0, 60)}${nonTypeObs.length > 60 ? '...' : ''}`
              : "No description";
              
            return `- **${v.name}** (${type}, Status: ${status}): ${preview}`;
          }));
          
          const sessionsText = recentSessions.map(s => {
            return `- ${s.project} - ${s.summary.substring(0, 60)}${s.summary.length > 60 ? '...' : ''}`;
          }).join("\n");
          
          return {
            content: [{
              type: "text",
              text: `# Choose what to focus on in this session

## Session ID
\`${sessionId}\`

## Recent Research Sessions
${sessionsText || "No recent sessions found."}

## Active Research Projects
${projectsText.join("\n") || "No active projects found."}

## Available Datasets
${datasetsText.join("\n") || "No datasets found."}

## Research Questions
${questionsText.join("\n") || "No research questions found."}

## Recent Statistical Models
${modelsText.join("\n") || "No models found."}

## Recent Visualizations
${visualizationsText.join("\n") || "No visualizations found."}

To load specific context, use the \`loadcontext\` tool with the entity name and session ID - ${sessionId}`
            }]
          };
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );

    /**
     * Create entities, relations, and observations.
     */
    server.tool(
      "buildcontext",
      toolDescriptions["buildcontext"],
      {
        type: z.enum(["entities", "relations", "observations"]).describe("Type of creation operation: 'entities', 'relations', or 'observations'"),
        data: z.array(z.any()).describe("Data for the creation operation, structure varies by type but must be an array")
      },
      async ({ type, data }) => {
        try {
          let result;
          
          switch (type) {
            case "entities":
              // Validate entity types
              for (const entity of data) {
                if (!validateEntityType(entity.entityType)) {
                  throw new Error(`Invalid entity type: ${entity.entityType}`);
                }
              }
              
              // Ensure entities match the Entity interface
              const typedEntities: Entity[] = data.map((e: any) => ({
                name: e.name,
                entityType: e.entityType,
                observations: e.observations
              }));
              result = await knowledgeGraphManager.createEntities(typedEntities);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, created: result }, null, 2)
                }]
              };
              
            case "relations":
              // Validate relation types
              for (const relation of data) {
                if (!validateRelationType(relation.relationType)) {
                  throw new Error(`Invalid relation type: ${relation.relationType}`);
                }
              }
              
              // Ensure relations match the Relation interface
              const typedRelations: Relation[] = data.map((r: any) => ({
                from: r.from,
                to: r.to,
                relationType: r.relationType
              }));
              result = await knowledgeGraphManager.createRelations(typedRelations);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, created: result }, null, 2)
                }]
              };
              
            case "observations":
              // For quantitative researcher domain, addObservations takes an array
              // Ensure observations match the required interface
              const typedObservations: { entityName: string; contents: string[] }[] = 
                Array.isArray(data) ? data.map((o: any) => ({
                  entityName: o.entityName,
                  contents: Array.isArray(o.contents) ? o.contents : 
                           Array.isArray(o.observations) ? o.observations : []
                })) : [data];
              
              result = await knowledgeGraphManager.addObservations(typedObservations);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, added: result }, null, 2)
                }]
              };
              
            default:
              throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
          }
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );
    
    /**
     * Delete entities, relations, and observations.
     */
    server.tool(
      "deletecontext",
      toolDescriptions["deletecontext"],
      {
        type: z.enum(["entities", "relations", "observations"]).describe("Type of deletion operation: 'entities', 'relations', or 'observations'"),
        data: z.array(z.any()).describe("Data for the deletion operation, structure varies by type but must be an array")
      },
      async ({ type, data }) => {
        try {
          switch (type) {
            case "entities":
              await knowledgeGraphManager.deleteEntities(data);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, message: `Deleted ${data.length} entities` }, null, 2)
                }]
              };
              
            case "relations":
              // Ensure relations match the Relation interface
              const typedRelations: Relation[] = data.map((r: any) => ({
                from: r.from,
                to: r.to,
                relationType: r.relationType
              }));
              await knowledgeGraphManager.deleteRelations(typedRelations);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, message: `Deleted ${data.length} relations` }, null, 2)
                }]
              };
              
            case "observations":
              // Ensure deletions match the required interface
              const typedDeletions: { entityName: string; observations: string[] }[] = data.map((d: any) => ({
                entityName: d.entityName,
                observations: d.observations
              }));
              await knowledgeGraphManager.deleteObservations(typedDeletions);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, message: `Deleted observations from ${data.length} entities` }, null, 2)
                }]
              };
              
            default:
              throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
          }
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );
    
    /**
     * Read the graph, search nodes, open nodes, get project overview, get dataset analysis, get hypothesis tests, get variable relationships, get statistical results, get visualization gallery, get model performance, get research question results, get variable distribution, and get related entities.
     */
    server.tool(
      "advancedcontext",
      toolDescriptions["advancedcontext"],
      {
        type: z.enum([
          "graph", 
          "search", 
          "nodes", 
          "project", 
          "dataset", 
          "hypothesis", 
          "variables", 
          "statistics", 
          "visualizations", 
          "model", 
          "question", 
          "distribution", 
          "related"
        ]).describe("Type of get operation"),
        params: z.record(z.string(), z.any()).describe("Parameters for the get operation, structure varies by type")
      },
      async ({ type, params }) => {
        try {
          let result;
          
          switch (type) {
            case "graph":
              result = await knowledgeGraphManager.readGraph();
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, graph: result }, null, 2)
                }]
              };
              
            case "search":
              result = await knowledgeGraphManager.searchNodes(params.query);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, results: result }, null, 2)
                }]
              };
              
            case "nodes":
              result = await knowledgeGraphManager.openNodes(params.names);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, nodes: result }, null, 2)
                }]
              };
              
            case "project":
              result = await knowledgeGraphManager.getProjectOverview(params.projectName);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, project: result }, null, 2)
                }]
              };
              
            case "dataset":
              result = await knowledgeGraphManager.getDatasetAnalysis(params.datasetName);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, dataset: result }, null, 2)
                }]
              };
              
            case "hypothesis":
              result = await knowledgeGraphManager.getHypothesisTests(
                params.projectName,
                params.hypothesisName
              );
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, hypothesis: result }, null, 2)
                }]
              };
              
            case "variables":
              result = await knowledgeGraphManager.getVariableRelationships(params.variableName);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, variables: result }, null, 2)
                }]
              };
              
            case "statistics":
              result = await knowledgeGraphManager.getStatisticalResults(
                params.projectName,
                params.testType
              );
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, statistics: result }, null, 2)
                }]
              };
              
            case "visualizations":
              result = await knowledgeGraphManager.getVisualizationGallery(
                params.projectName,
                params.datasetName
              );
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, visualizations: result }, null, 2)
                }]
              };
              
            case "model":
              result = await knowledgeGraphManager.getModelPerformance(params.modelName);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, model: result }, null, 2)
                }]
              };
              
            case "question":
              result = await knowledgeGraphManager.getResearchQuestionResults(params.questionName);
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, question: result }, null, 2)
                }]
              };
              
            case "distribution":
              result = await knowledgeGraphManager.getVariableDistribution(
                params.variableName,
                params.datasetName
              );
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({ success: true, distribution: result }, null, 2)
                }]
              };
              
            case "related":
              // For the related case, we don't have a specialized method in the manager
              // So we'll use the generic KnowledgeGraph search capabilities
              const entityGraph = await knowledgeGraphManager.searchNodes(params.entityName);
              const entity = entityGraph.entities.find(e => e.name === params.entityName);
              
              if (!entity) {
                throw new Error(`Entity "${params.entityName}" not found`);
              }
              
              // Find related entities
              const relations = entityGraph.relations.filter(r => 
                r.from === params.entityName || r.to === params.entityName
              );
              
              const relatedNames = relations.map(r => 
                r.from === params.entityName ? r.to : r.from
              );
              
              if (relatedNames.length === 0) {
                return {
                  content: [{
                    type: "text",
                    text: JSON.stringify({ success: true, related: { entity, relatedEntities: [] } }, null, 2)
                  }]
                };
              }
              
              const relatedEntitiesGraph = await knowledgeGraphManager.openNodes(relatedNames);
              
              return {
                content: [{
                  type: "text",
                  text: JSON.stringify({
                    success: true,
                    related: {
                      entity,
                      relations,
                      relatedEntities: relatedEntitiesGraph.entities
                    }
                  }, null, 2)
                }]
              };
              
            default:
              throw new Error(`Invalid type: ${type}. Must be one of the supported get operation types.`);
          }
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );

    server.tool(
      "loadcontext",
      toolDescriptions["loadcontext"],
      {
        entityName: z.string().describe("Name of the entity to load context for"),
        entityType: z.string().optional().describe("Type of entity to load (project, dataset, variable, etc.), defaults to 'project'"),
        sessionId: z.string().optional().describe("Session ID from startsession to track context loading")
      },
      async ({ entityName, entityType = "project", sessionId }: { entityName: string; entityType?: string; sessionId?: string }) => {
        try {
          // If sessionId is provided, load session state
          if (sessionId) {
            const sessionStates = await loadSessionStates();
            const sessionState = sessionStates.get(sessionId);
          }
          
          // Get the entity
          const entityGraph = await knowledgeGraphManager.searchNodes(entityName);
          if (entityGraph.entities.length === 0) {
            throw new Error(`Entity ${entityName} not found`);
          }
          
          // Find the exact entity by name (case-sensitive match)
          const entity = entityGraph.entities.find((e: Entity) => e.name === entityName);
          if (!entity) {
            throw new Error(`Entity ${entityName} not found`);
          }
          
          // Different context loading based on entity type
          let contextMessage = "";
          
          if (entityType === "project") {
            // Get project overview
            const projectOverview = await knowledgeGraphManager.getProjectOverview(entityName);
            
            // Get hypothesis tests
            let hypothesisTests;
            try {
              hypothesisTests = await knowledgeGraphManager.getHypothesisTests(entityName);
            } catch (error) {
              hypothesisTests = { hypotheses: [] };
            }
            
            // Get statistical results
            let statisticalResults;
            try {
              statisticalResults = await knowledgeGraphManager.getStatisticalResults(entityName);
            } catch (error) {
              statisticalResults = { tests: [] };
            }
            
            // Get visualization gallery
            let visualizations;
            try {
              visualizations = await knowledgeGraphManager.getVisualizationGallery(entityName);
            } catch (error) {
              visualizations = { visualizations: [] };
            }
            
            // Find datasets for this project
            const datasetsRelations = entityGraph.relations.filter((r: Relation) => 
              r.from === entityName && 
              r.relationType === "contains"
            );
            
            const datasetsGraph = await knowledgeGraphManager.searchNodes("entityType:dataset");
            const relatedDatasets = datasetsGraph.entities.filter((d: Entity) => 
              datasetsRelations.some((r: Relation) => r.to === d.name)
            );
            
            // Find models for this project
            const modelsGraph = await knowledgeGraphManager.searchNodes("entityType:model");
            const relatedModels = modelsGraph.entities.filter((m: Entity) => 
              datasetsRelations.some((r: Relation) => r.to === m.name)
            );
            
            // Get status and priority using relation-based approach
            const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
            const priority = await knowledgeGraphManager.getEntityPriority(entityName);
            const priorityText = priority ? `- **Priority**: ${priority}` : "";
            
            // Format observations without looking for specific patterns
            const observationsList = entity.observations.length > 0 
              ? entity.observations.map(obs => `- ${obs}`).join("\n")
              : "No observations";
            
            // Format datasets info
            const datasetsText = await Promise.all(relatedDatasets.map(async (d: Entity) => {
              const datasetStatus = await knowledgeGraphManager.getEntityStatus(d.name) || "Unknown";
              const size = d.observations.find((o: string) => o.startsWith("size:"))?.substring(5) || "Unknown size";
              const variables = d.observations.find((o: string) => o.startsWith("variables:"))?.substring(10) || "Unknown variables";
              return `- **${d.name}** (Status: ${datasetStatus}): ${size}, ${variables} variables`;
            }));
            
            // Format hypotheses
            const hypothesesText = await Promise.all((hypothesisTests.hypotheses || []).map(async (h: any) => {
              const hypothesisStatus = await knowledgeGraphManager.getEntityStatus(h.name) || "Unknown";
              return `- **${h.name}**: Status: ${hypothesisStatus} (p-value: ${h.pValue || "N/A"})${h.conclusion ? ` - ${h.conclusion}` : ""}`;
            }));
            
            // Format statistical tests
            const testsText = await Promise.all((statisticalResults.tests || []).map(async (t: any) => {
              const testStatus = await knowledgeGraphManager.getEntityStatus(t.name) || "Unknown";
              return `- **${t.name}** (${t.type}): Status: ${testStatus}, ${t.result || "No result"} - Variables: ${t.variables?.join(", ") || "N/A"}`;
            }));
            
            // Format models
            const modelsText = await Promise.all(relatedModels.map(async (m: Entity) => {
              const modelStatus = await knowledgeGraphManager.getEntityStatus(m.name) || "Unknown";
              const type = m.observations.find((o: string) => o.startsWith("type:"))?.substring(5) || "Unknown type";
              return `- **${m.name}** (${type}): Status: ${modelStatus}`;
            }));
            
            // Format visualizations
            const visualizationsText = await Promise.all((visualizations.visualizations || []).slice(0, 5).map(async (v: any) => {
              const vizStatus = await knowledgeGraphManager.getEntityStatus(v.name) || "Unknown";
              return `- **${v.name}** (${v.type}): Status: ${vizStatus}, ${v.description || "No description"}`;
            }));
            
            contextMessage = `# Quantitative Research Project Context: ${entityName}

## Project Overview
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Datasets
${datasetsText.join("\n") || "No datasets associated with this project"}

## Hypotheses
${hypothesesText.join("\n") || "No hypotheses found"}

## Statistical Tests
${testsText.join("\n") || "No statistical tests found"}

## Models
${modelsText.join("\n") || "No models associated with this project"}

## Key Visualizations
${visualizationsText.join("\n") || "No visualizations found"}`;
          } 
          else if (entityType === "dataset") {
            // Get dataset analysis
            let datasetAnalysis;
            try {
              datasetAnalysis = await knowledgeGraphManager.getDatasetAnalysis(entityName);
            } catch (error) {
              datasetAnalysis = { variables: [], descriptiveStats: {} };
            }
            
            // Find which project this dataset belongs to
            const projectRel = entityGraph.relations.find((r: Relation) => r.to === entityName && r.relationType === "contains");
            const projectName = projectRel ? projectRel.from : "Unknown project";
            
            // Get visualizations for this dataset
            let visualizations;
            try {
              visualizations = await knowledgeGraphManager.getVisualizationGallery(projectName, entityName);
            } catch (error) {
              visualizations = { visualizations: [] };
            }
            
            // Get models trained on this dataset
            const modelsGraph = await knowledgeGraphManager.searchNodes("entityType:model");
            const trainedModels = modelsGraph.entities.filter((m: Entity) => {
              return modelsGraph.relations.some((r: Relation) => 
                r.from === m.name && 
                r.to === entityName && 
                r.relationType === "trained_on"
              );
            });
            
            // Get status and priority using relation-based approach
            const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
            const priority = await knowledgeGraphManager.getEntityPriority(entityName);
            const priorityText = priority ? `- **Priority**: ${priority}` : "";
            
            // Format dataset observations without looking for specific patterns
            const observationsList = entity.observations.length > 0 
              ? entity.observations.map(obs => `- ${obs}`).join("\n")
              : "No observations";
            
            // Format variables
            const variablesText = await Promise.all((datasetAnalysis.variables || []).map(async (v: any) => {
              const variableStatus = v.variable ? await knowledgeGraphManager.getEntityStatus(v.variable.name) : "Unknown";
              const dataType = v.metadata?.dataType || "Unknown";
              const scale = v.metadata?.scale || "Unknown";
              const stats = v.distribution?.descriptiveStats || {};
              const statsText = Object.entries(stats)
                .map(([key, value]) => `${key}: ${value}`)
                .join(", ");
              return `- **${v.variable.name}** (${dataType}, ${scale}): Status: ${variableStatus}, ${statsText || "No statistics available"}`;
            }));
            
            // Format models
            const modelsText = await Promise.all(trainedModels.map(async (m: Entity) => {
              const modelStatus = await knowledgeGraphManager.getEntityStatus(m.name) || "Unknown";
              const type = m.observations.find((o: string) => o.startsWith("type:"))?.substring(5) || "Unknown type";
              return `- **${m.name}** (${type}): Status: ${modelStatus}`;
            }));
            
            // Format visualizations
            const visualizationsText = await Promise.all((visualizations.visualizations || []).slice(0, 5).map(async (v: any) => {
              const vizStatus = await knowledgeGraphManager.getEntityStatus(v.name) || "Unknown";
              return `- **${v.name}** (${v.type}): Status: ${vizStatus}, ${v.description || "No description"}`;
            }));
            
            contextMessage = `# Dataset Context: ${entityName}

## Dataset Overview
- **Project**: ${projectName}
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Variables
${variablesText.join("\n") || "No variables found"}

## Visualizations
${visualizationsText.join("\n") || "No visualizations found"}

## Models Trained on this Dataset
${modelsText.join("\n") || "No models have been trained on this dataset"}`;
          }
          else if (entityType === "variable") {
            // Get variable distribution
            let variableDistribution;
            try {
              // First find which dataset this variable belongs to
              const datasetRel = entityGraph.relations.find((r: Relation) => r.to === entityName && r.relationType === "contains");
              const datasetName = datasetRel ? datasetRel.from : undefined;
              
              if (datasetName) {
                variableDistribution = await knowledgeGraphManager.getVariableDistribution(entityName, datasetName);
              } else {
                variableDistribution = await knowledgeGraphManager.getVariableDistribution(entityName, "unknown");
              }
            } catch (error) {
              variableDistribution = { stats: {}, normality: "Unknown", histogram: "N/A" };
            }
            
            // Get variable relationships
            let relationships;
            try {
              relationships = await knowledgeGraphManager.getVariableRelationships(entityName);
            } catch (error) {
              relationships = { correlations: [], dependencies: [] };
            }
            
            // Format variable context
            const dataType = entity.observations.find((o: string) => o.startsWith("Type:"))?.substring(5) || "Unknown type";
            const role = entity.observations.find((o: string) => o.startsWith("Role:"))?.substring(5) || "Unknown role";
            const scale = entity.observations.find((o: string) => o.startsWith("Scale:"))?.substring(6) || "Unknown scale";
            const description = entity.observations.find((o: string) => !o.startsWith("Type:") && !o.startsWith("Role:") && !o.startsWith("Scale:"));
            
            // Format stats
            const statsText = Object.entries(variableDistribution.stats || {})
              .map(([key, value]) => `- **${key}**: ${value}`)
              .join("\n");
            
            // Format correlations
            const correlationsText = relationships.correlations?.map((c: any) => {
              return `- **${c.variable}**: ${c.coefficient} (p-value: ${c.pValue || "N/A"}) - ${c.strength || "Unknown"} ${c.direction || ""}`;
            }).join("\n") || "No correlations found";
            
            contextMessage = `# Variable Context: ${entityName}

## Variable Details
- **Data Type**: ${dataType}
- **Role**: ${role}
- **Scale**: ${scale}
- **Description**: ${description || "No description"}

## Descriptive Statistics
${statsText || "No statistics available"}

## Normality
${variableDistribution.normality || "Not tested"}

## Correlations with Other Variables
${correlationsText}`;
          }
          else if (entityType === "model") {
            // Get model performance
            let modelPerformance;
            try {
              modelPerformance = await knowledgeGraphManager.getModelPerformance(entityName);
            } catch (error) {
              modelPerformance = { metrics: {}, details: {}, confusionMatrix: null };
            }
            
            // Find which dataset this model was trained on
            const datasetRel = entityGraph.relations.find((r: Relation) => r.from === entityName && r.relationType === "trained_on");
            const datasetName = datasetRel ? datasetRel.to : "Unknown dataset";
            
            // Format model context
            const type = entity.observations.find((o: string) => o.startsWith("type:"))?.substring(5) || "Unknown type";
            const created = entity.observations.find((o: string) => o.startsWith("created:"))?.substring(8) || "Unknown";
            const updated = entity.observations.find((o: string) => o.startsWith("updated:"))?.substring(8) || "Unknown";
            const notes = entity.observations.find((o: string) => !o.startsWith("type:") && !o.startsWith("performance:") && !o.startsWith("created:") && !o.startsWith("updated:"));
            
            // Format metrics
            const metricsText = Object.entries(modelPerformance.metrics || {})
              .map(([key, value]) => `- **${key}**: ${value}`)
              .join("\n");
            
            // Format model parameters and hyperparameters
            const paramsText = Object.entries(modelPerformance.details?.parameters || {})
              .map(([key, value]) => `- **${key}**: ${value}`)
              .join("\n");
            
            contextMessage = `# Model Context: ${entityName}

## Model Overview
- **Type**: ${type}
- **Trained on**: ${datasetName}
- **Created**: ${created}
- **Last Updated**: ${updated}
- **Notes**: ${notes || "No notes"}

## Performance Metrics
${metricsText || "No metrics available"}

## Parameters
${paramsText || "No parameters available"}`;
          }
          else if (entityType === "hypothesis") {
            // Get related statistical tests
            const testsGraph = await knowledgeGraphManager.searchNodes("entityType:statistical_test");
            const relatedTests = testsGraph.entities.filter((t: Entity) => {
              return testsGraph.relations.some((r: Relation) => 
                r.from === entityName && 
                r.to === t.name && 
                r.relationType === "tested_by"
              );
            });
            
            // Format hypothesis context
            const status = entity.observations.find((o: string) => o.startsWith("status:"))?.substring(7) || "Unknown";
            const pValue = entity.observations.find((o: string) => o.startsWith("p-value:"))?.substring(8) || "N/A";
            const created = entity.observations.find((o: string) => o.startsWith("created:"))?.substring(8) || "Unknown";
            const updated = entity.observations.find((o: string) => o.startsWith("updated:"))?.substring(8) || "Unknown";
            const projectObs = entity.observations.find((o: string) => o.startsWith("project:"))?.substring(8);
            const notes = entity.observations.find((o: string) => 
              !o.startsWith("status:") && 
              !o.startsWith("p-value:") && 
              !o.startsWith("created:") && 
              !o.startsWith("updated:") && 
              !o.startsWith("project:")
            );
            
            // Format tests
            const testsText = relatedTests.map((t: Entity) => {
              const type = t.observations.find((o: string) => o.startsWith("type:"))?.substring(5) || "Unknown type";
              const result = t.observations.find((o: string) => o.startsWith("result:"))?.substring(7) || "No result";
              return `- **${t.name}** (${type}): ${result}`;
            }).join("\n");
            
            contextMessage = `# Hypothesis Context: ${entityName}

## Hypothesis Details
- **Status**: ${status}
- **P-value**: ${pValue}
- **Created**: ${created}
- **Last Updated**: ${updated}
- **Project**: ${projectObs || "Not associated with a specific project"}
- **Notes**: ${notes || "No notes"}

## Statistical Tests
${testsText || "No statistical tests associated with this hypothesis"}`;
          }
          else if (entityType === "statistical_test") {
            // Format test context
            const type = entity.observations.find((o: string) => o.startsWith("type:"))?.substring(5) || "Unknown type";
            const result = entity.observations.find((o: string) => o.startsWith("result:"))?.substring(7) || "No result";
            const pValue = entity.observations.find((o: string) => o.startsWith("p-value:"))?.substring(8) || "N/A";
            const date = entity.observations.find((o: string) => o.startsWith("date:"))?.substring(5) || "Unknown";
            const projectObs = entity.observations.find((o: string) => o.startsWith("project:"))?.substring(8);
            
            // Get variables analyzed by this test
            const variablesGraph = await knowledgeGraphManager.searchNodes("entityType:variable");
            const analyzedVariables = variablesGraph.entities.filter((v: Entity) => {
              return entityGraph.relations.some((r: Relation) => 
                r.from === entityName && 
                r.to === v.name && 
                r.relationType === "analyzes"
              );
            });
            
            // Get hypotheses tested by this test
            const hypothesesGraph = await knowledgeGraphManager.searchNodes("entityType:hypothesis");
            const relatedHypotheses = hypothesesGraph.entities.filter((h: Entity) => {
              return hypothesesGraph.relations.some((r: Relation) => 
                r.from === h.name && 
                r.to === entityName && 
                r.relationType === "tested_by"
              );
            });
            
            // Format variables
            const variablesText = analyzedVariables.map((v: Entity) => {
              const dataType = v.observations.find((o: string) => o.startsWith("Type:"))?.substring(5) || "Unknown type";
              const scale = v.observations.find((o: string) => o.startsWith("Scale:"))?.substring(6) || "Unknown scale";
              return `- **${v.name}** (${dataType}, ${scale})`;
            }).join("\n");
            
            // Format hypotheses
            const hypothesesText = relatedHypotheses.map((h: Entity) => {
              const status = h.observations.find((o: string) => o.startsWith("status:"))?.substring(7) || "Unknown";
              return `- **${h.name}**: ${status}`;
            }).join("\n");
            
            contextMessage = `# Statistical Test Context: ${entityName}

## Test Details
- **Type**: ${type}
- **Result**: ${result}
- **P-value**: ${pValue}
- **Date**: ${date}
- **Project**: ${projectObs || "Not associated with a specific project"}

## Variables Analyzed
${variablesText || "No variables explicitly associated with this test"}

## Hypotheses Tested
${hypothesesText || "No hypotheses explicitly linked to this test"}`;
          }
          else {
            // Generic entity context
            const observations = entity.observations.join("\n- ");
            
            contextMessage = `# Entity Context: ${entityName}

## Entity Type
${entity.entityType}

## Observations
- ${observations}`;
          }
          
          return {
            content: [{
              type: "text",
              text: contextMessage
            }]
          };
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );

    /**
     * Process a stage of session analysis based on the current stage type
     */
    async function processStage(params: {
      sessionId: string;
      stage: string;
      stageNumber: number;
      totalStages: number;
      analysis?: string;
      stageData?: any;
      nextStageNeeded: boolean;
      isRevision?: boolean;
      revisesStage?: number;
    }, previousStages: any[]): Promise<any> {
      // Process based on the stage
      switch (params.stage) {
        case "summary":
          // Process summary stage
          return {
            stage: "summary",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { 
              summary: "",
              duration: "",
              project: "",
              date: new Date().toISOString().split('T')[0]
            },
            completed: !params.nextStageNeeded
          };
          
        case "datasetUpdates":
          // Process dataset updates stage
          return {
            stage: "datasetUpdates",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { datasets: [] },
            completed: !params.nextStageNeeded
          };
          
        case "newAnalyses":
          // Process new analyses stage
          return {
            stage: "newAnalyses",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { analyses: [] },
            completed: !params.nextStageNeeded
          };
          
        case "newVisualizations":
          // Process visualizations stage
          return {
            stage: "newVisualizations",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { visualizations: [] },
            completed: !params.nextStageNeeded
          };
          
        case "hypothesisResults":
          // Process hypothesis results stage
          return {
            stage: "hypothesisResults",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { hypotheses: [] },
            completed: !params.nextStageNeeded
          };
          
        case "modelUpdates":
          // Process model updates stage
          return {
            stage: "modelUpdates",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { models: [] },
            completed: !params.nextStageNeeded
          };
          
        case "projectStatus":
          // Process project status stage
          return {
            stage: "projectStatus",
            stageNumber: params.stageNumber,
            analysis: params.analysis || "",
            stageData: params.stageData || { 
              projectStatus: "",
              projectObservation: ""
            },
            completed: !params.nextStageNeeded
          };
          
        case "assembly":
          // Final assembly stage - compile all arguments for end-session
          return {
            stage: "assembly",
            stageNumber: params.stageNumber,
            analysis: "Final assembly of end-session arguments",
            stageData: assembleEndSessionArgs(previousStages),
            completed: true
          };
          
        default:
          throw new Error(`Unknown stage: ${params.stage}`);
      }
    }

    /**
     * Assemble the final end-session arguments from all processed stages
     */
    function assembleEndSessionArgs(stages: any[]): any {
      const summaryStage = stages.find(s => s.stage === "summary");
      const datasetUpdatesStage = stages.find(s => s.stage === "datasetUpdates");
      const newAnalysesStage = stages.find(s => s.stage === "newAnalyses");
      const newVisualizationsStage = stages.find(s => s.stage === "newVisualizations");
      const hypothesisResultsStage = stages.find(s => s.stage === "hypothesisResults");
      const modelUpdatesStage = stages.find(s => s.stage === "modelUpdates");
      const projectStatusStage = stages.find(s => s.stage === "projectStatus");
      
      return {
        summary: summaryStage?.stageData?.summary || "",
        duration: summaryStage?.stageData?.duration || "unknown",
        project: summaryStage?.stageData?.project || "",
        datasetUpdates: JSON.stringify(datasetUpdatesStage?.stageData?.datasets || []),
        newAnalyses: JSON.stringify(newAnalysesStage?.stageData?.analyses || []),
        newVisualizations: JSON.stringify(newVisualizationsStage?.stageData?.visualizations || []),
        hypothesisResults: JSON.stringify(hypothesisResultsStage?.stageData?.hypotheses || []),
        modelUpdates: JSON.stringify(modelUpdatesStage?.stageData?.models || []),
        projectStatus: projectStatusStage?.stageData?.projectStatus || "",
        projectObservation: projectStatusStage?.stageData?.projectObservation || ""
      };
    }
  
    /**
     * End session by processing all stages and recording the final results.
     * Only use this tool if the user asks for it.
     * 
     * Usage examples:
     * 
     * 1. Starting the end session process with the summary stage:
     * {
     *   "sessionId": "quant_1234567890_abc123",  // From startsession
     *   "stage": "summary",
     *   "stageNumber": 1,
     *   "totalStages": 8, 
     *   "analysis": "Analyzed progress on the multiple regression analysis",
     *   "stageData": {
     *     "summary": "Completed data preparation and initial statistical tests",
     *     "duration": "4 hours",
     *     "project": "Customer Satisfaction Study"  // Project name
     *   },
     *   "nextStageNeeded": true,  // More stages coming
     *   "isRevision": false
     * }
     * 
     * 2. Middle stage for new analyses:
     * {
     *   "sessionId": "quant_1234567890_abc123",
     *   "stage": "newAnalyses",
     *   "stageNumber": 3,
     *   "totalStages": 8,
     *   "analysis": "Conducted statistical tests on prepared data",
     *   "stageData": {
     *     "analyses": [
     *       { 
     *         "name": "Age_Income_Regression", 
     *         "type": "multiple_regression", 
     *         "result": "Significant relationship found", 
     *         "pValue": "0.003",   
     *         "variables": ["age", "income", "satisfaction_score"] 
     *       },
     *       { 
     *         "name": "Gender_Satisfaction_Ttest", 
     *         "type": "t_test", 
     *         "result": "No significant difference", 
     *         "pValue": "0.42", 
     *         "variables": ["gender", "satisfaction_score"] 
     *       }
     *     ]
     *   },
     *   "nextStageNeeded": true,
     *   "isRevision": false
     * }
     * 
     * 3. Final assembly stage:
     * {
     *   "sessionId": "quant_1234567890_abc123",
     *   "stage": "assembly",
     *   "stageNumber": 8,
     *   "totalStages": 8,
     *   "nextStageNeeded": false,  // This completes the session
     *   "isRevision": false
     * }
     */
    server.tool(
      "endsession",
      toolDescriptions["endsession"],
      {
        sessionId: z.string().describe("The unique session identifier obtained from startsession"),
        stage: z.string().describe("Current stage of analysis: 'summary', 'datasetUpdates', 'newAnalyses', 'newVisualizations', 'hypothesisResults', 'modelUpdates', 'projectStatus', or 'assembly'"),
        stageNumber: z.number().int().positive().describe("The sequence number of the current stage (starts at 1)"),
        totalStages: z.number().int().positive().describe("Total number of stages in the workflow (typically 8 for standard workflow)"),
        analysis: z.string().optional().describe("Text analysis or observations for the current stage"),
        stageData: z.record(z.string(), z.any()).optional().describe(`Stage-specific data structure - format depends on the stage type:
        - For 'summary' stage: { summary: "Session summary text", duration: "3 hours", project: "Project Name" }
        - For 'datasetUpdates' stage: { datasets: [{ name: "Dataset1", size: "500 rows", variables: "10", status: "cleaned", description: "Dataset description" }] }
        - For 'newAnalyses' stage: { analyses: [{ name: "Analysis1", type: "regression", result: "p<0.05", pValue: "0.03", variables: ["var1", "var2"] }] }
        - For 'newVisualizations' stage: { visualizations: [{ name: "Viz1", type: "scatter", description: "Correlation visualization", datasetName: "Dataset1" }] }
        - For 'hypothesisResults' stage: { hypotheses: [{ name: "H1", status: "confirmed", evidence: "Statistical significance in regression model", pValue: "0.02" }] }
        - For 'modelUpdates' stage: { models: [{ name: "Model1", type: "regression", performance: "R²=0.85", variables: ["var1", "var2"] }] }
        - For 'projectStatus' stage: { projectStatus: "in_progress", projectObservation: "Data analysis phase complete" }
        - For 'assembly' stage: no stageData needed - automatic assembly of previous stages`),
        nextStageNeeded: z.boolean().describe("Whether additional stages are needed after this one (false for final stage)"),
        isRevision: z.boolean().optional().describe("Whether this is revising a previous stage"),
        revisesStage: z.number().int().positive().optional().describe("If revising, which stage number is being revised")
      },
      /* 
       * Usage examples:
       * 
       * 1. Starting the end session process with the summary stage:
       * {
       *   "sessionId": "quant_1234567890_abc123",  // From startsession
       *   "stage": "summary",
       *   "stageNumber": 1,
       *   "totalStages": 8, 
       *   "analysis": "Analyzed progress on the multiple regression analysis",
       *   "stageData": {
       *     "summary": "Completed data preparation and initial statistical tests",
       *     "duration": "4 hours",
       *     "project": "Customer Satisfaction Study"  // Project name
       *   },
       *   "nextStageNeeded": true,  // More stages coming
       *   "isRevision": false
       * }
       * 
       * 2. Middle stage for new analyses:
       * {
       *   "sessionId": "quant_1234567890_abc123",
       *   "stage": "newAnalyses",
       *   "stageNumber": 3,
       *   "totalStages": 8,
       *   "analysis": "Conducted statistical tests on prepared data",
       *   "stageData": {
       *     "analyses": [
       *       { 
       *         "name": "Age_Income_Regression", 
       *         "type": "multiple_regression", 
       *         "result": "Significant relationship found", 
       *         "pValue": "0.003", 
       *         "variables": ["age", "income", "satisfaction_score"] 
       *       },
       *       { 
       *         "name": "Gender_Satisfaction_Ttest", 
       *         "type": "t_test", 
       *         "result": "No significant difference", 
       *         "pValue": "0.42", 
       *         "variables": ["gender", "satisfaction_score"] 
       *       }
       *     ]
       *   },
       *   "nextStageNeeded": true,
       *   "isRevision": false
       * }
       * 
       * 3. Final assembly stage:
       * {
       *   "sessionId": "quant_1234567890_abc123",
       *   "stage": "assembly",
       *   "stageNumber": 8,
       *   "totalStages": 8,
       *   "nextStageNeeded": false,  // This completes the session
       *   "isRevision": false
       * }
       */
      async (params: {
        sessionId: string;
        stage: string;
        stageNumber: number;
        totalStages: number;
        analysis?: string;
        stageData?: any;
        nextStageNeeded: boolean;
        isRevision?: boolean;
        revisesStage?: number;
      }) => {
        try {
          // Get or initialize session state from persistent storage
          const sessionStates = await loadSessionStates();
          
          // Validate session ID
          if (!sessionStates.has(params.sessionId)) {
            return {
              content: [{
                type: "text",
                text: JSON.stringify({ 
                  success: false,
                  error: `Session with ID ${params.sessionId} not found. Please start a new session with startsession.`
                }, null, 2)
              }]
            };
          }
          
          let sessionState = sessionStates.get(params.sessionId) || [];
          
          // Process the current stage
          const stageResult = await processStage(params, sessionState);
          
          // Store updated state
          if (params.isRevision && params.revisesStage) {
            // Find the analysis stages in the session state
            const analysisStages = sessionState.filter(item => item.type === 'analysis_stage') || [];
            
            if (params.revisesStage <= analysisStages.length) {
              // Replace the revised stage
              analysisStages[params.revisesStage - 1] = {
                type: 'analysis_stage',
                ...stageResult
              };
            } else {
              // Add as a new stage
              analysisStages.push({
                type: 'analysis_stage',
                ...stageResult
              });
            }
            
            // Update the session state with the modified analysis stages
            sessionState = [
              ...sessionState.filter(item => item.type !== 'analysis_stage'),
              ...analysisStages
            ];
          } else {
            // Add new stage
            sessionState.push({
              type: 'analysis_stage',
              ...stageResult
            });
          }
          
          // Update persistent storage
          sessionStates.set(params.sessionId, sessionState);
          await saveSessionStates(sessionStates);
          
          
          // If this is the assembly stage and we're done (no next stage needed), perform the end-session operations
          if (params.stage === "assembly" && !params.nextStageNeeded) {
            const endSessionArgs = stageResult.stageData;
            
            try {
              // Parse arguments
              const summary = endSessionArgs.summary;
              const duration = endSessionArgs.duration;
              const project = endSessionArgs.project;
              const datasetUpdates = endSessionArgs.datasetUpdates ? JSON.parse(endSessionArgs.datasetUpdates) : [];
              const newAnalyses = endSessionArgs.newAnalyses ? JSON.parse(endSessionArgs.newAnalyses) : [];
              const newVisualizations = endSessionArgs.newVisualizations ? JSON.parse(endSessionArgs.newVisualizations) : [];
              const hypothesisResults = endSessionArgs.hypothesisResults ? JSON.parse(endSessionArgs.hypothesisResults) : [];
              const modelUpdates = endSessionArgs.modelUpdates ? JSON.parse(endSessionArgs.modelUpdates) : [];
              const projectStatus = endSessionArgs.projectStatus;
              const projectObservation = endSessionArgs.projectObservation;
              
              // Create a timestamp to use instead of dates
              const timestamp = new Date().getTime().toString();
              
              // No longer need to create session entity since we're using persistent storage
              
              // 2. Update or create dataset entities
              if (datasetUpdates.length > 0) {
                for (const datasetUpdate of datasetUpdates) {
                  // Check if dataset exists
                  const datasetGraph = await knowledgeGraphManager.searchNodes(`name:${datasetUpdate.name}`);
                  
                  if (datasetGraph.entities.length > 0) {
                    // Update existing dataset
                    const datasetEntity = datasetGraph.entities[0];
                    const observations = datasetEntity.observations.filter(o => 
                      !o.startsWith("size:") && 
                      !o.startsWith("variables:")
                    );
                    
                    observations.push(`size:${datasetUpdate.size || "unknown"}`);
                    observations.push(`variables:${datasetUpdate.variables || "unknown"}`);
                    
                    if (datasetUpdate.description) {
                      observations.push(datasetUpdate.description);
                    }
                    
                    await knowledgeGraphManager.deleteObservations([{
                      entityName: datasetUpdate.name,
                      observations: datasetEntity.observations
                    }]);
                    
                    await knowledgeGraphManager.addObservations([{
                      entityName: datasetUpdate.name,
                      contents: observations
                    }]);
                    
                    // Update dataset status using setEntityStatus helper
                    if (datasetUpdate.status) {
                      await knowledgeGraphManager.setEntityStatus(datasetUpdate.name, datasetUpdate.status);
                    }
                  } else {
                    // Create new dataset
                    await knowledgeGraphManager.createEntities([{
                      name: datasetUpdate.name,
                      entityType: "dataset",
                      observations: [
                        `size:${datasetUpdate.size || "unknown"}`,
                        `variables:${datasetUpdate.variables || "unknown"}`,
                        datasetUpdate.description || "No description"
                      ]
                    }]);
                    
                    // Set dataset status using setEntityStatus helper
                    if (datasetUpdate.status) {
                      await knowledgeGraphManager.setEntityStatus(datasetUpdate.name, datasetUpdate.status);
                    }
                    
                    // Link dataset to project
                    await knowledgeGraphManager.createRelations([{
                      from: project,
                      to: datasetUpdate.name,
                      relationType: "contains"
                    }]);
                  }
                }
              }
              
              // 3. Add new analyses (statistical tests)
              if (newAnalyses.length > 0) {
                const timestamp = new Date().getTime().toString();
                const analysisEntities = newAnalyses.map((analysis: {name: string, type: string, result: string, pValue?: string, variables?: string[]}, i: number) => ({
                  name: analysis.name || `Analysis_${timestamp}_${i + 1}`,
                  entityType: "statistical_test",
                  observations: [
                    `type:${analysis.type}`,
                    `result:${analysis.result}`,
                    analysis.pValue ? `p-value:${analysis.pValue}` : null,
                    `project:${project}`
                  ].filter(Boolean) // Remove null values
                }));
                
                await knowledgeGraphManager.createEntities(analysisEntities);
                
                // Link analyses to project and session
                const analysisRelations = analysisEntities.flatMap((analysis: {name: string}) => [
                  {
                    from: project,
                    to: analysis.name,
                    relationType: "contains"
                  },
                  {
                    from: project,
                    to: analysis.name,
                    relationType: "produced"
                  }
                ]);
                
                await knowledgeGraphManager.createRelations(analysisRelations);
                
                // Link analyses to variables if specified
                for (let i = 0; i < newAnalyses.length; i++) {
                  const analysis = newAnalyses[i];
                  const analysisName = analysisEntities[i].name;
                  
                  if (analysis.variables && analysis.variables.length > 0) {
                    for (const variableName of analysis.variables) {
                      await knowledgeGraphManager.createRelations([{
                        from: analysisName,
                        to: variableName,
                        relationType: "analyzes"
                      }]);
                    }
                  }
                }
              }
              
              // 4. Add new visualizations
              if (newVisualizations.length > 0) {
                const vizEntities = newVisualizations.map((viz: {name: string, type: string, description: string, datasetName?: string}, i: number) => ({
                  name: viz.name || `Visualization_${timestamp}_${i + 1}`,
                  entityType: "visualization",
                  observations: [
                    `type:${viz.type}`,
                    viz.description,
                    `date:${timestamp}`,
                    viz.datasetName ? `dataset:${viz.datasetName}` : null,
                    `project:${project}`
                  ].filter(Boolean) // Remove null values
                }));
                
                await knowledgeGraphManager.createEntities(vizEntities);
                
                // Link visualizations to project and session
                const vizRelations = vizEntities.flatMap((viz: {name: string}) => [
                  {
                    from: project,
                    to: viz.name,
                    relationType: "contains"
                  },
                  {
                    from: project,
                    to: viz.name,
                    relationType: "produced"
                  }
                ]);
                
                await knowledgeGraphManager.createRelations(vizRelations);
                
                // Link visualizations to datasets if specified
                for (let i = 0; i < newVisualizations.length; i++) {
                  const viz = newVisualizations[i];
                  const vizName = vizEntities[i].name;
                  
                  if (viz.datasetName) {
                    await knowledgeGraphManager.createRelations([{
                      from: vizName,
                      to: viz.datasetName,
                      relationType: "visualizes"
                    }]);
                  }
                }
              }
              
              // 5. Update hypothesis test results
              if (hypothesisResults.length > 0) {
                for (const hypothesis of hypothesisResults) {
                  // Check if hypothesis exists
                  const hypGraph = await knowledgeGraphManager.searchNodes(`name:${hypothesis.name}`);
                  
                  if (hypGraph.entities.length > 0) {
                    // Update existing hypothesis
                    const hypEntity = hypGraph.entities[0];
                    const observations = hypEntity.observations.filter(o => 
                      !o.startsWith("status:") && 
                      !o.startsWith("p-value:") && 
                      !o.startsWith("updated:")
                    );
                    
                    observations.push(`status:${hypothesis.status}`);
                    observations.push(`updated:${timestamp}`);
                    
                    if (hypothesis.pValue) {
                      observations.push(`p-value:${hypothesis.pValue}`);
                    }
                    
                    if (hypothesis.notes) {
                      observations.push(hypothesis.notes);
                    }
                    
                    await knowledgeGraphManager.deleteEntities([hypothesis.name]);
                    await knowledgeGraphManager.createEntities([{
                      name: hypothesis.name,
                      entityType: "hypothesis",
                      observations
                    }]);
                  } else {
                    // Create new hypothesis
                    await knowledgeGraphManager.createEntities([{
                      name: hypothesis.name,
                      entityType: "hypothesis",
                      observations: [
                        `status:${hypothesis.status}`,
                        `created:${timestamp}`,
                        `updated:${timestamp}`,
                        hypothesis.pValue ? `p-value:${hypothesis.pValue}` : null,
                        hypothesis.notes || "No notes",
                        `project:${project}`
                      ].filter(Boolean) // Remove null values
                    }]);
                    
                    // Link hypothesis to project
                    await knowledgeGraphManager.createRelations([{
                      from: project,
                      to: hypothesis.name,
                      relationType: "contains"
                    }]);
                  }
                  
                  // Link hypothesis to related test if provided
                  if (hypothesis.testName) {
                    await knowledgeGraphManager.createRelations([{
                      from: hypothesis.name,
                      to: hypothesis.testName,
                      relationType: "tested_by"
                    }]);
                  }
                }
              }
              
              // 6. Update model information
              if (modelUpdates.length > 0) {
                for (const modelUpdate of modelUpdates) {
                  // Check if model exists
                  const modelGraph = await knowledgeGraphManager.searchNodes(`name:${modelUpdate.name}`);
                  
                  if (modelGraph.entities.length > 0) {
                    // Update existing model
                    const modelEntity = modelGraph.entities[0];
                    const observations = modelEntity.observations.filter(o => 
                      !o.startsWith("performance:") && 
                      !o.startsWith("updated:")
                    );
                    
                    observations.push(`performance:${JSON.stringify(modelUpdate.metrics)}`);
                    observations.push(`updated:${timestamp}`);
                    
                    if (modelUpdate.notes) {
                      observations.push(modelUpdate.notes);
                    }
                    
                    await knowledgeGraphManager.deleteEntities([modelUpdate.name]);
                    await knowledgeGraphManager.createEntities([{
                      name: modelUpdate.name,
                      entityType: "model",
                      observations
                    }]);
                  } else {
                    // Create new model
                    await knowledgeGraphManager.createEntities([{
                      name: modelUpdate.name,
                      entityType: "model",
                      observations: [
                        `type:${modelUpdate.type || "unknown"}`,
                        `performance:${JSON.stringify(modelUpdate.metrics || {})}`,
                        `created:${timestamp}`,
                        `updated:${timestamp}`,
                        modelUpdate.notes || "No notes",
                        `project:${project}`
                      ]
                    }]);
                    
                    // Link model to project
                    await knowledgeGraphManager.createRelations([{
                      from: project,
                      to: modelUpdate.name,
                      relationType: "contains"
                    }]);
                    
                    // Link model to dataset if provided
                    if (modelUpdate.datasetName) {
                      await knowledgeGraphManager.createRelations([{
                        from: modelUpdate.name,
                        to: modelUpdate.datasetName,
                        relationType: "trained_on"
                      }]);
                    }
                  }
                }
              }
              
              // 7. Update project status
              const projectGraph = await knowledgeGraphManager.searchNodes(`name:${project}`);
              if (projectGraph.entities.length > 0) {
                // Update project status using setEntityStatus helper
                if (projectStatus) {
                  await knowledgeGraphManager.setEntityStatus(project, projectStatus);
                }
                
                // Add project observation if provided
                if (projectObservation) {
                  await knowledgeGraphManager.addObservations([{
                    entityName: project,
                    contents: [projectObservation]
                  }]);
                }
              }
              
              // Return a summary message
              return {
                content: [{
                  type: "text",
                  text: `# Quantitative Research Session Recorded

I've recorded your research session focusing on the ${project} project.

## Session Summary
${summary}

${datasetUpdates.length > 0 ? `## Dataset Updates
${datasetUpdates.map((d: {name: string, size?: string, variables?: string, status?: string}) => 
  `- ${d.name}${d.size ? ` (${d.size})` : ''}${d.variables ? ` with ${d.variables} variables` : ''}${d.status ? ` - Status: ${d.status}` : ''}`
).join('\n')}` : "No dataset updates were recorded."}

${newAnalyses.length > 0 ? `## New Statistical Analyses
${newAnalyses.map((a: {name: string, type: string, result: string, pValue?: string}) => 
  `- ${a.name}: ${a.type} - Result: ${a.result}${a.pValue ? ` (p-value: ${a.pValue})` : ''}`
).join('\n')}` : "No new analyses were performed."}

${newVisualizations.length > 0 ? `## New Visualizations
${newVisualizations.map((v: {name: string, type: string, description: string}) => 
  `- ${v.name}: ${v.type} - ${v.description}`
).join('\n')}` : "No new visualizations were created."}

${hypothesisResults.length > 0 ? `## Hypothesis Test Results
${hypothesisResults.map((h: {name: string, status: string, pValue?: string}) => 
  `- ${h.name}: ${h.status}${h.pValue ? ` (p-value: ${h.pValue})` : ''}`
).join('\n')}` : "No hypothesis test results were recorded."}

${modelUpdates.length > 0 ? `## Model Updates
${modelUpdates.map((m: {name: string, type?: string, metrics?: any}) => 
  `- ${m.name}${m.type ? ` (${m.type})` : ''}: ${m.metrics ? `Metrics: ${JSON.stringify(m.metrics)}` : 'No metrics provided'}`
).join('\n')}` : "No model updates were recorded."}

## Project Status
Project ${project} has been updated to: ${projectStatus}

Would you like me to perform any additional updates to your quantitative research knowledge graph?`
                }]
              };
            } catch (error) {
              return {
                content: [{
                  type: "text",
                  text: `Error recording quantitative research session: ${error instanceof Error ? error.message : String(error)}`
                }]
              };
            }
          } else {
            // Return normal stage processing result
            return {
              content: [{
                type: "text",
                text: JSON.stringify({
                  success: true,
                  stageCompleted: params.stage,
                  nextStageNeeded: params.nextStageNeeded,
                  stageResult: stageResult
                }, null, 2)
              }]
            };
          }
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: JSON.stringify({ 
                success: false,
                error: error instanceof Error ? error.message : String(error)
              }, null, 2)
            }]
          };
        }
      }
    );

    // Connect the server to the transport
    const transport = new StdioServerTransport();
    await server.connect(transport);
  } catch (error) {
    console.error("Error starting server:", error);
    process.exit(1);
  }
}

// Run the main function
main().catch(error => {
  console.error("Unhandled error:", error);
  process.exit(1);
});

// Export the KnowledgeGraphManager for testing
export { KnowledgeGraphManager, loadSessionStates, saveSessionStates }; 
```
Page 6/9FirstPrevNextLast