docs: 交付文档、维护指引与端到端回归
补齐 README、开发计划、维护交接与 E2E 用例,执行最终验收。
This commit is contained in:
1 parent
18732801b5
commit
6cd904d460
216 files changed
+37038
No files matched your search
@@ -0,0 +1,88 @@
|
||||
// A real MCP server (streamable HTTP, stateless) for the MCP-connector journeys:
|
||||
// the backend connects to it exactly as it would to a customer's server, lists
|
||||
// its tools and calls them when the (fake) model asks.
|
||||
//
|
||||
// POST /mcp the MCP endpoint
|
||||
// GET /__requests the headers each MCP request arrived with, oldest first
|
||||
// DELETE /__requests forget them
|
||||
//
|
||||
// Tools: lookup_order(order_id) → "Order <id>: shipped on 2 May via DHL".
|
||||
//
|
||||
// Run: node services/fake-mcp/server.ts --port 14030
|
||||
|
||||
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http'
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
|
||||
import { z } from 'zod'
|
||||
|
||||
interface SeenRequest {
|
||||
at: string
|
||||
method: string
|
||||
authorization: string | null
|
||||
rpcMethod: string | null
|
||||
}
|
||||
|
||||
const seen: SeenRequest[] = []
|
||||
|
||||
function mcpServer(): McpServer {
|
||||
const server = new McpServer({ name: 'e2e-orders', version: '1.0.0' })
|
||||
server.registerTool('lookup_order', {
|
||||
description: 'Look up an order by its id and return its shipping status.',
|
||||
inputSchema: { order_id: z.string().describe('The order id, e.g. A123') },
|
||||
}, async ({ order_id }) => ({
|
||||
content: [{ type: 'text', text: `Order ${order_id}: shipped on 2 May via DHL` }],
|
||||
}))
|
||||
return server
|
||||
}
|
||||
|
||||
async function readJson(req: IncomingMessage): Promise<unknown> {
|
||||
const chunks: Buffer[] = []
|
||||
for await (const chunk of req) chunks.push(chunk as Buffer)
|
||||
const raw = Buffer.concat(chunks).toString('utf8')
|
||||
return raw ? JSON.parse(raw) : undefined
|
||||
}
|
||||
|
||||
function send(res: ServerResponse, status: number, body: unknown) {
|
||||
res.writeHead(status, { 'content-type': 'application/json' })
|
||||
res.end(JSON.stringify(body))
|
||||
}
|
||||
|
||||
async function route(req: IncomingMessage, res: ServerResponse) {
|
||||
const path = new URL(req.url ?? '/', 'http://fake-mcp').pathname
|
||||
if (path === '/health') return send(res, 200, { status: 'ok' })
|
||||
if (path === '/__requests' && req.method === 'GET') return send(res, 200, seen)
|
||||
if (path === '/__requests' && req.method === 'DELETE') {
|
||||
seen.length = 0
|
||||
return send(res, 200, { ok: true })
|
||||
}
|
||||
if (path !== '/mcp') return send(res, 404, { error: `no route for ${path}` })
|
||||
if (req.method !== 'POST') return send(res, 405, { jsonrpc: '2.0', error: { code: -32000, message: 'Method not allowed.' }, id: null })
|
||||
|
||||
const body = await readJson(req)
|
||||
seen.push({
|
||||
at: new Date().toISOString(),
|
||||
method: req.method,
|
||||
authorization: req.headers.authorization ?? null,
|
||||
rpcMethod: (body as { method?: string } | undefined)?.method ?? null,
|
||||
})
|
||||
// Stateless: a fresh server and transport per request, as the SDK recommends.
|
||||
const server = mcpServer()
|
||||
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined })
|
||||
res.on('close', () => {
|
||||
void transport.close()
|
||||
void server.close()
|
||||
})
|
||||
await server.connect(transport)
|
||||
await transport.handleRequest(req, res, body)
|
||||
}
|
||||
|
||||
const portArg = process.argv.indexOf('--port')
|
||||
const port = Number(portArg > -1 ? process.argv[portArg + 1] : 14030)
|
||||
|
||||
createServer((req, res) => {
|
||||
route(req, res).catch((err: unknown) => {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
console.error(`[fake-mcp] ${req.method} ${req.url} -> 500: ${message}`)
|
||||
if (!res.headersSent) send(res, 500, { error: message })
|
||||
})
|
||||
}).listen(port, '127.0.0.1', () => console.log(`[fake-mcp] listening on http://127.0.0.1:${port}/mcp`))
|
||||
Reference in new issue
Block a user