Skip to main content
Glama

MCP Project Context Server

server.ts13.2 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { ProjectStore } from "./storage/project-store.js"; import { ContextManager } from "./storage/context-manager.js"; export class MCPProjectContextServer { private server: McpServer; private store: ProjectStore; private contextManager: ContextManager; constructor() { this.server = new McpServer({ name: "project-context-server", version: "1.0.0", }); this.store = new ProjectStore(); this.contextManager = new ContextManager(this.store); this.setupTools(); } private setupTools(): void { // Create Project this.server.registerTool( "create_project", { title: "Create Project", description: "Create a new project with initial context", inputSchema: { name: z.string().describe("Project name"), description: z.string().describe("Project description"), techStack: z .object({ frontend: z.array(z.string()).default([]), backend: z.array(z.string()).default([]), database: z.array(z.string()).default([]), infrastructure: z.array(z.string()).default([]), tools: z.array(z.string()).default([]), }) .optional(), currentPhase: z.string().describe("Current project phase"), }, }, async ({ name, description, techStack, currentPhase }) => { try { const project = await this.store.createProject({ name, description, status: "planning", techStack: techStack || { frontend: [], backend: [], database: [], infrastructure: [], tools: [], }, architecture: { observability: [], }, currentPhase, nextSteps: [], tasks: [], decisions: [], notes: [], }); return { content: [ { type: "text", text: `Project "${project.name}" created with ID: ${project.id}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error creating project: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Get Project Context this.server.registerTool( "get_project_context", { title: "Get Project Context", description: "Get comprehensive project context and current state", inputSchema: { projectId: z.string().describe("Project ID"), }, }, async ({ projectId }) => { try { const context = await this.contextManager.getCurrentContext( projectId ); return { content: [ { type: "text", text: context, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting project context: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // List Projects this.server.registerTool( "list_projects", { title: "List Projects", description: "List all projects ordered by last accessed", inputSchema: {}, }, async () => { try { const projects = await this.store.listProjects(); const projectList = projects .map( (p) => `- ${p.name} (${p.id}) - ${ p.status } - Last accessed: ${new Date( p.lastAccessedAt ).toLocaleDateString()}` ) .join("\n"); return { content: [ { type: "text", text: `Active Projects:\n${projectList || "No projects found"}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error listing projects: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Add Task this.server.registerTool( "add_task", { title: "Add Task", description: "Add a new task to the project", inputSchema: { projectId: z.string().describe("Project ID"), title: z.string().describe("Task title"), description: z.string().optional().describe("Task description"), priority: z .enum(["low", "medium", "high", "critical"]) .describe("Task priority"), tags: z.array(z.string()).default([]).describe("Task tags"), }, }, async ({ projectId, title, description, priority, tags }) => { try { const task = await this.contextManager.addTask(projectId, { title, description: description || "", status: "todo", priority, tags: tags || [], blockers: [], dependencies: [], }); return { content: [ { type: "text", text: `Task "${task.title}" added with ID: ${task.id}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error adding task: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Update Task this.server.registerTool( "update_task", { title: "Update Task", description: "Update task status or details", inputSchema: { projectId: z.string().describe("Project ID"), taskId: z.string().describe("Task ID"), status: z .enum(["todo", "in-progress", "blocked", "completed"]) .optional() .describe("New task status"), title: z.string().optional().describe("New task title"), description: z.string().optional().describe("New task description"), priority: z .enum(["low", "medium", "high", "critical"]) .optional() .describe("New task priority"), }, }, async ({ projectId, taskId, status, title, description, priority }) => { try { const updatedTask = await this.contextManager.updateTask( projectId, taskId, { ...(status && { status }), ...(title && { title }), ...(description && { description }), ...(priority && { priority }), } ); return { content: [ { type: "text", text: `Task "${updatedTask.title}" updated successfully`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error updating task: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Add Note this.server.registerTool( "add_note", { title: "Add Note", description: "Add a note to the project", inputSchema: { projectId: z.string().describe("Project ID"), content: z.string().describe("Note content"), category: z.string().optional().describe("Note category"), }, }, async ({ projectId, content, category }) => { try { await this.contextManager.addNote(projectId, content, category); return { content: [ { type: "text", text: "Note added successfully", }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error adding note: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Record Decision this.server.registerTool( "record_decision", { title: "Record Decision", description: "Record an architectural or technical decision", inputSchema: { projectId: z.string().describe("Project ID"), decision: z.string().describe("Decision made"), reasoning: z.string().describe("Reasoning behind the decision"), impact: z .string() .optional() .describe("Expected impact of the decision"), }, }, async ({ projectId, decision, reasoning, impact }) => { try { await this.contextManager.recordDecision( projectId, decision, reasoning, impact ); return { content: [ { type: "text", text: "Decision recorded successfully", }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error recording decision: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // Start Session this.server.registerTool( "start_session", { title: "Start Session", description: "Start a new development session", inputSchema: { projectId: z.string().describe("Project ID"), goals: z.array(z.string()).describe("Session goals"), }, }, async ({ projectId, goals }) => { try { const session = await this.store.createSession({ projectId, startTime: new Date().toISOString(), goals, achievements: [], blockers: [], nextSession: [], }); return { content: [ { type: "text", text: `Session started with ID: ${session.sessionId}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error starting session: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); // End Session this.server.registerTool( "end_session", { title: "End Session", description: "End current session with summary", inputSchema: { sessionId: z.string().describe("Session ID"), achievements: z .array(z.string()) .default([]) .describe("Session achievements"), blockers: z .array(z.string()) .default([]) .describe("Blockers encountered"), nextSession: z .array(z.string()) .default([]) .describe("Plans for next session"), }, }, async ({ sessionId, achievements, blockers, nextSession }) => { try { // Note: You'll need to implement updateSession in ProjectStore // For now, just return success return { content: [ { type: "text", text: `Session ${sessionId} ended successfully`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error ending session: ${ error instanceof Error ? error.message : "Unknown error" }`, }, ], }; } } ); } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.log("MCP Project Context Server connected and listening"); // Keep the process alive process.stdin.on("close", () => { console.error("Transport closed"); process.exit(0); }); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aaronfeingold/mcp-project-context'

If you have feedback or need assistance with the MCP directory API, please join our Discord server