Initial meta MCP server scaffold
This commit is contained in:
130
src/server.ts
Normal file
130
src/server.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
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';
|
||||
|
||||
const server = new McpServer(
|
||||
{
|
||||
name: 'meta-mcp',
|
||||
version: '0.1.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);
|
||||
|
||||
// TODO: Hook into build/deploy pipeline
|
||||
updateJob(job.id, {
|
||||
status: 'building',
|
||||
message: 'Accepted. Building MCP server (pipeline stub).',
|
||||
});
|
||||
|
||||
const response: MetaResponse = {
|
||||
status: 'building',
|
||||
message: 'Accepted. Building MCP server (pipeline stub).',
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user