Skip to content

Commit c19d80a

Browse files
refactor(mcp): split api/mcp.ts into focused modules under api/mcp/ (koala73#3881)
* refactor(mcp): split api/mcp.ts into focused modules under api/mcp/ Pure structural decomposition with zero behaviour change. The ~4,500-LOC `api/mcp.ts` god-file is split into ten focused modules under `api/mcp/`, with `api/mcp.ts` reduced to a ~50-LOC shim that re-exports the same public surface so the Vercel-edge route URL and every consumer (tests, scripts, sibling APIs) keeps working unchanged. Module layout: api/mcp.ts — thin re-export shim (~50 LOC) api/mcp/handler.ts — mcpHandler, default export, dispatch switch api/mcp/auth.ts — auth resolution, rate limiters, PRODUCTION_DEPS, buildAuthHeaders api/mcp/quota.ts — reserveQuota + F4 clamp loop api/mcp/dispatch.ts — dispatchToolsCall, executeTool, per-tool budget gate, telemetry emission api/mcp/registry/cache-tools.ts — 27 cache tools (no `_execute`) api/mcp/registry/rpc-tools.ts — 12 RPC tools (with `_execute`, incl. describe_tool) api/mcp/registry/index.ts — merged TOOL_REGISTRY, buildPublicTool, SUMMARY_SCHEMA, TOOL_LIST_RESPONSE, TOOL_LIST_BYTES, collision-guard api/mcp/telemetry.ts — emitTelemetry + key allowlists api/mcp/constants.ts — protocol versions, server name/version, SERVER_INSTRUCTIONS, log levels, byte caps api/mcp/freshness.ts — evaluateFreshness api/mcp/jmespath.ts — applyJmespath + JMESPATH_SCHEMA api/mcp/filters.ts — cache-tool _postFilter helpers + cacheEnvelope api/mcp/utils.ts — utf8ByteLength + compressDescription api/mcp/rpc.ts — rpcOk / rpcError (JSON-RPC envelope helpers) api/mcp/types.ts — shared type declarations Hard contracts preserved: - Vercel-edge route stays at api/mcp.ts; no vercel.json change. - All named exports previously consumed by tests + scripts re-exported from the shim (mcpHandler, evaluateFreshness, negotiateProtocolVersion, MCP_SUPPORTED_PROTOCOL_VERSIONS, MCP_PROTOCOL_VERSION, MCP_SUPPORTED_CLIENT_MATRIX, JMESPATH_SCHEMA, buildPublicTool, applyJmespath, utf8ByteLength, compressDescription, executeTool, dispatchToolsCall, MCP_TOOLCALL_TELEMETRY_KEYS, MCP_TOOLS_LIST_TELEMETRY_KEYS, JMESPATH_MAX_EXPR_BYTES, JMESPATH_MAX_OUTPUT_BYTES, TOOL_DESCRIPTION_MAX_BYTES, __testing__). - `__testing__.TOOL_REGISTRY` re-exported by REFERENCE so `_execute` monkey-patches in `tests/mcp-tool-output-contracts.test.mjs` propagate to the dispatcher. - The TOOL_REGISTRY collision-guard `for` loop and the `TOOL_LIST_RESPONSE` / `TOOL_LIST_BYTES` precomputes run at module load of `registry/index.ts` — same load-time behaviour as before. - `MCP_SUPPORTED_PROTOCOL_VERSIONS` / `MCP_PROTOCOL_VERSION` are declared inline in the shim (env at shim-load), and `negotiateProtocolVersion` re-reads env at call time. Together they preserve the dynamic-import cache-bust pattern used by `tests/mcp-protocol-version.test.mjs` AND guarantee the runtime handler always negotiates against the active env state. - No `SERVER_VERSION` bump; no wire change. - No new tests. The contract is that the existing test suite passes unchanged. Test edits limited to four files where existing tests read `api/mcp.ts` as source text to grep for symbols that now live under `api/mcp/`. Each edit retargets the file path to the new location (or concatenates two files for cross-cutting greps) — no test logic changed. Verification: - `npm run typecheck:api` — green - `npm run lint` — green (243 warnings, identical to main) - `npm run test:data` — 9603/9603 pass, 0 fail - Sabotage 1 (drop `evaluateFreshness` re-export from shim) → `tests/mcp.test.mjs` fails with `evaluateFreshness is not a function`. Reverted. - Sabotage 2 (per-tool value-copy `__TOOL_REGISTRY.map(t => ({...t}))`) → `tests/mcp-tool-output-contracts.test.mjs` fails on the `get_commodity_geo` RPC tool because the `_execute` monkey-patch lands on the clone instead of the dispatcher's reference. Reverted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(mcp): point collision-guard errors at registry/index.ts (Greptile P2) The TOOL_REGISTRY collision guard moved from api/mcp.ts to api/mcp/registry/index.ts during the structural split, but the two throw messages still cited the old file path. A future tool author who trips the guard would be sent to the wrong file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(mcp): list api/mcp/*.ts in api-route-exceptions.json The sebuf API contract enforcement (scripts/enforce-sebuf-api-contract.mjs) requires every file under api/ to be either a sebuf gateway or a listed exception. Pre-refactor only api/mcp.ts was listed; the 15 new modules under api/mcp/ now have their own entries, each citing the same external-protocol constraint as the parent MCP shim. No category/owner change; every entry inherits @SebastienMelki and external-protocol. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(mcp): drop stale api/mcp.ts:NNN line refs from registry/index.ts (Greptile P2 round 2) The buildPublicTool comment block cited `api/mcp.ts:810` and `api/mcp.ts:655` as examples of `enum`/`items.enum` shapes. Those line numbers don't exist after the split. Replaced with shape-named examples (get_market_data.asset_class.items.enum, get_news_intelligence.topic.enum) so the comment survives future renumbering. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c2c280c commit c19d80a

21 files changed

Lines changed: 4775 additions & 4504 deletions

api/api-route-exceptions.json

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,112 @@
55
{
66
"path": "api/mcp.ts",
77
"category": "external-protocol",
8-
"reason": "MCP streamable-HTTP transport — JSON-RPC 2.0 envelope dictated by the Model Context Protocol spec, not something we can or should redefine as proto.",
8+
"reason": "MCP streamable-HTTP transport — JSON-RPC 2.0 envelope dictated by the Model Context Protocol spec, not something we can or should redefine as proto. After the api/mcp.ts → api/mcp/ structural split, this file is a thin re-export shim that preserves the Vercel edge route URL and the public export surface; the actual handler and supporting modules live under api/mcp/ (each listed below).",
9+
"owner": "@SebastienMelki",
10+
"removal_issue": null
11+
},
12+
{
13+
"path": "api/mcp/handler.ts",
14+
"category": "external-protocol",
15+
"reason": "MCP transport handler — mcpHandler + default Vercel entry. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
16+
"owner": "@SebastienMelki",
17+
"removal_issue": null
18+
},
19+
{
20+
"path": "api/mcp/auth.ts",
21+
"category": "external-protocol",
22+
"reason": "MCP auth resolution (Bearer + X-WorldMonitor-Key), Pro pre-checks, rate-limiter init, and PRODUCTION_DEPS bundle for the MCP handler. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
23+
"owner": "@SebastienMelki",
24+
"removal_issue": null
25+
},
26+
{
27+
"path": "api/mcp/quota.ts",
28+
"category": "external-protocol",
29+
"reason": "MCP Pro daily-quota INCR-first reservation + F4 clamp loop. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
30+
"owner": "@SebastienMelki",
31+
"removal_issue": null
32+
},
33+
{
34+
"path": "api/mcp/dispatch.ts",
35+
"category": "external-protocol",
36+
"reason": "MCP tools/call dispatcher — executeTool (cache-tool path), dispatchToolsCall, per-tool budget gate, telemetry emission, F6 cache_all_null guard. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
37+
"owner": "@SebastienMelki",
38+
"removal_issue": null
39+
},
40+
{
41+
"path": "api/mcp/registry/cache-tools.ts",
42+
"category": "external-protocol",
43+
"reason": "MCP TOOL_REGISTRY cache-tool entries (no _execute). Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
44+
"owner": "@SebastienMelki",
45+
"removal_issue": null
46+
},
47+
{
48+
"path": "api/mcp/registry/rpc-tools.ts",
49+
"category": "external-protocol",
50+
"reason": "MCP TOOL_REGISTRY RPC-tool entries (with _execute, incl. describe_tool). Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
51+
"owner": "@SebastienMelki",
52+
"removal_issue": null
53+
},
54+
{
55+
"path": "api/mcp/registry/index.ts",
56+
"category": "external-protocol",
57+
"reason": "MCP TOOL_REGISTRY merge + buildPublicTool + SUMMARY_SCHEMA + TOOL_LIST_RESPONSE precompute + collision guard. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
58+
"owner": "@SebastienMelki",
59+
"removal_issue": null
60+
},
61+
{
62+
"path": "api/mcp/telemetry.ts",
63+
"category": "external-protocol",
64+
"reason": "MCP per-tools/call + per-initialize structured-log emission and the two closed-key telemetry allowlists (MCP_TOOLCALL_TELEMETRY_KEYS, MCP_TOOLS_LIST_TELEMETRY_KEYS). Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
65+
"owner": "@SebastienMelki",
66+
"removal_issue": null
67+
},
68+
{
69+
"path": "api/mcp/constants.ts",
70+
"category": "external-protocol",
71+
"reason": "MCP protocol version negotiation (env-at-call-time), SERVER_NAME, SERVER_VERSION, SERVER_INSTRUCTIONS, MCP_LOG_LEVELS, byte caps. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
72+
"owner": "@SebastienMelki",
73+
"removal_issue": null
74+
},
75+
{
76+
"path": "api/mcp/freshness.ts",
77+
"category": "external-protocol",
78+
"reason": "MCP cache-tool freshness evaluation (evaluateFreshness) — drives the per-response cached_at + stale envelope fields. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
79+
"owner": "@SebastienMelki",
80+
"removal_issue": null
81+
},
82+
{
83+
"path": "api/mcp/jmespath.ts",
84+
"category": "external-protocol",
85+
"reason": "MCP universal JMESPath projection (applyJmespath + JMESPATH_SCHEMA) — two-gate input/output byte cap, soft-failure envelopes. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
86+
"owner": "@SebastienMelki",
87+
"removal_issue": null
88+
},
89+
{
90+
"path": "api/mcp/filters.ts",
91+
"category": "external-protocol",
92+
"reason": "MCP cache-tool _postFilter helpers (argStr/argNum/narrowNested/etc.), summarizeData, and cacheEnvelope schema builder. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
93+
"owner": "@SebastienMelki",
94+
"removal_issue": null
95+
},
96+
{
97+
"path": "api/mcp/utils.ts",
98+
"category": "external-protocol",
99+
"reason": "MCP utf8ByteLength + compressDescription — UTF-8 byte counting and tools/list description compression. Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
100+
"owner": "@SebastienMelki",
101+
"removal_issue": null
102+
},
103+
{
104+
"path": "api/mcp/rpc.ts",
105+
"category": "external-protocol",
106+
"reason": "MCP JSON-RPC 2.0 envelope helpers (rpcOk + rpcError). Extracted from api/mcp.ts during the structural split; same external-protocol constraint as the parent shim.",
107+
"owner": "@SebastienMelki",
108+
"removal_issue": null
109+
},
110+
{
111+
"path": "api/mcp/types.ts",
112+
"category": "external-protocol",
113+
"reason": "MCP shared type declarations (McpAuthContext, McpHandlerDeps, ToolDef union, etc.). Pure types — no runtime behaviour — but lives under api/mcp/ so the contract script requires a listing.",
9114
"owner": "@SebastienMelki",
10115
"removal_issue": null
11116
},

0 commit comments

Comments
 (0)