UNPKG

@codervisor/devlog-mcp

Version:

MCP server for managing development logs and working notes

167 lines (164 loc) 5.89 kB
import { zodToJsonSchema } from '../utils/schema-converter.js'; import { ListProjectsArgsSchema, GetCurrentProjectArgsSchema, SwitchProjectArgsSchema, } from '../schemas/mcp-tool-schemas.js'; // Project management tools for MCP server export const listProjectsTool = { name: 'project_list', description: 'List all available projects with their configurations', inputSchema: zodToJsonSchema(ListProjectsArgsSchema), }; export const getCurrentProjectTool = { name: 'project_get_current', description: 'Get the currently active project information', inputSchema: zodToJsonSchema(GetCurrentProjectArgsSchema), }; export const switchProjectTool = { name: 'project_switch', description: 'Switch to a different project by ID', inputSchema: zodToJsonSchema(SwitchProjectArgsSchema), }; export const projectTools = [listProjectsTool, getCurrentProjectTool, switchProjectTool]; // Tool implementations for project management export async function handleListProjects(apiClient) { try { const projects = await apiClient.listProjects(); if (projects.length === 0) { return { content: [ { type: 'text', text: 'No projects found.', }, ], }; } const projectsText = projects .map((project, index) => { return `${index + 1}. **${project.name}** (${project.id}) Description: ${project.description || 'No description'} Created: ${new Date(project.createdAt).toLocaleDateString()} Updated: ${new Date(project.updatedAt).toLocaleDateString()}`; }) .join('\n\n'); return { content: [ { type: 'text', text: `Found ${projects.length} projects:\n\n${projectsText}`, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error listing projects: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } export async function handleGetCurrentProject(adapter) { try { const currentProjectId = adapter.getCurrentProjectId(); const projects = await adapter.apiClient.listProjects(); // Both should be numbers now const currentProject = projects.find((p) => p.id === currentProjectId); if (!currentProject) { return { content: [ { type: 'text', text: `Current project '${currentProjectId}' not found in available projects.`, }, ], isError: true, }; } const projectInfo = `Current Project: **${currentProject.name}** ID: ${currentProject.id} Description: ${currentProject.description || 'No description'} Created: ${new Date(currentProject.createdAt).toLocaleDateString()} Updated: ${new Date(currentProject.updatedAt).toLocaleDateString()} Note: This is the MCP server's in-memory current project. Web app project may differ.`; return { content: [ { type: 'text', text: projectInfo, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error getting current project: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } export async function handleSwitchProject(adapter, args) { try { // Convert string argument to number for consistency const targetProjectId = parseInt(args.projectId, 10); if (isNaN(targetProjectId)) { return { content: [ { type: 'text', text: `Invalid project ID '${args.projectId}'. Must be a valid number.`, }, ], isError: true, }; } // Validate that the project exists const projects = await adapter.apiClient.listProjects(); const targetProject = projects.find((p) => p.id === targetProjectId); if (!targetProject) { return { content: [ { type: 'text', text: `Project '${args.projectId}' not found. Available projects: ${projects.map((p) => p.id).join(', ')}`, }, ], isError: true, }; } // Switch current project in memory only adapter.setCurrentProjectId(targetProjectId); const switchInfo = `Successfully switched MCP server to project: **${targetProject.name}** ID: ${targetProject.id} Description: ${targetProject.description || 'No description'} Created: ${new Date(targetProject.createdAt).toLocaleDateString()} Updated: ${new Date(targetProject.updatedAt).toLocaleDateString()} Note: This only affects the MCP server's current project. Web app project is managed separately.`; return { content: [ { type: 'text', text: switchInfo, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error switching to project '${args.projectId}': ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }