refactor(mcp-server): prepare transport abstraction for HTTP#24
Merged
marmar9615-cloud merged 1 commit intomainfrom Apr 28, 2026
Merged
refactor(mcp-server): prepare transport abstraction for HTTP#24marmar9615-cloud merged 1 commit intomainfrom
marmar9615-cloud merged 1 commit intomainfrom
Conversation
Pure refactor on the v0.4.0 line. No runtime behavior change. stdio remains the default and only transport. No HTTP server. Why --- The v0.4.0 design (PR #23 / docs/designs/http-mcp-transport-auth.md) calls for an opt-in HTTP MCP transport that shares 100% of the tool dispatcher, safety checks, confirmation gate, audit redaction, and idempotency with the stdio path. This PR is the prerequisite factoring step: pull the MCP `Server` instance and all tools/resources/prompts request handlers out of the stdio entry point and into a transport-agnostic factory, so the HTTP transport (PR 2) can plug in without forking any business logic. Per ADR D9 in docs/adr/0001-http-mcp-transport.md. Refs #22. What changes ------------ - New apps/mcp-server/src/server.ts: - Exports createMcpServer() — builds the MCP `Server` and registers every handler. Same name/version, same TOOLS list, same dispatchTool switch, same response shapes (text + structuredContent or isError on dispatch failure), same error contract. - Re-exports TOOLS and dispatchTool so future transports can introspect or wrap them if needed. - New apps/mcp-server/src/transports/stdio.ts: - Exports runStdioServer() — calls createMcpServer() and connects it to a StdioServerTransport. Stdout discipline preserved (the SDK's StdioServerTransport writes only JSON-RPC bytes; this module writes nothing). - apps/mcp-server/src/index.ts becomes a 19-line thin entry that imports runStdioServer and routes top-level startup errors to console.error + process.exit(1) — exactly the pre-refactor fatal-error shape. What does not change -------------------- - Tools, resources, prompts: identical to the pre-refactor list. Verified by direct stdio JSON-RPC smoke (initialize + tools/list returns serverInfo {agentbridge, 0.3.0} and the same five tools in the same order, no stderr noise). - Safety: assertAllowedUrl, assertSameOrigin, the loopback default, AGENTBRIDGE_ALLOWED_TARGET_ORIGINS strict allowlist, AGENTBRIDGE_ALLOW_REMOTE escape, audit redaction — all untouched. - Confirmation tokens, idempotency keys — untouched. - Stdio hygiene — verified by the existing stdio-hygiene.test.ts subprocess test (still 3/3 green). - Package versions — unchanged at 0.3.0. Lockstep bump to 0.4.0 lands with implementation PR 3 per the design's migration plan. - Published-tarball contents — unchanged at 6 files for the mcp-server package (verified by npm run pack:dry-run). Tests added ----------- - apps/mcp-server/src/tests/server-factory.test.ts — 4 tests. Uses the SDK's InMemoryTransport.createLinkedPair() to drive the factory through the real MCP wire protocol in-process: - lists the five expected tools in the expected order, and cross-checks against the static TOOLS export - lists the four expected resources - lists the four expected prompts - returns isError=true (not a JSON-RPC error) when an unknown tool is called — pinning the pre-refactor dispatchTool default-throw-then-catch contract Verification ------------ - npm run typecheck:clean — green - npm test — 125/125 green (121 existing + 4 new) - npm run build — all six packages OK - npm run pack:dry-run — all six tarballs OK at 0.3.0; file counts unchanged - node apps/mcp-server/dist/index.js < /dev/null — exit 0 - node apps/mcp-server/dist/index.js with initialize + tools/list — serverInfo and tools list byte-identical to pre-refactor; stderr empty Docs ---- - apps/mcp-server/src/transports/README.md updated to reflect stdio.ts as the first concrete adapter and the migration plan. - docs/designs/http-mcp-transport-auth.md migration plan marks PR 1 as landed. - README / AGENTS / CLAUDE / threat-model / production-readiness unchanged: this is an internal refactor with no user-visible surface change. Refs #22. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Apr 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.4.0 implementation PR 1 — transport abstraction. Pure refactor.
No runtime behavior change. stdio remains the default and only
transport. No HTTP server.
Refs #22. Design:
docs/designs/http-mcp-transport-auth.md.Why this exists
The v0.4.0 design (PR #23) calls for an opt-in HTTP MCP transport
that shares 100% of the tool dispatcher, safety checks, confirmation
gate, audit redaction, and idempotency with the stdio path. This PR
is the prerequisite factoring step: pull the MCP
Serverinstanceand every tools/resources/prompts request handler out of the stdio
entry point and into a transport-agnostic factory, so the HTTP
transport (PR 2) can plug in without forking any business logic.
Decision D9 in
docs/adr/0001-http-mcp-transport.md.Files
apps/mcp-server/src/server.tscreateMcpServer()factory +TOOLS+dispatchTool. Builds the MCPServer, registers every handler, returns the configured server. Identical name/version/capabilities/handler shape as the pre-refactor inline wiring.apps/mcp-server/src/transports/stdio.tsrunStdioServer()— callscreateMcpServer()and connects it toStdioServerTransport.apps/mcp-server/src/index.tsrunStdioServer; routes top-level startup errors toconsole.error+process.exit(1)exactly as before.apps/mcp-server/src/tests/server-factory.test.tsInMemoryTransport.createLinkedPair()to drive the factory through real MCP wire protocol — lists tools, resources, prompts, and pins the unknown-tool isError contract.apps/mcp-server/src/transports/README.mdstdio.tsas the first concrete adapter.docs/designs/http-mcp-transport-auth.mdConfirmations
no
AGENTBRIDGE_HTTP_*runtime env vars.0.3.0;lockstep bump to
0.4.0lands with implementation PR 3.pinning, loopback default, audit redaction, simulated
destructive demo actions all untouched.
stdio-hygiene.test.ts(3/3 green) plus a direct subprocess smoke check.
Verification commands
Live stdio smoke after build (initialize + tools/list, stderr
captured separately):
serverInfo, tool list order, and content are byte-identical tothe pre-refactor binary; stderr is empty.
Test plan
npm run typecheck:cleanpasses locally.npm test— 125/125 (121 prior + 4 new factory tests).npm run build— all six packages.npm run pack:dry-run— six tarballs OK at 0.3.0; filecounts unchanged from v0.3.0 published.
node apps/mcp-server/dist/index.js < /dev/null— cleanexit 0.
tools/list returns expected serverInfo + tools list with
empty stderr.
Recommended next PR
**v0.4.0 implementation PR 2 — opt-in Streamable HTTP transport
StreamableHTTPServerTransportfrom@modelcontextprotocol/sdkbehind auth +Originallowlist +loopback-by-default bind, mounted in front of
transport.handleRequest().Adds the
AGENTBRIDGE_HTTP_*env vars toconfig.ts. Builds ontop of the
createMcpServer()factory landed here.🤖 Generated with Claude Code