|
8 | 8 | */ |
9 | 9 | import { createServer as createHttpServer } from "node:http"; |
10 | 10 | import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; |
11 | | -import { zodToJsonSchema } from "zod-to-json-schema"; |
12 | | -import createServer, { configSchema, createSandboxServer } from "./index.js"; |
| 11 | +import createServer, { createSandboxServer } from "./index.js"; |
13 | 12 | import type { IncomingMessage, ServerResponse } from "node:http"; |
14 | 13 |
|
15 | 14 | const PORT = parseInt(process.env.PORT || "10000", 10); |
@@ -52,18 +51,20 @@ function getConfig(req: IncomingMessage): { mineruApiKey?: string } { |
52 | 51 | } |
53 | 52 |
|
54 | 53 | // --------------------------------------------------------------------------- |
55 | | -// /.well-known/mcp-config — exposes config schema for Smithery form generation |
| 54 | +// Config schema for Smithery — must match Session Config format exactly |
| 55 | +// https://smithery.ai/docs/build/session-config |
56 | 56 | // --------------------------------------------------------------------------- |
57 | | -const configSchemaJson = zodToJsonSchema(configSchema, { |
58 | | - target: "openApi3", |
59 | | - $refStrategy: "none", |
60 | | -}) as Record<string, unknown>; |
61 | | - |
62 | | -// Smithery: x-from tells gateway to pass mineruApiKey via header (for secrets) |
63 | | -const props = (configSchemaJson.properties ?? {}) as Record<string, Record<string, unknown>>; |
64 | | -if (props.mineruApiKey) { |
65 | | - props.mineruApiKey["x-from"] = { header: "x-mineru-api-key" }; |
66 | | -} |
| 57 | +const configSchemaJson: Record<string, unknown> = { |
| 58 | + type: "object", |
| 59 | + properties: { |
| 60 | + mineruApiKey: { |
| 61 | + type: "string", |
| 62 | + title: "MinerU API Key", |
| 63 | + description: "Your MinerU API Key (obtain from https://mineru.net/apiManage/token)", |
| 64 | + "x-from": { header: "x-mineru-api-key" }, |
| 65 | + }, |
| 66 | + }, |
| 67 | +}; |
67 | 68 |
|
68 | 69 | const MCP_CONFIG_JSON = JSON.stringify({ |
69 | 70 | configSchema: configSchemaJson, |
@@ -185,17 +186,35 @@ async function handleRequest(req: IncomingMessage, res: ServerResponse) { |
185 | 186 | const method = req.method ?? "GET"; |
186 | 187 | const path = (req.url ?? "/").split("?")[0]; |
187 | 188 |
|
188 | | - // /.well-known/mcp/server-card.json — Smithery server scanning |
| 189 | + const corsHeaders = { |
| 190 | + "Access-Control-Allow-Origin": "*", |
| 191 | + "Access-Control-Allow-Methods": "GET", |
| 192 | + "Access-Control-Allow-Headers": "Content-Type", |
| 193 | + }; |
| 194 | + |
| 195 | + // /.well-known/mcp/server-card.json — Smithery server scanning (includes configSchema) |
189 | 196 | if (method === "GET" && path === "/.well-known/mcp/server-card.json") { |
190 | 197 | res.writeHead(200, { |
191 | 198 | "Content-Type": "application/json", |
192 | 199 | "Cache-Control": "public, max-age=300", |
| 200 | + ...corsHeaders, |
| 201 | + }); |
| 202 | + res.end(SERVER_CARD_JSON); |
| 203 | + return; |
| 204 | + } |
| 205 | + |
| 206 | + // /.well-known/mcp.json — alternate discovery path (SEP-1649) |
| 207 | + if (method === "GET" && path === "/.well-known/mcp.json") { |
| 208 | + res.writeHead(200, { |
| 209 | + "Content-Type": "application/json", |
| 210 | + "Cache-Control": "public, max-age=300", |
| 211 | + ...corsHeaders, |
193 | 212 | }); |
194 | 213 | res.end(SERVER_CARD_JSON); |
195 | 214 | return; |
196 | 215 | } |
197 | 216 |
|
198 | | - // /.well-known/mcp-config — config schema (legacy) |
| 217 | + // /.well-known/mcp-config — config schema only (legacy) |
199 | 218 | if (method === "GET" && path === "/.well-known/mcp-config") { |
200 | 219 | res.writeHead(200, { |
201 | 220 | "Content-Type": "application/json", |
|
0 commit comments