Skip to content

feat: migrate transport to the SDK's high-level McpServer API#8

Merged
sharpTrick merged 2 commits into
mainfrom
feat/mcpserver-migration
Jul 4, 2026
Merged

feat: migrate transport to the SDK's high-level McpServer API#8
sharpTrick merged 2 commits into
mainfrom
feat/mcpserver-migration

Conversation

@sharpTrick

Copy link
Copy Markdown
Owner

What

The low-level Server class is deprecated in @modelcontextprotocol/sdk v1
(@deprecated Use McpServer instead… Only use Server for advanced use cases).
This migrates the transport layer to the SDK's official high-level McpServer
same package, its blessed surface. McpServer wraps a low-level Server
(this.server = new Server(info, options)) and exposes it as .server "for
advanced usage (like sending notifications)" — exactly what Parley's claude/channel
push path needs.

Changes

  • tools.ts — register the four reactive tools via mcp.registerTool with Zod
    input shapes as the single source of truth
    , replacing the hand-authored JSON Schema
    • the separate (already-drifted) Zod parsers + the manual ListTools/CallTool
      dispatcher. topicSchema yields a z.enum for a closed allowlist (advertised as a
      JSON-Schema enum, unchanged) or z.string() when a post pattern widens the set.
  • stdio-bridge.ts / http.ts — construct McpServer; the constructor forwards
    capabilities (incl. experimental: { 'claude/channel': {} }) + instructions to the
    underlying Server. Verified registerCapabilities merges (deep, per-key), so
    registerTool's tools.listChanged does not clobber experimental.
  • channel-emit.ts — emit the custom notifications/claude/channel via
    mcp.server.notification (the sanctioned low-level escape hatch); same wire bytes.
  • push-loop.ts — retyped to McpServer.

Behavior

Preserved: unknown-tool / invalid-input / thrown-handler all surface as isError
results (McpServer funnels them through createToolError, matching the old manual
dispatcher). Also closes a latent drift — limit was int().positive() in Zod but a
bare number on the wire; now one Zod shape drives both.

One visible shift: under a closed allowlist, a disallowed topic is now rejected at
the schema layer (Invalid enum value, which lists the valid topics) instead of by
allow.assert's "topic not allowed". Equivalent enforcement (the enum is
allow.topics()), just earlier and more informative. With a post pattern the topic is
z.string() and allow.assert still produces "topic not allowed". Two assertions updated.

Pre-1.0 note

Changes exported signatures (registerTools / buildReactiveServer / emitChannel /
startPushLoop now take McpServer; ParleyBridge.server: McpServer). Per
CONTRIBUTING.md, landed as feat: rather than a breaking change.

Verification

  • tsc -b (build + typecheck, all packages): clean — no downstream plugin touched.
  • bridge-core: 124 passed / 1 skipped; transport subset (real Server↔Client InMemory
    path, push loop, dynamic-enum advertisement): 33 passed.
  • fakechat loopback (buildBridge → attach → live <channel> push + claude/channel
    capability advertised): 5 passed.
  • Grep guard: zero residual @modelcontextprotocol/sdk/server/index.js imports.

🤖 Generated with Claude Code

sharpTrick and others added 2 commits July 4, 2026 00:16
The low-level `Server` class is deprecated in @modelcontextprotocol/sdk v1
in favor of `McpServer`. Migrate the transport layer to the high-level API,
staying on the same package.

- tools.ts: register the reactive tools via `mcp.registerTool` with Zod
  input shapes as the single source of truth, replacing the hand-authored
  JSON Schema + separate (drifted) Zod parsers + the manual ListTools/
  CallTool dispatcher. `topicSchema` yields a `z.enum` for a closed
  allowlist (advertised as a JSON-Schema enum, unchanged) or `z.string()`
  when a post pattern widens the set.
- stdio-bridge.ts / http.ts: construct `McpServer`; the constructor forwards
  capabilities (incl. `experimental: claude/channel`) + instructions to the
  underlying Server.
- channel-emit.ts: emit the custom `notifications/claude/channel` via
  `mcp.server.notification` (McpServer's sanctioned low-level escape hatch).
- push-loop.ts: retyped to `McpServer`.

Behavior is preserved: unknown-tool / invalid-input / thrown-handler all
surface as `isError` results (McpServer funnels them through createToolError).
The one visible shift: a disallowed topic under a closed allowlist is now
rejected at the schema layer (Invalid enum value) instead of by allow.assert
— equivalent enforcement, earlier and more informative. Tests updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sharpTrick sharpTrick merged commit c140b11 into main Jul 4, 2026
3 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