feat: migrate transport to the SDK's high-level McpServer API#8
Merged
Conversation
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>
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.
What
The low-level
Serverclass is deprecated in@modelcontextprotocol/sdkv1(
@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.
McpServerwraps a low-levelServer(
this.server = new Server(info, options)) and exposes it as.server"foradvanced usage (like sending notifications)" — exactly what Parley's
claude/channelpush path needs.
Changes
tools.ts— register the four reactive tools viamcp.registerToolwith Zodinput shapes as the single source of truth, replacing the hand-authored JSON Schema
ListTools/CallTooldispatcher.
topicSchemayields az.enumfor a closed allowlist (advertised as aJSON-Schema
enum, unchanged) orz.string()when a post pattern widens the set.stdio-bridge.ts/http.ts— constructMcpServer; the constructor forwardscapabilities (incl.
experimental: { 'claude/channel': {} }) + instructions to theunderlying
Server. VerifiedregisterCapabilitiesmerges (deep, per-key), soregisterTool'stools.listChangeddoes not clobberexperimental.channel-emit.ts— emit the customnotifications/claude/channelviamcp.server.notification(the sanctioned low-level escape hatch); same wire bytes.push-loop.ts— retyped toMcpServer.Behavior
Preserved: unknown-tool / invalid-input / thrown-handler all surface as
isErrorresults (McpServer funnels them through
createToolError, matching the old manualdispatcher). Also closes a latent drift —
limitwasint().positive()in Zod but abare
numberon 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 byallow.assert's "topic not allowed". Equivalent enforcement (the enum isallow.topics()), just earlier and more informative. With a post pattern the topic isz.string()andallow.assertstill produces "topic not allowed". Two assertions updated.Pre-1.0 note
Changes exported signatures (
registerTools/buildReactiveServer/emitChannel/startPushLoopnow takeMcpServer;ParleyBridge.server: McpServer). PerCONTRIBUTING.md, landed asfeat: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 InMemorypath, push loop, dynamic-enum advertisement): 33 passed.
<channel>push +claude/channelcapability advertised): 5 passed.
@modelcontextprotocol/sdk/server/index.jsimports.🤖 Generated with Claude Code