feat: Add v2 SDK foundation (modern registration shell, prepare())#1136
Closed
jirispilka wants to merge 1 commit into
Closed
feat: Add v2 SDK foundation (modern registration shell, prepare())#1136jirispilka wants to merge 1 commit into
jirispilka wants to merge 1 commit into
Conversation
Public PR 1 of the 2026-07-28 stateless migration (#1130): - Add @modelcontextprotocol/core + /server at exact-pinned 2.0.0-beta.5, alongside the untouched v1 SDK (excluded from minimumReleaseAge: exact pins make every bump a reviewed change). - New src/mcp/modern_server.ts: createModernServer() registers tools/list, tools/call, resources/*, prompts/* on a v2 Server, calling today's unmodified ToolEntry.call() logic. Per-request: session ID optional, client identity/capabilities from the _meta envelope, server mode and report-problem gating re-resolved per request, Apify token from ctx.http.authInfo (never _meta.apifyToken). No tasks/* registration (v2 SDK rejects them -32601), no logging side-channel (SEP-2577). - ActorsMcpServer: new prepare() (pre-connect widget resolution; connect() now calls it), per-request helpers isReportProblemServableForClient()/resolveServerModeForClient()/ getAvailableWidgets(), buildPreflightFailureOutcome exported. - prepareTelemetryData accepts per-request initializeRequestData, defaulting to the initialize-scoped value on legacy connections. Existing ActorsMcpServer registration and behavior unchanged; legacy clients (including Tasks) are served exactly as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ABxfYds29KVxn2C7nA11r
An error occurred while trying to automatically change base from
fix/add-actor-cutoff-review-followups
to
refactor/isrestore-rename-cleanup
July 23, 2026 07:59
jirispilka
marked this pull request as draft
July 23, 2026 07:59
This was referenced Jul 23, 2026
jirispilka
added a commit
that referenced
this pull request
Jul 23, 2026
## Why Prerequisite refactor for the 2026-07-28 (stateless) MCP migration. The modern surface needs the same `tools/call` orchestration the v1 handler runs today; rather than clone that spine into a second dispatcher, this extracts it into one shared engine both eras will call. Landed first, behavior-preserving, per the repo's "refactoring is a separate PR — land the refactor first" rule. This is **PR 1a** of the refactor-first split of the original "PR 1" (#1130): the shared engine lands here; **#1140** (PR 1b) then adds the 2026-07-28 modern surface as a thin shell over it. The split was driven by an architecture review of the original single-PR attempt (#1136, now superseded), which cloned ~280 lines of orchestration per era and hid a latent `sendLoggingMessage`-on-unbound-v1-`Server` bug. The migration plan is updated to match in apify/apify-mcp-server-internal#684. Closes #1139. Part of #1130, #1128. ## What changed The v1 `CallToolRequest` handler's orchestration spine — token gate → tool resolution → payment context → AJV validation → standby/402 preflight → dispatch → error classification → report-problem nudge — moved into a new shared `src/mcp/tool_call_engine.ts` that returns a neutral, era-agnostic outcome and imports no SDK error type. The v1 handler is now a thin shell that maps that outcome back to today's exact wire results, JSON-RPC errors, telemetry, and `sendLoggingMessage` side-channel. `dispatchToolCall` gains an optional `emitLog` seam (default preserves the current call) so the shared leaf no longer hard-binds the v1 `Server`. No behavior change for v1 clients. Follow-up notes: - Contract-test count reads 36, not 29: the 29 pre-existing tests are unedited; 7 tests were appended, 5 of them characterization tests that fence previously-untested reject / side-channel / abort paths the extraction rewrites. - The engine ships a third function/return variant (`classifyToolCallError` / `PreparedCallError`) beyond a literal "two functions" split — it preserves actor-context telemetry on post-resolution prep-spine throws, which a two-variant engine would have dropped. - The 2026-07-28 modern-surface shell that consumes this engine is #1140 (PR 1b) — a separate follow-up. - The missing-token reject path and end-to-end actor dispatch aren't reachable without a platform token; a human should run `pnpm run test:integration` before merge as the belt-and-suspenders check. ## Notes for reviewers (human-written) <!-- your own words --> ## Proof it works All standard gates green: `type-check`, `lint` (0/0), `test:unit` **1157 passed / 1 skipped**, `check:agents`. The `mcp.server.tool_call_contracts.test.ts` suite passes at **36** with the 29 pre-existing assertions unedited (verified against `master` in an isolated worktree). Live `mcpc` probe of the refactored v1 stdio server: all 11 default tools register, and unknown-tool / invalid-args (5 tools) / legacy-name resolution return the correct `-32602 InvalidParams` — the exact reject paths the extraction rewrote. End-to-end actor dispatch needs a platform token and is deferred to a human integration run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Xax7bhBYLfE6agNXqRgyv6 --------- Co-authored-by: Claude <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.
Why
Closes #1130. Public PR 1 of the 2026-07-28 stateless migration (plan: apify/apify-mcp-server-internal#663, parent #1128): the v2 SDK foundation the hosted server's modern HTTP entry point (internal PR 3) will consume. Stacked on #1135 (→ #1133 → #1127) because it touches
src/mcp/server.ts, which the cutover chain also modifies — retarget/rebase ontomasterafter the chain merges.What changed
@modelcontextprotocol/core+@modelcontextprotocol/serverat exact-pinned2.0.0-beta.5, alongside the untouched v1 SDK. Betas can break between releases, hence exact pins — and hence theminimumReleaseAgeExcludeentries (the 3-day gate blocks a 41-hour-old beta; with exact pins every bump is a reviewed diff anyway).zodconverges on the already-present4.4.3(satisfies the v2^4.2.0range), as the plan's spike predicted.@modelcontextprotocol/nodeis deliberately absent — it belongs to internal PR 1 (apify/apify-mcp-server-internal#680).src/mcp/modern_server.ts(new):createModernServer(apifyMcpServer)— a v2 low-levelServerregisteringtools/list,tools/call,resources/*,prompts/*, calling today's unmodifiedToolEntry.call()/ resource-service / prompts logic. Thetools/calldispatcher is a port of the v1 sync path (token gate → tool resolution → payment context → AJV validation → standby/402 preflight →dispatchToolCall→ error-kind switch → telemetryfinally) with the plan's five per-request adaptations: optional session ID; client identity/capabilities from the_metaenvelope (synthesized into an initialize-shaped object so the existing client-keyed helpers are reused unchanged); server mode andreport-problemgating re-resolved per request; Apify token fromctx.http?.authInfo?.token, never_meta.apifyToken. Notasks/*registration (the v2 SDK rejects them-32601itself — pinned by test), no logging side-channel (SEP-2577). The v1 outer-catch'stoolTelemetrywire leak (fix: Uncaught tool errors leak toolTelemetry to the wire #1052) is intentionally not replicated on this new surface.ActorsMcpServer: new publicprepare()(pre-connect widget resolution;connect()now calls it — no behavior change for existing callers), plus per-request helpersisReportProblemServableForClient()/resolveServerModeForClient()/getAvailableWidgets();buildPreflightFailureOutcomeexported. Legacy registration and behavior untouched — legacy clients (including Tasks) are served exactly as before.prepareTelemetryDataaccepts an optional per-requestinitializeRequestData, defaulting to the initialize-scoped value on legacy connections.Plan corrections discovered against SDK
beta.5(worth folding back into theres/docs):ctx.mcpReq.envelopekeeps the full reserved key names (read via the exported*_META_KEYconstants, not.clientInfoshorthand); the published typings erase the envelope shape (RequestMetaEnvelope = {}), so the module carries a local typed view; the throwable on this path isProtocolError, not v1'sMcpError; a v2Serverbinds one transport, socreateModernServeris called per request from acreateMcpHandlerfactory.Notes for reviewers (human-written)
Proof it works
type-check,lint,format,check:agents,test:unitall green locally — 1154 passed / 1 skipped, including 11 new tests intests/unit/mcp.modern_server.test.ts(registration surface incl. the no-tasks/*assertion,report-problemgating by envelopeclientInfo,authInfo-over-instance-token precedence and fallback, per-request apps/default mode resolution, unknown-tool/missing-token rejections,prepare()running before transport connect). All 1143 pre-existing unit tests pass unchanged.An end-to-end probe of the modern path is not possible with mcpc (it can't negotiate 2026-07-28 — confirmed in the plan's spike); live-path verification arrives with the integration-suite
'2026-07-28'transport dimension, sequenced in the plan after internal PR 3.Generated by Claude Code