[DO NOT MERGE] Port to SDK v2 (extension() registrar / composition)#612
Draft
felixweinberger wants to merge 28 commits intomainfrom
Draft
[DO NOT MERGE] Port to SDK v2 (extension() registrar / composition)#612felixweinberger wants to merge 28 commits intomainfrom
felixweinberger wants to merge 28 commits intomainfrom
Conversation
…ocal SDK build)
…ompat pass-through schemas
…ansport on v2 Transport
…ssignment)
Preserves all public methods and on* handlers. Removed: 5 assert*Capability
no-op overrides, inherited Protocol surface. Wire renames: notifications/message
-> ui/log; oncalltool/onlisttools now on ui/{call-view-tool,list-view-tools}.
Standard MCP proxying via server.setRequestHandler. ui/initialize handler kept
for v1-iframe wire compat. callTool/listTools wire renamed to ui/{call-view-tool,
list-view-tools}.
…nHandle casts; ctx type params; exclude docs/; gen-schemas path
… tsc clean npx tsc --noEmit -> 0 errors npm run build -> see commit body
…pulls child_process) npm run build -> see body
…ed pre-connect (v1 parity)
…oolUiResourceUri validation (v1 parity)
…express,node}; restore test tsconfig includes
…mulate, onclose shim, onupdatemodelcontext return type, getToolUiResourceUri error message
…opped Protocol surface
…basic-host typo+v1 schema usage
… unported pdf-server suite The pdf-server example's server.test.ts (~77 tests) needs deeper v2 porting beyond the SDK migration scope. SDK tests + pdf-annotations.test.ts (no SDK coupling) all pass.
…ypescript-sdk#1871)
1cfc3dd to
76b3ba7
Compare
- spec.types.ts: import RequestId from @modelcontextprotocol/client (already public)
- app.ts/app-bridge.ts: replace pass-through *Schema shims with z.custom<T>(v => isSpecType('T', v))
- generate-schemas.ts: emit isSpecType-backed z.custom for external SDK types instead of importing from sdk-compat
- delete src/sdk-compat.ts
Friction surfaced: ExtensionHandle.setRequestHandler/sendRequest accept AnySchema (Zod-only),
so specTypeSchema()'s StandardSchemaV1 return cannot be passed directly. Wrapped via
z.custom(isSpecType) instead. #1868 should widen the param type to StandardSchemaV1 | AnySchema.
aa13066 to
2fe270f
Compare
…pt-sdk#1846 StandardSchemaV1 widening) generated/schema.ts keeps z.custom(isSpecType()) since it composes into Zod chains; specTypeSchema() is used at the ExtensionHandle boundary where the SDK now accepts StandardSchemaV1. app-bridge event-map params type widened ZodType -> StandardSchemaV1. app.ts no longer imports zod.
2fe270f to
60e9d69
Compare
- AppBridge dual-listens on legacy notifications/message → loggingmessage event - bridge.callTool/listTools throw descriptive error if iframe is v1 (instead of MethodNotFound) - Unskip ping test (Server.ping() is public; skip reason was wrong) - Document on*-setter replace-semantics with explicit test - BREAKING.md: v1↔v2 interop section, host-first upgrade guidance
…mappings
- Remove tsconfig excludes for *.examples.ts(x) and docs/ — all now typecheck
- Port companion files to v2 API (app.ui.sendRequest, client.callTool, z.object wraps)
- typedoc externalSymbolLinkMappings for @modelcontextprotocol/{client,server}
- Fix raw-shape inputSchema and Schema.shape→Schema across 9 example servers
- 25/25 examples now build; typedoc warnings 11→0
….registerTool) All 33 fails fixed: v2 registerTool requires StandardSchema (raw shapes lack ~standard.validate). Also extra.signal→extra.mcpReq.signal, drop stale v1 import. test:full now 277/2/0 (was 197/1/33). e2e API tests pass; browser tests need playwright install (env, not v2 break).
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.
DO NOT MERGE — proof-of-concept port to SDK v2. CI is expected to fail (
package.jsondepends on localfile:/tmp/*.tgzSDK builds that combine unpublished typescript-sdk changes).Review guide — file map, reading order, what to skip (105 files but ~90 are mechanical)
105 files changed, but ~90 of them are mechanical. This guide maps what to read vs skim.
If you have 10 minutes
BREAKING.md— the public-surface delta. This is the contract.src/app.ts—class Appdeclaration (search forclass App extends EventDispatcher). The whole composition pattern is visible in the first ~50 lines of the class body:readonly client: Client,readonly ui: ExtensionHandle<...>, thenui.setRequestHandler(...)calls in the constructor. Note: nozodimport — embedded spec types validated viaspecTypeSchema()from the SDK.src/app-bridge.ts— same, search forclass AppBridge extends EventDispatcher. Notereadonly server: Serverand theserver.setRequestHandler('tools/call', ...)proxy wiring alongsideui.*forui/*methods.src/app-bridge.test.ts— most of the file is unchanged. That's the point.File map
Read carefully (~6 files, the actual design)
BREAKING.mdsrc/app.tsAppcomposesClient+ExtensionHandle. Noassert*Capabilityoverrides. No zod import —specTypeSchema('CallToolResult')etc. passed directly.src/app-bridge.tsAppBridgecomposesServer+ExtensionHandle. Standardtools/calletc. viasetRequestHandler.src/events.tsProtocolWithEvents(subclass of SDKProtocol) → standaloneEventDispatcher<EventMap>. No SDK coupling.src/message-transport.tsPostMessageTransporton the v2Transportinterface.src/server/index.tsregisterAppTool/registerAppResourceon v2McpServer.Skim (mechanical, verify pattern then move on)
src/spec.types.ts,src/types.tsinterface McpUi*Capabilities→type(forJSONObjectconstraint).src/generated/{schema.ts,schema.json,schema.test.ts}z.custom<T>(isSpecType('T', v))for embedded SDK types. Don't review line-by-line.src/app-bridge.test.tssrc/react/useApp.tsx,src/server/index.test.ts,src/*.examples.tsexamples/**package.jsondeps,main.tsimport path (/stdiosubpath),server.tsv2McpServershape. Read one (examples/basic-server-react/) to see the pattern.docs/,scripts/generate-schemas.tsisSpecType()for SDK types.package.json,build.bun.ts,tsconfig.json, lockfiletsconfigexclusions for unported*.examples.ts.Recommended reading order (by commit)
25 commits, intentionally staged. Read bottom-up in groups:
1. Setup (skim):
231251a6deps swap,b50315b1types/schemas,a9713e3dEventDispatcher + transport.2. The core rewrite (read):
25da6658App,a1f1f016AppBridge,a5378733react/server.3. Compile fixes (skim):
ea3f4af5..a97206ca.4. v1 parity fixes (read commit messages):
87fee346,f7490c6b,47f4cdf3,be67283e— each is a behavior the test suite caught.5. Tests + examples (skim):
7e8ae100,cce8436b,570781e0,9998758b,4298d34a,b845fd7c.6. Upstream-fix follow-through (skim):
953a5d81/4e26407d(#1871),76b3ba7a/stdioimport.7. Validator integration (read):
c8bc2649eliminatessdk-compat.tsviaisSpecType();60e9d690passesspecTypeSchema()directly toExtensionHandleafter #1846's StandardSchemaV1 widen.Questions to evaluate
BREAKING.md's "Removed inherited member" table against what consumers actually use.ui/*↔ standard-method split clean? Inapp-bridge.ts, find whereui.setRequestHandler(...)andserver.setRequestHandler('tools/call', ...)coexist.specTypeSchema()the right validator API?app.tspasses it directly toExtensionHandle— no Zod at the consumer.generated/schema.tsusesz.custom(isSpecType())because that file is Zod-composed.AppBridgekeeps aui/initializehandler for v1-iframe back-compat. Right choice vs. clean break?Known gaps (intentional, documented)
npm run test:fullincludesexamples/pdf-server/server.test.ts(~33 fails) — heavy example, deeper port out of scope.tsconfig.jsonexcludessrc/**/*.examples.ts(x)anddocs/— companion JSDoc snippets use removed surface.package.jsonpoints atfile:/tmp/*.tgz.Depends on:
specTypeSchema()for runtime validation of any spec type)Motivation and Context
App/AppBridgemove from subclassingProtocolto composingClient/Server+ExtensionHandleper the SEP-1865 role assignment. SeeBREAKING.mdfor the full surface delta. 73/88 of the v1app-bridge.test.tstests pass unmodified against the rewrite (final: 85 pass / 1 skip / 0 fail).How Has This Been Tested?
Locally against an SDK build with the dependencies above:
npm run build,npm test(197 pass / 1 skip / 0 fail), andbasic-server-react/basic-server-vanillajs/quickstart/basic-hostexample builds all green.npm run test:fullretains the unportedexamples/pdf-serversuite.Breaking Changes
Yes — see
BREAKING.md. Peer dep moves from@modelcontextprotocol/sdk@^1to@modelcontextprotocol/{client,server}@^2.Types of changes
Checklist
Additional context
This PR is the artifact for reviewing the v2 shape. Once the SDK dependencies publish to
@alpha, thefile:deps will be swapped to npm versions and CI will go green.