@@ -60,13 +60,32 @@ onclose? / onerror? u2014 callbacks
6060fallbackNotificationHandler? u2014 catch-all
6161```
6262
63- A minimal shim reproducing this surface is ~ 300 lines:
63+ A minimal shim reproducing this surface is ~ 400-500 lines:
6464- JSON-RPC message routing (request/response correlation by ID)
6565- Handler map keyed by method string (extracted from schema at registration time)
66- - Timeout + AbortSignal support
67- - Zod schema validation on incoming requests and outgoing results
66+ - Timeout + AbortSignal support for outbound requests
67+ - ` notifications/cancelled ` handler — aborts in-flight request handlers via AbortController
68+ - ` notifications/progress ` handler — forwards to per-request progress callbacks, resets timeouts
69+ - Auto-registered ` ping ` handler (returns ` {} ` )
70+ - Zod schema validation on incoming requests
71+ - ` RequestHandlerExtra ` construction (signal, sessionId, sendRequest, sendNotification)
6872- No task management, no capability negotiation, no auth
6973
74+ ### Protocol features the shim MUST include
75+
76+ | Feature | Why | How it works in V2 Protocol |
77+ | ---------| -----| -----------------------------|
78+ | Request/response correlation | Core JSON-RPC plumbing | Map of message ID → response handler promise |
79+ | ` notifications/cancelled ` | Host/view can cancel in-flight requests | Auto-registered handler; calls ` abortController.abort() ` on matching request |
80+ | ` notifications/progress ` | Progress updates reset timeouts | Auto-registered handler; forwards to per-request progress callback |
81+ | ` ping ` auto-handler | Required by MCP spec | Auto-registered; returns ` {} ` |
82+ | Timeout + maxTotalTimeout | Prevents hung requests | ` setTimeout ` per request; reset on progress if opted in |
83+ | AbortSignal per request | Handler can observe cancellation | ` AbortController ` created per inbound request; passed in ` extra.signal ` |
84+ | ` RequestHandlerExtra ` | Handler context object | ` { signal, sessionId, sendRequest, sendNotification } ` |
85+ | ` onclose ` / ` onerror ` callbacks | Lifecycle hooks | Called on transport close/error |
86+ | ` fallbackRequestHandler ` / ` fallbackNotificationHandler ` | Catch-all for unknown methods | Checked when no specific handler matches |
87+ | Debounced notifications | Batching for list-changed etc. | ` _pendingDebouncedNotifications ` map with ` setTimeout ` |
88+
7089### For Zod schemas: Vendor from SDK or regenerate
7190
7291** Handler routing schemas** (11): These are only needed to extract the method string
@@ -87,13 +106,22 @@ the spec types. Or skip validation entirely (the SDK's V2 approach).
87106
88107** Composition schemas** (7 in ` generated/schema.ts ` ): These are the trickiest.
89108` ContentBlockSchema ` , ` ToolSchema ` , etc. are used to compose ext-apps' own schemas.
90- Options:
91- 1 . Vendor the specific Zod schemas from SDK 1.29.0 source
92- 2 . Regenerate from the spec schema.ts using ` ts-to-zod ` (ext-apps already uses this)
93- 3 . Hand-write minimal versions
94109
95- ** Wire validation** (1): ` JSONRPCMessageSchema ` u2014 vendor or redefine. It's a simple
96- discriminated union.
110+ ** Recommended: Generate all MCP Zod schemas from the spec types using ` ts-to-zod ` ** ,
111+ the same tool ext-apps already uses for its own ` spec.types.ts ` u2192 ` generated/schema.ts `
112+ pipeline. The workflow:
113+
114+ 1 . Copy ` schema/2025-11-25/schema.ts ` into ` src/vendor/mcp-types.ts `
115+ 2 . Add a ` generate:mcp-schemas ` script that runs ` ts-to-zod ` on ` mcp-types.ts `
116+ outputting to ` src/vendor/mcp-schemas.generated.ts `
117+ 3 . Update ` src/generated/schema.ts ` to import from ` ../vendor/mcp-schemas.generated.ts `
118+ instead of from ` @modelcontextprotocol/sdk/types.js `
119+
120+ This gives us Zod schemas for everything u2014 request routing, result validation,
121+ schema composition, and wire validation u2014 all generated from a single source of truth.
122+
123+ ** Wire validation** (` JSONRPCMessageSchema ` ): Also generated by ` ts-to-zod ` from the
124+ spec types which define ` JSONRPCMessage ` , ` JSONRPCRequest ` , ` JSONRPCNotification ` , etc.
97125
98126---
99127
@@ -103,13 +131,12 @@ discriminated union.
103131ext-apps/
104132u251cu2500u2500 src/
105133u2502 u251cu2500u2500 vendor/
106- u2502 u2502 u251cu2500u2500 protocol.ts # Minimal Protocol shim (~300 lines)
134+ u2502 u2502 u251cu2500u2500 protocol.ts # Minimal Protocol shim (~450 lines)
107135u2502 u2502 u251cu2500u2500 transport.ts # Transport interface (~30 lines)
108- u2502 u2502 u251cu2500u2500 jsonrpc.ts # JSONRPCMessage types + validation schema
109- u2502 u2502 u2514u2500u2500 mcp-types.ts # Copy of spec schema.ts (chosen version)
136+ u2502 u2502 u2514u2500u2500 mcp-types.ts # Copy of spec schema/2025-11-25/schema.ts
110137u2502 u251cu2500u2500 generated/
111- u2502 u2502 u2514u2500u2500 schema.ts # Updated: import from vendor/ instead of SDK
112- u2502 u251cu2500u2500 mcp-schemas.ts # Minimal Zod schemas for MCP request/result types
138+ u2502 u2502 u251cu2500u2500 schema.ts # ext-apps schemas (existing, updated imports)
139+ u2502 u2502 u2514u2500u2500 mcp-schemas.ts # MCP Zod schemas (generated by ts-to-zod from mcp- types.ts)
113140u2502 u251cu2500u2500 events.ts # ProtocolWithEvents u2014 import from vendor/protocol.ts
114141u2502 u251cu2500u2500 app.ts # Import types from vendor/mcp-types.ts
115142u2502 u251cu2500u2500 app-bridge.ts # Import types from vendor/mcp-types.ts
@@ -118,6 +145,11 @@ u251cu2500u2500 examples/ # Still depend on SDK for McpServer
118145u2514u2500u2500 docs/ # Same
119146```
120147
148+ The ` generated/mcp-schemas.ts ` file is produced by ` ts-to-zod ` from ` vendor/mcp-types.ts `
149+ using the same pipeline ext-apps already uses for its own ` spec.types.ts ` u2192 ` generated/schema.ts ` .
150+ This gives us Zod schemas for all MCP types: ` CallToolRequestSchema ` , ` JSONRPCMessageSchema ` ,
151+ ` ContentBlockSchema ` , etc. u2014 all from a single versioned source of truth.
152+
121153### What stays as SDK dependency
122154
123155- ** ` examples/ ` ** and ** ` docs/ ` ** : These use ` McpServer ` , ` StdioServerTransport ` ,
@@ -205,10 +237,11 @@ If we later need draft-only types, cherry-pick them.
205237
206238| Phase | Files changed | New code | Risk |
207239| -------| --------------| ----------| ------|
208- | 1. Vendor Protocol | 3-4 | ~ 350 lines | Medium u2014 must match V1 behavior exactly |
209- | 2. Vendor MCP Types | 8-10 | ~ 100 lines (schemas ) + copy spec | Low u2014 type-only changes except schemas |
240+ | 1. Vendor Protocol | 3-4 | ~ 450 lines | Medium u2014 must match V1 behavior (cancel, timeout, progress) |
241+ | 2. Vendor MCP Types + Schemas | 8-10 | ~ 0 hand-written (generated by ts-to-zod ) + copy spec | Low u2014 same codegen pipeline as existing |
210242| 3. Abstract Client | 3-4 | ~ 30 lines (interface) | Low u2014 structural subtyping |
211243| 4. Clean up | 5-10 | 0 | Low u2014 import path changes |
212244
213- Total new code: ~ 480 lines (Protocol shim + schemas + interface).
245+ Total hand-written code: ~ 480 lines (Protocol shim + interface).
246+ Generated code: MCP Zod schemas (via ts-to-zod, same pipeline as today).
214247Spec types file: ~ 67 KB copied from spec repo (2025-11-25 version).
0 commit comments