import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { createJob, getJob, listJobs, updateJob } from './storage.js'; import type { MetaRequest, MetaResponse } from './types.js'; import { runPipeline } from './pipeline.js'; const server = new McpServer( { name: 'meta-mcp', version: '0.2.0', }, { capabilities: { tools: {}, }, }, ); const ToolRequirementSchema = z.object({ name: z.string(), description: z.string(), inputSchema: z.record(z.unknown()), outputSchema: z.record(z.unknown()).optional(), notes: z.string().optional(), }); const MetaRequestSchema = z.object({ requirements: z.array(ToolRequirementSchema).min(1), timeoutSeconds: z.number().int().positive().optional(), requester: z .object({ name: z.string().optional(), pubkey: z.string().optional(), sessionId: z.string().optional(), }) .optional(), context: z.record(z.unknown()).optional(), }); server.registerTool( 'meta.request_tool', { description: 'Request creation of a new MCP tool/server. Returns a job id and later the server pubkey when available.', inputSchema: MetaRequestSchema, }, async (args) => { const parsed = MetaRequestSchema.parse(args); const job = createJob(parsed as MetaRequest); updateJob(job.id, { status: 'building', message: 'Accepted. Starting build pipeline.', }); // Run pipeline asynchronously runPipeline(job.id, parsed as MetaRequest).catch((err) => { updateJob(job.id, { status: 'failed', message: err instanceof Error ? err.message : String(err), }); }); const response: MetaResponse = { status: 'building', message: 'Accepted. Starting build pipeline.', jobId: job.id, }; return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; }, ); server.registerTool( 'meta.job_status', { description: 'Check status of a previously requested MCP tool build.', inputSchema: z.object({ jobId: z.string() }), }, async (args) => { const job = getJob(args.jobId); if (!job) { return { content: [ { type: 'text', text: JSON.stringify({ error: 'job_not_found', jobId: args.jobId }), }, ], }; } return { content: [ { type: 'text', text: JSON.stringify(job.response, null, 2), }, ], }; }, ); server.registerTool( 'meta.jobs_recent', { description: 'List recent build jobs for monitoring.', inputSchema: z.object({ limit: z.number().int().positive().optional() }), }, async (args) => { const jobs = listJobs().slice(0, args.limit ?? 10).map((job) => job.response); return { content: [ { type: 'text', text: JSON.stringify(jobs, null, 2), }, ], }; }, ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); } main().catch((err) => { console.error('Meta MCP server failed to start', err); process.exit(1); });