Skip to content

Commit c822761

Browse files
committed
docs: update divorce plan with Protocol feature audit and codegen approach
Protocol shim must include: - notifications/cancelled handler (AbortController per request) - notifications/progress handler (timeout reset on heartbeat) - Auto-registered ping handler - RequestHandlerExtra with signal, sessionId, sendRequest, sendNotification - Timeout + maxTotalTimeout + resetTimeoutOnProgress Schemas: generate all MCP Zod schemas from spec schema.ts via ts-to-zod (same pipeline as existing ext-apps codegen).
1 parent 8a0444e commit c822761

1 file changed

Lines changed: 50 additions & 17 deletions

File tree

docs/sdk-divorce-plan.md

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,32 @@ onclose? / onerror? u2014 callbacks
6060
fallbackNotificationHandler? 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.
103131
ext-apps/
104132
u251cu2500u2500 src/
105133
u2502 u251cu2500u2500 vendor/
106-
u2502 u2502 u251cu2500u2500 protocol.ts # Minimal Protocol shim (~300 lines)
134+
u2502 u2502 u251cu2500u2500 protocol.ts # Minimal Protocol shim (~450 lines)
107135
u2502 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
110137
u2502 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)
113140
u2502 u251cu2500u2500 events.ts # ProtocolWithEvents u2014 import from vendor/protocol.ts
114141
u2502 u251cu2500u2500 app.ts # Import types from vendor/mcp-types.ts
115142
u2502 u251cu2500u2500 app-bridge.ts # Import types from vendor/mcp-types.ts
@@ -118,6 +145,11 @@ u251cu2500u2500 examples/ # Still depend on SDK for McpServer
118145
u2514u2500u2500 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).
214247
Spec types file: ~67 KB copied from spec repo (2025-11-25 version).

0 commit comments

Comments
 (0)