Skip to content

refactor(mcp-server): prepare transport abstraction for HTTP#24

Merged
marmar9615-cloud merged 1 commit intomainfrom
feature/v040-transport-abstraction
Apr 28, 2026
Merged

refactor(mcp-server): prepare transport abstraction for HTTP#24
marmar9615-cloud merged 1 commit intomainfrom
feature/v040-transport-abstraction

Conversation

@marmar9615-cloud
Copy link
Copy Markdown
Owner

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 Server instance
and 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

Path Change
apps/mcp-server/src/server.ts NEW. Exports createMcpServer() factory + TOOLS + dispatchTool. Builds the MCP Server, 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.ts NEW. Exports runStdioServer() — calls createMcpServer() and connects it to StdioServerTransport.
apps/mcp-server/src/index.ts REFACTORED. 206 lines → 19 lines. Imports runStdioServer; routes top-level startup errors to console.error + process.exit(1) exactly as before.
apps/mcp-server/src/tests/server-factory.test.ts NEW. 4 in-process tests using the SDK's InMemoryTransport.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.md Updated to reflect stdio.ts as the first concrete adapter.
docs/designs/http-mcp-transport-auth.md Migration plan checklist marks PR 1 as landed.

Confirmations

  • stdio remains the default and only transport.
  • No HTTP server implemented. No listener, no auth, no CORS,
    no AGENTBRIDGE_HTTP_* runtime env vars.
  • No package versions changed. All six remain at 0.3.0;
    lockstep bump to 0.4.0 lands with implementation PR 3.
  • No npm publish, no git tag, no GitHub release.
  • Dependabot PRs untouched.
  • Safety invariants preserved — confirmation gate, origin
    pinning, loopback default, audit redaction, simulated
    destructive demo actions all untouched.
  • Stdout hygiene preserved — verified by
    stdio-hygiene.test.ts
    (3/3 green) plus a direct subprocess smoke check.

Verification commands

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

Live stdio smoke after build (initialize + tools/list, stderr
captured separately):

{"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{},"resources":{},"prompts":{}},"serverInfo":{"name":"agentbridge","version":"0.3.0"}},"jsonrpc":"2.0","id":1}
{"result":{"tools":[{"name":"discover_manifest", ...}]}, ...}
---stderr---  (empty)

serverInfo, tool list order, and content are byte-identical to
the pre-refactor binary; stderr is empty.

Test plan

  • npm run typecheck:clean passes 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; file
    counts unchanged from v0.3.0 published.
  • node apps/mcp-server/dist/index.js < /dev/null — clean
    exit 0.
  • Live JSON-RPC smoke against built dist — initialize +
    tools/list returns expected serverInfo + tools list with
    empty stderr.
  • CI green on Node 20.x and 22.x.
  • Main CI green after merge.
  • release-check green on main.

Recommended next PR

**v0.4.0 implementation PR 2 — opt-in Streamable HTTP transport

  • static bearer auth.** Wraps StreamableHTTPServerTransport from
    @modelcontextprotocol/sdk behind auth + Origin allowlist +
    loopback-by-default bind, mounted in front of transport.handleRequest().
    Adds the AGENTBRIDGE_HTTP_* env vars to config.ts. Builds on
    top of the createMcpServer() factory landed here.

🤖 Generated with Claude Code

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>
@marmar9615-cloud marmar9615-cloud merged commit df19489 into main Apr 28, 2026
2 checks passed
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