import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { executeTemplateAgentAction } from './runtime.js'; const onboardingSaveSchema = z.object({ ownerEmail: z.string().optional(), notes: z.string().optional(), confirm: z.boolean().optional(), }); const room13ClaimSchema = z.object({ room13Url: z.string().optional(), bearerToken: z.string().optional(), workerName: z.string().optional(), confirm: z.boolean().optional(), }); const TOOLS = [ { name: 'sin-code-database_help', description: 'Describe available agent actions.', inputSchema: { type: 'object', properties: {} }, parse: () => ({}), handler: async () => executeTemplateAgentAction({ action: 'agent.help' }), }, { name: 'sin-code-database_health', description: 'Check base agent readiness.', inputSchema: { type: 'object', properties: {} }, parse: () => ({}), handler: async () => executeTemplateAgentAction({ action: 'sin.code.database.health' }), }, { name: 'sin-code-database_room13_claim', description: 'Claim next task from Room-13. Requires confirm=true.', inputSchema: { type: 'object', properties: { room13Url: { type: 'string' }, bearerToken: { type: 'string' }, workerName: { type: 'string' }, confirm: { type: 'boolean' }, }, }, parse: (input: unknown) => room13ClaimSchema.parse(input ?? {}), handler: async (input: z.infer) => executeTemplateAgentAction({ action: 'sin.code.database.room13.claim', ...input }), }, { name: 'sin-code-database_onboarding_status', description: 'Read onboarding state.', inputSchema: { type: 'object', properties: {} }, parse: () => ({}), handler: async () => executeTemplateAgentAction({ action: 'sin.code.database.onboarding.status' }), }, { name: 'sin-code-database_onboarding_save', description: 'Persist onboarding state. Requires confirm=true.', inputSchema: { type: 'object', properties: { ownerEmail: { type: 'string' }, notes: { type: 'string' }, confirm: { type: 'boolean' }, }, }, parse: (input: unknown) => onboardingSaveSchema.parse(input ?? {}), handler: async (input: z.infer) => executeTemplateAgentAction({ action: 'sin.code.database.onboarding.save', ...input }), }, ] as const; export async function startMcpServer(): Promise { const server = new Server({ name: 'sin-code-database', version: '0.1.0' }, { capabilities: { tools: {} } }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: TOOLS.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const tool = TOOLS.find((entry) => entry.name === request.params.name); if (!tool) { return { content: [{ type: 'text', text: `Unknown tool: ${request.params.name}` }], isError: true, }; } const parsed = tool.parse(request.params.arguments ?? {}); const result = await tool.handler(parsed); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }); const transport = new StdioServerTransport(); await server.connect(transport); }