139 lines
3.2 KiB
TypeScript
139 lines
3.2 KiB
TypeScript
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);
|
|
});
|