Skip to content

feat(mcp): add the MCP server on the official TypeScript SDK - #129

Open
oto-macenauer-absa wants to merge 1 commit into
feat/mcp-search-indexfrom
feat/mcp-runtime
Open

oto-macenauer-absa wants to merge 1 commit into
feat/mcp-search-indexfrom
feat/mcp-runtime

Conversation

@oto-macenauer-absa

@oto-macenauer-absa oto-macenauer-absa commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

What

Second layer of the MCP server stack (#117): the MCP server itself, built on the official MCP TypeScript SDK v2 and bundled at build time. It is not deployed yet; #119 wires it into nginx and the image.

Stack: #128 (search index) ← this PR ← #119 (deployment and docs).

Changes

  • mcp/src/protocol/: one file per tool (search_documents, list_documents, read_document), the kb:// resources and zod 4 schemas, all on the SDK v2 McpServer. The SDK was chosen over FastMCP, mcp-framework, xmcp and a hand-rolled JSON-RPC server.

  • mcp/src/transport/: a stateless Streamable HTTP handler with:

    • an Origin check;
    • a 64 KiB body cap;
    • per-client and global rate limits;
    • an in-flight cap and a timeout.

    Also a listener with /healthz, and designed browser error pages.

  • mcp/src/config.ts: the only reader of argv and the environment (KB_MCP_*). mcp/src/main.ts: the stdio and HTTP entry point.

  • mcp/build/bundle.ts: esbuild produces one minified dist/_mcp/server.mjs of about 410 KB, against a 450 KiB budget. Two substitutions make that possible: zod keeps English locales only, and the SDK's Ajv validator is swapped for its Workers validator (src/sdk-shims.ts).

  • Build step 3b also writes the bundle and dist/_error/not-found.html.

  • Makefile: build, lint, test, dev, size, image and prod targets, all delegating to npm scripts. The CI lint job now runs make lint.

  • tests/fragment-server.mjs serves the MCP endpoint through the same handler, and keeps _mcp and missing routes on the designed 404.

  • Tests:

    • golden byte-exact protocol responses (UPDATE_GOLDEN=1 regenerates them);
    • bundle-vs-source equivalence and the size budget;
    • HTTP guards, CORS and rate limits;
    • error pages.

Verification

  • make lint: green
  • npm audit --omit=dev --audit-level=high: green
  • npm test: all passed
  • npm run test:mcp: all passed
  • npx playwright test --config=playwright.config.ci.js: all passed
  • npm run test:container: all passed

Part of #117

🤖 Generated with Claude Code

protocol/ registers search_documents, list_documents, read_document and
the kb:// resources on the SDK v2 McpServer with zod 4 schemas.
transport/ is a stateless Streamable HTTP handler (Origin check, 64 KiB
body cap, per-client and global rate limits, in-flight cap, timeout)
with /healthz and designed browser error pages; config.ts is the only
reader of argv and KB_MCP_*.

Build step 3b also bundles the server into one minified
dist/_mcp/server.mjs (~410 KB; English-only zod locales, the SDK's
Workers validator instead of Ajv) and writes dist/_error/not-found.html.
The fragment server serves the endpoint through the same handler.

Golden byte-exact protocol tests (UPDATE_GOLDEN=1), bundle-vs-source
equivalence and a size budget pin the behaviour. A Makefile fronts the
npm scripts; CI lints with make lint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant