diff --git a/.changeset/abort-handlers-on-close.md b/.changeset/abort-handlers-on-close.md index b6bc65e652..c09d8b5aac 100644 --- a/.changeset/abort-handlers-on-close.md +++ b/.changeset/abort-handlers-on-close.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Abort in-flight request handlers when the connection closes. Previously, request handlers would continue running after the transport disconnected, wasting resources and preventing proper cleanup. Also fixes `InMemoryTransport.close()` firing `onclose` twice on the initiating side. diff --git a/.changeset/add-core-public-package.md b/.changeset/add-core-public-package.md new file mode 100644 index 0000000000..23cb56cb21 --- /dev/null +++ b/.changeset/add-core-public-package.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/core': minor +--- + +Add `@modelcontextprotocol/core`: the public home for the MCP specification and OAuth/OpenID Zod schemas. It bundles the SDK's internal schema definitions and re-exports only the `*Schema` values, so consumers can validate protocol payloads (`Schema.parse(value)` / `.safeParse(value)`) without depending on a package's internal barrel. Alongside the spec schemas it also re-exports the auth schemas v1 exposed from `@modelcontextprotocol/sdk/shared/auth.js` (e.g. `OAuthTokensSchema`, `OAuthMetadataSchema`, `IdJagTokenExchangeResponseSchema`). Spec types, error classes, enums, and guards continue to live on `@modelcontextprotocol/server` and `@modelcontextprotocol/client`. diff --git a/.changeset/add-resource-size-field.md b/.changeset/add-resource-size-field.md index bef37cb408..07d06b436d 100644 --- a/.changeset/add-resource-size-field.md +++ b/.changeset/add-resource-size-field.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Add missing `size` field to `ResourceSchema` to match the MCP specification diff --git a/.changeset/add-sdk-http-error.md b/.changeset/add-sdk-http-error.md index c3331a565e..05abc0d8f1 100644 --- a/.changeset/add-sdk-http-error.md +++ b/.changeset/add-sdk-http-error.md @@ -1,5 +1,5 @@ --- -"@modelcontextprotocol/core": minor +"@modelcontextprotocol/core-internal": minor "@modelcontextprotocol/client": minor --- diff --git a/.changeset/add-version-negotiation-option.md b/.changeset/add-version-negotiation-option.md index 334796f879..a1433b61a4 100644 --- a/.changeset/add-version-negotiation-option.md +++ b/.changeset/add-version-negotiation-option.md @@ -1,6 +1,6 @@ --- '@modelcontextprotocol/client': minor -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor --- Add opt-in protocol version negotiation on `ClientOptions.versionNegotiation`. The default is unchanged: without the option (or with `mode: 'legacy'`) the client performs today's 2025 connect sequence byte-identically. `mode: 'auto'` probes the server with `server/discover` at diff --git a/.changeset/auth-dcr-hygiene.md b/.changeset/auth-dcr-hygiene.md index c6eb5e4140..b37808f011 100644 --- a/.changeset/auth-dcr-hygiene.md +++ b/.changeset/auth-dcr-hygiene.md @@ -1,6 +1,6 @@ --- '@modelcontextprotocol/client': minor -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor --- Dynamic Client Registration hygiene for the 2026-07-28 authorization requirements (SEP-837, SEP-2207). New `resolveClientMetadata(provider)` reads `provider.clientMetadata` and applies the spec defaults — `application_type` derived from the redirect URIs (loopback or custom scheme → `'native'`, otherwise `'web'`), `grant_types: ['authorization_code', 'refresh_token']` when omitted — and `auth()` feeds the resolved document to DCR only (scope selection still reads the raw consumer-supplied `clientMetadata` so statically-registered/CIMD clients are not pushed into `offline_access` + `prompt=consent`); consumer-set values are never overwritten. DCR rejection now throws the new `RegistrationRejectedError` carrying the HTTP status, raw body, and submitted metadata — **breaking for direct `registerClient()` callers**: rejection no longer throws `OAuthError`, so update `instanceof` checks. `OAuthClientMetadata` gains a typed `application_type?: string` field (expected `'native'` / `'web'`; tolerant on parse). `OAuthErrorCode` adds `InvalidRedirectUri`. The token-exchange, refresh, and Cross-App Access (`requestJwtAuthorizationGrant` / `exchangeJwtAuthGrant`) paths now throw the new `InsecureTokenEndpointError` for a non-`https:` token endpoint (`localhost` / `127.0.0.1` / `::1` exempt), and `auth()` surfaces it on the refresh branch instead of silently re-authorizing. diff --git a/.changeset/auth-iss-validation.md b/.changeset/auth-iss-validation.md index 1135eab96a..3f0c4283ef 100644 --- a/.changeset/auth-iss-validation.md +++ b/.changeset/auth-iss-validation.md @@ -1,5 +1,5 @@ --- -"@modelcontextprotocol/core": minor +"@modelcontextprotocol/core-internal": minor "@modelcontextprotocol/client": minor --- diff --git a/.changeset/auth-surface-delta.md b/.changeset/auth-surface-delta.md index 04600674b3..b1908834ca 100644 --- a/.changeset/auth-surface-delta.md +++ b/.changeset/auth-surface-delta.md @@ -1,6 +1,6 @@ --- '@modelcontextprotocol/client': minor -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor --- Add the public surface for the 2026-07-28 authorization requirements. New `AuthOptions` type names the `auth()` options object and adds `iss` and `skipIssuerMetadataValidation` fields. `OAuthClientProvider.clientInformation()` / `.saveClientInformation()` / `.tokens()` / `.saveTokens()` accept an optional `OAuthClientInformationContext` carrying the authorization server's `issuer` so providers can key persisted credentials per authorization server. New `StoredOAuthTokens` / `StoredOAuthClientInformation` aliases add an `issuer` stamp field on top of the wire types (kept off the wire schemas so an authorization server cannot populate it) and become the parameter/return types of the credential methods. New `OAuthClientFlowError` base class in `authErrors.ts` for the flow-specific error classes that follow. All changes are additive — existing `OAuthClientProvider` implementations compile unchanged; the new fields are inert until the behavior changes that follow wire them up. diff --git a/.changeset/busy-weeks-hang.md b/.changeset/busy-weeks-hang.md index a045aaa41f..0a8801eb37 100644 --- a/.changeset/busy-weeks-hang.md +++ b/.changeset/busy-weeks-hang.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/cacheable-result-cache-fields.md b/.changeset/cacheable-result-cache-fields.md index cb8d917e3f..67c0c0a207 100644 --- a/.changeset/cacheable-result-cache-fields.md +++ b/.changeset/cacheable-result-cache-fields.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/client-http-stream-close-cancel.md b/.changeset/client-http-stream-close-cancel.md index 3af099e644..bca1c6d19f 100644 --- a/.changeset/client-http-stream-close-cancel.md +++ b/.changeset/client-http-stream-close-cancel.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/codec-era-gates.md b/.changeset/codec-era-gates.md index 30855b7f87..e3bb78c5ec 100644 --- a/.changeset/codec-era-gates.md +++ b/.changeset/codec-era-gates.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/codec-split-wire-break.md b/.changeset/codec-split-wire-break.md index d481ac6ccf..3f24d5de30 100644 --- a/.changeset/codec-split-wire-break.md +++ b/.changeset/codec-split-wire-break.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': major +'@modelcontextprotocol/core-internal': major '@modelcontextprotocol/client': major '@modelcontextprotocol/server': major --- diff --git a/.changeset/codemod-core-routing.md b/.changeset/codemod-core-routing.md new file mode 100644 index 0000000000..624a847238 --- /dev/null +++ b/.changeset/codemod-core-routing.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/codemod': minor +--- + +Route v1 `@modelcontextprotocol/sdk/types.js` schema imports to the new `@modelcontextprotocol/core` package. The `*Schema` Zod constants now migrate as a behavior-preserving import-path swap — `Schema.parse(value)` / `.safeParse(value)` keep working — while spec types, error classes, enums, and guards continue to resolve to `@modelcontextprotocol/client` / `@modelcontextprotocol/server` by context. A single `import { CallToolResult, CallToolResultSchema } from '.../types.js'` is split accordingly. The v1 OAuth/OpenID `*Schema` constants imported from `@modelcontextprotocol/sdk/shared/auth.js` are routed to `@modelcontextprotocol/core` the same way (their auth TYPES keep resolving to `client` / `server`). The previous `specSchemaAccess` transform (which rewrote `.parse()` into `specTypeSchemas.X['~standard'].validate(...)`) is removed. diff --git a/.changeset/codemod-infer-project-type.md b/.changeset/codemod-infer-project-type.md new file mode 100644 index 0000000000..1fa114c775 --- /dev/null +++ b/.changeset/codemod-infer-project-type.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/codemod': patch +--- + +Infer client/server project type from source for v1 projects. A project being migrated still declares the single v1 `@modelcontextprotocol/sdk` dependency, so detecting the project type from `package.json` came back "unknown" and every file importing only shared protocol symbols defaulted to `@modelcontextprotocol/server` with an action-required warning. The codemod now scans the source for quoted `@modelcontextprotocol/sdk/client/…` and `…/server/…` import specifiers to infer the type (both → "both", one → that side, neither → "unknown"), routing shared symbols to the installed package and replacing the spurious warnings with at most an info note for genuinely ambiguous "both" projects. diff --git a/.changeset/codemod-task-handler-methods.md b/.changeset/codemod-task-handler-methods.md new file mode 100644 index 0000000000..140805338f --- /dev/null +++ b/.changeset/codemod-task-handler-methods.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/codemod': patch +--- + +Emit a dedicated action-required diagnostic for v1 task-handler registrations (`setRequestHandler(GetTaskRequestSchema, …)`, `setNotificationHandler(TaskStatusNotificationSchema, …)`, and the other `tasks/*` schemas). The experimental tasks feature was removed in v2 (SEP-2663) and the `tasks/*` method strings are excluded from the typed `RequestMethod` / `NotificationMethod` surface, so these registrations are **not** rewritten to method-string form — the codemod marks each site with an `@mcp-codemod-error` comment pointing at the migration guide's tasks-removed section instead. diff --git a/.changeset/custom-methods-minimal.md b/.changeset/custom-methods-minimal.md index f722f4504e..103332b166 100644 --- a/.changeset/custom-methods-minimal.md +++ b/.changeset/custom-methods-minimal.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/envelope-auto-emission.md b/.changeset/envelope-auto-emission.md index 9ae614a84f..b8e9caf9d3 100644 --- a/.changeset/envelope-auto-emission.md +++ b/.changeset/envelope-auto-emission.md @@ -1,6 +1,6 @@ --- '@modelcontextprotocol/client': minor -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor --- Per-request `_meta` envelope auto-emission on modern-era connections: once a client negotiates a 2026-07-28+ protocol revision (via `versionNegotiation: { mode: 'auto' }` or `{ pin }`), it automatically attaches the reserved protocol-version / client-info / client-capabilities diff --git a/.changeset/finish-sdkerror-capability.md b/.changeset/finish-sdkerror-capability.md index f9145a5058..8e8b0bca31 100644 --- a/.changeset/finish-sdkerror-capability.md +++ b/.changeset/finish-sdkerror-capability.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/fix-abort-listener-leak.md b/.changeset/fix-abort-listener-leak.md index f1dd3163b9..0a87e559c7 100644 --- a/.changeset/fix-abort-listener-leak.md +++ b/.changeset/fix-abort-listener-leak.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Consolidate per-request cleanup in `_requestWithSchema` into a single `.finally()` block. This fixes an abort signal listener leak (listeners accumulated when a caller reused one `AbortSignal` across requests) and two cases where `_responseHandlers` entries leaked on send-failure paths. diff --git a/.changeset/fix-transport-exact-optional-property-types.md b/.changeset/fix-transport-exact-optional-property-types.md index c3187db8ad..57b4d00cd5 100644 --- a/.changeset/fix-transport-exact-optional-property-types.md +++ b/.changeset/fix-transport-exact-optional-property-types.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Add explicit `| undefined` to optional properties on the `Transport` interface and `TransportSendOptions` (`onclose`, `onerror`, `onmessage`, `sessionId`, `setProtocolVersion`, `setSupportedProtocolVersions`, `onresumptiontoken`). diff --git a/.changeset/fix-unknown-tool-protocol-error.md b/.changeset/fix-unknown-tool-protocol-error.md index 9e6ce81ffd..6d214221ca 100644 --- a/.changeset/fix-unknown-tool-protocol-error.md +++ b/.changeset/fix-unknown-tool-protocol-error.md @@ -1,5 +1,5 @@ --- -"@modelcontextprotocol/core": minor +"@modelcontextprotocol/core-internal": minor "@modelcontextprotocol/server": major --- diff --git a/.changeset/funky-baths-attack.md b/.changeset/funky-baths-attack.md index f65f1263c8..8f7e20f73b 100644 --- a/.changeset/funky-baths-attack.md +++ b/.changeset/funky-baths-attack.md @@ -2,7 +2,7 @@ '@modelcontextprotocol/node': patch '@modelcontextprotocol/test-integration': patch '@modelcontextprotocol/server': patch -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- remove deprecated .tool, .prompt, .resource method signatures diff --git a/.changeset/hide-wire-only-members.md b/.changeset/hide-wire-only-members.md index a247993107..082ca73312 100644 --- a/.changeset/hide-wire-only-members.md +++ b/.changeset/hide-wire-only-members.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': major +'@modelcontextprotocol/core-internal': major '@modelcontextprotocol/client': major '@modelcontextprotocol/server': major --- diff --git a/.changeset/idjag-spec-type-export.md b/.changeset/idjag-spec-type-export.md new file mode 100644 index 0000000000..8fb5816036 --- /dev/null +++ b/.changeset/idjag-spec-type-export.md @@ -0,0 +1,6 @@ +--- +'@modelcontextprotocol/client': minor +'@modelcontextprotocol/server': minor +--- + +Add the v2 `IdJagTokenExchangeResponse` type to the public API and register its schema as an MCP spec type. `IdJagTokenExchangeResponse` is now exported from `@modelcontextprotocol/client` and `@modelcontextprotocol/server`, `'IdJagTokenExchangeResponse'` joins the `SpecTypeName` union, and `isSpecType.IdJagTokenExchangeResponse(value)` / `specTypeSchemas.IdJagTokenExchangeResponse` validate it by name — matching how the OAuth/OpenID auth schemas are already exposed. The Zod schema itself, `IdJagTokenExchangeResponseSchema`, is available from `@modelcontextprotocol/core`. diff --git a/.changeset/missing-client-capability-error.md b/.changeset/missing-client-capability-error.md index 842e44073b..7f40814001 100644 --- a/.changeset/missing-client-capability-error.md +++ b/.changeset/missing-client-capability-error.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/mrtr-client-engine.md b/.changeset/mrtr-client-engine.md index 451f717e10..3330480f42 100644 --- a/.changeset/mrtr-client-engine.md +++ b/.changeset/mrtr-client-engine.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/mrtr-server-seam.md b/.changeset/mrtr-server-seam.md index 51f7fa06b5..fd1198b2c8 100644 --- a/.changeset/mrtr-server-seam.md +++ b/.changeset/mrtr-server-seam.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/pin-modern-rejection-codes.md b/.changeset/pin-modern-rejection-codes.md index a00bd2f4a2..c131e8ea73 100644 --- a/.changeset/pin-modern-rejection-codes.md +++ b/.changeset/pin-modern-rejection-codes.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/pre.json b/.changeset/pre.json index 0fa4e3b738..6c0c4763db 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -9,60 +9,100 @@ "@modelcontextprotocol/examples-client-quickstart": "2.0.0-alpha.0", "@modelcontextprotocol/examples-server-quickstart": "2.0.0-alpha.0", "@modelcontextprotocol/client": "2.0.0-alpha.0", - "@modelcontextprotocol/core": "2.0.0-alpha.0", + "@modelcontextprotocol/core-internal": "2.0.0-alpha.0", "@modelcontextprotocol/express": "2.0.0-alpha.0", "@modelcontextprotocol/fastify": "2.0.0-alpha.0", "@modelcontextprotocol/hono": "2.0.0-alpha.0", "@modelcontextprotocol/node": "2.0.0-alpha.0", "@modelcontextprotocol/server": "2.0.0-alpha.0", "@modelcontextprotocol/server-legacy": "2.0.0-alpha.0", + "@modelcontextprotocol/core": "2.0.0-alpha.0", "@modelcontextprotocol/codemod": "2.0.0-alpha.0", "@modelcontextprotocol/test-conformance": "2.0.0-alpha.0", "@modelcontextprotocol/test-helpers": "2.0.0-alpha.0", - "@modelcontextprotocol/test-integration": "2.0.0-alpha.0" + "@modelcontextprotocol/test-integration": "2.0.0-alpha.0", + "@modelcontextprotocol/test-e2e": "2.0.0-alpha.0" }, "changesets": [ "abort-handlers-on-close", + "add-consumer-sse-e2e", + "add-core-public-package", + "add-e2e-test-suite", "add-fastify-middleware", "add-hono-peer-dep", "add-resource-size-field", + "add-sdk-http-error", + "add-server-legacy-package", + "bound-resumability-version-gates", "brave-lions-glow", "busy-rice-smoke", "busy-weeks-hang", + "cfworker-out-of-barrel", + "codemod-core-routing", + "codemod-infer-project-type", + "codemod-resolve-legacy-imports", + "codemod-streamablehttperror-sdkhttperror", + "codemod-task-handler-methods", + "custom-methods-minimal", "cyan-cycles-pump", + "draft-spec-non-sep-conformance", "drop-zod-peer-dep", + "export-inmemory-transport", "expose-auth-server-discovery", + "expose-icons-on-tools-and-prompts", + "express-resource-server-auth", "extract-task-manager", "fast-dragons-lead", "finish-sdkerror-capability", "fix-abort-listener-leak", + "fix-conformance-server-leak", "fix-oauth-5xx-discovery", "fix-onerror-callbacks", "fix-server-protocol-version", "fix-session-status-codes", "fix-stdio-epipe-crash", "fix-stdio-windows-hide", + "fix-streamable-close-reentrant", "fix-streamable-http-error-response", "fix-task-session-isolation", "fix-transport-exact-optional-property-types", "fix-unknown-tool-protocol-error", + "fix-validate-client-metadata-url", "funky-baths-attack", + "gentle-planets-rest", "heavy-walls-swim", + "hono-peer-optional", + "idjag-spec-type-export", + "legacy-module-resolution-types", "oauth-error-http200", + "odd-forks-enjoy", "quick-islands-occur", "reconnection-scheduler", + "register-rawshape-compat", "remove-websocket-transport", "respect-capability-negotiation", + "restore-task-wire-types", "rich-hounds-report", "schema-object-type-for-unions", + "sep-2577-deprecate-runtime-apis", + "sep-2663-tasks-removal", + "sep-414-trace-context-meta-keys", "shy-times-learn", + "spec-reference-types-2026-07-28", + "spec-type-schema", "spotty-cats-tickle", + "stdio-max-buffer-size", "stdio-skip-non-json", + "stdio-subpath-export", "support-standard-json-schema", "tame-camels-greet", "tender-snails-fold", "token-provider-composable-auth", "twelve-dodos-taste", - "use-scopes-supported-in-dcr" + "use-scopes-supported-in-dcr", + "workerd-shim-vendors-cfworker", + "wraphandler-hook", + "zod-json-schema-compat", + "zod-jsonschema-fallback" ] } diff --git a/.changeset/protocol-pre-aborted-signal-wrap.md b/.changeset/protocol-pre-aborted-signal-wrap.md index a0a95758c8..80b31f5136 100644 --- a/.changeset/protocol-pre-aborted-signal-wrap.md +++ b/.changeset/protocol-pre-aborted-signal-wrap.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- `Protocol.request()` now rejects with `SdkError(RequestTimeout, reason)` when called with an already-aborted signal, matching in-flight aborts. Previously the raw `signal.reason` was thrown. diff --git a/.changeset/quick-islands-occur.md b/.changeset/quick-islands-occur.md index 2ec83908d1..b229b82c36 100644 --- a/.changeset/quick-islands-occur.md +++ b/.changeset/quick-islands-occur.md @@ -4,7 +4,7 @@ '@modelcontextprotocol/node': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- remove npm references, use pnpm diff --git a/.changeset/register-rawshape-compat.md b/.changeset/register-rawshape-compat.md index 5f1f167848..84fccdd726 100644 --- a/.changeset/register-rawshape-compat.md +++ b/.changeset/register-rawshape-compat.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/resource-not-found-32602.md b/.changeset/resource-not-found-32602.md index 4909224219..a578ecda5f 100644 --- a/.changeset/resource-not-found-32602.md +++ b/.changeset/resource-not-found-32602.md @@ -1,5 +1,5 @@ --- -"@modelcontextprotocol/core": minor +"@modelcontextprotocol/core-internal": minor "@modelcontextprotocol/server": major "@modelcontextprotocol/client": minor --- diff --git a/.changeset/restore-task-wire-types.md b/.changeset/restore-task-wire-types.md index ebe9b5ddf5..05c0875364 100644 --- a/.changeset/restore-task-wire-types.md +++ b/.changeset/restore-task-wire-types.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/rich-hounds-report.md b/.changeset/rich-hounds-report.md index d1736bf72c..b05e7c4656 100644 --- a/.changeset/rich-hounds-report.md +++ b/.changeset/rich-hounds-report.md @@ -4,7 +4,7 @@ '@modelcontextprotocol/node': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- clean up package manager usage, all pnpm diff --git a/.changeset/schema-object-type-for-unions.md b/.changeset/schema-object-type-for-unions.md index 7749bb6c5c..d307f2af58 100644 --- a/.changeset/schema-object-type-for-unions.md +++ b/.changeset/schema-object-type-for-unions.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Ensure `standardSchemaToJsonSchema` emits `type: "object"` at the root, fixing discriminated-union tool/prompt schemas that previously produced `{oneOf: [...]}` without the MCP-required top-level type. Also throws a clear error when given an explicitly non-object schema (e.g. `z.string()`). Fixes #1643. diff --git a/.changeset/sep-2106-dialect-posture.md b/.changeset/sep-2106-dialect-posture.md index cf38126120..5328276841 100644 --- a/.changeset/sep-2106-dialect-posture.md +++ b/.changeset/sep-2106-dialect-posture.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': major '@modelcontextprotocol/server': major --- diff --git a/.changeset/sep-2243-mcp-param-client.md b/.changeset/sep-2243-mcp-param-client.md index bdefc019a4..ffb90b1d1c 100644 --- a/.changeset/sep-2243-mcp-param-client.md +++ b/.changeset/sep-2243-mcp-param-client.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/sep-2243-std-header-server.md b/.changeset/sep-2243-std-header-server.md index 584492034a..eb8bc03fd9 100644 --- a/.changeset/sep-2243-std-header-server.md +++ b/.changeset/sep-2243-std-header-server.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor --- @@ -7,4 +7,4 @@ SEP-2243 standard-header server-side validation (protocol revision 2026-07-28). New public surface: -- `@modelcontextprotocol/core`: `validateStandardRequestHeaders` (function), `MCP_NAME_HEADER_SOURCE` (const), the `mcpNameHeader` field on `InboundHttpRequest`, and the `'standard-header-validation'` member of `InboundValidationRung` (with `client-capabilities` / `param-header-validation` renumbered). +- `@modelcontextprotocol/server`: the `mcpNameHeader` field on `InboundHttpRequest`, and the `'standard-header-validation'` member of `InboundValidationRung` (with `client-capabilities` / `param-header-validation` renumbered). diff --git a/.changeset/sep-2577-deprecate-runtime-apis.md b/.changeset/sep-2577-deprecate-runtime-apis.md index 60afaaceb2..e042112d08 100644 --- a/.changeset/sep-2577-deprecate-runtime-apis.md +++ b/.changeset/sep-2577-deprecate-runtime-apis.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/server': patch '@modelcontextprotocol/client': patch --- diff --git a/.changeset/sep-2577-deprecate-type-stacks.md b/.changeset/sep-2577-deprecate-type-stacks.md index 0fbe31bf9e..7471457f7a 100644 --- a/.changeset/sep-2577-deprecate-type-stacks.md +++ b/.changeset/sep-2577-deprecate-type-stacks.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch --- diff --git a/.changeset/sep-2663-tasks-removal.md b/.changeset/sep-2663-tasks-removal.md index 51ece994a4..8316165b50 100644 --- a/.changeset/sep-2663-tasks-removal.md +++ b/.changeset/sep-2663-tasks-removal.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': major +'@modelcontextprotocol/core-internal': major '@modelcontextprotocol/server': major '@modelcontextprotocol/client': major --- diff --git a/.changeset/sep-414-trace-context-meta-keys.md b/.changeset/sep-414-trace-context-meta-keys.md index f8f21b63aa..1281c9dafb 100644 --- a/.changeset/sep-414-trace-context-meta-keys.md +++ b/.changeset/sep-414-trace-context-meta-keys.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Add reserved trace context `_meta` key constants (`TRACEPARENT_META_KEY`, `TRACESTATE_META_KEY`, `BAGGAGE_META_KEY`) per SEP-414, plus docs and a passthrough regression test. The spec reserves the unprefixed `_meta` keys `traceparent`, `tracestate`, and `baggage` (W3C Trace Context / W3C Baggage formats) for distributed tracing; the SDK passes them through untouched. diff --git a/.changeset/shy-times-learn.md b/.changeset/shy-times-learn.md index 99617f8b7d..24d47206eb 100644 --- a/.changeset/shy-times-learn.md +++ b/.changeset/shy-times-learn.md @@ -2,7 +2,7 @@ '@modelcontextprotocol/node': patch '@modelcontextprotocol/test-integration': patch '@modelcontextprotocol/server': patch -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- deprecated .tool, .prompt, .resource method removal diff --git a/.changeset/spec-2907-error-code-renumber.md b/.changeset/spec-2907-error-code-renumber.md index aeed3f11e2..a58191756b 100644 --- a/.changeset/spec-2907-error-code-renumber.md +++ b/.changeset/spec-2907-error-code-renumber.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor '@modelcontextprotocol/server': minor --- diff --git a/.changeset/spec-anchor-repin-2fb207da.md b/.changeset/spec-anchor-repin-2fb207da.md index b021ff4d77..cdb774acad 100644 --- a/.changeset/spec-anchor-repin-2fb207da.md +++ b/.changeset/spec-anchor-repin-2fb207da.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/spec-corpus-and-leak-net.md b/.changeset/spec-corpus-and-leak-net.md index 017ecd1501..9e8ebbbc54 100644 --- a/.changeset/spec-corpus-and-leak-net.md +++ b/.changeset/spec-corpus-and-leak-net.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Test-only hardening, no runtime changes: a spec example corpus harness (the draft revision's 86 example directories vendored from the specification repository plus a frozen hand-built 2025-11-25 corpus, with rejection-side fixtures routed through real dispatch), a cross-bundle typed-error recognition guard, and extended end-to-end draft-vocabulary leak coverage for hosted transports, SSE streams, and compatibility fallback paths. diff --git a/.changeset/spec-reference-types-2026-07-28.md b/.changeset/spec-reference-types-2026-07-28.md index 36f0a1f677..ea3c5c0fda 100644 --- a/.changeset/spec-reference-types-2026-07-28.md +++ b/.changeset/spec-reference-types-2026-07-28.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/codemod': patch --- diff --git a/.changeset/spec-types-2026-repin.md b/.changeset/spec-types-2026-repin.md index dbf757cd4e..32eea35562 100644 --- a/.changeset/spec-types-2026-repin.md +++ b/.changeset/spec-types-2026-repin.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/stdio-max-buffer-size.md b/.changeset/stdio-max-buffer-size.md index a4b71e9dcd..080a6ae81c 100644 --- a/.changeset/stdio-max-buffer-size.md +++ b/.changeset/stdio-max-buffer-size.md @@ -1,7 +1,7 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- -Add a configurable `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/core` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`. +Add a configurable `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/client` / `@modelcontextprotocol/server` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`. diff --git a/.changeset/stdio-skip-non-json.md b/.changeset/stdio-skip-non-json.md index d20b740c9c..7c70e412f3 100644 --- a/.changeset/stdio-skip-non-json.md +++ b/.changeset/stdio-skip-non-json.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- `ReadBuffer.readMessage()` now silently skips non-JSON lines instead of throwing `SyntaxError`. This prevents noisy `onerror` callbacks when hot-reload tools (tsx, nodemon) write debug output like "Gracefully restarting..." to stdout. Lines that parse as JSON but fail JSONRPC schema validation still throw. diff --git a/.changeset/subscriptions-listen-client.md b/.changeset/subscriptions-listen-client.md index 3cc5c10757..db7b1fb4eb 100644 --- a/.changeset/subscriptions-listen-client.md +++ b/.changeset/subscriptions-listen-client.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/subscriptions-listen-result.md b/.changeset/subscriptions-listen-result.md index 4f62eb608b..60117a325b 100644 --- a/.changeset/subscriptions-listen-result.md +++ b/.changeset/subscriptions-listen-result.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/subscriptions-listen-server.md b/.changeset/subscriptions-listen-server.md index abaf0d6261..70462dea60 100644 --- a/.changeset/subscriptions-listen-server.md +++ b/.changeset/subscriptions-listen-server.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor --- @@ -14,4 +14,4 @@ New public surface: - `McpHttpHandler` gains `.notify` (`ServerNotifier`: `toolsChanged()`, `promptsChanged()`, `resourcesChanged()`, `resourceUpdated(uri)`) and `.bus` (the `ServerEventBus` listen streams subscribe to). - `CreateMcpHandlerOptions` gains `bus?: ServerEventBus` (an in-process `InMemoryServerEventBus` is created when omitted), `maxSubscriptions?: number` (default 1024), and `keepAliveMs?: number` (default 15000). - `ServeStdioOptions` gains `maxSubscriptions?: number` (default 1024). On a modern-pinned connection `serveStdio` routes the pinned instance's existing `send*ListChanged()` calls onto active subscriptions; legacy connections are unchanged. -- `@modelcontextprotocol/core`: `SUBSCRIPTION_ID_META_KEY` (const); `SubscriptionFilter`, `SubscriptionsListenRequest`, `SubscriptionsListenRequestParams`, `SubscriptionsAcknowledgedNotification`, `SubscriptionsAcknowledgedNotificationParams` (types). +- `@modelcontextprotocol/server`: `SUBSCRIPTION_ID_META_KEY` (const); `SubscriptionFilter`, `SubscriptionsListenRequest`, `SubscriptionsListenRequestParams`, `SubscriptionsAcknowledgedNotification`, `SubscriptionsAcknowledgedNotificationParams` (types). diff --git a/.changeset/support-standard-json-schema.md b/.changeset/support-standard-json-schema.md index 792e15f1f7..38a9998893 100644 --- a/.changeset/support-standard-json-schema.md +++ b/.changeset/support-standard-json-schema.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor '@modelcontextprotocol/client': minor --- @@ -30,5 +30,5 @@ server.registerTool('greet', { **Breaking changes:** - `experimental.tasks.getTaskResult()` no longer accepts a `resultSchema` parameter. Returns `GetTaskPayloadResult` (a loose `Result`); cast to the expected type at the call site. -- Removed unused exports from `@modelcontextprotocol/core`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` instead. +- Removed unused exports from `@modelcontextprotocol/core-internal`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` instead. - `completable()` remains Zod-specific (it relies on Zod's `.shape` introspection). diff --git a/.changeset/wire-public-separation.md b/.changeset/wire-public-separation.md index 7930cc7060..5e88cf5895 100644 --- a/.changeset/wire-public-separation.md +++ b/.changeset/wire-public-separation.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/wire-server-discover.md b/.changeset/wire-server-discover.md index b83b860e5e..ea8eaea832 100644 --- a/.changeset/wire-server-discover.md +++ b/.changeset/wire-server-discover.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/server': minor '@modelcontextprotocol/client': minor --- diff --git a/.changeset/workerd-shim-vendors-cfworker.md b/.changeset/workerd-shim-vendors-cfworker.md index 9759e73009..38c8222913 100644 --- a/.changeset/workerd-shim-vendors-cfworker.md +++ b/.changeset/workerd-shim-vendors-cfworker.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': minor +'@modelcontextprotocol/core-internal': minor '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/wraphandler-hook.md b/.changeset/wraphandler-hook.md index 935f576588..114ebf0332 100644 --- a/.changeset/wraphandler-hook.md +++ b/.changeset/wraphandler-hook.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/client': patch '@modelcontextprotocol/server': patch --- diff --git a/.changeset/zod-json-schema-compat.md b/.changeset/zod-json-schema-compat.md index 5ca1470e82..b3180fb06b 100644 --- a/.changeset/zod-json-schema-compat.md +++ b/.changeset/zod-json-schema-compat.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch --- Allow additional JSON Schema properties in elicitInput's requestedSchema type by adding .catchall(z.unknown()), matching the pattern used by inputSchema. This fixes type incompatibility when using Zod v4's .toJSONSchema() output which includes extra properties like $schema and additionalProperties. diff --git a/.changeset/zod-jsonschema-fallback.md b/.changeset/zod-jsonschema-fallback.md index e2936cf568..a02662da12 100644 --- a/.changeset/zod-jsonschema-fallback.md +++ b/.changeset/zod-jsonschema-fallback.md @@ -1,5 +1,5 @@ --- -'@modelcontextprotocol/core': patch +'@modelcontextprotocol/core-internal': patch '@modelcontextprotocol/server': patch '@modelcontextprotocol/client': patch --- diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6d184c9867..829b634bdc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -39,5 +39,5 @@ jobs: - name: Publish preview packages run: - pnpm dlx pkg-pr-new publish --packageManager=npm --pnpm './packages/server' './packages/server-legacy' './packages/client' + pnpm dlx pkg-pr-new publish --packageManager=npm --pnpm './packages/core' './packages/server' './packages/server-legacy' './packages/client' './packages/codemod' './packages/middleware/express' './packages/middleware/fastify' './packages/middleware/hono' './packages/middleware/node' diff --git a/.github/workflows/update-spec-types.yml b/.github/workflows/update-spec-types.yml index 41c1303b0a..d9bb15969c 100644 --- a/.github/workflows/update-spec-types.yml +++ b/.github/workflows/update-spec-types.yml @@ -1,6 +1,6 @@ # Nightly refresh of the draft-tracking spec anchor (2026-07-28). # -# Anchor lifecycle (see packages/core/src/types/README.md for the full policy): +# Anchor lifecycle (see packages/core-internal/src/types/README.md for the full policy): # - Draft anchors float: this job regenerates the draft-tracking anchor from the # latest upstream draft schema and, on drift, opens a refresh PR for review. # It only ever proposes — it never merges. @@ -50,11 +50,11 @@ jobs: - name: Check for changes id: check_changes run: | - if git diff --quiet packages/core/src/types/spec.types.2026-07-28.ts; then + if git diff --quiet packages/core-internal/src/types/spec.types.2026-07-28.ts; then echo "has_changes=false" >> $GITHUB_OUTPUT else echo "has_changes=true" >> $GITHUB_OUTPUT - LATEST_SHA=$(grep "Last updated from commit:" packages/core/src/types/spec.types.2026-07-28.ts | cut -d: -f2 | tr -d ' ') + LATEST_SHA=$(grep "Last updated from commit:" packages/core-internal/src/types/spec.types.2026-07-28.ts | cut -d: -f2 | tr -d ' ') echo "sha=$LATEST_SHA" >> $GITHUB_OUTPUT fi @@ -70,12 +70,12 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" git checkout -B update-spec-types - git add packages/core/src/types/spec.types.2026-07-28.ts + git add packages/core-internal/src/types/spec.types.2026-07-28.ts git commit -m "chore: update spec.types.2026-07-28.ts from upstream" git push -f --no-verify origin update-spec-types # Create PR if it doesn't exist, or update if it does - PR_BODY="This PR updates \`packages/core/src/types/spec.types.2026-07-28.ts\` from the Model Context Protocol specification. + PR_BODY="This PR updates \`packages/core-internal/src/types/spec.types.2026-07-28.ts\` from the Model Context Protocol specification. Source file: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/${{ steps.check_changes.outputs.sha }}/schema/draft/schema.ts diff --git a/.prettierignore b/.prettierignore index 0ece978310..ad18072c52 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,11 +15,11 @@ pnpm-lock.yaml # Spec example corpora: vendored verbatim from the spec repository # (fetch:spec-examples) or hand-built and frozen - byte-faithful artifacts. -packages/core/test/corpus/fixtures/ +packages/core-internal/test/corpus/fixtures/ # Schema twins: raw upstream schema.json bytes (fetch:schema-twins), locked to # manifest.json by sha256 in schemaTwinConformance - reformatting breaks the lock. -packages/core/test/corpus/schema-twins/ +packages/core-internal/test/corpus/schema-twins/ # Batch test cloned repos and results packages/codemod/batch-test/repos diff --git a/CLAUDE.md b/CLAUDE.md index c2c664b970..f3ae8c1ce3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,10 +16,10 @@ pnpm check:all # typecheck + lint across all packages # Run a single package script (examples) # Run a single package script from the repo root with pnpm filter -pnpm --filter @modelcontextprotocol/core test # vitest run (core) -pnpm --filter @modelcontextprotocol/core test:watch # vitest (watch) -pnpm --filter @modelcontextprotocol/core test -- path/to/file.test.ts -pnpm --filter @modelcontextprotocol/core test -- -t "test name" +pnpm --filter @modelcontextprotocol/core-internal test # vitest run (core) +pnpm --filter @modelcontextprotocol/core-internal test:watch # vitest (watch) +pnpm --filter @modelcontextprotocol/core-internal test -- path/to/file.test.ts +pnpm --filter @modelcontextprotocol/core-internal test -- -t "test name" ``` ## Breaking Changes @@ -37,7 +37,7 @@ Include what changed, why, and how to migrate. Search for related sections and g - **TypeScript**: Strict type checking, ES modules, explicit return types - **Naming**: PascalCase for classes/types, camelCase for functions/variables - **Files**: Lowercase with hyphens, test files with `.test.ts` suffix -- **Imports**: ES module style, include `.js` extension, group imports logically +- **Imports**: ES module style, no `.js` extension on relative imports (project uses `moduleResolution: bundler`), group imports logically - **Formatting**: 2-space indentation, semicolons required, single quotes preferred - **Testing**: Place tests under each package's `test/` directory (vitest only includes `test/**/*.test.ts`), use descriptive test names - **Comments**: JSDoc for public APIs, inline comments for complex logic @@ -54,9 +54,9 @@ Run `pnpm sync:snippets` to sync example content into JSDoc comments and markdow The SDK is organized into three main layers: -1. **Types Layer** (`packages/core/src/types/types.ts`) - Protocol types generated from the MCP specification. All JSON-RPC message types, schemas, and protocol constants are defined here using Zod v4. +1. **Types Layer** (`packages/core-internal/src/types/types.ts`) - Protocol types generated from the MCP specification. All JSON-RPC message types, schemas, and protocol constants are defined here using Zod v4. -2. **Protocol Layer** (`packages/core/src/shared/protocol.ts`) - The abstract `Protocol` class that handles JSON-RPC message routing, request/response correlation, capability negotiation, and transport management. Both `Client` and `Server` extend this class. +2. **Protocol Layer** (`packages/core-internal/src/shared/protocol.ts`) - The abstract `Protocol` class that handles JSON-RPC message routing, request/response correlation, capability negotiation, and transport management. Both `Client` and `Server` extend this class. 3. **High-Level APIs**: - `Client` (`packages/client/src/client/client.ts`) - Client implementation extending Protocol with typed methods for MCP operations @@ -65,21 +65,22 @@ The SDK is organized into three main layers: ### Public API Exports -The SDK has a two-layer export structure to separate internal code from the public API: +The SDK separates internal code from the public API surface: -- **`@modelcontextprotocol/core`** (main entry, `packages/core/src/index.ts`) — Internal barrel. Exports everything (including Zod schemas, Protocol class, stdio utils). Only consumed by sibling packages within the monorepo (`private: true`). -- **`@modelcontextprotocol/core/public`** (`packages/core/src/exports/public/index.ts`) — Curated public API. Exports only TypeScript types, error classes, constants, and guards. Re-exported by client and server packages. -- **`@modelcontextprotocol/client`** and **`@modelcontextprotocol/server`** (`packages/*/src/index.ts`) — Final public surface. Package-specific exports (named explicitly) plus re-exports from `core/public`. +- **`@modelcontextprotocol/core-internal`** (main entry, `packages/core-internal/src/index.ts`) — Internal barrel. Exports everything (including Zod schemas, Protocol class, stdio utils). Only consumed by sibling packages within the monorepo (`private: true`). +- **`@modelcontextprotocol/core-internal/public`** (`packages/core-internal/src/exports/public/index.ts`) — Curated public API. Exports only TypeScript types, error classes, constants, and guards. Re-exported by client and server packages. +- **`@modelcontextprotocol/client`** and **`@modelcontextprotocol/server`** (`packages/*/src/index.ts`) — Final public surface. Package-specific exports (named explicitly) plus re-exports from `core-internal/public`. +- **`@modelcontextprotocol/core`** (`packages/core/src/index.ts`) — Public Zod-schema package. Re-exports **only** the `*Schema` Zod constants (MCP spec + OAuth/OpenID), bundled from `core-internal` at build time. The published home for raw runtime validation (`CallToolResultSchema.parse(...)`); runtime-neutral (`zod` is its only dependency). Not consumed by the sibling packages — `client`/`server` keep their own bundled schema copies and stay Zod-free in their public surface. When modifying exports: -- Use explicit named exports, not `export *`, in package `index.ts` files and `core/public`. +- Use explicit named exports, not `export *`, in package `index.ts` files and `core-internal/public`. - Adding a symbol to a package `index.ts` makes it public API — do so intentionally. -- Internal helpers should stay in the core internal barrel and not be added to `core/public` or package index files. +- Internal helpers should stay in the core internal barrel and not be added to `core-internal/public` or package index files. - The package root entry must stay runtime-neutral so browser and Cloudflare Workers bundlers can consume it. Exports whose module graph transitively touches unpolyfillable Node builtins (`node:child_process`, `node:net`, `cross-spawn`, etc.) must live at a named subpath export (e.g. `./stdio`) and be covered by a `barrelClean` test in that package. ### Transport System -Transports (`packages/core/src/shared/transport.ts`) provide the communication layer: +Transports (`packages/core-internal/src/shared/transport.ts`) provide the communication layer: - **Streamable HTTP** (`packages/server/src/server/streamableHttp.ts`, `packages/client/src/client/streamableHttp.ts`) - Recommended transport for remote servers, supports SSE for streaming - **SSE** (`packages/server/src/server/sse.ts`, `packages/client/src/client/sse.ts`) - Legacy HTTP+SSE transport for backwards compatibility @@ -111,11 +112,11 @@ Located in `packages/*/src/experimental/`. Currently empty. The SDK uses `zod/v4` internally. Schema utilities live in: -- `packages/core/src/util/schema.ts` - AnySchema alias and helpers for inspecting Zod objects +- `packages/core-internal/src/util/schema.ts` - AnySchema alias and helpers for inspecting Zod objects ### Validation -Pluggable JSON Schema validation (`packages/core/src/validators/`): +Pluggable JSON Schema validation (`packages/core-internal/src/validators/`): - `ajvProvider.ts` - Default Ajv-based validator - `cfWorkerProvider.ts` - Cloudflare Workers-compatible alternative diff --git a/common/eslint-config/eslint.config.mjs b/common/eslint-config/eslint.config.mjs index a32b4208cc..fb0b5d3db6 100644 --- a/common/eslint-config/eslint.config.mjs +++ b/common/eslint-config/eslint.config.mjs @@ -36,7 +36,7 @@ export default defineConfig( settings: { 'import/resolver': { typescript: { - // Let the TS resolver handle NodeNext-style imports like "./foo.js" + // Resolve extensionless relative imports (moduleResolution: bundler) to their TS sources extensions: ['.js', '.jsx', '.ts', '.tsx', '.d.ts'], // Use the tsconfig in each package root (when running ESLint from that package) project: 'tsconfig.json' diff --git a/common/tsconfig/tsconfig.json b/common/tsconfig/tsconfig.json index 6db7d705bf..c6fff64f48 100644 --- a/common/tsconfig/tsconfig.json +++ b/common/tsconfig/tsconfig.json @@ -2,8 +2,8 @@ "compilerOptions": { "target": "esnext", "lib": ["esnext"], - "module": "NodeNext", - "moduleResolution": "NodeNext", + "module": "ESNext", + "moduleResolution": "bundler", "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, diff --git a/docs/behavior-surface-pins.md b/docs/behavior-surface-pins.md index 29eb95a848..4631ea8e37 100644 --- a/docs/behavior-surface-pins.md +++ b/docs/behavior-surface-pins.md @@ -25,9 +25,9 @@ CI pass — that reopens the silent-drift hole the pin exists to close. | Surface | File | | --- | --- | -| Wire error-code tables, error classes, version constants | `packages/core/test/types/errorSurfacePins.test.ts` | -| Schema strict/strip/loose boundaries, key existence | `packages/core/test/types/schemaBoundaryPins.test.ts` | -| Published package set, export maps, ESM-only topology | `packages/core/test/packageTopologyPins.test.ts` | +| Wire error-code tables, error classes, version constants | `packages/core-internal/test/types/errorSurfacePins.test.ts` | +| Schema strict/strip/loose boundaries, key existence | `packages/core-internal/test/types/schemaBoundaryPins.test.ts` | +| Published package set, export maps, ESM-only topology | `packages/core-internal/test/packageTopologyPins.test.ts` | | stdio environment-inheritance safelist | `packages/client/test/client/stdioEnvPins.test.ts` | ## Writing a new pin diff --git a/docs/client-quickstart.md b/docs/client-quickstart.md index f26324636f..4c287bd925 100644 --- a/docs/client-quickstart.md +++ b/docs/client-quickstart.md @@ -88,10 +88,10 @@ Create a `tsconfig.json` in the root of your project: ```json { "compilerOptions": { - "target": "ES2023", - "lib": ["ES2023"], - "module": "Node16", - "moduleResolution": "Node16", + "target": "ESNext", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", "outDir": "./build", "rootDir": "./src", "strict": true, @@ -236,7 +236,8 @@ Now let's add the core functionality for processing queries and handling tool ca messages, }); - finalText.push(followUp.content[0].type === 'text' ? followUp.content[0].text : ''); + const firstBlock = followUp.content[0]; + finalText.push(firstBlock?.type === 'text' ? firstBlock.text : ''); } } @@ -284,13 +285,14 @@ Finally, we'll add the main execution logic: ```ts source="../examples/client-quickstart/src/index.ts#main" async function main() { - if (process.argv.length < 3) { + const serverScriptPath = process.argv[2]; + if (!serverScriptPath) { console.log('Usage: node build/index.js '); return; } const mcpClient = new MCPClient(); try { - await mcpClient.connectToServer(process.argv[2]); + await mcpClient.connectToServer(serverScriptPath); // Check if we have a valid API key to continue const apiKey = process.env.ANTHROPIC_API_KEY; diff --git a/docs/migration/upgrade-to-v2.md b/docs/migration/upgrade-to-v2.md index c08c2b8867..c48c0a2b9c 100644 --- a/docs/migration/upgrade-to-v2.md +++ b/docs/migration/upgrade-to-v2.md @@ -27,7 +27,10 @@ If you are already on v2 and want to adopt the **2026-07-28 protocol revision**, ``` 4. **Type-check.** `tsc --noEmit` (or your build). Remaining errors map to the [manual sections](#manual-changes-what-the-codemod-does-not-handle) below. -5. **Run your tests.** +5. **Format.** The codemod rewrites the AST without reformatting — run your formatter on + the changed files (`prettier --write` / `eslint --fix` / `biome format --write`); the + codemod prints the exact command after it runs. +6. **Run your tests.** ## Contents @@ -71,11 +74,13 @@ In addition the codemod: `uriSchema` raw Zod shapes with `z.object()`. - Drops the result-schema argument from `client.request()` / `client.callTool()` for spec methods. -- Rewrites standalone Zod-spec-schema usages: `XSchema.safeParse(v).success` → - `isSpecType.X(v)`; captured `const r = XSchema.safeParse(v)` → - `specTypeSchemas.X['~standard'].validate(v)` with `.success`/`.data`/`.error` - remapped; bare `XSchema` value uses → `specTypeSchemas.X`; `XSchema.parse()` is - rewritten and marked `@mcp-codemod-error` (the throw-on-invalid semantics differ). +- Routes the spec Zod `*Schema` constants imported from `sdk/types.js` to + `@modelcontextprotocol/core` (mixed imports are split; `.parse()` / `.safeParse()` + calls are left untouched). Task-handler schema constants + (`GetTaskRequestSchema` etc.) used as `setRequestHandler` args are **not** rewritten + — the experimental tasks feature was removed (SEP-2663), so each such registration + is marked with an action-required diagnostic instead (see + [Experimental tasks interception removed](#experimental-tasks-interception-removed)). - Renames `ErrorCode` → `ProtocolErrorCode` and routes the local-only members (`RequestTimeout`, `ConnectionClosed`) to `SdkErrorCode`. - Renames every `StreamableHTTPError` reference to `SdkHttpError` and adds the import @@ -109,9 +114,10 @@ recognized but could not safely rewrite with an `@mcp-codemod-error` comment. - **`SdkErrorCode` branch selection** — the codemod renames `StreamableHTTPError` → `SdkHttpError`; deciding which `SdkErrorCode` branch a given catch should match is judgment. → [Errors](#errors) -- **`.parse()` throw semantics** — the codemod rewrites `XSchema.parse()` to - `specTypeSchemas.X['~standard'].validate()` but `validate()` does not throw on - invalid input; the site is marked `@mcp-codemod-error`. → [Types & schemas](#types--schemas) +- **Namespace schema access** — `import * as t from '…/types.js'` + + `t.CallToolResultSchema.parse(…)` can't be split per-symbol; the codemod flags it + action-required — re-import the schema from `@modelcontextprotocol/core` by hand. + → [Types & schemas](#types--schemas) - **Behavioral adaptation** — list auto-aggregation, capability empties, lazy validator compilation, output-schema validation rules. → [Behavioral changes](#behavioral-changes) @@ -127,13 +133,16 @@ The single `@modelcontextprotocol/sdk` package is split: | --- | --- | | `@modelcontextprotocol/sdk` | `@modelcontextprotocol/client` (client implementation) | | | `@modelcontextprotocol/server` (server implementation) | -| | `@modelcontextprotocol/core` (internal — never import directly) | +| | `@modelcontextprotocol/core` (public Zod `*Schema` constants) | +| | `@modelcontextprotocol/core-internal` (internal — never import directly) | | Built-in HTTP framework support | `@modelcontextprotocol/node` / `@modelcontextprotocol/express` / `@modelcontextprotocol/hono` / `@modelcontextprotocol/fastify` | `@modelcontextprotocol/client` and `@modelcontextprotocol/server` both re-export shared -types from `@modelcontextprotocol/core`, so import types and error classes from -whichever package you already depend on. **Do not import from `@modelcontextprotocol/core` -directly.** +types from `@modelcontextprotocol/core-internal`, so import types and error classes from +whichever package you already depend on. `@modelcontextprotocol/core-internal` is +`private: true` and is not published — **do not import from it directly.** +`@modelcontextprotocol/core` is the public Zod-schema package (raw `*Schema` constants +only); see [Zod `*Schema` constants moved to `@modelcontextprotocol/core`](#zod-schema-constants-moved-to-modelcontextprotocolcore) below. The framework adapter packages declare their framework as a **peer dependency** (`express`, `hono`, `fastify`); v1 shipped them as direct deps. The codemod adds the @@ -166,6 +175,9 @@ A few transports need a decision the codemod can't make: these (the root entries are runtime-neutral so browser/Workers bundlers can consume them). The stdio utilities `ReadBuffer`, `serializeMessage`, `deserializeMessage` stay in the root barrel. +- **Zod `*Schema` constants → `@modelcontextprotocol/core`.** A mixed + `import { CallToolResult, CallToolResultSchema } from '…/types.js'` is split by the + codemod — see [Types & schemas](#types--schemas). ```typescript // v1 @@ -710,28 +722,38 @@ The SDK enforces every authorization MUST that lands in SDK code. The following ### Types & schemas -#### Zod `*Schema` constants are no longer public API +#### Zod `*Schema` constants moved to `@modelcontextprotocol/core` The Zod schemas (`CallToolResultSchema`, `ListToolsResultSchema`, …) that v1 exported -from `types.js` are **not** part of the v2 public surface. They live in the internal -core barrel only; `@modelcontextprotocol/client` and `@modelcontextprotocol/server` do -not re-export them. +from `types.js` now live in a separate **`@modelcontextprotocol/core`** package. Neither +`@modelcontextprotocol/client` nor `@modelcontextprotocol/server` re-exports them — both +packages stay Zod-free in their public surface. -If you used a `*Schema` constant for **runtime validation** (not just as a `request()` -argument), replace with `isSpecType` / `specTypeSchemas`: +The v1→v2 change is just an import-path swap — `.parse()` / `.safeParse()` keep working +unchanged: ```typescript // v1 import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'; if (CallToolResultSchema.safeParse(value).success) { ... } -// v2: keyed type predicate -import { isSpecType } from '@modelcontextprotocol/client'; +// v2 — same Zod schema, new package +import { CallToolResultSchema } from '@modelcontextprotocol/core'; +if (CallToolResultSchema.safeParse(value).success) { ... } +``` + +`@modelcontextprotocol/core` is the canonical home for the spec's Zod schema constants +(and the OAuth/OpenID metadata schemas). It is runtime-neutral (its only dependency is +`zod`) and is **not** required by `client` / `server` — install it only if you import the +raw schemas directly. + +If you would rather keep your project Zod-free, the **`isSpecType` / `specTypeSchemas`** +alternatives are exported from `@modelcontextprotocol/client` and `…/server`: + +```typescript +import { isSpecType, specTypeSchemas } from '@modelcontextprotocol/client'; if (isSpecType.CallToolResult(value)) { ... } const blocks = mixed.filter(isSpecType.ContentBlock); - -// v2: or get the StandardSchemaV1Sync validator object directly -import { specTypeSchemas } from '@modelcontextprotocol/client'; const result = specTypeSchemas.CallToolResult['~standard'].validate(value); ``` @@ -741,12 +763,14 @@ every named type in the MCP spec — so you get autocomplete and a compile error The pre-existing `isCallToolResult(value)` guard still works. **`specTypeSchemas.X` is `StandardSchemaV1`, not `ZodType`.** Zod-specific composition -methods — `.extend()`, `.pick()`, `.omit()`, `.merge()`, `.shape`, `.passthrough()`, -`.parseAsync()` — will not compile on a `specTypeSchemas` entry. The codemod emits an -`@mcp-codemod-error` warning at every such site; define your own schema (Zod, ArkType, -…) instead of extending the SDK's. The Zod-specific `AnySchema` / `SchemaOutput` types -from `…/zod-compat.js` are removed — replace with `StandardSchemaV1` / -`StandardSchemaV1.InferOutput` (the codemod's removal message says the same). +— `.extend()`, `.pick()`, `.omit()`, `.merge()`, `.shape`, `.passthrough()`, +`.parseAsync()` — does **not** compile on a `specTypeSchemas` entry; reach for the real +Zod schema from `@modelcontextprotocol/core` when you need to derive a tolerant variant +of a spec schema (e.g. +`ListToolsResultSchema.extend({ tools: ToolSchema.omit({ outputSchema: true }).array() })`). +The Zod-specific `AnySchema` / `SchemaOutput` types from `…/zod-compat.js` are removed — +replace with `StandardSchemaV1` / `StandardSchemaV1.InferOutput` (the codemod's +removal message says the same). The role-aggregate unions (`ClientRequest`, `ServerResult`, `ServerRequest`, `ClientResult`, `ClientNotification`, `ServerNotification`) and the typed-method maps @@ -761,23 +785,28 @@ include task vocabulary; the deprecated `Task*` types remain importable on their | `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` | | `isJSONRPCError` | `isJSONRPCErrorResponse` | | `isJSONRPCResponse` (deprecated in v1) | `isJSONRPCResultResponse` ² | +| `JSONRPCResponseSchema` (result-only in v1) | `JSONRPCResultResponseSchema` ² | +| `JSONRPCResponse` (result-only in v1) | `JSONRPCResultResponse` ² | | `ResourceReference` / `ResourceReferenceSchema` | `ResourceTemplateReference` / `ResourceTemplateReferenceSchema` | | `IsomorphicHeaders` | Web Standard `Headers` | | `RequestHandlerExtra` | `ServerContext` / `ClientContext` / `BaseContext` | | `ResourceTemplate` (the spec wire **type** from `sdk/types.js`) | `ResourceTemplateType` ³ | -² v2 introduces a **new** `isJSONRPCResponse` with corrected semantics — it matches -**both** result and error responses. v1's `isJSONRPCResponse` only matched results. To -preserve v1 behavior, rename to `isJSONRPCResultResponse` (the codemod does this). +² v2 introduces **new** `isJSONRPCResponse` / `JSONRPCResponse` / `JSONRPCResponseSchema` +with corrected semantics — they match **both** result and error responses (the schema is +`z.union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema])`). v1's symbols only +matched results. To preserve v1 behavior, rename to `isJSONRPCResultResponse` / +`JSONRPCResultResponse` / `JSONRPCResultResponseSchema` (the codemod does this). ³ The `ResourceTemplate` URI-template helper **class** (from `sdk/server/mcp.js`) is **unchanged** — keep `new ResourceTemplate(...)` as-is. Only the like-named spec wire type from `types.js` was renamed to `ResourceTemplateType` to resolve the v1 collision; the codemod scopes the rename to imports from `sdk/types.js` only. -All other **type** symbols from `@modelcontextprotocol/sdk/types.js` retain their -original names — import them from `@modelcontextprotocol/client` or -`@modelcontextprotocol/server`. +All other symbols from `@modelcontextprotocol/sdk/types.js` retain their original +names — import the TypeScript types, error classes, enums, and type guards from +`@modelcontextprotocol/client` or `@modelcontextprotocol/server`, and the Zod +`*Schema` constants from `@modelcontextprotocol/core`. #### JSON Schema 2020-12 posture (SEP-1613, SEP-2106) diff --git a/docs/server-quickstart.md b/docs/server-quickstart.md index 0ed198be18..7b75629dfb 100644 --- a/docs/server-quickstart.md +++ b/docs/server-quickstart.md @@ -103,9 +103,10 @@ Create a `tsconfig.json` in the root of your project: ```json { "compilerOptions": { - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", + "target": "ESNext", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", "outDir": "./build", "rootDir": "./src", "strict": true, diff --git a/examples/CONTRIBUTING.md b/examples/CONTRIBUTING.md index a0ad23e880..ccd1443423 100644 --- a/examples/CONTRIBUTING.md +++ b/examples/CONTRIBUTING.md @@ -79,14 +79,14 @@ timeout is reported as a hang — investigate it as a possible unclosed handle). Stories may import from: -- `@modelcontextprotocol/{server,client,node,express,hono}` and their published +- `@modelcontextprotocol/{server,client,core,node,express,hono}` and their published subpath exports (e.g. `@modelcontextprotocol/server/stdio`) - `@mcp-examples/shared` (args/assert) and `@mcp-examples/shared/auth` (demo OAuth + `InMemoryEventStore`) - third-party packages a consumer would `npm install` Stories may **not** import from: -- `@modelcontextprotocol/core` or `@modelcontextprotocol/core/*` (internal barrel) +- `@modelcontextprotocol/core-internal` or `@modelcontextprotocol/core-internal/*` (internal barrel) - `@modelcontextprotocol/*/src/*` or `@modelcontextprotocol/*/dist/*` (deep paths) - `@modelcontextprotocol/test-helpers` - any relative path that hides the SDK transport setup behind a shared helper diff --git a/examples/client-quickstart/package.json b/examples/client-quickstart/package.json index 98919df995..646890492e 100644 --- a/examples/client-quickstart/package.json +++ b/examples/client-quickstart/package.json @@ -15,6 +15,7 @@ "@modelcontextprotocol/client": "workspace:^" }, "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", "@types/node": "^24.10.1", "typescript": "catalog:devTools" } diff --git a/examples/client-quickstart/src/index.ts b/examples/client-quickstart/src/index.ts index f677834c03..6764fe61ff 100644 --- a/examples/client-quickstart/src/index.ts +++ b/examples/client-quickstart/src/index.ts @@ -116,7 +116,8 @@ class MCPClient { messages, }); - finalText.push(followUp.content[0].type === 'text' ? followUp.content[0].text : ''); + const firstBlock = followUp.content[0]; + finalText.push(firstBlock?.type === 'text' ? firstBlock.text : ''); } } @@ -156,13 +157,14 @@ class MCPClient { //#region main async function main() { - if (process.argv.length < 3) { + const serverScriptPath = process.argv[2]; + if (!serverScriptPath) { console.log('Usage: node build/index.js '); return; } const mcpClient = new MCPClient(); try { - await mcpClient.connectToServer(process.argv[2]); + await mcpClient.connectToServer(serverScriptPath); // Check if we have a valid API key to continue const apiKey = process.env.ANTHROPIC_API_KEY; diff --git a/examples/client-quickstart/tsconfig.json b/examples/client-quickstart/tsconfig.json index e7b40b59ba..cf326c78d8 100644 --- a/examples/client-quickstart/tsconfig.json +++ b/examples/client-quickstart/tsconfig.json @@ -1,24 +1,20 @@ { + "extends": "@modelcontextprotocol/tsconfig", "compilerOptions": { - "target": "ES2023", - "lib": ["ES2023"], - "module": "Node16", - "moduleResolution": "Node16", "outDir": "./build", "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, + "declaration": false, + "declarationMap": false, + "types": ["node"], "paths": { "@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"], "@modelcontextprotocol/client/stdio": ["./node_modules/@modelcontextprotocol/client/src/stdio.ts"], "@modelcontextprotocol/client/_shims": ["./node_modules/@modelcontextprotocol/client/src/shimsNode.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ] } }, diff --git a/examples/eslint.config.mjs b/examples/eslint.config.mjs index 08e956e733..1d4848ec63 100644 --- a/examples/eslint.config.mjs +++ b/examples/eslint.config.mjs @@ -31,7 +31,7 @@ export default [ message: 'Examples must not reach into workspace source.' }, { - group: ['@modelcontextprotocol/core', '@modelcontextprotocol/core/*'], + group: ['@modelcontextprotocol/core-internal', '@modelcontextprotocol/core-internal/*'], message: 'Examples must import from @modelcontextprotocol/{server,client}, not the internal core barrel.' }, { diff --git a/examples/oauth/client.ts b/examples/oauth/client.ts index 330ae0b247..4da94f4b5d 100644 --- a/examples/oauth/client.ts +++ b/examples/oauth/client.ts @@ -33,7 +33,7 @@ import { check, parseExampleArgs } from '@mcp-examples/shared'; import type { OAuthClientMetadata } from '@modelcontextprotocol/client'; import { Client, StreamableHTTPClientTransport, UnauthorizedError } from '@modelcontextprotocol/client'; -import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js'; +import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider'; // The redirect target the AS will 302 back to with `?code=...`. In the real // browser flow (`simpleOAuthClient.ts`) a tiny HTTP server listens here so the diff --git a/examples/oauth/simpleOAuthClient.ts b/examples/oauth/simpleOAuthClient.ts index a1a37f3382..8bea598f1f 100644 --- a/examples/oauth/simpleOAuthClient.ts +++ b/examples/oauth/simpleOAuthClient.ts @@ -8,7 +8,7 @@ import type { ListToolsRequest, OAuthClientMetadata } from '@modelcontextprotoco import { Client, StreamableHTTPClientTransport, UnauthorizedError } from '@modelcontextprotocol/client'; import open from 'open'; -import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js'; +import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider'; // Configuration const DEFAULT_SERVER_URL = 'http://127.0.0.1:3000/mcp'; diff --git a/examples/scoped-tools/client.ts b/examples/scoped-tools/client.ts index 357b7273c5..6a6ae3ee88 100644 --- a/examples/scoped-tools/client.ts +++ b/examples/scoped-tools/client.ts @@ -17,7 +17,7 @@ import { check, parseExampleArgs } from '@mcp-examples/shared'; import type { OAuthClientMetadata } from '@modelcontextprotocol/client'; import { Client, StreamableHTTPClientTransport, UnauthorizedError } from '@modelcontextprotocol/client'; -import { InMemoryOAuthClientProvider } from '../oauth/simpleOAuthClientProvider.js'; +import { InMemoryOAuthClientProvider } from '../oauth/simpleOAuthClientProvider'; const CALLBACK_URL = 'http://127.0.0.1:8091/callback'; diff --git a/examples/server-quickstart/package.json b/examples/server-quickstart/package.json index 133af7a1d6..e06a9832f9 100644 --- a/examples/server-quickstart/package.json +++ b/examples/server-quickstart/package.json @@ -15,6 +15,7 @@ "zod": "catalog:runtimeShared" }, "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", "@types/node": "^24.10.1", "typescript": "catalog:devTools" } diff --git a/examples/server-quickstart/tsconfig.json b/examples/server-quickstart/tsconfig.json index c760b5e4c0..36dccebc19 100644 --- a/examples/server-quickstart/tsconfig.json +++ b/examples/server-quickstart/tsconfig.json @@ -1,23 +1,20 @@ { + "extends": "@modelcontextprotocol/tsconfig", "compilerOptions": { - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", "outDir": "./build", "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, + "declaration": false, + "declarationMap": false, + "types": ["node"], "paths": { "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/stdio": ["./node_modules/@modelcontextprotocol/server/src/stdio.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ] } }, diff --git a/examples/shared/package.json b/examples/shared/package.json index 7ecfc11157..084daf3052 100644 --- a/examples/shared/package.json +++ b/examples/shared/package.json @@ -32,7 +32,6 @@ "test:watch": "vitest" }, "dependencies": { - "@modelcontextprotocol/core": "workspace:^", "@modelcontextprotocol/server": "workspace:^", "@modelcontextprotocol/express": "workspace:^", "better-auth": "^1.4.17", @@ -54,7 +53,6 @@ "eslint-config-prettier": "catalog:devTools", "eslint-plugin-n": "catalog:devTools", "prettier": "catalog:devTools", - "tsx": "catalog:devTools", "typescript": "catalog:devTools", "typescript-eslint": "catalog:devTools", "vitest": "catalog:devTools" diff --git a/examples/shared/src/authServer.ts b/examples/shared/src/authServer.ts index dc7d602cee..51606aa795 100644 --- a/examples/shared/src/authServer.ts +++ b/examples/shared/src/authServer.ts @@ -18,8 +18,8 @@ import cors from 'cors'; import type { NextFunction, Request, Response as ExpressResponse, Router } from 'express'; import express from 'express'; -import type { DemoAuth } from './auth.js'; -import { createDemoAuth, DEMO_USER_CREDENTIALS } from './auth.js'; +import type { DemoAuth } from './auth'; +import { createDemoAuth, DEMO_USER_CREDENTIALS } from './auth'; export interface SetupAuthServerOptions { authServerUrl: URL; diff --git a/examples/shared/src/index.ts b/examples/shared/src/index.ts index 3753ae4e4f..641fdb8828 100644 --- a/examples/shared/src/index.ts +++ b/examples/shared/src/index.ts @@ -3,5 +3,5 @@ // not eagerly evaluate better-auth/express/cors/better-sqlite3 just by // importing `parseExampleArgs`. The OAuth scaffolding lives at the `./auth` // subpath — see `./indexAuth.ts`. -export type { ExampleArgs, ExampleEra, ExampleTransport } from './args.js'; -export { check, parseExampleArgs, siblingPath } from './args.js'; +export type { ExampleArgs, ExampleEra, ExampleTransport } from './args'; +export { check, parseExampleArgs, siblingPath } from './args'; diff --git a/examples/shared/src/indexAuth.ts b/examples/shared/src/indexAuth.ts index 0e9ec62c51..cb7cbac791 100644 --- a/examples/shared/src/indexAuth.ts +++ b/examples/shared/src/indexAuth.ts @@ -4,16 +4,16 @@ // better-auth/express/cors/better-sqlite3 via `parseExampleArgs`. // Auth configuration -export type { CreateDemoAuthOptions, DemoAuth } from './auth.js'; -export { createDemoAuth } from './auth.js'; +export type { CreateDemoAuthOptions, DemoAuth } from './auth'; +export { createDemoAuth } from './auth'; // Auth server setup + demo token verifier (pass to `requireBearerAuth` from @modelcontextprotocol/express) -export type { SetupAuthServerOptions } from './authServer.js'; -export { createProtectedResourceMetadataRouter, demoTokenVerifier, getAuth, setupAuthServer } from './authServer.js'; +export type { SetupAuthServerOptions } from './authServer'; +export { createProtectedResourceMetadataRouter, demoTokenVerifier, getAuth, setupAuthServer } from './authServer'; // In-memory EventStore for resumability examples (sse-polling, repl) -export { InMemoryEventStore } from './inMemoryEventStore.js'; +export { InMemoryEventStore } from './inMemoryEventStore'; // Minimal client_credentials-only AS (machine-to-machine; no browser) -export type { ClientCredentialsAuthServer, ClientCredentialsAuthServerOptions, RegisteredClient } from './clientCredentialsAuthServer.js'; -export { clientCredentialsTokenVerifier, createClientCredentialsAuthServer } from './clientCredentialsAuthServer.js'; +export type { ClientCredentialsAuthServer, ClientCredentialsAuthServerOptions, RegisteredClient } from './clientCredentialsAuthServer'; +export { clientCredentialsTokenVerifier, createClientCredentialsAuthServer } from './clientCredentialsAuthServer'; diff --git a/examples/shared/test/demoInMemoryOAuthProvider.test.ts b/examples/shared/test/demoInMemoryOAuthProvider.test.ts index bd3131dbad..a7eb35dbfd 100644 --- a/examples/shared/test/demoInMemoryOAuthProvider.test.ts +++ b/examples/shared/test/demoInMemoryOAuthProvider.test.ts @@ -9,8 +9,8 @@ import { describe, expect, it } from 'vitest'; -import type { CreateDemoAuthOptions } from '../src/auth.js'; -import { createDemoAuth } from '../src/auth.js'; +import type { CreateDemoAuthOptions } from '../src/auth'; +import { createDemoAuth } from '../src/auth'; describe('createDemoAuth', () => { const validOptions: CreateDemoAuthOptions = { diff --git a/examples/shared/tsconfig.json b/examples/shared/tsconfig.json index bfc4eab524..ba240dda77 100644 --- a/examples/shared/tsconfig.json +++ b/examples/shared/tsconfig.json @@ -10,11 +10,11 @@ "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], "@modelcontextprotocol/express": ["./node_modules/@modelcontextprotocol/express/src/index.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ], "@modelcontextprotocol/eslint-config": ["./node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], "@modelcontextprotocol/vitest-config": ["./node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"], diff --git a/examples/tsconfig.json b/examples/tsconfig.json index f8f4ab184e..9770b47a55 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -15,11 +15,11 @@ "@modelcontextprotocol/express": ["./node_modules/@modelcontextprotocol/express/src/index.ts"], "@modelcontextprotocol/node": ["./node_modules/@modelcontextprotocol/node/src/index.ts"], "@modelcontextprotocol/hono": ["./node_modules/@modelcontextprotocol/hono/src/index.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ], "@mcp-examples/shared": ["./node_modules/@mcp-examples/shared/src/index.ts"] } diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index bc024d94f3..615fa16bed 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -1,5 +1,104 @@ # @modelcontextprotocol/client +## 2.0.0-alpha.3 + +### Major Changes + +- [#2128](https://github.com/modelcontextprotocol/typescript-sdk/pull/2128) [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6) Thanks [@felixweinberger](https://github.com/felixweinberger)! - SEP-2663: remove + 2025-11 experimental tasks (TaskManager, experimental.tasks.\* accessors). Tasks are now Extensions Track. + +### Minor Changes + +- [#2049](https://github.com/modelcontextprotocol/typescript-sdk/pull/2049) [`4f226c1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/4f226c1e35200616d62f1d7e46a2daa33d91172a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add `SdkHttpError` subclass + with typed `.status` / `.statusText` accessors for HTTP transport failures. `StreamableHTTPClientTransport` now throws `SdkHttpError` (which extends `SdkError`) for non-OK HTTP responses; `SSEClientTransport` throws `SdkHttpError` for 401-after-reauth (circuit breaker). + +- [#1974](https://github.com/modelcontextprotocol/typescript-sdk/pull/1974) [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add custom (non-spec) + method support: a 3-arg `setRequestHandler(method, schemas, handler)` / `setNotificationHandler(method, schemas, handler)` form for vendor-prefixed methods, and a `request(req, resultSchema)` overload (also on `ctx.mcpReq.send`) for typed custom-method results. Spec-method + calls are unchanged. + + Response result-schema validation failure now rejects with `SdkError(InvalidResult)` instead of a raw `ZodError`. Adds `SdkErrorCode.InvalidResult`. + +- [#1653](https://github.com/modelcontextprotocol/typescript-sdk/pull/1653) [`6bec24a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/6bec24a14cb7e3dbe9f5e04aeb893cd0d6e8cb83) Thanks [@rechedev9](https://github.com/rechedev9)! - Add `validateClientMetadataUrl()` + utility for early validation of `clientMetadataUrl` + + Exports a `validateClientMetadataUrl()` function that `OAuthClientProvider` implementations can call in their constructors to fail fast on invalid URL-based client IDs, instead of discovering the error deep in the auth flow. + +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add the v2 + `IdJagTokenExchangeResponse` type to the public API and register its schema as an MCP spec type. `IdJagTokenExchangeResponse` is now exported from `@modelcontextprotocol/client` and `@modelcontextprotocol/server`, `'IdJagTokenExchangeResponse'` joins the `SpecTypeName` union, + and `isSpecType.IdJagTokenExchangeResponse(value)` / `specTypeSchemas.IdJagTokenExchangeResponse` validate it by name — matching how the OAuth/OpenID auth schemas are already exposed. The Zod schema itself, `IdJagTokenExchangeResponseSchema`, is available from + `@modelcontextprotocol/core`. + +- [#2248](https://github.com/modelcontextprotocol/typescript-sdk/pull/2248) [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Restore the 2025-11-25 + task wire types that were removed together with the task feature: the task schemas and inferred types, task members of the request/result/notification unions, the `task` request-params augmentation, the `tasks` capability key, the `isTaskAugmentedRequestParams` guard, and + `RELATED_TASK_META_KEY`. The task feature itself remains removed — servers do not advertise the `tasks` capability and inbound `tasks/*` requests receive `-32601` — but the wire surface stays so SDKs interoperate cleanly with peers on the 2025-11-25 revision. + +- [#1887](https://github.com/modelcontextprotocol/typescript-sdk/pull/1887) [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Export `isSpecType` and + `specTypeSchemas` records for runtime validation of any MCP spec type by name. `isSpecType.ContentBlock(value)` is a type predicate; `specTypeSchemas.ContentBlock` is a `StandardSchemaV1Sync` validator — `validate()` returns the result synchronously. Guards are + standalone functions, so `arr.filter(isSpecType.ContentBlock)` works. Also export the `SpecTypeName`, `SpecTypes`, and `StandardSchemaV1Sync` types. + +- [#1871](https://github.com/modelcontextprotocol/typescript-sdk/pull/1871) [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Move stdio transports + to a `./stdio` subpath export. Import `StdioClientTransport`, `getDefaultEnvironment`, `DEFAULT_INHERITED_ENV_VARS`, and `StdioServerParameters` from `@modelcontextprotocol/client/stdio`, and `StdioServerTransport` from `@modelcontextprotocol/server/stdio`. The + `@modelcontextprotocol/client` root entry no longer pulls in `node:child_process`, `node:stream`, or `cross-spawn`, fixing bundling for browser and Cloudflare Workers targets; the `@modelcontextprotocol/server` root entry drops its `node:stream` reference. Node.js, Bun, and + Deno consumers update the import path; runtime behavior is unchanged. + +### Patch Changes + +- [#1897](https://github.com/modelcontextprotocol/typescript-sdk/pull/1897) [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Stop bundling + `@cfworker/json-schema` into the main package barrel. Previously `CfWorkerJsonSchemaValidator` was re-exported from the core internal barrel, so tsdown inlined the `@cfworker/json-schema` dependency into every consumer's bundle even when it was never used. The named validator + classes are now reachable only via the explicit `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths and the runtime `_shims` conditional, so consumers that import only from the root entry point no longer ship the validator dep. + +- [#2269](https://github.com/modelcontextprotocol/typescript-sdk/pull/2269) [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Non-SEP draft spec conformance + fixes + - `McpServer` now eagerly installs list/read/call handlers for every primitive capability (`tools`, `resources`, `prompts`) declared in `ServerOptions.capabilities`. Per the draft spec, a server that declares a capability MUST respond to its list method (potentially with an + empty result) instead of returning "Method not found". Previously, handlers were only installed lazily on first registration, so a server constructed with e.g. `capabilities: { tools: {} }` and zero registered tools answered `tools/list` with `-32601`. Low-level `Server` + users remain responsible for registering handlers for declared capabilities (documented on `ServerOptions.capabilities`). + - Fixed pagination doc examples on `Client.listTools`/`listPrompts`/`listResources` to loop `while (cursor !== undefined)` instead of `while (cursor)` — per the draft spec, clients MUST NOT treat an empty-string cursor as the end of results. + +- [#1834](https://github.com/modelcontextprotocol/typescript-sdk/pull/1834) [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Export + `InMemoryTransport` for in-process testing. + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- [#1655](https://github.com/modelcontextprotocol/typescript-sdk/pull/1655) [`1eb3123`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1eb31236e707c4f4ab9234d87db21ab3f34bf0bc) Thanks [@nielskaspers](https://github.com/nielskaspers)! - fix(client): append custom + Accept headers to spec-required defaults in StreamableHTTPClientTransport + + Custom Accept headers provided via `requestInit.headers` are now appended to the spec-mandated Accept types instead of being overwritten. This ensures the required media types (`application/json, text/event-stream` for POST; `text/event-stream` for GET SSE) are always present + while allowing users to include additional types for proxy/gateway routing. + +- [#2268](https://github.com/modelcontextprotocol/typescript-sdk/pull/2268) [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Mark the roots, sampling, and + logging runtime APIs as `@deprecated` per SEP-2577 (deprecated as of protocol version 2026-07-28; functional for at least twelve months). Annotates `Server.createMessage`/`listRoots`/`sendLoggingMessage`, `McpServer.sendLoggingMessage`, + `Client.setLoggingLevel`/`sendRootsListChanged`, the `ServerContext.mcpReq.log`/`requestSampling` helpers, and the `roots`/`sampling`/`logging` capability schema fields. JSDoc/docs only — no behavior change. + +- [#2275](https://github.com/modelcontextprotocol/typescript-sdk/pull/2275) [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add a configurable + `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or + `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/client` / `@modelcontextprotocol/server` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`. + +- [#2088](https://github.com/modelcontextprotocol/typescript-sdk/pull/2088) [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Bundle automatic JSON Schema + validator defaults in `@modelcontextprotocol/client` and `@modelcontextprotocol/server` runtime shims. + + Client and server pick the right validator automatically based on the runtime: the Node shim uses AJV, the browser/workerd shim uses `@cfworker/json-schema`. Both backends are bundled into the shim chunks that select them, so the default code path needs no extra installs — + `import { McpServer } from '@modelcontextprotocol/server'` does not pull `ajv` or `@cfworker/json-schema` into the root entry chunk. + + The named validator classes remain part of the public surface for consumers who want to customize the built-in backend (pre-register schemas by `$id`, register custom AJV formats, switch dialects, change `@cfworker/json-schema` draft). They are exposed through explicit + subpaths so they do not bloat the root index chunk: + - `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/ajv'` + - `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/cf-worker'` + + Importing from one of these subpaths means the corresponding peer dep (`ajv` + `ajv-formats`, or `@cfworker/json-schema`) must be in your `package.json`. The shim keeps its own vendored copy for the default path, so a project can use the subpath in some files and rely on the + default in others. + + The `jsonSchemaValidator` interface remains the public extension point for replacing validation entirely with a custom implementation. + +- [#1976](https://github.com/modelcontextprotocol/typescript-sdk/pull/1976) [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - refactor: subclasses + override `_wrapHandler` hook instead of redeclaring `setRequestHandler`. + +- [#1895](https://github.com/modelcontextprotocol/typescript-sdk/pull/1895) [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Fix runtime crash on + `tools/list` when a tool's `inputSchema` comes from zod 4.0–4.1. The SDK requires `~standard.jsonSchema` (StandardJSONSchemaV1, added in zod 4.2.0); previously a missing `jsonSchema` crashed at `undefined[io]`. `standardSchemaToJsonSchema` now detects zod 4 schemas lacking + `jsonSchema` and falls back to the SDK-bundled `z.toJSONSchema()`, emitting a one-time console warning. zod 3 schemas (which the bundled zod 4 converter cannot introspect) and non-zod schema libraries without `jsonSchema` get a clear error pointing to `fromJsonSchema()`. The + workspace zod catalog is also bumped to `^4.2.0`. + ## 2.0.0-alpha.2 ### Patch Changes @@ -61,7 +160,8 @@ For raw JSON Schema (e.g. TypeBox output), use the new `fromJsonSchema` adapter: ```typescript - import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core'; + import { fromJsonSchema } from '@modelcontextprotocol/server'; + import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv'; server.registerTool( 'greet', @@ -74,7 +174,8 @@ **Breaking changes:** - `experimental.tasks.getTaskResult()` no longer accepts a `resultSchema` parameter. Returns `GetTaskPayloadResult` (a loose `Result`); cast to the expected type at the call site. - - Removed unused exports from `@modelcontextprotocol/core`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` instead. + - Removed unused exports from `@modelcontextprotocol/core-internal`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` + instead. - `completable()` remains Zod-specific (it relies on Zod's `.shape` introspection). - [#1710](https://github.com/modelcontextprotocol/typescript-sdk/pull/1710) [`e563e63`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e563e63bd2b3c2c1d1137406bef3f842c946201e) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add `AuthProvider` for diff --git a/packages/client/eslint.config.mjs b/packages/client/eslint.config.mjs index 4f034f2235..dd9e88588a 100644 --- a/packages/client/eslint.config.mjs +++ b/packages/client/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/core' + 'import/internal-regex': '^@modelcontextprotocol/core-internal' } } ]; diff --git a/packages/client/package.json b/packages/client/package.json index 4362c4fe86..0ecbdaa6be 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/client", - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Model Context Protocol implementation for TypeScript - Client package", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -81,9 +81,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "pnpm run typecheck && pnpm run lint", "test": "vitest run", - "test:watch": "vitest", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "test:watch": "vitest" }, "dependencies": { "cross-spawn": "catalog:runtimeClientOnly", @@ -94,7 +92,7 @@ "zod": "catalog:runtimeShared" }, "devDependencies": { - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", "@modelcontextprotocol/vitest-config": "workspace:^", "@modelcontextprotocol/eslint-config": "workspace:^", @@ -111,7 +109,6 @@ "eslint-config-prettier": "catalog:devTools", "eslint-plugin-n": "catalog:devTools", "prettier": "catalog:devTools", - "tsx": "catalog:devTools", "typescript": "catalog:devTools", "typescript-eslint": "catalog:devTools", "vitest": "catalog:devTools", diff --git a/packages/client/src/client/auth.examples.ts b/packages/client/src/client/auth.examples.ts index 17c04e6a04..fc4c52deaf 100644 --- a/packages/client/src/client/auth.examples.ts +++ b/packages/client/src/client/auth.examples.ts @@ -7,10 +7,10 @@ * @module */ -import type { AuthorizationServerMetadata } from '@modelcontextprotocol/core'; +import type { AuthorizationServerMetadata } from '@modelcontextprotocol/core-internal'; -import type { OAuthClientProvider } from './auth.js'; -import { fetchToken } from './auth.js'; +import type { OAuthClientProvider } from './auth'; +import { fetchToken } from './auth'; /** * Base class providing no-op implementations of required OAuthClientProvider methods. diff --git a/packages/client/src/client/auth.ts b/packages/client/src/client/auth.ts index 68ae5fe8f5..a4d5b14c62 100644 --- a/packages/client/src/client/auth.ts +++ b/packages/client/src/client/auth.ts @@ -11,7 +11,7 @@ import type { OAuthTokens, StoredOAuthClientInformation, StoredOAuthTokens -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { checkResourceAllowed, LATEST_PROTOCOL_VERSION, @@ -24,23 +24,13 @@ import { OAuthTokensSchema, OpenIdProviderDiscoveryMetadataSchema, resourceUrlFromServerUrl -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import pkceChallenge from 'pkce-challenge'; -import { - AuthorizationServerMismatchError, - InsecureTokenEndpointError, - IssuerMismatchError, - RegistrationRejectedError -} from './authErrors.js'; +import { AuthorizationServerMismatchError, InsecureTokenEndpointError, IssuerMismatchError, RegistrationRejectedError } from './authErrors'; // Re-exported for back-compat — the canonical home is ./authErrors.js. -export { - AuthorizationServerMismatchError, - InsecureTokenEndpointError, - IssuerMismatchError, - RegistrationRejectedError -} from './authErrors.js'; +export { AuthorizationServerMismatchError, InsecureTokenEndpointError, IssuerMismatchError, RegistrationRejectedError } from './authErrors'; /** * Function type for adding client authentication to token requests. diff --git a/packages/client/src/client/authErrors.ts b/packages/client/src/client/authErrors.ts index 4ced2d6f0d..896eab6e36 100644 --- a/packages/client/src/client/authErrors.ts +++ b/packages/client/src/client/authErrors.ts @@ -6,7 +6,7 @@ * the failure mode without string-matching messages. */ -import type { OAuthClientMetadata } from '@modelcontextprotocol/core'; +import type { OAuthClientMetadata } from '@modelcontextprotocol/core-internal'; /** * Base class for the OAuth-client-flow error family. Concrete subclasses are diff --git a/packages/client/src/client/authExtensions.examples.ts b/packages/client/src/client/authExtensions.examples.ts index bcb26a3d41..668cdd3504 100644 --- a/packages/client/src/client/authExtensions.examples.ts +++ b/packages/client/src/client/authExtensions.examples.ts @@ -7,8 +7,8 @@ * @module */ -import { ClientCredentialsProvider, createPrivateKeyJwtAuth, PrivateKeyJwtProvider } from './authExtensions.js'; -import { StreamableHTTPClientTransport } from './streamableHttp.js'; +import { ClientCredentialsProvider, createPrivateKeyJwtAuth, PrivateKeyJwtProvider } from './authExtensions'; +import { StreamableHTTPClientTransport } from './streamableHttp'; /** * Example: Creating a private key JWT authentication function. diff --git a/packages/client/src/client/authExtensions.ts b/packages/client/src/client/authExtensions.ts index 74cec964ae..f01ba75698 100644 --- a/packages/client/src/client/authExtensions.ts +++ b/packages/client/src/client/authExtensions.ts @@ -5,10 +5,10 @@ * for common machine-to-machine authentication scenarios. */ -import type { FetchLike, OAuthClientMetadata, StoredOAuthClientInformation, StoredOAuthTokens } from '@modelcontextprotocol/core'; +import type { FetchLike, OAuthClientMetadata, StoredOAuthClientInformation, StoredOAuthTokens } from '@modelcontextprotocol/core-internal'; import type { CryptoKey, JWK } from 'jose'; -import type { AddClientAuthentication, OAuthClientProvider } from './auth.js'; +import type { AddClientAuthentication, OAuthClientProvider } from './auth'; /** * Helper to produce a `private_key_jwt` client authentication function. diff --git a/packages/client/src/client/client.examples.ts b/packages/client/src/client/client.examples.ts index dbc4ce00cf..6813d65a15 100644 --- a/packages/client/src/client/client.examples.ts +++ b/packages/client/src/client/client.examples.ts @@ -7,10 +7,10 @@ * @module */ -import { Client } from './client.js'; -import { SSEClientTransport } from './sse.js'; -import { StdioClientTransport } from './stdio.js'; -import { StreamableHTTPClientTransport } from './streamableHttp.js'; +import { Client } from './client'; +import { SSEClientTransport } from './sse'; +import { StdioClientTransport } from './stdio'; +import { StreamableHTTPClientTransport } from './streamableHttp'; /** * Example: Using listChanged to automatically track tool and prompt updates. diff --git a/packages/client/src/client/client.ts b/packages/client/src/client/client.ts index a77a29b20c..5028e937cd 100644 --- a/packages/client/src/client/client.ts +++ b/packages/client/src/client/client.ts @@ -51,7 +51,7 @@ import type { Transport, UnsubscribeRequest, XMcpHeaderScanResult -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { buildMcpParamHeaders, codecForVersion, @@ -76,12 +76,12 @@ import { SdkErrorCode, SUBSCRIPTION_ID_META_KEY, SUPPORTED_MODERN_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; -import type { CacheMode, CacheScope, ResponseCacheStore } from './responseCache.js'; -import { ClientResponseCache, InMemoryResponseCacheStore, MAX_CACHE_TTL_MS } from './responseCache.js'; -import type { ResolvedVersionNegotiation, VersionNegotiationOptions } from './versionNegotiation.js'; -import { detectProbeEnvironment, detectProbeTransportKind, negotiateEra, resolveVersionNegotiation } from './versionNegotiation.js'; +import type { CacheMode, CacheScope, ResponseCacheStore } from './responseCache'; +import { ClientResponseCache, InMemoryResponseCacheStore, MAX_CACHE_TTL_MS } from './responseCache'; +import type { ResolvedVersionNegotiation, VersionNegotiationOptions } from './versionNegotiation'; +import { detectProbeEnvironment, detectProbeTransportKind, negotiateEra, resolveVersionNegotiation } from './versionNegotiation'; /** * Elicitation default application helper. Applies defaults to the `data` based on the `schema`. diff --git a/packages/client/src/client/crossAppAccess.ts b/packages/client/src/client/crossAppAccess.ts index 87dadb9234..a7703dbf15 100644 --- a/packages/client/src/client/crossAppAccess.ts +++ b/packages/client/src/client/crossAppAccess.ts @@ -8,11 +8,11 @@ * @module */ -import type { FetchLike } from '@modelcontextprotocol/core'; -import { IdJagTokenExchangeResponseSchema, OAuthErrorResponseSchema, OAuthTokensSchema } from '@modelcontextprotocol/core'; +import type { FetchLike } from '@modelcontextprotocol/core-internal'; +import { IdJagTokenExchangeResponseSchema, OAuthErrorResponseSchema, OAuthTokensSchema } from '@modelcontextprotocol/core-internal'; -import type { ClientAuthMethod } from './auth.js'; -import { applyClientAuthentication, assertSecureTokenEndpoint, discoverAuthorizationServerMetadata } from './auth.js'; +import type { ClientAuthMethod } from './auth'; +import { applyClientAuthentication, assertSecureTokenEndpoint, discoverAuthorizationServerMetadata } from './auth'; /** * Options for requesting a JWT Authorization Grant via RFC 8693 Token Exchange. diff --git a/packages/client/src/client/middleware.examples.ts b/packages/client/src/client/middleware.examples.ts index 9ccea3abc3..1782ac8502 100644 --- a/packages/client/src/client/middleware.examples.ts +++ b/packages/client/src/client/middleware.examples.ts @@ -7,8 +7,8 @@ * @module */ -import type { Middleware } from './middleware.js'; -import { applyMiddlewares, createMiddleware } from './middleware.js'; +import type { Middleware } from './middleware'; +import { applyMiddlewares, createMiddleware } from './middleware'; // Stubs for hypothetical application middleware declare function withOAuth(provider: unknown, url: string): Middleware; diff --git a/packages/client/src/client/middleware.ts b/packages/client/src/client/middleware.ts index 7494144410..c86db72d2c 100644 --- a/packages/client/src/client/middleware.ts +++ b/packages/client/src/client/middleware.ts @@ -1,7 +1,7 @@ -import type { FetchLike } from '@modelcontextprotocol/core'; +import type { FetchLike } from '@modelcontextprotocol/core-internal'; -import type { OAuthClientProvider } from './auth.js'; -import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth.js'; +import type { OAuthClientProvider } from './auth'; +import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth'; /** * Middleware function that wraps and enhances fetch functionality. diff --git a/packages/client/src/client/probeClassifier.ts b/packages/client/src/client/probeClassifier.ts index 0eef6cfa63..37c2f65701 100644 --- a/packages/client/src/client/probeClassifier.ts +++ b/packages/client/src/client/probeClassifier.ts @@ -10,7 +10,7 @@ * negotiation phase only — an established modern connection is never silently * demoted to `initialize` by a later failure. */ -import type { DiscoverResult } from '@modelcontextprotocol/core'; +import type { DiscoverResult } from '@modelcontextprotocol/core-internal'; import { codecForVersion, MODERN_WIRE_REVISION, @@ -18,7 +18,7 @@ import { SdkError, SdkErrorCode, UnsupportedProtocolVersionError -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; /** * The runtime environment the probe executed in. Only consulted for the diff --git a/packages/client/src/client/responseCache.ts b/packages/client/src/client/responseCache.ts index 0fbf451cc2..171d4cfbc7 100644 --- a/packages/client/src/client/responseCache.ts +++ b/packages/client/src/client/responseCache.ts @@ -1,4 +1,4 @@ -import type { ListToolsResult, Tool } from '@modelcontextprotocol/core'; +import type { ListToolsResult, Tool } from '@modelcontextprotocol/core-internal'; /** * Client-side response cache for SEP-2549 (`CacheableResult`) freshness hints. diff --git a/packages/client/src/client/sse.ts b/packages/client/src/client/sse.ts index af7a1276ba..b983fcbcb3 100644 --- a/packages/client/src/client/sse.ts +++ b/packages/client/src/client/sse.ts @@ -1,4 +1,4 @@ -import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; +import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; import { createFetchWithInit, JSONRPCMessageSchema, @@ -6,11 +6,11 @@ import { SdkError, SdkErrorCode, SdkHttpError -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import type { ErrorEvent, EventSourceInit } from 'eventsource'; import { EventSource } from 'eventsource'; -import type { AuthProvider, OAuthClientProvider } from './auth.js'; +import type { AuthProvider, OAuthClientProvider } from './auth'; import { adaptOAuthProvider, auth, @@ -18,9 +18,9 @@ import { isOAuthClientProvider, resolveAuthorizationCallbackParams, UnauthorizedError -} from './auth.js'; +} from './auth'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -- referenced in JSDoc {@linkcode} -import type { IssuerMismatchError } from './authErrors.js'; +import type { IssuerMismatchError } from './authErrors'; export class SseError extends Error { constructor( diff --git a/packages/client/src/client/stdio.ts b/packages/client/src/client/stdio.ts index 37c6d9a252..29b0027eae 100644 --- a/packages/client/src/client/stdio.ts +++ b/packages/client/src/client/stdio.ts @@ -3,8 +3,8 @@ import process from 'node:process'; import type { Stream } from 'node:stream'; import { PassThrough } from 'node:stream'; -import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; -import { ReadBuffer, SdkError, SdkErrorCode, serializeMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; +import { ReadBuffer, SdkError, SdkErrorCode, serializeMessage } from '@modelcontextprotocol/core-internal'; import spawn from 'cross-spawn'; export type StdioServerParameters = { diff --git a/packages/client/src/client/streamableHttp.examples.ts b/packages/client/src/client/streamableHttp.examples.ts index 5a67ed576f..7383cb752d 100644 --- a/packages/client/src/client/streamableHttp.examples.ts +++ b/packages/client/src/client/streamableHttp.examples.ts @@ -9,7 +9,7 @@ /* eslint-disable unicorn/consistent-function-scoping -- examples must live inside region blocks */ -import type { ReconnectionScheduler } from './streamableHttp.js'; +import type { ReconnectionScheduler } from './streamableHttp'; // Stub for a hypothetical platform-specific background scheduling API declare const platformBackgroundTask: { diff --git a/packages/client/src/client/streamableHttp.ts b/packages/client/src/client/streamableHttp.ts index b3b8da915d..04c7ac6f84 100644 --- a/packages/client/src/client/streamableHttp.ts +++ b/packages/client/src/client/streamableHttp.ts @@ -1,6 +1,6 @@ import type { ReadableWritablePair } from 'node:stream/web'; -import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; +import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; import { createFetchWithInit, encodeMcpParamValue, @@ -15,10 +15,10 @@ import { SdkError, SdkErrorCode, SdkHttpError -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { EventSourceParserStream } from 'eventsource-parser/stream'; -import type { AuthProvider, OAuthClientProvider } from './auth.js'; +import type { AuthProvider, OAuthClientProvider } from './auth'; import { adaptOAuthProvider, auth, @@ -28,10 +28,10 @@ import { isStrictScopeSuperset, resolveAuthorizationCallbackParams, UnauthorizedError -} from './auth.js'; +} from './auth'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -- referenced via {@linkcode} in finishAuth JSDoc -import type { IssuerMismatchError } from './authErrors.js'; -import { InsufficientScopeError } from './authErrors.js'; +import type { IssuerMismatchError } from './authErrors'; +import { InsufficientScopeError } from './authErrors'; /** Default cap on step-up re-authorization retries within a single send/stream-open. */ const DEFAULT_MAX_STEP_UP_RETRIES = 1; diff --git a/packages/client/src/client/versionNegotiation.ts b/packages/client/src/client/versionNegotiation.ts index a791fdc57c..bced563626 100644 --- a/packages/client/src/client/versionNegotiation.ts +++ b/packages/client/src/client/versionNegotiation.ts @@ -11,7 +11,7 @@ * after a modern resolution; while the probe window is open, inbound messages * that are not the probe response are dropped with zero bytes written back. */ -import type { ClientCapabilities, DiscoverResult, Implementation, JSONRPCRequest, Transport } from '@modelcontextprotocol/core'; +import type { ClientCapabilities, DiscoverResult, Implementation, JSONRPCRequest, Transport } from '@modelcontextprotocol/core-internal'; import { codecForVersion, isJSONRPCErrorResponse, @@ -23,10 +23,10 @@ import { SdkErrorCode, SdkHttpError, SUPPORTED_MODERN_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; -import type { ProbeEnvironment, ProbeOutcome, ProbeTransportKind, ProbeVerdict } from './probeClassifier.js'; -import { classifyProbeOutcome } from './probeClassifier.js'; +import type { ProbeEnvironment, ProbeOutcome, ProbeTransportKind, ProbeVerdict } from './probeClassifier'; +import { classifyProbeOutcome } from './probeClassifier'; /** * Probe policy for `'auto'` and pinned negotiation modes. diff --git a/packages/client/src/fromJsonSchema.ts b/packages/client/src/fromJsonSchema.ts index 575db2a8c4..588a096d5f 100644 --- a/packages/client/src/fromJsonSchema.ts +++ b/packages/client/src/fromJsonSchema.ts @@ -1,6 +1,6 @@ import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/client/_shims'; -import type { JsonSchemaType, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core'; -import { fromJsonSchema as coreFromJsonSchema } from '@modelcontextprotocol/core'; +import type { JsonSchemaType, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core-internal'; +import { fromJsonSchema as coreFromJsonSchema } from '@modelcontextprotocol/core-internal'; let _defaultValidator: jsonSchemaValidator | undefined; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 2ed3f062dc..c9088fc499 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -2,7 +2,7 @@ // // This file defines the complete public surface. It consists of: // - Package-specific exports: listed explicitly below (named imports) -// - Protocol-level types: re-exported from @modelcontextprotocol/core/public +// - Protocol-level types: re-exported from @modelcontextprotocol/core-internal/public // // Any new export added here becomes public API. Use named exports, not wildcards. @@ -16,7 +16,7 @@ export type { OAuthClientProvider, OAuthDiscoveryState, OAuthServerInfo -} from './client/auth.js'; +} from './client/auth'; export { assertSecureTokenEndpoint, auth, @@ -43,7 +43,7 @@ export { UnauthorizedError, validateAuthorizationResponseIssuer, validateClientMetadataUrl -} from './client/auth.js'; +} from './client/auth'; export { AuthorizationServerMismatchError, InsecureTokenEndpointError, @@ -51,7 +51,7 @@ export { IssuerMismatchError, OAuthClientFlowError, RegistrationRejectedError -} from './client/authErrors.js'; +} from './client/authErrors'; export type { AssertionCallback, ClientCredentialsProviderOptions, @@ -59,21 +59,21 @@ export type { CrossAppAccessProviderOptions, PrivateKeyJwtProviderOptions, StaticPrivateKeyJwtProviderOptions -} from './client/authExtensions.js'; +} from './client/authExtensions'; export { ClientCredentialsProvider, createPrivateKeyJwtAuth, CrossAppAccessProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider -} from './client/authExtensions.js'; -export type { CacheableRequestOptions, CallToolRequestOptions, ClientOptions, ConnectOptions, McpSubscription } from './client/client.js'; -export { Client } from './client/client.js'; -export { getSupportedElicitationModes } from './client/client.js'; -export type { DiscoverAndRequestJwtAuthGrantOptions, JwtAuthGrantResult, RequestJwtAuthGrantOptions } from './client/crossAppAccess.js'; -export { discoverAndRequestJwtAuthGrant, exchangeJwtAuthGrant, requestJwtAuthorizationGrant } from './client/crossAppAccess.js'; -export type { LoggingOptions, Middleware, RequestLogger } from './client/middleware.js'; -export { applyMiddlewares, createMiddleware, withLogging, withOAuth } from './client/middleware.js'; +} from './client/authExtensions'; +export type { CacheableRequestOptions, CallToolRequestOptions, ClientOptions, ConnectOptions, McpSubscription } from './client/client'; +export { Client } from './client/client'; +export { getSupportedElicitationModes } from './client/client'; +export type { DiscoverAndRequestJwtAuthGrantOptions, JwtAuthGrantResult, RequestJwtAuthGrantOptions } from './client/crossAppAccess'; +export { discoverAndRequestJwtAuthGrant, exchangeJwtAuthGrant, requestJwtAuthorizationGrant } from './client/crossAppAccess'; +export type { LoggingOptions, Middleware, RequestLogger } from './client/middleware'; +export { applyMiddlewares, createMiddleware, withLogging, withOAuth } from './client/middleware'; export type { CacheEntry, CacheKey, @@ -82,11 +82,11 @@ export type { InMemoryResponseCacheStoreOptions, MaybePromise, ResponseCacheStore -} from './client/responseCache.js'; -export { InMemoryResponseCacheStore, MAX_CACHE_TTL_MS } from './client/responseCache.js'; -export type { SSEClientTransportOptions } from './client/sse.js'; -export { SSEClientTransport, SseError } from './client/sse.js'; -export type { VersionNegotiationMode, VersionNegotiationOptions, VersionNegotiationProbeOptions } from './client/versionNegotiation.js'; +} from './client/responseCache'; +export { InMemoryResponseCacheStore, MAX_CACHE_TTL_MS } from './client/responseCache'; +export type { SSEClientTransportOptions } from './client/sse'; +export { SSEClientTransport, SseError } from './client/sse'; +export type { VersionNegotiationMode, VersionNegotiationOptions, VersionNegotiationProbeOptions } from './client/versionNegotiation'; // StdioClientTransport, getDefaultEnvironment, DEFAULT_INHERITED_ENV_VARS, StdioServerParameters are exported from // the './stdio' subpath to keep the root entry free of process-spawning runtime dependencies (child_process, cross-spawn). export type { @@ -94,17 +94,17 @@ export type { StartSSEOptions, StreamableHTTPClientTransportOptions, StreamableHTTPReconnectionOptions -} from './client/streamableHttp.js'; -export { StreamableHTTPClientTransport } from './client/streamableHttp.js'; +} from './client/streamableHttp'; +export { StreamableHTTPClientTransport } from './client/streamableHttp'; // runtime-aware wrapper (shadows core/public's fromJsonSchema with optional validator) -export { fromJsonSchema } from './fromJsonSchema.js'; +export { fromJsonSchema } from './fromJsonSchema'; // Multi-round-trip requests (protocol revision 2026-07-28): the client-side // auto-fulfilment knobs (ClientOptions.inputRequired) and the manual-mode // schema wrapper for callers that opt out of auto-fulfilment per call. -export type { InputRequiredOptions } from '@modelcontextprotocol/core'; -export { withInputRequired } from '@modelcontextprotocol/core'; +export type { InputRequiredOptions } from '@modelcontextprotocol/core-internal'; +export { withInputRequired } from '@modelcontextprotocol/core-internal'; // re-export curated public API from core -export * from '@modelcontextprotocol/core/public'; +export * from '@modelcontextprotocol/core-internal/public'; diff --git a/packages/client/src/shimsBrowser.ts b/packages/client/src/shimsBrowser.ts index de126d53bf..ee5d6373f9 100644 --- a/packages/client/src/shimsBrowser.ts +++ b/packages/client/src/shimsBrowser.ts @@ -3,7 +3,7 @@ * * This file is selected via package.json export conditions when running in a browser. */ -export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; /** * Whether `fetch()` may throw `TypeError` due to CORS. Only true in browser contexts diff --git a/packages/client/src/shimsNode.ts b/packages/client/src/shimsNode.ts index de48ea2de6..5c411d731b 100644 --- a/packages/client/src/shimsNode.ts +++ b/packages/client/src/shimsNode.ts @@ -3,7 +3,7 @@ * * This file is selected via package.json export conditions when running in Node.js. */ -export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv'; +export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/ajv'; /** * Whether `fetch()` may throw `TypeError` due to CORS. CORS is a browser-only concept — diff --git a/packages/client/src/shimsWorkerd.ts b/packages/client/src/shimsWorkerd.ts index 9e6660b9ab..bd680e4358 100644 --- a/packages/client/src/shimsWorkerd.ts +++ b/packages/client/src/shimsWorkerd.ts @@ -3,7 +3,7 @@ * * This file is selected via package.json export conditions when running in workerd. */ -export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; /** * Whether `fetch()` may throw `TypeError` due to CORS. CORS is a browser-only concept — diff --git a/packages/client/src/stdio.ts b/packages/client/src/stdio.ts index a6ecd1697e..f0c7b1af4d 100644 --- a/packages/client/src/stdio.ts +++ b/packages/client/src/stdio.ts @@ -4,5 +4,5 @@ // Cloudflare Workers targets does not pull in `node:child_process`, `node:stream`, or `cross-spawn`. Import // from `@modelcontextprotocol/client/stdio` only in process-spawning runtimes (Node.js, Bun, Deno). -export type { StdioServerParameters } from './client/stdio.js'; -export { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment, StdioClientTransport } from './client/stdio.js'; +export type { StdioServerParameters } from './client/stdio'; +export { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment, StdioClientTransport } from './client/stdio'; diff --git a/packages/client/src/validators/ajv.ts b/packages/client/src/validators/ajv.ts index 770df3f57a..059c6b73f2 100644 --- a/packages/client/src/validators/ajv.ts +++ b/packages/client/src/validators/ajv.ts @@ -11,4 +11,4 @@ * const validator = new AjvJsonSchemaValidator(ajv); * ``` */ -export { addFormats, Ajv, AjvJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv'; +export { addFormats, Ajv, AjvJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/ajv'; diff --git a/packages/client/src/validators/cfWorker.ts b/packages/client/src/validators/cfWorker.ts index 2969b4dc9d..f1d9379afc 100644 --- a/packages/client/src/validators/cfWorker.ts +++ b/packages/client/src/validators/cfWorker.ts @@ -1,3 +1,3 @@ /** Customisation entry point for the `@cfworker/json-schema` validator. */ -export type { CfWorkerSchemaDraft } from '@modelcontextprotocol/core/validators/cfWorker'; -export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +export type { CfWorkerSchemaDraft } from '@modelcontextprotocol/core-internal/validators/cfWorker'; +export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; diff --git a/packages/client/test/client/auth.test.ts b/packages/client/test/client/auth.test.ts index 5a65a76711..62c6faed9a 100644 --- a/packages/client/test/client/auth.test.ts +++ b/packages/client/test/client/auth.test.ts @@ -5,12 +5,12 @@ import type { OAuthTokens, StoredOAuthClientInformation, StoredOAuthTokens -} from '@modelcontextprotocol/core'; -import { LATEST_PROTOCOL_VERSION, OAuthError, OAuthErrorCode } from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; +import { LATEST_PROTOCOL_VERSION, OAuthError, OAuthErrorCode } from '@modelcontextprotocol/core-internal'; import type { Mock } from 'vitest'; import { expect, vi } from 'vitest'; -import type { OAuthClientProvider } from '../../src/client/auth.js'; +import type { OAuthClientProvider } from '../../src/client/auth'; import { assertSecureTokenEndpoint, auth, @@ -39,9 +39,9 @@ import { UnauthorizedError, validateAuthorizationResponseIssuer, validateClientMetadataUrl -} from '../../src/client/auth.js'; -import type { OAuthClientInformationContext, OAuthDiscoveryState } from '../../src/client/auth.js'; -import { ClientCredentialsProvider, createPrivateKeyJwtAuth } from '../../src/client/authExtensions.js'; +} from '../../src/client/auth'; +import type { OAuthClientInformationContext, OAuthDiscoveryState } from '../../src/client/auth'; +import { ClientCredentialsProvider, createPrivateKeyJwtAuth } from '../../src/client/authExtensions'; // Mock pkce-challenge vi.mock('pkce-challenge', () => ({ @@ -155,6 +155,25 @@ describe('OAuth Authorization', () => { expect(extractWWWAuthenticateParams(mockResponse)).toEqual({ error: 'insufficient_scope', scope: 'admin' }); }); + it('parses invalid_token challenges with protected resource metadata', async () => { + const resourceUrl = 'https://resource.example.com/.well-known/oauth-protected-resource/mcp'; + const mockResponse = { + headers: { + get: vi.fn(name => + name === 'WWW-Authenticate' + ? `Bearer resource_metadata="${resourceUrl}", error="invalid_token", error_description="The access token expired"` + : null + ) + } + } as unknown as Response; + + expect(extractWWWAuthenticateParams(mockResponse)).toEqual({ + resourceMetadataUrl: new URL(resourceUrl), + error: 'invalid_token', + errorDescription: 'The access token expired' + }); + }); + it('returns error_description when present', async () => { const mockResponse = { headers: { @@ -3850,7 +3869,7 @@ describe('OAuth Authorization', () => { describe('RequestInit headers passthrough', () => { it('custom headers from RequestInit are passed to auth discovery requests', async () => { - const { createFetchWithInit } = await import('@modelcontextprotocol/core'); + const { createFetchWithInit } = await import('@modelcontextprotocol/core-internal'); const customFetch = vi.fn().mockResolvedValue({ ok: true, @@ -3883,7 +3902,7 @@ describe('OAuth Authorization', () => { }); it('auth-specific headers override base headers from RequestInit', async () => { - const { createFetchWithInit } = await import('@modelcontextprotocol/core'); + const { createFetchWithInit } = await import('@modelcontextprotocol/core-internal'); const customFetch = vi.fn().mockResolvedValue({ ok: true, @@ -3921,7 +3940,7 @@ describe('OAuth Authorization', () => { }); it('other RequestInit options are passed through', async () => { - const { createFetchWithInit } = await import('@modelcontextprotocol/core'); + const { createFetchWithInit } = await import('@modelcontextprotocol/core-internal'); const customFetch = vi.fn().mockResolvedValue({ ok: true, diff --git a/packages/client/test/client/authExtensions.test.ts b/packages/client/test/client/authExtensions.test.ts index 16c3ea33e1..3f55593fc7 100644 --- a/packages/client/test/client/authExtensions.test.ts +++ b/packages/client/test/client/authExtensions.test.ts @@ -1,14 +1,14 @@ import { createMockOAuthFetch } from '@modelcontextprotocol/test-helpers'; import { describe, expect, it, vi } from 'vitest'; -import { auth } from '../../src/client/auth.js'; +import { auth } from '../../src/client/auth'; import { ClientCredentialsProvider, createPrivateKeyJwtAuth, CrossAppAccessProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider -} from '../../src/client/authExtensions.js'; +} from '../../src/client/authExtensions'; const RESOURCE_SERVER_URL = 'https://resource.example.com/'; const AUTH_SERVER_URL = 'https://auth.example.com'; diff --git a/packages/client/test/client/bodyDerivedProbeHeaders.test.ts b/packages/client/test/client/bodyDerivedProbeHeaders.test.ts index de886f61e0..26cfebf656 100644 --- a/packages/client/test/client/bodyDerivedProbeHeaders.test.ts +++ b/packages/client/test/client/bodyDerivedProbeHeaders.test.ts @@ -6,11 +6,11 @@ * itself. The connection-level version slot is never consulted or mutated for * those sends, and envelope-less (2025-era) traffic gets no new headers. */ -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; +import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp'; describe('body-derived probe headers', () => { let transport: StreamableHTTPClientTransport; diff --git a/packages/client/test/client/clientTypeSurface.test.ts b/packages/client/test/client/clientTypeSurface.test.ts index c6246a8fed..aedad0e3ba 100644 --- a/packages/client/test/client/clientTypeSurface.test.ts +++ b/packages/client/test/client/clientTypeSurface.test.ts @@ -6,10 +6,10 @@ * unreachable from its API) and no wire-only members (`resultType` is * consumed at the protocol layer and never reaches consumers). */ -import type { CallToolResult, EmptyResult, ListToolsResult, ReadResourceResult } from '@modelcontextprotocol/core'; +import type { CallToolResult, EmptyResult, ListToolsResult, ReadResourceResult } from '@modelcontextprotocol/core-internal'; import { describe, expectTypeOf, test } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; type KnownKeyOf = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] }; diff --git a/packages/client/test/client/connectPrior.test.ts b/packages/client/test/client/connectPrior.test.ts index 6eaec28985..c2b443e476 100644 --- a/packages/client/test/client/connectPrior.test.ts +++ b/packages/client/test/client/connectPrior.test.ts @@ -6,11 +6,11 @@ * legacy fallback). Populates `getDiscoverResult()` (alongside the * `'auto'`-mode probe path) and round-trips through JSON. */ -import type { DiscoverResult, JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; -import { isJSONRPCRequest, SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import type { DiscoverResult, JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; +import { isJSONRPCRequest, SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { describe, expect, test } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/crossAppAccess.test.ts b/packages/client/test/client/crossAppAccess.test.ts index fa0385d49d..b81d3527c8 100644 --- a/packages/client/test/client/crossAppAccess.test.ts +++ b/packages/client/test/client/crossAppAccess.test.ts @@ -1,8 +1,8 @@ -import type { FetchLike } from '@modelcontextprotocol/core'; +import type { FetchLike } from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; -import { InsecureTokenEndpointError } from '../../src/client/authErrors.js'; -import { discoverAndRequestJwtAuthGrant, exchangeJwtAuthGrant, requestJwtAuthorizationGrant } from '../../src/client/crossAppAccess.js'; +import { InsecureTokenEndpointError } from '../../src/client/authErrors'; +import { discoverAndRequestJwtAuthGrant, exchangeJwtAuthGrant, requestJwtAuthorizationGrant } from '../../src/client/crossAppAccess'; describe('crossAppAccess', () => { describe('requestJwtAuthorizationGrant', () => { diff --git a/packages/client/test/client/crossSpawn.test.ts b/packages/client/test/client/crossSpawn.test.ts index a6d0272a4c..41839565ab 100644 --- a/packages/client/test/client/crossSpawn.test.ts +++ b/packages/client/test/client/crossSpawn.test.ts @@ -1,10 +1,10 @@ import type { ChildProcess } from 'node:child_process'; -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; import spawn from 'cross-spawn'; import type { Mock, MockedFunction } from 'vitest'; -import { getDefaultEnvironment, StdioClientTransport } from '../../src/client/stdio.js'; +import { getDefaultEnvironment, StdioClientTransport } from '../../src/client/stdio'; // mock cross-spawn vi.mock('cross-spawn'); diff --git a/packages/client/test/client/discover.test.ts b/packages/client/test/client/discover.test.ts index 9e971f1cc5..af5c4ab318 100644 --- a/packages/client/test/client/discover.test.ts +++ b/packages/client/test/client/discover.test.ts @@ -5,11 +5,11 @@ * outbound era gate rejects it locally with a typed error before anything * reaches the transport. */ -import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; -import { isJSONRPCRequest, SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; +import { isJSONRPCRequest, SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { describe, expect, test } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/envelopeAutoEmission.test.ts b/packages/client/test/client/envelopeAutoEmission.test.ts index 307baa1a9e..0ab3deecd3 100644 --- a/packages/client/test/client/envelopeAutoEmission.test.ts +++ b/packages/client/test/client/envelopeAutoEmission.test.ts @@ -6,17 +6,17 @@ * notification. User-supplied `_meta` keys win over the auto-attached ones. * Legacy-era connections never gain these keys (D9b byte-identity holds). */ -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, InMemoryTransport, LATEST_PROTOCOL_VERSION, PROTOCOL_VERSION_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/inputRequiredEngine.test.ts b/packages/client/test/client/inputRequiredEngine.test.ts index f688e57e1a..786a95857f 100644 --- a/packages/client/test/client/inputRequiredEngine.test.ts +++ b/packages/client/test/client/inputRequiredEngine.test.ts @@ -5,12 +5,12 @@ * (never wrapped) inputResponses, multi-round flows, the round cap, manual * mode, and the synthesized handler context contract. */ -import type { ElicitResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core'; -import { InMemoryTransport, SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import type { ElicitResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; -import { Client } from '../../src/client/client.js'; -import type { ClientOptions } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; +import type { ClientOptions } from '../../src/client/client'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/jsonSchemaValidatorOverride.test.ts b/packages/client/test/client/jsonSchemaValidatorOverride.test.ts index dc55776eda..ecd3b5d5ca 100644 --- a/packages/client/test/client/jsonSchemaValidatorOverride.test.ts +++ b/packages/client/test/client/jsonSchemaValidatorOverride.test.ts @@ -1,7 +1,7 @@ -import type { JSONRPCMessage, JsonSchemaType, JsonSchemaValidatorResult, jsonSchemaValidator } from '@modelcontextprotocol/core'; -import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; -import { Client } from '../../src/client/client.js'; -import { fromJsonSchema } from '../../src/fromJsonSchema.js'; +import type { JSONRPCMessage, JsonSchemaType, JsonSchemaValidatorResult, jsonSchemaValidator } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; +import { Client } from '../../src/client/client'; +import { fromJsonSchema } from '../../src/fromJsonSchema'; class RecordingValidator implements jsonSchemaValidator { schemas: JsonSchemaType[] = []; diff --git a/packages/client/test/client/legacyHandshakeModernOnlyGuard.test.ts b/packages/client/test/client/legacyHandshakeModernOnlyGuard.test.ts index cf6c34af2b..12fe9e4085 100644 --- a/packages/client/test/client/legacyHandshakeModernOnlyGuard.test.ts +++ b/packages/client/test/client/legacyHandshakeModernOnlyGuard.test.ts @@ -5,11 +5,11 @@ * connect() rejects with the typed negotiation error before anything reaches * the wire — independently of the same guard on the auto-negotiation path. */ -import type { JSONRPCMessage, MessageExtraInfo, Transport } from '@modelcontextprotocol/core'; -import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, MessageExtraInfo, Transport } from '@modelcontextprotocol/core-internal'; +import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { describe, expect, test } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; function recordingTransport(): Transport & { sent: JSONRPCMessage[] } { const sent: JSONRPCMessage[] = []; diff --git a/packages/client/test/client/listen.test.ts b/packages/client/test/client/listen.test.ts index 86e921e960..408fe1ea39 100644 --- a/packages/client/test/client/listen.test.ts +++ b/packages/client/test/client/listen.test.ts @@ -6,7 +6,7 @@ * server-side cancel, and ClientOptions.listChanged auto-open on a modern * connection. */ -import type { JSONRPCMessage, JSONRPCNotification } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCNotification } from '@modelcontextprotocol/core-internal'; import { InMemoryTransport, LATEST_PROTOCOL_VERSION, @@ -14,10 +14,10 @@ import { SdkError, SdkErrorCode, SUBSCRIPTION_ID_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; const MODERN = '2026-07-28'; const flush = () => new Promise(r => setTimeout(r, 10)); diff --git a/packages/client/test/client/mcpParamMirroring.test.ts b/packages/client/test/client/mcpParamMirroring.test.ts index 1d8752d469..8402aad515 100644 --- a/packages/client/test/client/mcpParamMirroring.test.ts +++ b/packages/client/test/client/mcpParamMirroring.test.ts @@ -7,13 +7,18 @@ * byte-untouched); stdio MAY-ignore (no headers on a single-channel * transport); the one-evict-refetch-retry on `HEADER_MISMATCH`. */ -import type { JSONRPCMessage, JSONRPCRequest, Tool, TransportSendOptions } from '@modelcontextprotocol/core'; -import { encodeMcpParamValue, HEADER_MISMATCH_ERROR_CODE, InMemoryTransport, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCRequest, Tool, TransportSendOptions } from '@modelcontextprotocol/core-internal'; +import { + encodeMcpParamValue, + HEADER_MISMATCH_ERROR_CODE, + InMemoryTransport, + PROTOCOL_VERSION_META_KEY +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; -import { Client } from '../../src/client/client.js'; -import { InMemoryResponseCacheStore, type ResponseCacheStore } from '../../src/client/responseCache.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; +import { Client } from '../../src/client/client'; +import { InMemoryResponseCacheStore, type ResponseCacheStore } from '../../src/client/responseCache'; +import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp'; const MODERN = '2026-07-28'; /** Partition the `Client` derives for the scripted server (`serverInfo.name@version`, default `cachePartition`). */ diff --git a/packages/client/test/client/middleware.test.ts b/packages/client/test/client/middleware.test.ts index 64bbfa6735..c0c0886952 100644 --- a/packages/client/test/client/middleware.test.ts +++ b/packages/client/test/client/middleware.test.ts @@ -1,11 +1,11 @@ -import type { FetchLike } from '@modelcontextprotocol/core'; +import type { FetchLike } from '@modelcontextprotocol/core-internal'; import type { Mocked, MockedFunction, MockInstance } from 'vitest'; -import type { OAuthClientProvider } from '../../src/client/auth.js'; -import { applyMiddlewares, createMiddleware, withLogging, withOAuth } from '../../src/client/middleware.js'; +import type { OAuthClientProvider } from '../../src/client/auth'; +import { applyMiddlewares, createMiddleware, withLogging, withOAuth } from '../../src/client/middleware'; -vi.mock('../../src/client/auth.js', async () => { - const actual = await vi.importActual('../../src/client/auth.js'); +vi.mock('../../src/client/auth', async () => { + const actual = await vi.importActual('../../src/client/auth'); return { ...actual, auth: vi.fn(), @@ -13,7 +13,7 @@ vi.mock('../../src/client/auth.js', async () => { }; }); -import { auth, extractWWWAuthenticateParams } from '../../src/client/auth.js'; +import { auth, extractWWWAuthenticateParams } from '../../src/client/auth'; const mockAuth = auth as MockedFunction; const mockExtractWWWAuthenticateParams = extractWWWAuthenticateParams as MockedFunction; diff --git a/packages/client/test/client/modernEraInboundDrop.test.ts b/packages/client/test/client/modernEraInboundDrop.test.ts index fbdc1f0af0..61d433f99d 100644 --- a/packages/client/test/client/modernEraInboundDrop.test.ts +++ b/packages/client/test/client/modernEraInboundDrop.test.ts @@ -6,11 +6,11 @@ * connections keep today's behavior (the client answers, e.g. with −32601 for * methods it has no handler for). */ -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; -import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Client } from '../../src/client/client.js'; +import { Client } from '../../src/client/client'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/probeClassifier.test.ts b/packages/client/test/client/probeClassifier.test.ts index 2991acd3d0..74d0c3248f 100644 --- a/packages/client/test/client/probeClassifier.test.ts +++ b/packages/client/test/client/probeClassifier.test.ts @@ -7,11 +7,11 @@ * end-to-end capture of the same shapes from real server transports lives in * test/integration/test/client/versionNegotiation.test.ts. */ -import { SdkError, SdkErrorCode, UnsupportedProtocolVersionError } from '@modelcontextprotocol/core'; +import { SdkError, SdkErrorCode, UnsupportedProtocolVersionError } from '@modelcontextprotocol/core-internal'; import { describe, expect, test } from 'vitest'; -import type { ProbeClassifierContext, ProbeOutcome, ProbeVerdict } from '../../src/client/probeClassifier.js'; -import { classifyProbeOutcome } from '../../src/client/probeClassifier.js'; +import type { ProbeClassifierContext, ProbeOutcome, ProbeVerdict } from '../../src/client/probeClassifier'; +import { classifyProbeOutcome } from '../../src/client/probeClassifier'; const MODERN = '2026-07-28'; const LEGACY = '2025-11-25'; diff --git a/packages/client/test/client/probeFixtureCorpus.test.ts b/packages/client/test/client/probeFixtureCorpus.test.ts index bb02c76fa9..d823b89c9c 100644 --- a/packages/client/test/client/probeFixtureCorpus.test.ts +++ b/packages/client/test/client/probeFixtureCorpus.test.ts @@ -18,13 +18,13 @@ * negotiation engine suites; this corpus pins classification only, plus the * probe wire shape (string id, `server/discover` first, never a real request). */ -import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; -import { LATEST_PROTOCOL_VERSION, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; +import { LATEST_PROTOCOL_VERSION, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Client } from '../../src/client/client.js'; -import type { ProbeClassifierContext, ProbeOutcome, ProbeVerdict } from '../../src/client/probeClassifier.js'; -import { classifyProbeOutcome } from '../../src/client/probeClassifier.js'; +import { Client } from '../../src/client/client'; +import type { ProbeClassifierContext, ProbeOutcome, ProbeVerdict } from '../../src/client/probeClassifier'; +import { classifyProbeOutcome } from '../../src/client/probeClassifier'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/responseCache.test.ts b/packages/client/test/client/responseCache.test.ts index c10cb521a3..5006f383cd 100644 --- a/packages/client/test/client/responseCache.test.ts +++ b/packages/client/test/client/responseCache.test.ts @@ -7,13 +7,13 @@ * `toolDefinition` hit/miss and re-derivation only on a stamp change; the * generation guard skipping a stale write. */ -import type { JSONRPCMessage, JSONRPCRequest, Tool } from '@modelcontextprotocol/core'; -import { InMemoryTransport, SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCRequest, Tool } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Client } from '../../src/client/client.js'; -import type { CacheEntry, ResponseCacheStore } from '../../src/client/responseCache.js'; -import { ClientResponseCache, InMemoryResponseCacheStore } from '../../src/client/responseCache.js'; +import { Client } from '../../src/client/client'; +import type { CacheEntry, ResponseCacheStore } from '../../src/client/responseCache'; +import { ClientResponseCache, InMemoryResponseCacheStore } from '../../src/client/responseCache'; const MODERN = '2026-07-28'; diff --git a/packages/client/test/client/sse.test.ts b/packages/client/test/client/sse.test.ts index 1be1f03c70..a0d4e7b6f9 100644 --- a/packages/client/test/client/sse.test.ts +++ b/packages/client/test/client/sse.test.ts @@ -2,14 +2,14 @@ import type { IncomingMessage, Server, ServerResponse } from 'node:http'; import { createServer } from 'node:http'; import type { AddressInfo } from 'node:net'; -import type { JSONRPCMessage, OAuthTokens } from '@modelcontextprotocol/core'; -import { OAuthError, OAuthErrorCode, SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, OAuthTokens } from '@modelcontextprotocol/core-internal'; +import { OAuthError, OAuthErrorCode, SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core-internal'; import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers'; import type { Mock, Mocked, MockedFunction, MockInstance } from 'vitest'; -import type { AuthProvider, OAuthClientProvider } from '../../src/client/auth.js'; -import { UnauthorizedError } from '../../src/client/auth.js'; -import { SSEClientTransport } from '../../src/client/sse.js'; +import type { AuthProvider, OAuthClientProvider } from '../../src/client/auth'; +import { UnauthorizedError } from '../../src/client/auth'; +import { SSEClientTransport } from '../../src/client/sse'; /** * Parses HTTP Basic auth from a request's Authorization header. diff --git a/packages/client/test/client/stdio.test.ts b/packages/client/test/client/stdio.test.ts index 3eaa88d71a..594ad6dc63 100644 --- a/packages/client/test/client/stdio.test.ts +++ b/packages/client/test/client/stdio.test.ts @@ -1,7 +1,7 @@ -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; -import type { StdioServerParameters } from '../../src/client/stdio.js'; -import { StdioClientTransport } from '../../src/client/stdio.js'; +import type { StdioServerParameters } from '../../src/client/stdio'; +import { StdioClientTransport } from '../../src/client/stdio'; // Configure default server parameters based on OS // Uses 'more' command for Windows and 'tee' command for Unix/Linux diff --git a/packages/client/test/client/stdioEnvPins.test.ts b/packages/client/test/client/stdioEnvPins.test.ts index 35d6d8747d..7a9f03d3b0 100644 --- a/packages/client/test/client/stdioEnvPins.test.ts +++ b/packages/client/test/client/stdioEnvPins.test.ts @@ -12,7 +12,7 @@ */ import { afterEach, describe, expect, test, vi } from 'vitest'; -import { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment } from '../../src/client/stdio.js'; +import { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment } from '../../src/client/stdio'; // Frozen copy of the documented safelist. The expectation side is a literal, // not derived from src, so any edit to DEFAULT_INHERITED_ENV_VARS goes red diff --git a/packages/client/test/client/streamableHttp.test.ts b/packages/client/test/client/streamableHttp.test.ts index 866ca52be9..a20fb92252 100644 --- a/packages/client/test/client/streamableHttp.test.ts +++ b/packages/client/test/client/streamableHttp.test.ts @@ -1,11 +1,11 @@ -import type { JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core'; -import { OAuthError, OAuthErrorCode, SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; +import { OAuthError, OAuthErrorCode, SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core-internal'; import type { Mock, Mocked } from 'vitest'; -import type { OAuthClientProvider } from '../../src/client/auth.js'; -import { UnauthorizedError } from '../../src/client/auth.js'; -import type { ReconnectionScheduler, StartSSEOptions, StreamableHTTPReconnectionOptions } from '../../src/client/streamableHttp.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; +import type { OAuthClientProvider } from '../../src/client/auth'; +import { UnauthorizedError } from '../../src/client/auth'; +import type { ReconnectionScheduler, StartSSEOptions, StreamableHTTPReconnectionOptions } from '../../src/client/streamableHttp'; +import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp'; describe('StreamableHTTPClientTransport', () => { let transport: StreamableHTTPClientTransport; @@ -793,6 +793,108 @@ describe('StreamableHTTPClientTransport', () => { expect(mockAuthProvider.redirectToAuthorization.mock.calls).toHaveLength(1); }); + it('silently refreshes and retries when a POST returns 401 invalid_token', async () => { + const message: JSONRPCMessage = { + jsonrpc: '2.0', + method: 'tools/call', + params: { + name: 'power-bi-query', + arguments: {} + }, + id: 'tool-use-1' + }; + const resourceMetadataUrl = 'http://localhost:1234/.well-known/oauth-protected-resource/mcp'; + let currentTokens: OAuthTokens = { + access_token: 'expired-access-token', + token_type: 'Bearer', + refresh_token: 'refresh-token' + }; + + mockAuthProvider.tokens.mockImplementation(() => currentTokens); + mockAuthProvider.saveTokens.mockImplementation(tokens => { + currentTokens = tokens; + }); + + const fetchMock = globalThis.fetch as Mock; + fetchMock.mockImplementation(async (url, init) => { + const urlString = url.toString(); + + if (urlString === 'http://localhost:1234/mcp' && init?.method === 'POST') { + const headers = new Headers(init.headers); + const authorization = headers.get('authorization'); + + if (authorization === 'Bearer expired-access-token') { + return new Response('expired', { + status: 401, + statusText: 'Unauthorized', + headers: { + 'WWW-Authenticate': `Bearer resource_metadata="${resourceMetadataUrl}", error="invalid_token", error_description="The access token expired"` + } + }); + } + + if (authorization === 'Bearer new-access-token') { + return new Response(null, { status: 202 }); + } + + return new Response('unexpected bearer', { status: 401, statusText: 'Unauthorized' }); + } + + if (urlString === resourceMetadataUrl) { + return Response.json({ + resource: 'http://localhost:1234/mcp', + authorization_servers: ['http://localhost:1234'] + }); + } + + if (urlString === 'http://localhost:1234/.well-known/oauth-authorization-server') { + return Response.json({ + issuer: 'http://localhost:1234', + authorization_endpoint: 'http://localhost:1234/authorize', + token_endpoint: 'http://localhost:1234/token', + response_types_supported: ['code'], + code_challenge_methods_supported: ['S256'] + }); + } + + if (urlString === 'http://localhost:1234/token' && init?.method === 'POST') { + const params = new URLSearchParams(init.body as string); + expect(params.get('grant_type')).toBe('refresh_token'); + expect(params.get('refresh_token')).toBe('refresh-token'); + + return Response.json({ + access_token: 'new-access-token', + token_type: 'Bearer', + refresh_token: 'new-refresh-token' + }); + } + + return new Response('not found', { status: 404 }); + }); + + await transport.send(message); + + const mcpPostCalls = fetchMock.mock.calls.filter( + ([url, init]) => url.toString() === 'http://localhost:1234/mcp' && init?.method === 'POST' + ); + expect(mcpPostCalls).toHaveLength(2); + const firstPost = mcpPostCalls[0]!; + const secondPost = mcpPostCalls[1]!; + expect(new Headers(firstPost[1]?.headers).get('authorization')).toBe('Bearer expired-access-token'); + expect(new Headers(secondPost[1]?.headers).get('authorization')).toBe('Bearer new-access-token'); + expect(firstPost[1]?.body).toBe(JSON.stringify(message)); + expect(secondPost[1]?.body).toBe(JSON.stringify(message)); + expect(mockAuthProvider.saveTokens).toHaveBeenCalledWith( + expect.objectContaining({ + access_token: 'new-access-token', + token_type: 'Bearer', + refresh_token: 'new-refresh-token' + }), + expect.anything() + ); + expect(mockAuthProvider.redirectToAuthorization).not.toHaveBeenCalled(); + }); + it('attempts upscoping on 403 with WWW-Authenticate header', async () => { const message: JSONRPCMessage = { jsonrpc: '2.0', @@ -822,7 +924,7 @@ describe('StreamableHTTPClientTransport', () => { }); // Spy on the imported auth function and mock successful authorization - const authModule = await import('../../src/client/auth.js'); + const authModule = await import('../../src/client/auth'); const authSpy = vi.spyOn(authModule, 'auth'); authSpy.mockResolvedValue('AUTHORIZED'); @@ -867,8 +969,8 @@ describe('StreamableHTTPClientTransport', () => { }); // Spy on the imported auth function and mock successful authorization - const authModule = await import('../../src/client/auth.js'); - const authSpy = vi.spyOn(authModule as typeof import('../../src/client/auth.js'), 'auth'); + const authModule = await import('../../src/client/auth'); + const authSpy = vi.spyOn(authModule as typeof import('../../src/client/auth'), 'auth'); authSpy.mockResolvedValue('AUTHORIZED'); // First send: one step-up retry (default cap = 1), then fails. @@ -916,7 +1018,7 @@ describe('StreamableHTTPClientTransport', () => { }) .mockResolvedValueOnce({ ok: true, status: 202, headers: new Headers() }); - const authModule = await import('../../src/client/auth.js'); + const authModule = await import('../../src/client/auth'); const authSpy = vi.spyOn(authModule, 'auth'); authSpy.mockResolvedValue('AUTHORIZED'); @@ -948,9 +1050,9 @@ describe('StreamableHTTPClientTransport', () => { text: () => Promise.resolve('Insufficient scope') }); - const authModule = await import('../../src/client/auth.js'); + const authModule = await import('../../src/client/auth'); const authSpy = vi.spyOn(authModule, 'auth'); - const { InsufficientScopeError } = await import('../../src/client/authErrors.js'); + const { InsufficientScopeError } = await import('../../src/client/authErrors'); const sendPromise = transport.send(message); await expect(sendPromise).rejects.toBeInstanceOf(InsufficientScopeError); diff --git a/packages/client/test/client/tokenProvider.test.ts b/packages/client/test/client/tokenProvider.test.ts index 4defbc2bd1..71cf11ab58 100644 --- a/packages/client/test/client/tokenProvider.test.ts +++ b/packages/client/test/client/tokenProvider.test.ts @@ -1,14 +1,14 @@ import type { IncomingMessage, Server } from 'node:http'; import { createServer } from 'node:http'; -import type { JSONRPCMessage, OAuthClientInformation, OAuthClientMetadata, OAuthTokens } from '@modelcontextprotocol/core'; -import { SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, OAuthClientInformation, OAuthClientMetadata, OAuthTokens } from '@modelcontextprotocol/core-internal'; +import { SdkErrorCode, SdkHttpError } from '@modelcontextprotocol/core-internal'; import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers'; import type { Mock } from 'vitest'; -import type { AuthProvider, OAuthClientProvider } from '../../src/client/auth.js'; -import { UnauthorizedError } from '../../src/client/auth.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; +import type { AuthProvider, OAuthClientProvider } from '../../src/client/auth'; +import { UnauthorizedError } from '../../src/client/auth'; +import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp'; describe('StreamableHTTPClientTransport with AuthProvider', () => { let transport: StreamableHTTPClientTransport; diff --git a/packages/client/test/client/versionNegotiation.test.ts b/packages/client/test/client/versionNegotiation.test.ts index b3f9d8df74..7a41347ae1 100644 --- a/packages/client/test/client/versionNegotiation.test.ts +++ b/packages/client/test/client/versionNegotiation.test.ts @@ -8,20 +8,20 @@ * required 400) are exercised against real server transports in * test/integration/test/client/versionNegotiation.test.ts. */ -import type { JSONRPCMessage, JSONRPCRequest, Transport } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCRequest, Transport } from '@modelcontextprotocol/core-internal'; import { isJSONRPCRequest, PROTOCOL_VERSION_META_KEY, SdkError, SdkErrorCode, UnsupportedProtocolVersionError -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, test } from 'vitest'; -import { Client } from '../../src/client/client.js'; -import type { StreamableHTTPClientTransportOptions } from '../../src/client/streamableHttp.js'; -import type { StdioServerParameters } from '../../src/client/stdio.js'; -import { resolveVersionNegotiation } from '../../src/client/versionNegotiation.js'; +import { Client } from '../../src/client/client'; +import type { StreamableHTTPClientTransportOptions } from '../../src/client/streamableHttp'; +import type { StdioServerParameters } from '../../src/client/stdio'; +import { resolveVersionNegotiation } from '../../src/client/versionNegotiation'; const MODERN = '2026-07-28'; diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 5f47efeceb..f351f4cb76 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -5,11 +5,15 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], - "@modelcontextprotocol/core/validators/ajv": ["./node_modules/@modelcontextprotocol/core/src/validators/ajvProvider.ts"], - "@modelcontextprotocol/core/validators/cfWorker": [ - "./node_modules/@modelcontextprotocol/core/src/validators/cfWorkerProvider.ts" + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], + "@modelcontextprotocol/core-internal/validators/ajv": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/ajvProvider.ts" + ], + "@modelcontextprotocol/core-internal/validators/cfWorker": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/cfWorkerProvider.ts" ], "@modelcontextprotocol/test-helpers": ["./node_modules/@modelcontextprotocol/test-helpers/src/index.ts"], "@modelcontextprotocol/client/_shims": ["./src/shimsNode.ts"] diff --git a/packages/client/tsdown.config.ts b/packages/client/tsdown.config.ts index 773e07c920..883fbf6f40 100644 --- a/packages/client/tsdown.config.ts +++ b/packages/client/tsdown.config.ts @@ -24,13 +24,13 @@ export default defineConfig({ compilerOptions: { baseUrl: '.', paths: { - '@modelcontextprotocol/core': ['../core/src/index.ts'], - '@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts'], - '@modelcontextprotocol/core/validators/ajv': ['../core/src/validators/ajvProvider.ts'], - '@modelcontextprotocol/core/validators/cfWorker': ['../core/src/validators/cfWorkerProvider.ts'] + '@modelcontextprotocol/core-internal': ['../core-internal/src/index.ts'], + '@modelcontextprotocol/core-internal/public': ['../core-internal/src/exports/public/index.ts'], + '@modelcontextprotocol/core-internal/validators/ajv': ['../core-internal/src/validators/ajvProvider.ts'], + '@modelcontextprotocol/core-internal/validators/cfWorker': ['../core-internal/src/validators/cfWorkerProvider.ts'] } } }, - noExternal: ['@modelcontextprotocol/core', 'ajv', 'ajv-formats', '@cfworker/json-schema'], + noExternal: ['@modelcontextprotocol/core-internal', 'ajv', 'ajv-formats', '@cfworker/json-schema'], external: ['@modelcontextprotocol/client/_shims'] }); diff --git a/packages/codemod/CHANGELOG.md b/packages/codemod/CHANGELOG.md new file mode 100644 index 0000000000..4fbc0a3f9c --- /dev/null +++ b/packages/codemod/CHANGELOG.md @@ -0,0 +1,33 @@ +# @modelcontextprotocol/codemod + +## 2.0.0-alpha.1 + +### Minor Changes + +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Route v1 + `@modelcontextprotocol/sdk/types.js` schema imports to the new `@modelcontextprotocol/core` package. The `*Schema` Zod constants now migrate as a behavior-preserving import-path swap — `Schema.parse(value)` / `.safeParse(value)` keep working — while spec types, error + classes, enums, and guards continue to resolve to `@modelcontextprotocol/client` / `@modelcontextprotocol/server` by context. A single `import { CallToolResult, CallToolResultSchema } from '.../types.js'` is split accordingly. The v1 OAuth/OpenID `*Schema` constants imported + from `@modelcontextprotocol/sdk/shared/auth.js` are routed to `@modelcontextprotocol/core` the same way (their auth TYPES keep resolving to `client` / `server`). The previous `specSchemaAccess` transform (which rewrote `.parse()` into + `specTypeSchemas.X['~standard'].validate(...)`) is removed. + +- [#2206](https://github.com/modelcontextprotocol/typescript-sdk/pull/2206) [`e03bca9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e03bca90c1f925f80843dc27fb4eb2421408a0c1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Codemod now resolves SSE + server and OAuth auth imports to @modelcontextprotocol/server-legacy sub-paths instead of removing them. An info diagnostic suggests eventual migration to v2 equivalents. + +### Patch Changes + +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Infer client/server project + type from source for v1 projects. A project being migrated still declares the single v1 `@modelcontextprotocol/sdk` dependency, so detecting the project type from `package.json` came back "unknown" and every file importing only shared protocol symbols defaulted to + `@modelcontextprotocol/server` with an action-required warning. The codemod now scans the source for quoted `@modelcontextprotocol/sdk/client/…` and `…/server/…` import specifiers to infer the type (both → "both", one → that side, neither → "unknown"), routing shared symbols to + the installed package and replacing the spurious warnings with at most an info note for genuinely ambiguous "both" projects. + +- [#2137](https://github.com/modelcontextprotocol/typescript-sdk/pull/2137) [`542d5c9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/542d5c95860c03d0c1a689f579b925250e25de6c) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - The v1→v2 codemod now + migrates the removed `StreamableHTTPError` to `SdkHttpError` (instead of the base `SdkError`), matching the shipped error type and the migration guide. Diagnostics now point at the typed `error.status` / `error.statusText` accessors and note that unexpected-content-type + responses are thrown as the base `SdkError`. + +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Map the task + request/notification schemas to their v2 method strings in the handler-registration transform. `setRequestHandler(GetTaskRequestSchema, …)`, `setNotificationHandler(TaskStatusNotificationSchema, …)`, and the other task handlers (`tasks/get`, `tasks/result`, `tasks/list`, + `tasks/cancel`, `notifications/tasks/status`) now rewrite to the v2 two-argument method-string form instead of falling through to the generic "use the 3-argument form" manual-migration diagnostic. + +- [#2252](https://github.com/modelcontextprotocol/typescript-sdk/pull/2252) [`8d55531`](https://github.com/modelcontextprotocol/typescript-sdk/commit/8d55531dabd5aa2de8864d691520cd6c6fe77541) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add per-revision spec + reference types (2025-11-25 and 2026-07-28) with split comparison tests, and the 2026-07-28 wire contract surface: request-meta key constants, `RequestMetaEnvelopeSchema`, `server/discover` shapes, the typed `-32004` error, the `-32003` code constant, and a `resultType` + passthrough on the base result. Types and constants only — no behavior changes. diff --git a/packages/codemod/README.md b/packages/codemod/README.md index d498c07df8..6409f83e4c 100644 --- a/packages/codemod/README.md +++ b/packages/codemod/README.md @@ -29,8 +29,8 @@ The mechanical rename mappings are the source of truth — see Transforms in `src/migrations/v1-to-v2/transforms/` also rewrite `.tool()` → `registerTool` (wrapping `inputSchema` / `outputSchema` / `argsSchema` / `uriSchema` raw shapes with `z.object()`), drop the result-schema argument from `client.request()` -/ `client.callTool()` for spec methods, rewrite spec-`*Schema` -constant accesses (`.safeParse` → `isSpecType` / `specTypeSchemas`), rename +/ `client.callTool()` for spec methods, route spec `*Schema` imports to +`@modelcontextprotocol/core`, rename `StreamableHTTPError` → `SdkHttpError` / `IsomorphicHeaders` → `Headers`, rewrite `SchemaInput` → `StandardSchemaWithJSON.InferInput`, route `ErrorCode.{RequestTimeout,ConnectionClosed}` to `SdkErrorCode`, and rewrite `vi.mock` diff --git a/packages/codemod/batch-test/repos.json b/packages/codemod/batch-test/repos.json index e8d5515800..28dbc4348d 100644 --- a/packages/codemod/batch-test/repos.json +++ b/packages/codemod/batch-test/repos.json @@ -1,40 +1,14 @@ [ { - "repo": "modelcontextprotocol/servers", + "repo": "firebase/firebase-tools", "ref": "main", "packages": [ { - "dir": "src/everything", - "sourceDir": ".", + "dir": ".", + "sourceDir": "src/mcp", "checks": { - "typecheck": "npx tsc --noEmit", - "build": "npm run build", - "test": "npm run test", - "lint": "npm run prettier:check" - } - } - ] - }, - { - "repo": "modelcontextprotocol/inspector", - "ref": "main", - "packages": [ - { - "dir": "client", - "sourceDir": "src", - "checks": { - "typecheck": "npx tsc --noEmit", - "build": "npm run build", - "test": "npm run test", - "lint": "npm run lint" - } - }, - { - "dir": "server", - "sourceDir": "src", - "checks": { - "typecheck": "npx tsc --noEmit", - "build": "npm run build", + "typecheck": "npx tsc -p tsconfig.compile.json", + "build": null, "test": null, "lint": null } diff --git a/packages/codemod/package.json b/packages/codemod/package.json index 264f973ac6..fa4a15ec3e 100644 --- a/packages/codemod/package.json +++ b/packages/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/codemod", - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "description": "Codemod to migrate MCP TypeScript SDK code from v1 to v2", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -35,8 +35,7 @@ "scripts": { "typecheck": "tsgo -p tsconfig.json --noEmit", "generate:versions": "tsx scripts/generateVersions.ts", - "generate:spec-schemas": "tsx scripts/generateSpecSchemaMap.ts", - "prebuild": "pnpm run generate:versions && pnpm run generate:spec-schemas", + "prebuild": "pnpm run generate:versions", "build": "tsdown", "build:watch": "tsdown --watch", "prepack": "pnpm run build", diff --git a/packages/codemod/scripts/generateSpecSchemaMap.ts b/packages/codemod/scripts/generateSpecSchemaMap.ts deleted file mode 100644 index 29796f62ab..0000000000 --- a/packages/codemod/scripts/generateSpecSchemaMap.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { readFileSync, writeFileSync } from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const specTypeSchemaPath = path.resolve(__dirname, '../../core/src/types/specTypeSchema.ts'); - -const source = readFileSync(specTypeSchemaPath, 'utf8'); - -// Extract SPEC_SCHEMA_KEYS array entries -const keysMatch = source.match(/const SPEC_SCHEMA_KEYS = \[([\s\S]*?)\] as const/); -if (!keysMatch) throw new Error('Could not find SPEC_SCHEMA_KEYS in specTypeSchema.ts'); - -const protocolSchemas = [...keysMatch[1]!.matchAll(/'([^']+)'/g)].map(m => m[1]!); - -// Extract auth schema keys -const authMatch = source.match(/const authSchemas = \{([\s\S]*?)\} as const/); -if (!authMatch) throw new Error('Could not find authSchemas in specTypeSchema.ts'); - -const authSchemas = [...authMatch[1]!.matchAll(/(\w+Schema)/g)].map(m => m[1]!); - -const allSchemas = [...protocolSchemas, ...authSchemas].toSorted(); - -const entries = allSchemas.map((s, i) => ` '${s}'${i < allSchemas.length - 1 ? ',' : ''}`).join('\n'); - -const output = `// AUTO-GENERATED — do not edit. Run \`pnpm run generate:spec-schemas\` to regenerate. -export const SPEC_SCHEMA_NAMES: ReadonlySet = new Set([ -${entries} -]); - -export function specSchemaToTypeName(schemaName: string): string | undefined { - if (!SPEC_SCHEMA_NAMES.has(schemaName)) return undefined; - return schemaName.slice(0, -'Schema'.length); -} -`; - -const outPath = path.resolve(__dirname, '../src/generated/specSchemaMap.ts'); -writeFileSync(outPath, output); -console.log(`Wrote ${outPath} (${allSchemas.length} schemas)`); diff --git a/packages/codemod/scripts/generateVersions.ts b/packages/codemod/scripts/generateVersions.ts index 3a77b592bf..f4d827d76d 100644 --- a/packages/codemod/scripts/generateVersions.ts +++ b/packages/codemod/scripts/generateVersions.ts @@ -10,7 +10,8 @@ const PACKAGE_DIRS: Record = { '@modelcontextprotocol/server': 'server', '@modelcontextprotocol/node': 'middleware/node', '@modelcontextprotocol/express': 'middleware/express', - '@modelcontextprotocol/server-legacy': 'server-legacy' + '@modelcontextprotocol/server-legacy': 'server-legacy', + '@modelcontextprotocol/core': 'core' }; const versions: Record = {}; diff --git a/packages/codemod/src/bin/batchTest.ts b/packages/codemod/src/bin/batchTest.ts index 0e45e1715b..f935e90ca5 100644 --- a/packages/codemod/src/bin/batchTest.ts +++ b/packages/codemod/src/bin/batchTest.ts @@ -5,9 +5,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { getMigration } from '../migrations/index.js'; -import { run } from '../runner.js'; -import type { Diagnostic, RunnerResult } from '../types.js'; +import { getMigration } from '../migrations/index'; +import { run } from '../runner'; +import type { Diagnostic, RunnerResult } from '../types'; // --------------------------------------------------------------------------- // Types @@ -85,9 +85,10 @@ const BATCH_DIR = path.resolve(SDK_ROOT, 'packages/codemod/batch-test'); const LOCAL_PACKAGE_DIRS: Record = { '@modelcontextprotocol/client': path.join(SDK_ROOT, 'packages/client'), - '@modelcontextprotocol/core': path.join(SDK_ROOT, 'packages/core'), + '@modelcontextprotocol/core-internal': path.join(SDK_ROOT, 'packages/core-internal'), '@modelcontextprotocol/server': path.join(SDK_ROOT, 'packages/server'), '@modelcontextprotocol/server-legacy': path.join(SDK_ROOT, 'packages/server-legacy'), + '@modelcontextprotocol/core': path.join(SDK_ROOT, 'packages/core'), '@modelcontextprotocol/express': path.join(SDK_ROOT, 'packages/middleware/express'), '@modelcontextprotocol/fastify': path.join(SDK_ROOT, 'packages/middleware/fastify'), '@modelcontextprotocol/hono': path.join(SDK_ROOT, 'packages/middleware/hono'), @@ -110,6 +111,22 @@ function detectPm(repoRoot: string): string { return 'npm'; } +function installCommand(pm: string): string { + if (pm !== 'pnpm') return `${pm} install --ignore-scripts`; + // pnpm walks up to find a workspace; clones live inside this SDK's pnpm workspace, so a plain + // `pnpm install` targets the OUTER workspace and never populates the clone's node_modules — every + // downstream check (tsc base config, tsup, vitest) then fails identically at baseline and post, + // masking real codemod signal. + // --ignore-workspace: treat the clone as a standalone project (not part of the SDK workspace). + // --no-frozen-lockfile: the codemod rewrites package.json to swap v1 → v2 deps, so the lockfile + // must be allowed to change. CI=true (set in shell()) otherwise defaults + // pnpm to a frozen lockfile and the post-codemod reinstall silently skips + // the new v2 deps, leaving the clone on v1. + // npm/yarn/bun key off a `workspaces` field in package.json (absent at this repo root), so they + // need no equivalent flags. + return 'pnpm install --ignore-scripts --ignore-workspace --no-frozen-lockfile'; +} + function detectCheckCmd(pkgDir: string, checkType: string): string | null { const pkgJsonPath = path.join(pkgDir, 'package.json'); if (!existsSync(pkgJsonPath)) return null; @@ -132,7 +149,11 @@ function shell(cmd: string, cwd?: string): { exitCode: number; stdout: string; s cwd, stdio: ['pipe', 'pipe', 'pipe'], maxBuffer: 10 * 1024 * 1024, - timeout: 5 * 60 * 1000 + timeout: 5 * 60 * 1000, + // Commands are spawned without a TTY (piped stdio). Set CI so package managers run fully + // non-interactively — without it, pnpm aborts rebuilding a clone's modules dir with + // ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY when --ignore-workspace changes its link mode. + env: { ...process.env, CI: 'true' } }).toString(); return { exitCode: 0, stdout, stderr: '' }; } catch (error: unknown) { @@ -318,7 +339,7 @@ function main(): void { // Step 3: Install console.log(' Installing dependencies...'); - const installResult = shell(`${pm} install --ignore-scripts`, clonePath); + const installResult = shell(installCommand(pm), clonePath); if (installResult.exitCode !== 0) { console.log(` ERROR: install failed, skipping\n ${installResult.stderr.split('\n')[0]}`); continue; @@ -366,7 +387,7 @@ function main(): void { console.log(` Rewrote ${rewrites} deps to local tarballs`); } console.log(' Re-installing dependencies...'); - shell(`${pm} install --ignore-scripts`, clonePath); + shell(installCommand(pm), clonePath); // Step 7: Post-codemod checks console.log(' Running post-codemod checks...'); diff --git a/packages/codemod/src/cli.ts b/packages/codemod/src/cli.ts index d8599c70a0..8325b352e6 100644 --- a/packages/codemod/src/cli.ts +++ b/packages/codemod/src/cli.ts @@ -6,14 +6,39 @@ import path from 'node:path'; import { Command } from 'commander'; -import { listMigrations } from './migrations/index.js'; -import { run } from './runner.js'; -import { DiagnosticLevel } from './types.js'; -import { CODEMOD_ERROR_PREFIX, formatDiagnostic } from './utils/diagnostics.js'; +import { listMigrations } from './migrations/index'; +import { run } from './runner'; +import { DiagnosticLevel } from './types'; +import { detectFormatter } from './utils/detectFormatter'; +import { CODEMOD_ERROR_PREFIX, formatDiagnostic } from './utils/diagnostics'; const require = createRequire(import.meta.url); const { version } = require('../package.json') as { version: string }; +function quoteArg(arg: string): string { + return /\s/.test(arg) ? `"${arg}"` : arg; +} + +/** + * The codemod transforms the AST but does not reformat — wrapped schemas and + * generated string literals can violate a repo's lint/formatting rules. Point + * the user at their own formatter (which respects their config) for the exact + * files that changed. + */ +function printFormatGuidance(targetDir: string, changedFiles: string[]): void { + if (changedFiles.length === 0) return; + + const formatter = detectFormatter(targetDir); + const fileArgs = changedFiles.map(file => quoteArg(path.relative(process.cwd(), file) || file)); + + console.log("This codemod doesn't reformat its output. Run your formatter on the changed file(s):"); + if (formatter) { + console.log(` ${formatter.bin} ${[...formatter.writeArgs, ...fileArgs].join(' ')}\n`); + } else { + console.log(` e.g. prettier --write ${fileArgs.join(' ')}\n`); + } +} + const program = new Command(); program.name('mcp-codemod').description('Codemod to migrate MCP TypeScript SDK code between versions').version(version); @@ -150,6 +175,8 @@ for (const [name, migration] of listMigrations()) { if (opts['dryRun']) { console.log('Run without --dry-run to apply changes.\n'); } else { + const changedFiles = result.fileResults.filter(fr => fr.changes > 0).map(fr => fr.filePath); + printFormatGuidance(resolvedDir, changedFiles); if (result.packageJsonChanges) { console.log('Run your package manager to install the new packages.\n'); } diff --git a/packages/codemod/src/generated/versions.ts b/packages/codemod/src/generated/versions.ts index 7166154021..4fa12a1a87 100644 --- a/packages/codemod/src/generated/versions.ts +++ b/packages/codemod/src/generated/versions.ts @@ -4,5 +4,6 @@ export const V2_PACKAGE_VERSIONS: Record = { '@modelcontextprotocol/server': '^2.0.0-alpha.2', '@modelcontextprotocol/node': '^2.0.0-alpha.2', '@modelcontextprotocol/express': '^2.0.0-alpha.2', - '@modelcontextprotocol/server-legacy': '^2.0.0-alpha.2' + '@modelcontextprotocol/server-legacy': '^2.0.0-alpha.2', + '@modelcontextprotocol/core': '^2.0.0-alpha.0' }; diff --git a/packages/codemod/src/index.ts b/packages/codemod/src/index.ts index 724cd2697e..4698196c9a 100644 --- a/packages/codemod/src/index.ts +++ b/packages/codemod/src/index.ts @@ -1,5 +1,5 @@ -export { getMigration, listMigrations } from './migrations/index.js'; -export { run } from './runner.js'; +export { getMigration, listMigrations } from './migrations/index'; +export { run } from './runner'; export type { Diagnostic, FileResult, @@ -10,5 +10,5 @@ export type { Transform, TransformContext, TransformResult -} from './types.js'; -export { DiagnosticLevel } from './types.js'; +} from './types'; +export { DiagnosticLevel } from './types'; diff --git a/packages/codemod/src/migrations/index.ts b/packages/codemod/src/migrations/index.ts index 1630393a8f..09d9093453 100644 --- a/packages/codemod/src/migrations/index.ts +++ b/packages/codemod/src/migrations/index.ts @@ -1,5 +1,5 @@ -import type { Migration } from '../types.js'; -import { v1ToV2Migration } from './v1-to-v2/index.js'; +import type { Migration } from '../types'; +import { v1ToV2Migration } from './v1-to-v2/index'; const migrations = new Map([['v1-to-v2', v1ToV2Migration]]); diff --git a/packages/codemod/src/migrations/v1-to-v2/index.ts b/packages/codemod/src/migrations/v1-to-v2/index.ts index 689331a9c3..083aa56123 100644 --- a/packages/codemod/src/migrations/v1-to-v2/index.ts +++ b/packages/codemod/src/migrations/v1-to-v2/index.ts @@ -1,5 +1,5 @@ -import type { Migration } from '../../types.js'; -import { v1ToV2Transforms } from './transforms/index.js'; +import type { Migration } from '../../types'; +import { v1ToV2Transforms } from './transforms/index'; export const v1ToV2Migration: Migration = { name: 'v1-to-v2', diff --git a/packages/codemod/src/migrations/v1-to-v2/mappings/authSchemaNames.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/authSchemaNames.ts new file mode 100644 index 0000000000..89a9083b15 --- /dev/null +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/authSchemaNames.ts @@ -0,0 +1,30 @@ +// The auth (OAuth / OpenID) Zod schema CONSTANTS that v1 exported from +// `@modelcontextprotocol/sdk/shared/auth.js` and that core still re-exports in v2. The import +// transform routes a `*Schema` symbol imported from that v1 path to core when its name is in this +// set (the corresponding TYPES, e.g. OAuthTokens, resolve by context to @modelcontextprotocol/client | +// /server). This is the v1 auth-schema set — a SUBSET of core's auth exports. v2-only auth schemas +// (e.g. IdJagTokenExchangeResponseSchema) are exported by core but NOT listed here: v1 never had +// them, so there is nothing to migrate. test/v1-to-v2/authSchemaNames.test.ts asserts every name here is +// exported by core (so the rewritten import resolves). Keep alphabetized. +export const AUTH_SCHEMA_NAMES: ReadonlySet = new Set([ + 'OAuthClientInformationFullSchema', + 'OAuthClientInformationSchema', + 'OAuthClientMetadataSchema', + 'OAuthClientRegistrationErrorSchema', + 'OAuthErrorResponseSchema', + 'OAuthMetadataSchema', + 'OAuthProtectedResourceMetadataSchema', + 'OAuthTokenRevocationRequestSchema', + 'OAuthTokensSchema', + 'OpenIdProviderDiscoveryMetadataSchema', + 'OpenIdProviderMetadataSchema' +]); + +// v1's `@modelcontextprotocol/sdk/shared/auth.js` also exported these as Zod schema CONSTANTS, but they +// are typeless internal URL field-validators (no public spec type), so v2's core deliberately does +// NOT re-export them (see packages/core/src/index.ts) and no other public v2 package exports them. +// They therefore have no v2 home: routed by context they would produce a codemod-introduced "has no +// exported member" error. importPaths emits an actionRequired diagnostic instead of silently breaking. +// test/v1-to-v2/authSchemaNames.test.ts asserts these are NOT in AUTH_SCHEMA_NAMES (and so are not +// claimed to be core exports). +export const AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT: ReadonlySet = new Set(['SafeUrlSchema', 'OptionalSafeUrlSchema']); diff --git a/packages/codemod/src/migrations/v1-to-v2/mappings/importMap.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/importMap.ts index ffc4a2268f..e861140fd2 100644 --- a/packages/codemod/src/migrations/v1-to-v2/mappings/importMap.ts +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/importMap.ts @@ -4,6 +4,17 @@ export interface ImportMapping { renamedSymbols?: Record; /** Route specific symbols to a different target package than `target`. */ symbolTargetOverrides?: Record; + /** + * Route an imported symbol to this package (instead of `target`) when its rename-resolved name is + * a Zod schema constant re-exported by core — a member of `SPEC_SCHEMA_NAMES` (spec schemas, + * for `sdk/types.js`) or `AUTH_SCHEMA_NAMES` (OAuth/OpenID schemas, for `sdk/shared/auth.js`). The + * schemas now live in `@modelcontextprotocol/core` (so `Schema.parse(...)` keeps + * working), while the corresponding types/constants/guards resolve by context. Matching on + * membership (not a `*Schema` suffix) keeps TYPES whose name ends in `Schema` — e.g. the + * elicitation primitives `BooleanSchema`/`StringSchema`/`EnumSchema` — routed by context, where + * their types live. `symbolTargetOverrides` (exact-name) takes precedence. + */ + schemaSymbolTarget?: string; removalMessage?: string; /** No entries currently set this; scaffolding for when a v1 symbol has no v2 equivalent yet. */ isV2Gap?: boolean; @@ -131,6 +142,7 @@ export const IMPORT_MAP: Record = { '@modelcontextprotocol/sdk/types.js': { target: 'RESOLVE_BY_CONTEXT', status: 'moved', + schemaSymbolTarget: '@modelcontextprotocol/core', renamedSymbols: { ResourceTemplate: 'ResourceTemplateType' } @@ -157,7 +169,12 @@ export const IMPORT_MAP: Record = { }, '@modelcontextprotocol/sdk/shared/auth.js': { target: 'RESOLVE_BY_CONTEXT', - status: 'moved' + status: 'moved', + // OAuth/OpenID Zod schema constants (AUTH_SCHEMA_NAMES) are re-exported by core as a + // separate group, so route them there (keeping `OAuthTokensSchema.parse(...)` working). The + // OAuth/OpenID TYPES (OAuthTokens, etc.) carry no `schemaSymbolTarget` match and resolve by + // context to @modelcontextprotocol/client | /server. + schemaSymbolTarget: '@modelcontextprotocol/core' }, '@modelcontextprotocol/sdk/shared/stdio.js': { target: 'RESOLVE_BY_CONTEXT', @@ -210,3 +227,28 @@ for (const barrelSpecifier of ['@modelcontextprotocol/sdk/validation/index.js', export function isAuthImport(specifier: string): boolean { return specifier.includes('/server/auth/') || specifier.includes('/server/auth.'); } + +// SDK subpath specifiers can be written with or without a JS extension +// (e.g. `@modelcontextprotocol/sdk/types` vs `.../types.js`) depending on the +// consumer's module resolution (`bundler`/`nodenext` allow the extensionless form). +// Normalize the extension so both spellings resolve to the same mapping. Built +// after every IMPORT_MAP entry above is populated; entries whose `.js` and +// extensionless forms coexist (e.g. `experimental/tasks`) share an identical +// mapping, so the collapse is lossless. +function stripJsExtension(specifier: string): string { + return specifier.replace(/\.(?:js|mjs|cjs)$/, ''); +} + +const NORMALIZED_IMPORT_MAP: Record = {}; +for (const [key, mapping] of Object.entries(IMPORT_MAP)) { + NORMALIZED_IMPORT_MAP[stripJsExtension(key)] = mapping; +} + +/** + * Resolves the v2 mapping for a v1 SDK import/export/mock specifier, tolerating + * JS extension variance. An exact match always wins; otherwise the specifier is + * matched ignoring a trailing `.js`/`.mjs`/`.cjs` (or its absence). + */ +export function lookupImportMapping(specifier: string): ImportMapping | undefined { + return IMPORT_MAP[specifier] ?? NORMALIZED_IMPORT_MAP[stripJsExtension(specifier)]; +} diff --git a/packages/codemod/src/migrations/v1-to-v2/mappings/schemaRouting.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/schemaRouting.ts new file mode 100644 index 0000000000..7aead7c17a --- /dev/null +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/schemaRouting.ts @@ -0,0 +1,39 @@ +// Shared per-symbol routing logic for v1→v2 import/export/mock rewrites. Centralized here so the +// import-path transform (static imports/re-exports) and the mock-path transform (vi.mock/jest.mock +// factories, dynamic import() destructurings) route a given symbol to exactly the same v2 package. +import { AUTH_SCHEMA_NAMES } from './authSchemaNames'; +import type { ImportMapping } from './importMap'; +import { SPEC_SCHEMA_NAMES } from './specSchemaNames'; +import { SIMPLE_RENAMES } from './symbolMap'; + +/** The v2 name a symbol resolves to after renames (per-mapping override, then global SIMPLE_RENAMES). */ +export function resolveRenamedName(name: string, mapping: ImportMapping): string { + return mapping.renamedSymbols?.[name] ?? SIMPLE_RENAMES[name] ?? name; +} + +/** + * True when `name` (after renames) is a Zod schema CONSTANT that core re-exports — either a spec + * schema (`SPEC_SCHEMA_NAMES`) or an OAuth/OpenID schema (`AUTH_SCHEMA_NAMES`). Membership (not a + * `*Schema` suffix) is what keeps TYPES whose name ends in `Schema` — e.g. `BooleanSchema` — out. + */ +export function isSharedSchemaConst(name: string, mapping: ImportMapping): boolean { + const resolved = resolveRenamedName(name, mapping); + return SPEC_SCHEMA_NAMES.has(resolved) || AUTH_SCHEMA_NAMES.has(resolved); +} + +/** + * The per-symbol target package for a symbol imported/re-exported/mocked from `mapping`'s module, or + * `undefined` when the symbol should use the mapping's resolved `target`. Exact-name + * `symbolTargetOverrides` win over `schemaSymbolTarget`, which routes a symbol to the shared-schemas + * package only when its rename-resolved name is a schema constant re-exported by core (see + * `isSharedSchemaConst`). + */ +export function symbolTargetOverride(name: string, mapping: ImportMapping): string | undefined { + if (mapping.symbolTargetOverrides && name in mapping.symbolTargetOverrides) { + return mapping.symbolTargetOverrides[name]; + } + if (mapping.schemaSymbolTarget && isSharedSchemaConst(name, mapping)) { + return mapping.schemaSymbolTarget; + } + return undefined; +} diff --git a/packages/codemod/src/migrations/v1-to-v2/mappings/schemaToMethodMap.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/schemaToMethodMap.ts index daa7278c8f..973a6ef37b 100644 --- a/packages/codemod/src/migrations/v1-to-v2/mappings/schemaToMethodMap.ts +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/schemaToMethodMap.ts @@ -29,3 +29,19 @@ export const NOTIFICATION_SCHEMA_TO_METHOD: Record = { RootsListChangedNotificationSchema: 'notifications/roots/list_changed', ElicitationCompleteNotificationSchema: 'notifications/elicitation/complete' }; + +/** + * v1 task-handler schema names. The experimental tasks feature was removed in v2 + * (SEP-2663) and the task method strings are excluded from the typed + * `RequestMethod` / `NotificationMethod` surface, so these are NOT in the rewrite + * maps above — the handler-registration transform emits a dedicated + * action-required diagnostic instead. + */ +export const REMOVED_TASK_SCHEMAS: ReadonlySet = new Set([ + 'GetTaskRequestSchema', + 'GetTaskPayloadRequestSchema', + 'ListTasksRequestSchema', + 'CancelTaskRequestSchema', + 'CreateTaskRequestSchema', + 'TaskStatusNotificationSchema' +]); diff --git a/packages/codemod/src/generated/specSchemaMap.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/specSchemaNames.ts similarity index 88% rename from packages/codemod/src/generated/specSchemaMap.ts rename to packages/codemod/src/migrations/v1-to-v2/mappings/specSchemaNames.ts index 4b130b5e6f..9b714d1125 100644 --- a/packages/codemod/src/generated/specSchemaMap.ts +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/specSchemaNames.ts @@ -1,4 +1,11 @@ -// AUTO-GENERATED — do not edit. Run `pnpm run generate:spec-schemas` to regenerate. +// AUTO-VERIFIED against @modelcontextprotocol/core's public exports by +// test/v1-to-v2/specSchemaNames.test.ts (drift guard). These are the spec Zod schema CONSTANTS that +// core re-exports as standalone values; the v1->v2 import transform routes a `*Schema` symbol +// imported from `@modelcontextprotocol/sdk/types.js` to core ONLY when its (rename-resolved) +// name is in this set. Names that merely END in `Schema` but are NOT here — e.g. the elicitation +// primitive TYPES `BooleanSchema`/`StringSchema`/`EnumSchema` (whose Zod const is `SchemaSchema`) +// — fall through to context resolution (@modelcontextprotocol/client | /server), where their TYPES +// live. Keep alphabetized. export const SPEC_SCHEMA_NAMES: ReadonlySet = new Set([ 'AnnotationsSchema', 'AudioContentSchema', @@ -84,17 +91,6 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet = new Set([ 'MultiSelectEnumSchemaSchema', 'NotificationSchema', 'NumberSchemaSchema', - 'OAuthClientInformationFullSchema', - 'OAuthClientInformationSchema', - 'OAuthClientMetadataSchema', - 'OAuthClientRegistrationErrorSchema', - 'OAuthErrorResponseSchema', - 'OAuthMetadataSchema', - 'OAuthProtectedResourceMetadataSchema', - 'OAuthTokenRevocationRequestSchema', - 'OAuthTokensSchema', - 'OpenIdProviderDiscoveryMetadataSchema', - 'OpenIdProviderMetadataSchema', 'PaginatedRequestParamsSchema', 'PaginatedRequestSchema', 'PaginatedResultSchema', @@ -172,8 +168,3 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet = new Set([ 'UntitledMultiSelectEnumSchemaSchema', 'UntitledSingleSelectEnumSchemaSchema' ]); - -export function specSchemaToTypeName(schemaName: string): string | undefined { - if (!SPEC_SCHEMA_NAMES.has(schemaName)) return undefined; - return schemaName.slice(0, -'Schema'.length); -} diff --git a/packages/codemod/src/migrations/v1-to-v2/mappings/symbolMap.ts b/packages/codemod/src/migrations/v1-to-v2/mappings/symbolMap.ts index 7671a3ee0d..b2670dd097 100644 --- a/packages/codemod/src/migrations/v1-to-v2/mappings/symbolMap.ts +++ b/packages/codemod/src/migrations/v1-to-v2/mappings/symbolMap.ts @@ -4,6 +4,15 @@ export const SIMPLE_RENAMES: Record = { JSONRPCErrorSchema: 'JSONRPCErrorResponseSchema', isJSONRPCError: 'isJSONRPCErrorResponse', isJSONRPCResponse: 'isJSONRPCResultResponse', + // v1's JSONRPCResponse type / JSONRPCResponseSchema constant both validated only *result* + // responses. v2 reuses each name for the result|error form — the type becomes + // `Infer` and the schema the + // matching `z.union([...])` — so a migrated `JSONRPCResponseSchema.parse(...)` (or a typed + // `JSONRPCResponse` value) would silently widen. Rename both to the result-only equivalents to + // preserve v1 behavior — mirroring the isJSONRPCResponse guard rename above. Both the type and the + // schema are public in v2 (re-exported from core via @modelcontextprotocol/client | /server). + JSONRPCResponse: 'JSONRPCResultResponse', + JSONRPCResponseSchema: 'JSONRPCResultResponseSchema', ResourceReference: 'ResourceTemplateReference', ResourceReferenceSchema: 'ResourceTemplateReferenceSchema' }; diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/contextTypes.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/contextTypes.ts index b55efdb877..78ebc2487d 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/contextTypes.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/contextTypes.ts @@ -1,11 +1,11 @@ import type { SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { isKeyPositionIdentifier } from '../../../utils/astUtils.js'; -import { actionRequired, info } from '../../../utils/diagnostics.js'; -import { hasMcpImports } from '../../../utils/importUtils.js'; -import { CONTEXT_PROPERTY_MAP, CTX_PARAM_NAME, EXTRA_PARAM_NAME } from '../mappings/contextPropertyMap.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { isKeyPositionIdentifier } from '../../../utils/astUtils'; +import { actionRequired, info } from '../../../utils/diagnostics'; +import { hasMcpImports } from '../../../utils/importUtils'; +import { CONTEXT_PROPERTY_MAP, CTX_PARAM_NAME, EXTRA_PARAM_NAME } from '../mappings/contextPropertyMap'; const HANDLER_METHODS = new Set(['setRequestHandler', 'setNotificationHandler']); diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/handlerRegistration.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/handlerRegistration.ts index b76e501306..1dd2dcacc6 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/handlerRegistration.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/handlerRegistration.ts @@ -1,10 +1,10 @@ import type { SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { actionRequired } from '../../../utils/diagnostics.js'; -import { hasMcpImports, isImportedFromMcp, removeUnusedImport, resolveOriginalImportName } from '../../../utils/importUtils.js'; -import { NOTIFICATION_SCHEMA_TO_METHOD, SCHEMA_TO_METHOD } from '../mappings/schemaToMethodMap.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { actionRequired } from '../../../utils/diagnostics'; +import { hasMcpImports, isImportedFromMcp, removeUnusedImport, resolveOriginalImportName } from '../../../utils/importUtils'; +import { NOTIFICATION_SCHEMA_TO_METHOD, REMOVED_TASK_SCHEMAS, SCHEMA_TO_METHOD } from '../mappings/schemaToMethodMap'; const ALL_SCHEMA_TO_METHOD: Record = { ...SCHEMA_TO_METHOD, @@ -41,6 +41,21 @@ export const handlerRegistrationTransform: Transform = { const schemaName = firstArg.getText(); const originalName = resolveOriginalImportName(sourceFile, schemaName) ?? schemaName; + + if (REMOVED_TASK_SCHEMAS.has(originalName) && isImportedFromMcp(sourceFile, schemaName)) { + diagnostics.push( + actionRequired( + sourceFile.getFilePath(), + call, + `Task handler registration: ${methodName}(${schemaName}, ...). ` + + `The experimental tasks feature was removed in v2 (SEP-2663); the tasks/* method strings ` + + `are not part of the typed RequestMethod surface. Remove this registration. ` + + `See docs/migration/upgrade-to-v2.md#experimental-tasks-interception-removed.` + ) + ); + continue; + } + const methodString = ALL_SCHEMA_TO_METHOD[originalName]; if (!methodString) { diagnostics.push( diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/importPaths.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/importPaths.ts index 482ae3e57d..89397901f8 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/importPaths.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/importPaths.ts @@ -1,12 +1,16 @@ import type { SourceFile } from 'ts-morph'; - -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { renameAllReferences } from '../../../utils/astUtils.js'; -import { actionRequired, info, v2Gap, warning } from '../../../utils/diagnostics.js'; -import { addOrMergeImport, getSdkExports, getSdkImports, isTypeOnlyImport } from '../../../utils/importUtils.js'; -import { resolveTypesPackage } from '../../../utils/projectAnalyzer.js'; -import { IMPORT_MAP, isAuthImport } from '../mappings/importMap.js'; -import { SIMPLE_RENAMES } from '../mappings/symbolMap.js'; +import { SyntaxKind } from 'ts-morph'; + +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { renameAllReferences } from '../../../utils/astUtils'; +import { actionRequired, info, v2Gap, warning } from '../../../utils/diagnostics'; +import type { NamedImportSpec } from '../../../utils/importUtils'; +import { addOrMergeImport, getSdkExports, getSdkImports, isTypeOnlyImport } from '../../../utils/importUtils'; +import { resolveTypesPackage } from '../../../utils/projectAnalyzer'; +import { AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT } from '../mappings/authSchemaNames'; +import { isAuthImport, lookupImportMapping } from '../mappings/importMap'; +import { isSharedSchemaConst, resolveRenamedName, symbolTargetOverride } from '../mappings/schemaRouting'; +import { SIMPLE_RENAMES } from '../mappings/symbolMap'; const REEXPORT_WARNINGS: Record = { ErrorCode: 'Re-exported ErrorCode was split into ProtocolErrorCode and SdkErrorCode in v2. Update this re-export manually.', @@ -50,17 +54,29 @@ export const importPathsTransform: Transform = { const insertIndex = sourceFile.getImportDeclarations().indexOf(sdkImports[0]!); + // A leading file-header / JSDoc comment attaches to the first SDK import as leading trivia. When + // that import is removed and re-emitted (the per-symbol split/merge path calls imp.remove()), + // ts-morph drops the comment with it. Capture it now and restore it after emitting if it was lost. + // Capture the EXACT source bytes spanning all leading comment ranges (first range's start to last + // range's end) rather than re-joining each range with '\n' — a join drops the original separators + // (a blank line, or CRLF in CRLF files), so the later survival check would never match a header + // that actually survived (in-place setModuleSpecifier rewrite) and would re-insert it, duplicating + // it. The slice reproduces the block verbatim, so the includes() guard below is byte-exact. + const leadingRanges = sdkImports[0]!.getLeadingCommentRanges(); + const leadingCommentText = + leadingRanges.length > 0 ? sourceFile.getFullText().slice(leadingRanges[0]!.getPos(), leadingRanges.at(-1)!.getEnd()) : ''; + interface PendingImport { - names: string[]; + specs: NamedImportSpec[]; isTypeOnly: boolean; } const pendingImports = new Map(); - function addPending(target: string, names: string[], isTypeOnly: boolean): void { + function addPending(target: string, specs: NamedImportSpec[], isTypeOnly: boolean): void { if (!pendingImports.has(target)) { pendingImports.set(target, []); } - pendingImports.get(target)!.push({ names, isTypeOnly }); + pendingImports.get(target)!.push({ specs, isTypeOnly }); } for (const imp of sdkImports) { @@ -71,7 +87,7 @@ export const importPathsTransform: Transform = { const defaultImport = imp.getDefaultImport(); const namespaceImport = imp.getNamespaceImport(); - let mapping = IMPORT_MAP[specifier]; + let mapping = lookupImportMapping(specifier); if (!mapping && isAuthImport(specifier)) { mapping = { @@ -94,15 +110,22 @@ export const importPathsTransform: Transform = { continue; } + // Resolve a RESOLVE_BY_CONTEXT mapping (sdk/types.js, sdk/shared/auth.js) only when a binding + // actually routes to the context package. resolveTypesPackage's diagnostic sink emits a "could + // not determine project type" warning (or, for a 'both' project, an info note), so resolving + // eagerly would emit that note even for an import of nothing but `*Schema` constants — which + // routes entirely to core and never uses the context package. A namespace or default + // binding always needs context; a named symbol needs it only when it has no per-symbol override + // (i.e. it is not a `*Schema` routed to core). let targetPackage = mapping.target; if (targetPackage === 'RESOLVE_BY_CONTEXT') { - targetPackage = resolveTypesPackage(context, hasClientImport, hasServerImport, { - filePath, - line, - diagnostics - }); - if (mapping.subpathSuffix) { - targetPackage = `${targetPackage}${mapping.subpathSuffix}`; + const needsContext = + namespaceImport != null || + defaultImport != null || + namedImports.some(n => symbolTargetOverride(n.getName(), mapping!) === undefined); + if (needsContext) { + const base = resolveTypesPackage(context, hasClientImport, hasServerImport, { filePath, line, diagnostics }); + targetPackage = mapping.subpathSuffix ? `${base}${mapping.subpathSuffix}` : base; } } @@ -116,20 +139,42 @@ export const importPathsTransform: Transform = { } } - const hasAlias = namedImports.some(n => n.getAliasNode() !== undefined); - if (defaultImport || namespaceImport || hasAlias) { - let effectiveTarget = targetPackage; - if (mapping.symbolTargetOverrides && !namespaceImport && !defaultImport) { - const allOverridden = namedImports.length > 0 && namedImports.every(n => n.getName() in mapping.symbolTargetOverrides!); - if (allOverridden) { - effectiveTarget = mapping.symbolTargetOverrides[namedImports[0]!.getName()]!; - } else if (namedImports.some(n => n.getName() in mapping.symbolTargetOverrides!)) { + // A namespace import (`import * as ns from …`) cannot be split per-symbol — usages are + // qualified (`ns.Foo`), so the whole binding moves to one package. Named imports (aliased or + // not), including the named siblings of a default import, DO fall through to the per-symbol + // splitter below — so an all-`*Schema` import routes entirely to core, a single aliased + // specifier no longer forces unrelated symbols into the wrong package, and a mixed + // `import sdk, { CallToolResultSchema }` routes the schema to core while the default + // binding (handled at the end of the per-symbol path) moves to the context package. + if (namespaceImport) { + const effectiveTarget = targetPackage; + // Any `ns.Schema` accesses would silently resolve against the wrong package (the + // namespace can't be split), so flag them. + if (mapping.schemaSymbolTarget) { + const nsName = namespaceImport.getText(); + // Map each accessed v1 name to the v2 name core actually exports — some are + // renamed (e.g. JSONRPCErrorSchema → JSONRPCErrorResponseSchema), and core only + // exports the v2 name. Dedupe by the accessed (v1) name. + const schemaAccesses = [ + ...new Map( + sourceFile + .getDescendantsOfKind(SyntaxKind.PropertyAccessExpression) + .filter(pa => pa.getExpression().getText() === nsName && isSharedSchemaConst(pa.getName(), mapping)) + .map(pa => [pa.getName(), resolveRenamedName(pa.getName(), mapping)] as const) + ) + ]; + if (schemaAccesses.length > 0) { + const accessed = schemaAccesses.map(([v1]) => v1).join(', '); + const importName = schemaAccesses[0]![1]; + const renamed = schemaAccesses.filter(([v1, v2]) => v1 !== v2); + const renameNote = + renamed.length > 0 ? ` Renamed in v2: ${renamed.map(([v1, v2]) => `${v1} → ${v2}`).join(', ')}.` : ''; diagnostics.push( actionRequired( filePath, imp, - `Aliased import from ${specifier} mixes symbols that belong to different v2 packages. ` + - `Split the import manually so each symbol targets the correct package.` + `Namespace import of ${specifier} is used to access Zod schema(s) (${accessed}) that moved to ${mapping.schemaSymbolTarget}.${renameNote} ` + + `Import them with a named import (e.g. \`import { ${importName} } from '${mapping.schemaSymbolTarget}'\`) and update the qualified usages.` ) ); } @@ -137,22 +182,14 @@ export const importPathsTransform: Transform = { usedPackages.add(effectiveTarget); imp.setModuleSpecifier(effectiveTarget); if (mapping.renamedSymbols) { - for (const n of namedImports) { - const newName = mapping.renamedSymbols[n.getName()]; - if (newName) { - n.setName(newName); - } - } - if (namespaceImport) { - diagnostics.push( - actionRequired( - filePath, - imp, - `Namespace import of ${specifier}: exported symbol(s) ${Object.keys(mapping.renamedSymbols).join(', ')} ` + - `were renamed in ${effectiveTarget}. Update qualified accesses manually.` - ) - ); - } + diagnostics.push( + actionRequired( + filePath, + imp, + `Namespace import of ${specifier}: exported symbol(s) ${Object.keys(mapping.renamedSymbols).join(', ')} ` + + `were renamed in ${effectiveTarget}. Update qualified accesses manually.` + ) + ); } changesCount++; if (mapping.migrationHint) { @@ -166,13 +203,40 @@ export const importPathsTransform: Transform = { for (const n of namedImports) { const name = n.getName(); + const alias = n.getAliasNode()?.getText(); const resolvedName = mapping.renamedSymbols?.[name] ?? name; const specifierTypeOnly = typeOnly || n.isTypeOnly(); - const symbolTarget = mapping.symbolTargetOverrides?.[name] ?? targetPackage; + const symbolTarget = symbolTargetOverride(name, mapping) ?? targetPackage; + // A v1 auth-schema constant with no public v2 home (SafeUrlSchema/OptionalSafeUrlSchema) + // routes by context to a package that doesn't export it. Flag it so the user inlines the + // validation instead of hitting a silent "has no exported member" error. + if (mapping.schemaSymbolTarget && AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT.has(name)) { + diagnostics.push( + actionRequired( + filePath, + imp, + `${name} was an internal URL field-validator in v1's ${specifier} with no public v2 equivalent ` + + `(it is not re-exported by @modelcontextprotocol/core). Remove this import and inline the ` + + `validation (e.g. validate the URL with the WHATWG \`URL\` constructor or your own Zod schema).` + ) + ); + } usedPackages.add(symbolTarget); - addPending(symbolTarget, [resolvedName], specifierTypeOnly); + addPending(symbolTarget, [alias ? { name: resolvedName, alias } : resolvedName], specifierTypeOnly); + } + if (defaultImport) { + // The default binding can't be split per-symbol, so move it (and the module specifier) to + // the resolved context/target package. The named siblings were just routed per-symbol + // above, so drop them from this now default-only import. + const effectiveTarget = targetPackage; + usedPackages.add(effectiveTarget); + if (namedImports.length > 0) { + imp.removeNamedImports(); + } + imp.setModuleSpecifier(effectiveTarget); + } else { + imp.remove(); } - imp.remove(); changesCount++; if (mapping.migrationHint) { diagnostics.push(info(filePath, line, mapping.migrationHint)); @@ -182,28 +246,34 @@ export const importPathsTransform: Transform = { } } + const specLocal = (spec: NamedImportSpec): string => (typeof spec === 'string' ? spec : (spec.alias ?? spec.name)); for (const [target, groups] of pendingImports) { - const typeOnlyNames = new Set(); - const valueNames = new Set(); + // Dedupe by local binding name (alias when present), keeping the spec so aliases survive. + const typeOnlySpecs = new Map(); + const valueSpecs = new Map(); for (const group of groups) { - for (const name of group.names) { - if (group.isTypeOnly) { - typeOnlyNames.add(name); - } else { - valueNames.add(name); - } + for (const spec of group.specs) { + (group.isTypeOnly ? typeOnlySpecs : valueSpecs).set(specLocal(spec), spec); } } - if (valueNames.size > 0) { - addOrMergeImport(sourceFile, target, [...valueNames], false, insertIndex); + if (valueSpecs.size > 0) { + addOrMergeImport(sourceFile, target, [...valueSpecs.values()], false, insertIndex); } - if (typeOnlyNames.size > 0) { - const typeInsertIndex = valueNames.size > 0 ? insertIndex + 1 : insertIndex; - addOrMergeImport(sourceFile, target, [...typeOnlyNames], true, typeInsertIndex); + if (typeOnlySpecs.size > 0) { + const typeInsertIndex = valueSpecs.size > 0 ? insertIndex + 1 : insertIndex; + addOrMergeImport(sourceFile, target, [...typeOnlySpecs.values()], true, typeInsertIndex); } } + // Restore the captured leading comment if the rewrite dropped it (guard against duplication when + // the first import was rewritten in place and kept its comment). + if (leadingCommentText && !sourceFile.getFullText().includes(leadingCommentText)) { + const imports = sourceFile.getImportDeclarations(); + const anchor = imports[Math.min(insertIndex, imports.length - 1)]; + sourceFile.insertText(anchor ? anchor.getStart() : 0, `${leadingCommentText}\n`); + } + return { changesCount, diagnostics, usedPackages }; } }; @@ -223,7 +293,7 @@ function rewriteExportDeclarations( if (!specifier) continue; const line = exp.getStartLineNumber(); - let mapping = IMPORT_MAP[specifier]; + let mapping = lookupImportMapping(specifier); if (!mapping && isAuthImport(specifier)) { mapping = { @@ -262,12 +332,30 @@ function rewriteExportDeclarations( } } - if (mapping.symbolTargetOverrides) { + if (mapping.symbolTargetOverrides || mapping.schemaSymbolTarget) { const namedExports = exp.getNamedExports(); - const allOverridden = namedExports.length > 0 && namedExports.every(s => s.getName() in mapping.symbolTargetOverrides!); - if (allOverridden) { - targetPackage = mapping.symbolTargetOverrides[namedExports[0]!.getName()]!; - } else if (namedExports.some(s => s.getName() in mapping.symbolTargetOverrides!)) { + // A star re-export (`export * from …`, including `export * as ns from …`) has no named + // exports to route per-symbol, so it moves wholesale to the context package — which exports + // none of the Zod `*Schema` constants the v1 module re-exported. Downstream consumers of this + // barrel would hit "has no exported member" with no pointer to where the schemas went, so flag + // it (mirroring the namespace-import diagnostic on the import side). + if (mapping.schemaSymbolTarget && namedExports.length === 0) { + diagnostics.push( + actionRequired( + filePath, + exp, + `Star re-export of ${specifier} will not include the Zod schema constants that moved to ` + + `${mapping.schemaSymbolTarget} (they are no longer exported by ${targetPackage}). ` + + `Add an explicit \`export { … } from '${mapping.schemaSymbolTarget}'\` for any re-exported \`*Schema\` constants.` + ) + ); + } + const overrides = namedExports.map(s => symbolTargetOverride(s.getName(), mapping)); + const uniqueOverrides = new Set(overrides.filter((t): t is string => t !== undefined)); + const allOverridden = namedExports.length > 0 && overrides.every(t => t !== undefined); + if (allOverridden && uniqueOverrides.size === 1) { + targetPackage = [...uniqueOverrides][0]!; + } else if (uniqueOverrides.size > 0) { diagnostics.push( actionRequired( filePath, diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/index.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/index.ts index fe00099514..18121109bf 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/index.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/index.ts @@ -1,13 +1,12 @@ -import type { Transform } from '../../../types.js'; -import { contextTypesTransform } from './contextTypes.js'; -import { handlerRegistrationTransform } from './handlerRegistration.js'; -import { importPathsTransform } from './importPaths.js'; -import { mcpServerApiTransform } from './mcpServerApi.js'; -import { mockPathsTransform } from './mockPaths.js'; -import { removedApisTransform } from './removedApis.js'; -import { schemaParamRemovalTransform } from './schemaParamRemoval.js'; -import { specSchemaAccessTransform } from './specSchemaAccess.js'; -import { symbolRenamesTransform } from './symbolRenames.js'; +import type { Transform } from '../../../types'; +import { contextTypesTransform } from './contextTypes'; +import { handlerRegistrationTransform } from './handlerRegistration'; +import { importPathsTransform } from './importPaths'; +import { mcpServerApiTransform } from './mcpServerApi'; +import { mockPathsTransform } from './mockPaths'; +import { removedApisTransform } from './removedApis'; +import { schemaParamRemovalTransform } from './schemaParamRemoval'; +import { symbolRenamesTransform } from './symbolRenames'; // Ordering matters — do not reorder without understanding dependencies: // @@ -30,11 +29,7 @@ import { symbolRenamesTransform } from './symbolRenames.js'; // 5. handlerRegistration and schemaParamRemoval are independent of each // other but both depend on importPaths having run. // -// 6. specSchemaAccess runs after handlerRegistration and schemaParamRemoval: -// those transforms remove spec schema references they handle. specSchemaAccess -// then processes remaining standalone usages (safeParse, parse, z.infer, etc.). -// -// 7. mockPaths runs last: handles test mocks and dynamic imports, +// 6. mockPaths runs last: handles test mocks and dynamic imports, // independent of the other transforms. export const v1ToV2Transforms: Transform[] = [ importPathsTransform, @@ -43,7 +38,6 @@ export const v1ToV2Transforms: Transform[] = [ mcpServerApiTransform, handlerRegistrationTransform, schemaParamRemovalTransform, - specSchemaAccessTransform, contextTypesTransform, mockPathsTransform ]; diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/mcpServerApi.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/mcpServerApi.ts index 631c995884..7db21088e1 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/mcpServerApi.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/mcpServerApi.ts @@ -1,9 +1,9 @@ import type { CallExpression, SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { actionRequired, info } from '../../../utils/diagnostics.js'; -import { isOriginalNameImportedFromMcp, resolveLocalImportName } from '../../../utils/importUtils.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { actionRequired, info } from '../../../utils/diagnostics'; +import { isOriginalNameImportedFromMcp, resolveLocalImportName } from '../../../utils/importUtils'; export const mcpServerApiTransform: Transform = { name: 'McpServer API migration', diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/mockPaths.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/mockPaths.ts index 65ce7a4d6b..7ffdd53887 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/mockPaths.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/mockPaths.ts @@ -1,12 +1,32 @@ import type { SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { actionRequired, v2Gap, warning } from '../../../utils/diagnostics.js'; -import { isSdkSpecifier } from '../../../utils/importUtils.js'; -import { resolveTypesPackage } from '../../../utils/projectAnalyzer.js'; -import { IMPORT_MAP, isAuthImport } from '../mappings/importMap.js'; -import { SIMPLE_RENAMES } from '../mappings/symbolMap.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { actionRequired, v2Gap, warning } from '../../../utils/diagnostics'; +import { isSdkSpecifier } from '../../../utils/importUtils'; +import { resolveTypesPackage } from '../../../utils/projectAnalyzer'; +import type { ImportMapping } from '../mappings/importMap'; +import { isAuthImport, lookupImportMapping } from '../mappings/importMap'; +import { isSharedSchemaConst, resolveRenamedName, symbolTargetOverride } from '../mappings/schemaRouting'; +import { SIMPLE_RENAMES } from '../mappings/symbolMap'; + +/** + * Resolve the single per-symbol target package shared by every `symbol` (mocked factory keys or + * destructured `import()` bindings), or report that they mix v2 packages. A mock/dynamic-import + * specifier is a single string and cannot be split, so a mix can only be flagged, not rewritten. + * Returns `target: undefined` when no symbol carries a per-symbol override (the caller keeps the + * mapping's resolved context/`target` package). Mirrors `symbolTargetOverride` routing used by the + * static import/export transform so e.g. a factory of only `*Schema` constants routes to core. + */ +function routeSymbols(symbols: string[], mapping: ImportMapping): { target?: string; mixed: boolean } { + if (symbols.length === 0) return { mixed: false }; + const targets = symbols.map(s => symbolTargetOverride(s, mapping)); + const overridden = targets.filter((t): t is string => t !== undefined); + const unique = new Set(overridden); + if (overridden.length === symbols.length && unique.size === 1) return { target: [...unique][0]!, mixed: false }; + if (unique.size > 0) return { mixed: true }; + return { mixed: false }; +} const MOCK_METHODS = new Set([ 'mock', @@ -53,13 +73,14 @@ function resolveTarget( specifier: string, context: TransformContext, sourceFile: SourceFile, + symbols: string[], diagnosticSink?: { filePath: string; line: number; diagnostics: Diagnostic[] } -): - | { target: string; renamedSymbols?: Record; symbolTargetOverrides?: Record } - | { removed: true; isV2Gap?: boolean; removalMessage?: string } - | null { - const mapping = IMPORT_MAP[specifier]; - if (!mapping && isAuthImport(specifier)) return { target: '@modelcontextprotocol/server-legacy/auth' }; +): { target: string; mapping: ImportMapping } | { removed: true; isV2Gap?: boolean; removalMessage?: string } | null { + const mapping = lookupImportMapping(specifier); + if (!mapping && isAuthImport(specifier)) { + const authMapping: ImportMapping = { target: '@modelcontextprotocol/server-legacy/auth', status: 'moved' }; + return { target: authMapping.target, mapping: authMapping }; + } if (!mapping) return null; if (mapping.status === 'removed') return { removed: true, isV2Gap: mapping.isV2Gap, removalMessage: mapping.removalMessage }; @@ -73,13 +94,24 @@ function resolveTarget( const s = i.getModuleSpecifierValue(); return s.includes('/server/') || s === '@modelcontextprotocol/server'; }); - target = resolveTypesPackage(context, hasClient, hasServer, diagnosticSink); + // Resolve lazily: only pass the diagnostic sink to resolveTypesPackage when the routed target + // actually falls back to the context package. A factory/destructuring whose symbols all route + // elsewhere (e.g. only `*Schema` constants → core) never uses the context package, so emitting a + // "could not determine project type" warning (or a 'both'-project info note) for it would be + // spurious. Mirrors the lazy `needsContext` guard in the static import transform. A + // non-destructured/non-routable binding has no symbols, so `routeSymbols` returns no target and + // context is (correctly) treated as needed. + const needsContext = routeSymbols(symbols, mapping).target === undefined; + target = resolveTypesPackage(context, hasClient, hasServer, needsContext ? diagnosticSink : undefined); if (mapping.subpathSuffix) { target = `${target}${mapping.subpathSuffix}`; } } - return { target, renamedSymbols: mapping.renamedSymbols, symbolTargetOverrides: mapping.symbolTargetOverrides }; + // Return the original mapping (not just `renamedSymbols`/`symbolTargetOverrides`) so per-symbol + // routing can consult `schemaSymbolTarget` via the shared `symbolTargetOverride`/`routeSymbols`, + // matching how the static import transform routes `*Schema` constants to core. + return { target, mapping }; } function rewriteMockCall( @@ -98,7 +130,8 @@ function rewriteMockCall( const specifier = firstArg.getLiteralValue(); if (!isSdkSpecifier(specifier)) return 0; - const resolved = resolveTarget(specifier, context, sourceFile, { + const factorySymbols = args.length >= 2 ? collectFactorySymbols(args[1]!) : []; + const resolved = resolveTarget(specifier, context, sourceFile, factorySymbols, { filePath: sourceFile.getFilePath(), line: call.getStartLineNumber(), diagnostics @@ -122,13 +155,15 @@ function rewriteMockCall( let changes = 0; let effectiveTarget = resolved.target; - if (resolved.symbolTargetOverrides && args.length >= 2) { - const factorySymbols = collectFactorySymbols(args[1]!); - const allOverridden = factorySymbols.length > 0 && factorySymbols.every(s => s in resolved.symbolTargetOverrides!); - const someOverridden = factorySymbols.some(s => s in resolved.symbolTargetOverrides!); - if (allOverridden) { - effectiveTarget = resolved.symbolTargetOverrides[factorySymbols[0]!]!; - } else if (someOverridden) { + if (args.length >= 2) { + // Route the factory's mocked symbols the same way the static import transform would: a factory of + // only `*Schema` constants (from sdk/types.js or sdk/shared/auth.js) moves to core; a factory + // of only `StreamableHTTPServerTransport` moves to @modelcontextprotocol/node. A single mock path + // can't be split, so a mix of packages is flagged for manual migration. + const { target: routedTarget, mixed } = routeSymbols(factorySymbols, resolved.mapping); + if (routedTarget) { + effectiveTarget = routedTarget; + } else if (mixed) { diagnostics.push( actionRequired( sourceFile.getFilePath(), @@ -144,7 +179,7 @@ function rewriteMockCall( firstArg.setLiteralValue(effectiveTarget); changes++; - const allRenames: Record = { ...SIMPLE_RENAMES, ...resolved.renamedSymbols }; + const allRenames: Record = { ...SIMPLE_RENAMES, ...resolved.mapping.renamedSymbols }; if (args.length >= 2) { changes += renameSymbolsInFactory(args[1]!, allRenames); } @@ -216,6 +251,106 @@ function renameSymbolsInFactory(factoryArg: import('ts-morph').Node, renamedSymb return changes; } +/** + * The object binding pattern through which a dynamic import's named symbols are pulled — either + * `const { … } = await import('…')` or `import('…').then(({ … }) => …)`. Returns undefined for a + * non-destructured binding (`const mod = await import()`), an identifier `.then` param (`m => …`), or + * an unassigned `await import()`. Both destructured shapes expose named symbols that can be routed and + * renamed per-symbol (the specifier itself can't be split). + */ +function getModuleBindingPattern(node: import('ts-morph').CallExpression): import('ts-morph').ObjectBindingPattern | undefined { + const parent = node.getParent(); + if (parent && Node.isAwaitExpression(parent)) { + const grandParent = parent.getParent(); + if (grandParent && Node.isVariableDeclaration(grandParent)) { + const nameNode = grandParent.getNameNode(); + if (Node.isObjectBindingPattern(nameNode)) return nameNode; + } + return undefined; + } + if (parent && Node.isPropertyAccessExpression(parent) && parent.getName() === 'then') { + const thenCall = parent.getParent(); + if (thenCall && Node.isCallExpression(thenCall)) { + const cb = thenCall.getArguments()[0]; + if (cb && (Node.isArrowFunction(cb) || Node.isFunctionExpression(cb))) { + const paramName = cb.getParameters()[0]?.getNameNode(); + if (paramName && Node.isObjectBindingPattern(paramName)) return paramName; + } + } + } + return undefined; +} + +/** + * The destructured binding keys of a dynamic import — for both `const { … } = await import('…')` and + * `import('…').then(({ … }) => …)` — or `[]` for a non-destructured binding, an identifier `.then` + * param, or an unassigned `await import()`. The keys feed per-symbol routing; the specifier itself + * can't be split. + */ +function getDestructuredKeys(node: import('ts-morph').CallExpression): string[] { + const pattern = getModuleBindingPattern(node); + if (!pattern) return []; + return pattern.getElements().map(el => el.getPropertyNameNode()?.getText() ?? el.getName()); +} + +/** + * For a dynamic import whose module binding is NOT a destructurable object pattern — a non-destructured + * `const mod = await import('…')` or a `.then(m => …)` chain — collect the Zod schema constants + * accessed off that binding (e.g. `mod.OAuthTokensSchema`). The destructured form is routed/renamed + * elsewhere; these forms can't be split per-symbol, so the schema accesses are surfaced as a diagnostic + * (mirroring the namespace-import branch of the static import transform — see `importPaths.ts`). Returns + * deduped `[v1Name, v2Name]` pairs (a schema may be renamed, e.g. JSONRPCResponseSchema → + * JSONRPCResultResponseSchema, and core only exports the v2 name). Empty unless the mapping carries a + * `schemaSymbolTarget`. + */ +function collectModuleSchemaAccesses( + node: import('ts-morph').CallExpression, + mapping: ImportMapping, + sourceFile: SourceFile +): Array { + if (!mapping.schemaSymbolTarget) return []; + + let bindingName: string | undefined; + let scope: import('ts-morph').Node | undefined; + + const parent = node.getParent(); + if (parent && Node.isAwaitExpression(parent)) { + // const mod = await import('…') → `mod` is in scope for the rest of the file. + const grandParent = parent.getParent(); + if (grandParent && Node.isVariableDeclaration(grandParent)) { + const nameNode = grandParent.getNameNode(); + if (Node.isIdentifier(nameNode)) { + bindingName = nameNode.getText(); + scope = sourceFile; + } + } + } else if (parent && Node.isPropertyAccessExpression(parent) && parent.getName() === 'then') { + // import('…').then(m => m.XxxSchema…) → the module is the `.then` callback's first parameter. + const thenCall = parent.getParent(); + if (thenCall && Node.isCallExpression(thenCall)) { + const cb = thenCall.getArguments()[0]; + if (cb && (Node.isArrowFunction(cb) || Node.isFunctionExpression(cb))) { + const paramName = cb.getParameters()[0]?.getNameNode(); + if (paramName && Node.isIdentifier(paramName)) { + bindingName = paramName.getText(); + scope = cb; + } + } + } + } + + if (!bindingName || !scope) return []; + + return [ + ...new Map( + scope + .getDescendantsOfKind(SyntaxKind.PropertyAccessExpression) + .filter(pa => pa.getExpression().getText() === bindingName && isSharedSchemaConst(pa.getName(), mapping)) + .map(pa => [pa.getName(), resolveRenamedName(pa.getName(), mapping)] as const) + ) + ]; +} + function rewriteDynamicImports( sourceFile: SourceFile, context: TransformContext, @@ -239,7 +374,8 @@ function rewriteDynamicImports( const specifier = firstArg.getLiteralValue(); if (!isSdkSpecifier(specifier)) return; - const resolved = resolveTarget(specifier, context, sourceFile, { + const destructuredKeys = getDestructuredKeys(node); + const resolved = resolveTarget(specifier, context, sourceFile, destructuredKeys, { filePath: sourceFile.getFilePath(), line: node.getStartLineNumber(), diagnostics @@ -263,59 +399,81 @@ function rewriteDynamicImports( } let effectiveTarget = resolved.target; - const allRenames: Record = { ...SIMPLE_RENAMES, ...resolved.renamedSymbols }; - - // Check if destructured symbols should route to an override target - if (resolved.symbolTargetOverrides) { - const parent = node.getParent(); - if (parent && Node.isAwaitExpression(parent)) { - const grandParent = parent.getParent(); - if (grandParent && Node.isVariableDeclaration(grandParent)) { - const nameNode = grandParent.getNameNode(); - if (Node.isObjectBindingPattern(nameNode)) { - const elements = nameNode.getElements(); - const allOverridden = - elements.length > 0 && - elements.every(el => { - const key = el.getPropertyNameNode()?.getText() ?? el.getName(); - return key in resolved.symbolTargetOverrides!; - }); - if (allOverridden) { - effectiveTarget = - resolved.symbolTargetOverrides[elements[0]!.getPropertyNameNode()?.getText() ?? elements[0]!.getName()]!; - } - } - } - } + const allRenames: Record = { ...SIMPLE_RENAMES, ...resolved.mapping.renamedSymbols }; + + // Route the destructured bindings the same way the static import transform would: a destructuring + // of only `*Schema` constants (e.g. `const { CallToolResultSchema } = await import('…/types.js')`) + // moves to core, and `StreamableHTTPServerTransport` moves to @modelcontextprotocol/node. A + // single import() specifier can't be split, so a mix of packages is flagged for manual migration. + const { target: routedTarget, mixed } = routeSymbols(destructuredKeys, resolved.mapping); + if (routedTarget) { + effectiveTarget = routedTarget; + } else if (mixed) { + diagnostics.push( + actionRequired( + sourceFile.getFilePath(), + node, + `Dynamic import of ${specifier} destructures symbols that belong to different v2 packages. ` + + `Split the import manually so each symbol targets the correct package.` + ) + ); + } + + // A non-destructured binding (`const mod = await import('…')`) or a `.then(m => …)` chain can't be + // routed per-symbol, so the specifier moves to the context package — which does NOT export the + // Zod `*Schema` constants (those live in `schemaSymbolTarget`/core). Any `mod.Schema` / + // `m.Schema` accesses would silently break, so flag them (mirroring the namespace-import + // branch of the static import transform). The destructured form is handled by `routeSymbols` above. + const schemaAccesses = collectModuleSchemaAccesses(node, resolved.mapping, sourceFile); + if (schemaAccesses.length > 0) { + const accessed = schemaAccesses.map(([v1]) => v1).join(', '); + const importName = schemaAccesses[0]![1]; + const renamed = schemaAccesses.filter(([v1, v2]) => v1 !== v2); + const renameNote = renamed.length > 0 ? ` Renamed in v2: ${renamed.map(([v1, v2]) => `${v1} → ${v2}`).join(', ')}.` : ''; + diagnostics.push( + actionRequired( + sourceFile.getFilePath(), + node, + `Dynamic import of ${specifier} is used to access Zod schema(s) (${accessed}) that moved to ${resolved.mapping.schemaSymbolTarget}.${renameNote} ` + + `Import them with a named import (e.g. \`import { ${importName} } from '${resolved.mapping.schemaSymbolTarget}'\`) and update the qualified usages.` + ) + ); } usedPackages.add(effectiveTarget); firstArg.setLiteralValue(effectiveTarget); changes++; - const parent = node.getParent(); - if (parent && Node.isAwaitExpression(parent)) { - const grandParent = parent.getParent(); - if (grandParent && Node.isVariableDeclaration(grandParent)) { - const nameNode = grandParent.getNameNode(); - if (Node.isObjectBindingPattern(nameNode)) { - for (const element of nameNode.getElements()) { - const propertyName = element.getPropertyNameNode()?.getText(); - const bindingName = element.getName(); - const lookupKey = propertyName ?? bindingName; - const newName = allRenames[lookupKey]; - if (newName) { - if (propertyName) { - element.getPropertyNameNode()!.replaceWithText(newName); - } else { - element.replaceWithText(`${newName}: ${bindingName}`); - } - changes++; - } + // Apply symbol renames to the destructured binding elements — for both `await import()` + // destructuring and a `.then(({ … }) => …)` param (both routed per-symbol above when their + // symbols share a target, e.g. schema-only → core). + const bindingPattern = getModuleBindingPattern(node); + if (bindingPattern) { + for (const element of bindingPattern.getElements()) { + const propertyName = element.getPropertyNameNode()?.getText(); + const bindingName = element.getName(); + const lookupKey = propertyName ?? bindingName; + const newName = allRenames[lookupKey]; + if (newName) { + if (propertyName) { + element.getPropertyNameNode()!.replaceWithText(newName); + } else { + element.replaceWithText(`${newName}: ${bindingName}`); } + changes++; } - const moduleRenames = resolved.renamedSymbols ?? {}; - if (!Node.isObjectBindingPattern(nameNode) && Object.keys(moduleRenames).length > 0) { + } + } + + // A non-destructured awaited binding (`const mod = await import('…')`) can't have per-symbol + // renames applied, so flag them if the mapping carries any. (Identifier `.then` params and bare + // `mod.Schema` accesses are surfaced by `collectModuleSchemaAccesses` above.) + const awaitParent = node.getParent(); + if (awaitParent && Node.isAwaitExpression(awaitParent)) { + const decl = awaitParent.getParent(); + if (decl && Node.isVariableDeclaration(decl) && !Node.isObjectBindingPattern(decl.getNameNode())) { + const moduleRenames = resolved.mapping.renamedSymbols ?? {}; + if (Object.keys(moduleRenames).length > 0) { diagnostics.push( actionRequired( sourceFile.getFilePath(), diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/removedApis.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/removedApis.ts index e4bf721dd4..2fc2573fed 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/removedApis.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/removedApis.ts @@ -1,10 +1,10 @@ import type { SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { renameAllReferences } from '../../../utils/astUtils.js'; -import { warning } from '../../../utils/diagnostics.js'; -import { addOrMergeImport, isAnyMcpSpecifier } from '../../../utils/importUtils.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { renameAllReferences } from '../../../utils/astUtils'; +import { warning } from '../../../utils/diagnostics'; +import { addOrMergeImport, isAnyMcpSpecifier } from '../../../utils/importUtils'; const REMOVED_ZOD_HELPERS: Record = { schemaToJson: diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/schemaParamRemoval.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/schemaParamRemoval.ts index eea8e33fd8..66143b2534 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/schemaParamRemoval.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/schemaParamRemoval.ts @@ -1,8 +1,8 @@ import type { SourceFile } from 'ts-morph'; import { Node, SyntaxKind } from 'ts-morph'; -import type { Transform, TransformContext, TransformResult } from '../../../types.js'; -import { isImportedFromMcp, removeUnusedImport, resolveOriginalImportName } from '../../../utils/importUtils.js'; +import type { Transform, TransformContext, TransformResult } from '../../../types'; +import { hasMcpImports, isImportedFromMcp, removeUnusedImport, resolveOriginalImportName } from '../../../utils/importUtils'; const TARGET_METHODS = new Set(['request', 'callTool']); @@ -12,6 +12,11 @@ export const schemaParamRemovalTransform: Transform = { apply(sourceFile: SourceFile, _context: TransformContext): TransformResult { let changesCount = 0; + // `request`/`callTool` are common method names on non-MCP receivers too. The schema-identifier + // path guards per-symbol via `isImportedFromMcp`; the `undefined` path has no symbol to check, so + // gate it on a file-level MCP signal to avoid rewriting unrelated calls. + const fileHasMcpImports = hasMcpImports(sourceFile); + const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression); for (const call of calls) { @@ -27,6 +32,19 @@ export const schemaParamRemovalTransform: Transform = { const secondArg = args[1]!; if (!Node.isIdentifier(secondArg)) continue; + // `request(req, undefined, options)` / `callTool(params, undefined, options)`: v1 passed an + // explicit `undefined` result schema before the trailing options argument. v2 removed the + // schema parameter for spec methods, so the literal `undefined` leaves the call with one + // argument too many (TS2554). Drop it only when a third argument follows — a 2-arg + // `callTool(params, undefined)` already type-checks, since `undefined` is a valid options arg. + if (secondArg.getText() === 'undefined') { + if (fileHasMcpImports && args.length >= 3) { + call.removeArgument(1); + changesCount++; + } + continue; + } + const schemaName = secondArg.getText(); const originalName = resolveOriginalImportName(sourceFile, schemaName) ?? schemaName; if (!originalName.endsWith('Schema')) continue; diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/specSchemaAccess.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/specSchemaAccess.ts deleted file mode 100644 index 79f4a0a707..0000000000 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/specSchemaAccess.ts +++ /dev/null @@ -1,392 +0,0 @@ -import type { SourceFile } from 'ts-morph'; -import { Node, SyntaxKind } from 'ts-morph'; - -import { SPEC_SCHEMA_NAMES, specSchemaToTypeName } from '../../../generated/specSchemaMap.js'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { isKeyPositionIdentifier } from '../../../utils/astUtils.js'; -import { actionRequired, warning } from '../../../utils/diagnostics.js'; -import { addOrMergeImport, isAnyMcpSpecifier, removeUnusedImport } from '../../../utils/importUtils.js'; - -export const specSchemaAccessTransform: Transform = { - name: 'Spec schema standalone usage', - id: 'spec-schemas', - apply(sourceFile: SourceFile, _context: TransformContext): TransformResult { - const diagnostics: Diagnostic[] = []; - let changesCount = 0; - - const schemaImports = collectSpecSchemaImports(sourceFile); - if (schemaImports.size === 0) return { changesCount: 0, diagnostics: [] }; - - for (const [localName, originalName] of schemaImports) { - const typeName = specSchemaToTypeName(originalName); - if (!typeName) continue; - - const refs = findNonImportReferences(sourceFile, localName); - if (refs.length === 0) continue; - - for (const ref of refs) { - const result = handleReference(ref, localName, typeName, sourceFile, diagnostics); - if (result) changesCount++; - } - removeUnusedImport(sourceFile, localName, true); - } - - return { changesCount, diagnostics }; - } -}; - -function collectSpecSchemaImports(sourceFile: SourceFile): Map { - const result = new Map(); - for (const imp of sourceFile.getImportDeclarations()) { - if (!isAnyMcpSpecifier(imp.getModuleSpecifierValue())) continue; - for (const n of imp.getNamedImports()) { - const exportName = n.getName(); - if (!SPEC_SCHEMA_NAMES.has(exportName)) continue; - const localName = n.getAliasNode()?.getText() ?? exportName; - result.set(localName, exportName); - } - } - return result; -} - -function findNonImportReferences(sourceFile: SourceFile, localName: string): import('ts-morph').Node[] { - const refs: import('ts-morph').Node[] = []; - sourceFile.forEachDescendant(node => { - if (!Node.isIdentifier(node)) return; - if (node.getText() !== localName) return; - const parent = node.getParent(); - if (parent && Node.isImportSpecifier(parent)) return; - refs.push(node); - }); - return refs; -} - -function handleReference( - ref: import('ts-morph').Node, - localName: string, - typeName: string, - sourceFile: SourceFile, - diagnostics: Diagnostic[] -): boolean { - // Pattern: z.infer — type position - if (isTypeofInTypePosition(ref)) { - diagnostics.push( - actionRequired( - sourceFile.getFilePath(), - ref, - `Replace \`z.infer\` with the \`${typeName}\` type (already exported from the same v2 package).` - ) - ); - return false; - } - - // Pattern: XSchema.safeParse(v).success — auto-transform to isSpecType.X(v) - if (isSafeParseSuccessPattern(ref)) { - const safeParseAccess = ref.getParent() as import('ts-morph').PropertyAccessExpression; - const safeParseCall = safeParseAccess.getParent() as import('ts-morph').CallExpression; - const successAccess = safeParseCall.getParent() as import('ts-morph').PropertyAccessExpression; - const args = safeParseCall.getArguments(); - const argText = args.length > 0 ? args[0]!.getText() : ''; - successAccess.replaceWithText(`isSpecType.${typeName}(${argText})`); - ensureImport(sourceFile, 'isSpecType'); - return true; - } - - // Pattern: const x = XSchema.safeParse(v) — auto-transform when result is captured in a variable - if (isSafeParsePattern(ref)) { - const safeParseAccess = ref.getParent() as import('ts-morph').PropertyAccessExpression; - const safeParseCall = safeParseAccess.getParent() as import('ts-morph').CallExpression; - - if (isCapturedSafeParsePattern(safeParseCall)) { - return rewriteCapturedSafeParse(safeParseCall, localName, typeName, sourceFile, diagnostics); - } - - return rewriteUnsupportedSchemaCall(ref, safeParseCall, localName, typeName, 'safeParse', sourceFile, diagnostics); - } - - // Pattern: XSchema.parse(v) — rewrite to the StandardSchema validate() primitive (or, when the - // result is used, swap the identifier) so we never leave behind an import of a non-exported schema. - if (isParsePattern(ref)) { - const parseAccess = ref.getParent() as import('ts-morph').PropertyAccessExpression; - const parseCall = parseAccess.getParent() as import('ts-morph').CallExpression; - return rewriteUnsupportedSchemaCall(ref, parseCall, localName, typeName, 'parse', sourceFile, diagnostics); - } - - // Pattern: XSchema used as value (function arg, assignment, etc.) - const parent = ref.getParent(); - if (parent && Node.isPropertyAccessExpression(parent) && parent.getExpression() === ref) { - const line = ref.getStartLineNumber(); - ref.replaceWithText(`specTypeSchemas.${typeName}`); - ensureImport(sourceFile, 'specTypeSchemas'); - diagnostics.push( - warning( - sourceFile.getFilePath(), - line, - `Replaced ${localName} with specTypeSchemas.${typeName}. Note: typed as StandardSchemaV1, not ZodType — Zod methods like .safeParse()/.parse()/.parseAsync() are not available. Manual rewrite required.` - ) - ); - return true; - } - - if (parent && Node.isExportSpecifier(parent)) { - diagnostics.push( - actionRequired( - sourceFile.getFilePath(), - ref, - `Re-export of ${localName} requires manual update: replace with specTypeSchemas.${typeName} or remove.` - ) - ); - return false; - } - - if (parent && Node.isShorthandPropertyAssignment(parent)) { - const line = ref.getStartLineNumber(); - parent.replaceWithText(`'${localName}': specTypeSchemas.${typeName}`); - ensureImport(sourceFile, 'specTypeSchemas'); - diagnostics.push( - warning( - sourceFile.getFilePath(), - line, - `Replaced ${localName} with specTypeSchemas.${typeName}. Note: typed as StandardSchemaV1, not ZodType — Zod methods like .safeParse()/.parse() are not available.` - ) - ); - return true; - } - - if (parent && isKeyPositionIdentifier(ref)) { - return false; - } - - // Value position: replace identifier with specTypeSchemas.X - const line = ref.getStartLineNumber(); - ref.replaceWithText(`specTypeSchemas.${typeName}`); - ensureImport(sourceFile, 'specTypeSchemas'); - diagnostics.push( - warning( - sourceFile.getFilePath(), - line, - `Replaced ${localName} with specTypeSchemas.${typeName}. Note: typed as StandardSchemaV1, not ZodType — Zod methods like .safeParse()/.parse() are not available.` - ) - ); - return true; -} - -function isSafeParseSuccessPattern(ref: import('ts-morph').Node): boolean { - const parent = ref.getParent(); - if (!parent || !Node.isPropertyAccessExpression(parent)) return false; - if (parent.getName() !== 'safeParse' || parent.getExpression() !== ref) return false; - const grandParent = parent.getParent(); - if (!grandParent || !Node.isCallExpression(grandParent)) return false; - const greatGrandParent = grandParent.getParent(); - if (!greatGrandParent || !Node.isPropertyAccessExpression(greatGrandParent)) return false; - return greatGrandParent.getName() === 'success'; -} - -function isSafeParsePattern(ref: import('ts-morph').Node): boolean { - const parent = ref.getParent(); - if (!parent || !Node.isPropertyAccessExpression(parent)) return false; - if (parent.getName() !== 'safeParse' || parent.getExpression() !== ref) return false; - const grandParent = parent.getParent(); - return !!grandParent && Node.isCallExpression(grandParent); -} - -function isParsePattern(ref: import('ts-morph').Node): boolean { - const parent = ref.getParent(); - if (!parent || !Node.isPropertyAccessExpression(parent)) return false; - if (parent.getName() !== 'parse' || parent.getExpression() !== ref) return false; - const grandParent = parent.getParent(); - return !!grandParent && Node.isCallExpression(grandParent); -} - -function isTypeofInTypePosition(ref: import('ts-morph').Node): boolean { - const parent = ref.getParent(); - if (!parent) return false; - return Node.isTypeQuery(parent); -} - -/** - * Checks if a safeParse call result is captured in a `const` variable declaration. - * Pattern: `const x = Schema.safeParse(v);` - */ -function isCapturedSafeParsePattern(safeParseCall: import('ts-morph').CallExpression): boolean { - const parent = safeParseCall.getParent(); - if (!parent || !Node.isVariableDeclaration(parent)) return false; - const nameNode = parent.getNameNode(); - if (!Node.isIdentifier(nameNode)) return false; - const declList = parent.getParent(); - if (!declList || !Node.isVariableDeclarationList(declList)) return false; - const flags = declList.getDeclarationKind(); - return flags === 'const' || flags === 'let'; -} - -/** - * Rewrites a captured safeParse pattern: - * const x = Schema.safeParse(v) → const x = specTypeSchemas.T['~standard'].validate(v) - * x.success → x.issues === undefined - * x.data → x.value - * x.error → x.issues - */ -function rewriteCapturedSafeParse( - safeParseCall: import('ts-morph').CallExpression, - localName: string, - typeName: string, - sourceFile: SourceFile, - diagnostics: Diagnostic[] -): boolean { - const varDecl = safeParseCall.getParent() as import('ts-morph').VariableDeclaration; - const varName = varDecl.getName(); - - const args = safeParseCall.getArguments(); - const argText = args.length > 0 ? args[0]!.getText() : ''; - - // Rewrite the safeParse call - safeParseCall.replaceWithText(`specTypeSchemas.${typeName}['~standard'].validate(${argText})`); - ensureImport(sourceFile, 'specTypeSchemas'); - - // Find and rewrite all property accesses on the result variable (scoped to declaring block) - const replacements: { node: import('ts-morph').Node; newText: string }[] = []; - const scope = varDecl.getFirstAncestorByKind(SyntaxKind.Block) ?? sourceFile; - scope.forEachDescendant(node => { - if (!Node.isPropertyAccessExpression(node)) return; - const expr = node.getExpression(); - if (!Node.isIdentifier(expr) || expr.getText() !== varName) return; - - const propName = node.getName(); - switch (propName) { - case 'success': { - // Check for !x.success → x.issues !== undefined - const parentNode = node.getParent(); - if ( - parentNode && - Node.isPrefixUnaryExpression(parentNode) && - parentNode.getOperatorToken() === SyntaxKind.ExclamationToken - ) { - replacements.push({ node: parentNode, newText: `${varName}.issues !== undefined` }); - } else { - replacements.push({ node, newText: `(${varName}.issues === undefined)` }); - } - break; - } - case 'data': { - replacements.push({ node, newText: `${varName}.value` }); - break; - } - case 'error': { - const errorParent = node.getParent(); - if (errorParent && Node.isPropertyAccessExpression(errorParent) && errorParent.getExpression() === node) { - const subProp = errorParent.getName(); - if (subProp === 'issues') { - replacements.push({ node: errorParent, newText: `${varName}.issues` }); - } else if (subProp === 'message') { - replacements.push({ node: errorParent, newText: `${varName}.issues?.map(i => i.message).join(', ')` }); - } else { - diagnostics.push( - actionRequired( - sourceFile.getFilePath(), - errorParent, - `${varName}.error.${subProp} has no StandardSchema equivalent. Manual migration required.` - ) - ); - } - } else { - replacements.push({ node, newText: `${varName}.issues` }); - } - break; - } - } - }); - - // Apply in reverse order to avoid position shifts - const sorted = replacements.toSorted((a, b) => b.node.getStart() - a.node.getStart()); - for (const { node, newText } of sorted) { - node.replaceWithText(newText); - } - - diagnostics.push( - warning( - sourceFile.getFilePath(), - varDecl.getStartLineNumber(), - `Rewrote ${localName}.safeParse() to specTypeSchemas.${typeName}['~standard'].validate(). ` + - `Result properties remapped: .success → .issues === undefined, .data → .value, .error → .issues.` - ) - ); - - return true; -} - -/** - * Handles spec-schema usages that have no behavior-preserving v2 equivalent: the Zod-only - * methods `.parse()` and (uncaptured) `.safeParse()`. In v2 these schemas are StandardSchemaV1 - * values that are NOT named public exports, so leaving the original import in place produces an - * unresolved-import error (e.g. `PromptSchema` is not exported by `@modelcontextprotocol/server`). - * - * - Result discarded (validation for side-effect only): rewrite `XSchema.parse(v)` → - * `specTypeSchemas.T['~standard'].validate(v)` so the code compiles. NOTE: `validate()` does not - * throw, so `.parse()`'s throw-on-invalid behavior is lost — flagged via an actionRequired comment. - * - Result used: swap only the identifier to `specTypeSchemas.T` so the import resolves; the - * `.parse()`/`.safeParse()` call and its result shape still need a manual fix (flagged). - * - * Either way the original (now non-exported) schema import is dropped by the caller's - * removeUnusedImport, so no dangling import survives. - */ -function rewriteUnsupportedSchemaCall( - ref: import('ts-morph').Node, - callNode: import('ts-morph').CallExpression, - localName: string, - typeName: string, - method: 'parse' | 'safeParse', - sourceFile: SourceFile, - diagnostics: Diagnostic[] -): boolean { - const resultDiscarded = Node.isExpressionStatement(callNode.getParent()); - - if (resultDiscarded) { - const argText = callNode - .getArguments() - .map(a => a.getText()) - .join(', '); - const semantics = - method === 'parse' - ? 'validate() does NOT throw on invalid input (parse() did) — if you relied on that, add `if (result.issues) throw …`.' - : 'the result shape changed from { success, data, error } to { value, issues }.'; - diagnostics.push( - actionRequired( - sourceFile.getFilePath(), - callNode, - `Rewrote ${localName}.${method}() to specTypeSchemas.${typeName}['~standard'].validate(): ` + - `v2 spec schemas are StandardSchemaV1, not Zod. Note: ${semantics}` - ) - ); - callNode.replaceWithText(`specTypeSchemas.${typeName}['~standard'].validate(${argText})`); - ensureImport(sourceFile, 'specTypeSchemas'); - return true; - } - - diagnostics.push( - actionRequired( - sourceFile.getFilePath(), - ref, - `${localName}.${method}() is not available on v2 spec schemas (StandardSchemaV1, not Zod). ` + - `Replaced ${localName} with specTypeSchemas.${typeName}; rewrite the .${method}(...) call using ` + - `specTypeSchemas.${typeName}['~standard'].validate(...) (returns { value, issues }, does not throw).` - ) - ); - ref.replaceWithText(`specTypeSchemas.${typeName}`); - ensureImport(sourceFile, 'specTypeSchemas'); - return true; -} - -function ensureImport(sourceFile: SourceFile, symbol: string): void { - const existingImport = sourceFile.getImportDeclarations().find(imp => { - if (!isAnyMcpSpecifier(imp.getModuleSpecifierValue())) return false; - return imp.getNamedImports().some(n => n.getName() === symbol); - }); - if (existingImport) return; - - const targetPkg = sourceFile.getImportDeclarations().find(imp => { - const spec = imp.getModuleSpecifierValue(); - return spec === '@modelcontextprotocol/server' || spec === '@modelcontextprotocol/client'; - }); - const target = targetPkg?.getModuleSpecifierValue() ?? '@modelcontextprotocol/server'; - addOrMergeImport(sourceFile, target, [symbol], false, sourceFile.getImportDeclarations().length); -} diff --git a/packages/codemod/src/migrations/v1-to-v2/transforms/symbolRenames.ts b/packages/codemod/src/migrations/v1-to-v2/transforms/symbolRenames.ts index 651faf5680..4e47c1ee68 100644 --- a/packages/codemod/src/migrations/v1-to-v2/transforms/symbolRenames.ts +++ b/packages/codemod/src/migrations/v1-to-v2/transforms/symbolRenames.ts @@ -1,12 +1,12 @@ import type { SourceFile } from 'ts-morph'; import { Node } from 'ts-morph'; -import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types.js'; -import { renameAllReferences } from '../../../utils/astUtils.js'; -import { info, warning } from '../../../utils/diagnostics.js'; -import { addOrMergeImport, isAnyMcpSpecifier, removeUnusedImport } from '../../../utils/importUtils.js'; -import { resolveTypesPackage } from '../../../utils/projectAnalyzer.js'; -import { ERROR_CODE_SDK_MEMBERS, SIMPLE_RENAMES } from '../mappings/symbolMap.js'; +import type { Diagnostic, Transform, TransformContext, TransformResult } from '../../../types'; +import { renameAllReferences } from '../../../utils/astUtils'; +import { info, warning } from '../../../utils/diagnostics'; +import { addOrMergeImport, isAnyMcpSpecifier, removeUnusedImport } from '../../../utils/importUtils'; +import { resolveTypesPackage } from '../../../utils/projectAnalyzer'; +import { ERROR_CODE_SDK_MEMBERS, SIMPLE_RENAMES } from '../mappings/symbolMap'; const SERVER_GENERIC_ARGS = new Set(['ServerRequest', 'ServerNotification']); const CLIENT_GENERIC_ARGS = new Set(['ClientRequest', 'ClientNotification']); diff --git a/packages/codemod/src/runner.ts b/packages/codemod/src/runner.ts index 965d5827c3..1554429fae 100644 --- a/packages/codemod/src/runner.ts +++ b/packages/codemod/src/runner.ts @@ -1,10 +1,10 @@ import type { Node } from 'ts-morph'; import { Project, SyntaxKind } from 'ts-morph'; -import type { Diagnostic, FileResult, Migration, RunnerOptions, RunnerResult } from './types.js'; -import { CODEMOD_ERROR_PREFIX, error } from './utils/diagnostics.js'; -import { updatePackageJson } from './utils/packageJsonUpdater.js'; -import { analyzeProject } from './utils/projectAnalyzer.js'; +import type { Diagnostic, FileResult, Migration, RunnerOptions, RunnerResult } from './types'; +import { CODEMOD_ERROR_PREFIX, error } from './utils/diagnostics'; +import { updatePackageJson } from './utils/packageJsonUpdater'; +import { analyzeProject } from './utils/projectAnalyzer'; const LITERAL_NODE_KINDS = new Set([ SyntaxKind.NoSubstitutionTemplateLiteral, @@ -143,7 +143,7 @@ export function run(migration: Migration, options: RunnerOptions): RunnerResult const fileDiagnostics: Diagnostic[] = []; const originalText = sourceFile.getFullText(); - const fileUsedPackages = new Set(); + const fileClaimedPackages = new Set(); try { for (const transform of enabledTransforms) { const result = transform.apply(sourceFile, context); @@ -151,12 +151,25 @@ export function run(migration: Migration, options: RunnerOptions): RunnerResult fileDiagnostics.push(...result.diagnostics); if (result.usedPackages) { for (const pkg of result.usedPackages) { - fileUsedPackages.add(pkg); + fileClaimedPackages.add(pkg); } } } - for (const pkg of fileUsedPackages) { - allUsedPackages.add(pkg); + // A transform records a package as "used" when it routes a binding there — but importPaths does + // so the moment it rewrites an import, and later transforms (handlerRegistration, + // schemaParamRemoval) routinely rewrite the schema usage away and delete that very import. + // Honouring a claim whose import did not survive would add an unused dependency to package.json, + // so a claim counts only when the FINAL file still references the specifier. Every claim + // originates from a string literal the transform wrote (an import/export module specifier, or a + // vi.mock()/dynamic import() argument), so a surviving string-literal match is the ground truth. + const survivingSpecifiers = new Set(); + for (const literal of sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral)) { + survivingSpecifiers.add(literal.getLiteralValue()); + } + for (const pkg of fileClaimedPackages) { + if (survivingSpecifiers.has(pkg)) { + allUsedPackages.add(pkg); + } } } catch (error_) { const filePath = sourceFile.getFilePath(); @@ -164,7 +177,7 @@ export function run(migration: Migration, options: RunnerOptions): RunnerResult fileDiagnostics.push(error(filePath, 1, `Transform failed: ${error_ instanceof Error ? error_.message : String(error_)}`)); sourceFile.replaceWithText(originalText); fileChanges = 0; - fileUsedPackages.clear(); + fileClaimedPackages.clear(); } for (const d of fileDiagnostics) { diff --git a/packages/codemod/src/utils/detectFormatter.ts b/packages/codemod/src/utils/detectFormatter.ts new file mode 100644 index 0000000000..81fc66da64 --- /dev/null +++ b/packages/codemod/src/utils/detectFormatter.ts @@ -0,0 +1,126 @@ +import { existsSync, readFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +/** A code formatter the codemod can recommend running after a migration. */ +export interface DetectedFormatter { + /** Display name, e.g. `Prettier`. */ + name: string; + /** Executable name, e.g. `prettier`. */ + bin: string; + /** Arguments that write formatting in place; changed file paths are appended after these. */ + writeArgs: readonly string[]; +} + +const BIOME_CONFIG_FILES = ['biome.json', 'biome.jsonc']; +const PRETTIER_CONFIG_FILES = [ + '.prettierrc', + '.prettierrc.json', + '.prettierrc.json5', + '.prettierrc.yaml', + '.prettierrc.yml', + '.prettierrc.toml', + '.prettierrc.js', + '.prettierrc.cjs', + '.prettierrc.mjs', + '.prettierrc.ts', + 'prettier.config.js', + 'prettier.config.cjs', + 'prettier.config.mjs', + 'prettier.config.ts' +]; +const ESLINT_CONFIG_FILES = [ + 'eslint.config.js', + 'eslint.config.mjs', + 'eslint.config.cjs', + 'eslint.config.ts', + 'eslint.config.mts', + 'eslint.config.cts', + '.eslintrc', + '.eslintrc.js', + '.eslintrc.cjs', + '.eslintrc.json', + '.eslintrc.yml', + '.eslintrc.yaml' +]; + +// Precedence order: a configured dedicated formatter wins over ESLint's --fix. +const FORMATTERS = { + biome: { name: 'Biome', bin: 'biome', writeArgs: ['format', '--write'] }, + prettier: { name: 'Prettier', bin: 'prettier', writeArgs: ['--write'] }, + eslint: { name: 'ESLint', bin: 'eslint', writeArgs: ['--fix'] } +} as const satisfies Record; + +function hasAnyFile(dir: string, files: readonly string[]): boolean { + return files.some(file => existsSync(path.join(dir, file))); +} + +interface PackageJsonSignals { + prettier: boolean; + eslint: boolean; +} + +function readPackageJsonSignals(dir: string): PackageJsonSignals { + const pkgJsonPath = path.join(dir, 'package.json'); + if (!existsSync(pkgJsonPath)) return { prettier: false, eslint: false }; + try { + const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8')) as Record; + const allDeps = { + ...(pkgJson.dependencies as Record | undefined), + ...(pkgJson.devDependencies as Record | undefined) + }; + return { + prettier: 'prettier' in pkgJson || 'prettier' in allDeps, + eslint: 'eslint' in allDeps + }; + } catch { + return { prettier: false, eslint: false }; + } +} + +/** + * Walks up from `startDir` looking for a configured code formatter, so the CLI can suggest the right + * "format your changed files" command after a migration. + * + * The walk is bounded so a user-level global config is never mistaken for the project's. It stops at the + * repository root (a `.git` directory) or the filesystem root, and — for a project that is not a git + * checkout (tarball, fresh scaffold, CI workspace) — never ascends into or above `$HOME`, so a + * `~/.prettierrc`, `~/biome.json`, or `~/package.json` with formatter deps is never matched. (A `.git` + * boundary alone did not hold this guarantee for non-git projects, which would otherwise walk to `$HOME`.) + * + * Detection is config-based and runs nothing. When multiple formatters are configured, precedence is + * Biome > Prettier > ESLint. + * + * @param startDir the directory to start the upward search from. + * @param homeDir the user's home directory; the walk never reads it or any ancestor. Injectable for tests; + * defaults to `os.homedir()`. + * @returns the detected formatter, or `null` if none is configured. + */ +export function detectFormatter(startDir: string, homeDir: string = os.homedir()): DetectedFormatter | null { + let dir = path.resolve(startDir); + const root = path.parse(dir).root; + const home = path.resolve(homeDir); + const found = { biome: false, prettier: false, eslint: false }; + + while (true) { + if (hasAnyFile(dir, BIOME_CONFIG_FILES)) found.biome = true; + if (hasAnyFile(dir, PRETTIER_CONFIG_FILES)) found.prettier = true; + if (hasAnyFile(dir, ESLINT_CONFIG_FILES)) found.eslint = true; + + const signals = readPackageJsonSignals(dir); + if (signals.prettier) found.prettier = true; + if (signals.eslint) found.eslint = true; + + // Stop at the repository root (a `.git` dir) or the filesystem root. For a project that is not a + // git checkout (tarball, fresh scaffold, CI workspace), also stop before ascending into `$HOME`: + // the project is a descendant of `$HOME`, so a user-level `~/.prettierrc`, `~/biome.json`, or + // `~/package.json` with formatter deps must never be read as the project's own config. + if (existsSync(path.join(dir, '.git')) || dir === root || dir === home || path.dirname(dir) === home) break; + dir = path.dirname(dir); + } + + if (found.biome) return FORMATTERS.biome; + if (found.prettier) return FORMATTERS.prettier; + if (found.eslint) return FORMATTERS.eslint; + return null; +} diff --git a/packages/codemod/src/utils/diagnostics.ts b/packages/codemod/src/utils/diagnostics.ts index 3ebfd8e1be..b3d961d3e6 100644 --- a/packages/codemod/src/utils/diagnostics.ts +++ b/packages/codemod/src/utils/diagnostics.ts @@ -1,7 +1,7 @@ import type { Node } from 'ts-morph'; -import type { Diagnostic } from '../types.js'; -import { DiagnosticLevel } from '../types.js'; +import type { Diagnostic } from '../types'; +import { DiagnosticLevel } from '../types'; export const CODEMOD_ERROR_PREFIX = '@mcp-codemod-error'; diff --git a/packages/codemod/src/utils/importUtils.ts b/packages/codemod/src/utils/importUtils.ts index 145c95328c..ecf3670af5 100644 --- a/packages/codemod/src/utils/importUtils.ts +++ b/packages/codemod/src/utils/importUtils.ts @@ -6,6 +6,7 @@ const SDK_PREFIX = '@modelcontextprotocol/sdk'; const V2_PACKAGES = new Set([ '@modelcontextprotocol/client', '@modelcontextprotocol/server', + '@modelcontextprotocol/core-internal', '@modelcontextprotocol/core', '@modelcontextprotocol/node', '@modelcontextprotocol/express' @@ -32,31 +33,52 @@ export function isTypeOnlyImport(imp: ImportDeclaration): boolean { return imp.isTypeOnly(); } +/** A named import to emit: either a bare name, or a `{ name, alias }` pair preserving an `as` alias. */ +export type NamedImportSpec = string | { name: string; alias?: string }; + +function toSpec(n: NamedImportSpec): { name: string; alias?: string } { + return typeof n === 'string' ? { name: n } : n; +} + +/** Local binding a spec introduces — the alias when present, otherwise the imported name. */ +function specLocalName(s: { name: string; alias?: string }): string { + return s.alias ?? s.name; +} + export function addOrMergeImport( sourceFile: SourceFile, moduleSpecifier: string, - namedImports: string[], + namedImports: NamedImportSpec[], isTypeOnly: boolean, insertIndex: number ): void { if (namedImports.length === 0) return; + const specs = namedImports.map(n => toSpec(n)); + const existing = sourceFile.getImportDeclarations().find(imp => { if (imp.getNamespaceImport()) return false; return imp.getModuleSpecifierValue() === moduleSpecifier && imp.isTypeOnly() === isTypeOnly; }); if (existing) { - const existingNames = new Set(existing.getNamedImports().map(n => n.getName())); - const newNames = namedImports.filter(n => !existingNames.has(n)); - if (newNames.length > 0) { - existing.addNamedImports(newNames); + const existingLocals = new Set(existing.getNamedImports().map(n => n.getAliasNode()?.getText() ?? n.getName())); + const newSpecs = specs.filter(s => !existingLocals.has(specLocalName(s))); + if (newSpecs.length > 0) { + existing.addNamedImports(newSpecs.map(s => (s.alias ? { name: s.name, alias: s.alias } : { name: s.name }))); } } else { + const seen = new Set(); + const deduped = specs.filter(s => { + const local = specLocalName(s); + if (seen.has(local)) return false; + seen.add(local); + return true; + }); const clampedIndex = Math.min(insertIndex, sourceFile.getImportDeclarations().length); sourceFile.insertImportDeclaration(clampedIndex, { moduleSpecifier, - namedImports: [...new Set(namedImports)], + namedImports: deduped.map(s => (s.alias ? { name: s.name, alias: s.alias } : { name: s.name })), isTypeOnly }); } diff --git a/packages/codemod/src/utils/packageJsonUpdater.ts b/packages/codemod/src/utils/packageJsonUpdater.ts index 96a41430c8..1b3eb07f8a 100644 --- a/packages/codemod/src/utils/packageJsonUpdater.ts +++ b/packages/codemod/src/utils/packageJsonUpdater.ts @@ -1,11 +1,11 @@ import { readFileSync, writeFileSync } from 'node:fs'; -import { V2_PACKAGE_VERSIONS } from '../generated/versions.js'; -import type { PackageJsonChange } from '../types.js'; -import { findPackageJson } from './projectAnalyzer.js'; +import { V2_PACKAGE_VERSIONS } from '../generated/versions'; +import type { PackageJsonChange } from '../types'; +import { findPackageJson } from './projectAnalyzer'; const V1_PACKAGE = '@modelcontextprotocol/sdk'; -const PRIVATE_PACKAGES = new Set(['@modelcontextprotocol/core']); +const PRIVATE_PACKAGES = new Set(['@modelcontextprotocol/core-internal']); function normalizeToRoot(pkg: string): string { const secondSlash = pkg.indexOf('/', pkg.indexOf('/') + 1); diff --git a/packages/codemod/src/utils/projectAnalyzer.ts b/packages/codemod/src/utils/projectAnalyzer.ts index daf4088876..1a836021c7 100644 --- a/packages/codemod/src/utils/projectAnalyzer.ts +++ b/packages/codemod/src/utils/projectAnalyzer.ts @@ -1,11 +1,24 @@ -import { existsSync, readFileSync } from 'node:fs'; +import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import path from 'node:path'; -import type { Diagnostic, TransformContext } from '../types.js'; -import { warning } from './diagnostics.js'; +import type { Diagnostic, TransformContext } from '../types'; +import { info, warning } from './diagnostics'; const PROJECT_ROOT_MARKERS = ['.git', 'node_modules']; +const SCAN_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs']); +const SCAN_SKIP_DIRS = new Set(['node_modules', 'dist', '.git', 'build', '.next', '.nuxt', 'coverage']); +const SCAN_FILE_BUDGET = 5000; + +// Matches a quoted v1 SDK client/server subpath import specifier — e.g. +// '@modelcontextprotocol/sdk/client/index.js' "@modelcontextprotocol/sdk/server/mcp.js" +// '@modelcontextprotocol/sdk/client' (extensionless / bare subpath; see the extensionless +// import matching the codemod already supports) +// Anchored to the opening quote and a trailing `/` or closing quote so that comments or prose that +// merely mention the path do not count, and `…/client` is not confused with `…/clientfoo`. +const CLIENT_IMPORT_RE = /['"`]@modelcontextprotocol\/sdk\/client(?:\/|['"`])/; +const SERVER_IMPORT_RE = /['"`]@modelcontextprotocol\/sdk\/server(?:\/|['"`])/; + export function findPackageJson(startDir: string): string | undefined { let dir = path.resolve(startDir); const root = path.parse(dir).root; @@ -20,27 +33,86 @@ export function findPackageJson(startDir: string): string | undefined { export function analyzeProject(targetDir: string): TransformContext { const pkgJsonPath = findPackageJson(targetDir); - if (!pkgJsonPath) { - return { projectType: 'unknown' }; + if (pkgJsonPath) { + try { + const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8')); + const allDeps = { + ...pkgJson.dependencies, + ...pkgJson.devDependencies + }; + + const hasClient = '@modelcontextprotocol/client' in allDeps; + const hasServer = '@modelcontextprotocol/server' in allDeps; + + if (hasClient && hasServer) return { projectType: 'both' }; + if (hasClient) return { projectType: 'client' }; + if (hasServer) return { projectType: 'server' }; + // No v2 split deps — this is almost always a v1 project mid-migration (v1 ships as the single + // `@modelcontextprotocol/sdk` package). Fall through to inferring the type from source usage. + } catch { + // Malformed package.json — fall through to source inference. + } } - try { - const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8')); - const allDeps = { - ...pkgJson.dependencies, - ...pkgJson.devDependencies - }; + return { projectType: inferProjectTypeFromSource(targetDir) }; +} - const hasClient = '@modelcontextprotocol/client' in allDeps; - const hasServer = '@modelcontextprotocol/server' in allDeps; +/** + * Infer client vs server vs both by scanning the source for v1 SDK subpath imports: a + * `@modelcontextprotocol/sdk/client/...` specifier means the project will need + * `@modelcontextprotocol/client`; a `.../server/...` specifier means it needs `@modelcontextprotocol/server`. + * Files that import only shared paths (`types.js`, `shared/...`) give no signal. The scan matches quoted + * specifiers (not bare substrings), so comments/prose are ignored. Bounded: skips heavy dirs, caps the + * file count, and early-exits once both signals are seen. + */ +function inferProjectTypeFromSource(targetDir: string): TransformContext['projectType'] { + let usesClient = false; + let usesServer = false; + let scanned = 0; - if (hasClient && hasServer) return { projectType: 'both' }; - if (hasClient) return { projectType: 'client' }; - if (hasServer) return { projectType: 'server' }; - return { projectType: 'unknown' }; + const visit = (dir: string): void => { + if (usesClient && usesServer) return; + let entries: import('node:fs').Dirent[]; + try { + entries = readdirSync(dir, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + if (usesClient && usesServer) return; + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (SCAN_SKIP_DIRS.has(entry.name)) continue; + visit(full); + } else if (entry.isFile()) { + const ext = path.extname(entry.name); + if (!SCAN_EXTENSIONS.has(ext) || entry.name.endsWith('.d.ts')) continue; + if (scanned >= SCAN_FILE_BUDGET) return; + scanned++; + let content: string; + try { + content = readFileSync(full, 'utf8'); + } catch { + continue; + } + if (!usesClient && CLIENT_IMPORT_RE.test(content)) usesClient = true; + if (!usesServer && SERVER_IMPORT_RE.test(content)) usesServer = true; + } + } + }; + + let root = targetDir; + try { + if (!statSync(targetDir).isDirectory()) root = path.dirname(targetDir); } catch { - return { projectType: 'unknown' }; + return 'unknown'; } + visit(root); + + if (usesClient && usesServer) return 'both'; + if (usesClient) return 'client'; + if (usesServer) return 'server'; + return 'unknown'; } export function resolveTypesPackage( @@ -61,6 +133,22 @@ export function resolveTypesPackage( if (context.projectType === 'server') { return '@modelcontextprotocol/server'; } + if (context.projectType === 'both') { + // Both packages are present and both re-export the shared protocol types (from core), so importing + // from either compiles. This file has no client/server-specific signal — default to server and note + // it as an optional preference, not an action-required warning. + if (diagnosticSink) { + diagnosticSink.diagnostics.push( + info( + diagnosticSink.filePath, + diagnosticSink.line, + 'Shared protocol types imported from @modelcontextprotocol/server (both client and server ' + + 're-export them). Switch to @modelcontextprotocol/client if this is client-only code.' + ) + ); + } + return '@modelcontextprotocol/server'; + } if (diagnosticSink) { diagnosticSink.diagnostics.push( warning( diff --git a/packages/codemod/test/cli.test.ts b/packages/codemod/test/cli.test.ts index b32244364c..01f36a9d44 100644 --- a/packages/codemod/test/cli.test.ts +++ b/packages/codemod/test/cli.test.ts @@ -3,9 +3,9 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import { describe, it, expect, afterEach } from 'vitest'; -import { getMigration } from '../src/migrations/index.js'; -import { run } from '../src/runner.js'; -import { DiagnosticLevel } from '../src/types.js'; +import { getMigration } from '../src/migrations/index'; +import { run } from '../src/runner'; +import { DiagnosticLevel } from '../src/types'; const migration = getMigration('v1-to-v2')!; diff --git a/packages/codemod/test/commentInsertion.test.ts b/packages/codemod/test/commentInsertion.test.ts index a50c4698be..8862303633 100644 --- a/packages/codemod/test/commentInsertion.test.ts +++ b/packages/codemod/test/commentInsertion.test.ts @@ -3,9 +3,9 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import { afterEach, describe, expect, it } from 'vitest'; -import { getMigration } from '../src/migrations/index.js'; -import { run } from '../src/runner.js'; -import { CODEMOD_ERROR_PREFIX } from '../src/utils/diagnostics.js'; +import { getMigration } from '../src/migrations/index'; +import { run } from '../src/runner'; +import { CODEMOD_ERROR_PREFIX } from '../src/utils/diagnostics'; const migration = getMigration('v1-to-v2')!; @@ -87,11 +87,12 @@ describe('comment insertion', () => { it('inserts multiple comments in one file in correct positions', () => { const dir = createTempDir(); - // Two .parse() calls on different schemas trigger two actionRequired diagnostics + // Two custom-schema handler registrations on different lines trigger two actionRequired diagnostics const input = [ - `import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `const a = CallToolRequestSchema.parse(data1);`, - `const b = ListToolsRequestSchema.parse(data2);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(FooSchema, async () => ({}));`, + `server.setRequestHandler(BarSchema, async () => ({}));`, `` ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -107,9 +108,9 @@ describe('comment insertion', () => { it('preserves indentation of the target line', () => { const dir = createTempDir(); const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `function validate() {`, - ` const a = CallToolRequestSchema.parse(data);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `function register(server: McpServer) {`, + ` server.setRequestHandler(FooSchema, async () => ({}));`, `}`, `` ].join('\n'); @@ -125,8 +126,9 @@ describe('comment insertion', () => { it('does not duplicate comments on re-run (idempotency)', () => { const dir = createTempDir(); const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `const a = CallToolRequestSchema.parse(data);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(FooSchema, async () => ({}));`, `` ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -146,10 +148,11 @@ describe('comment insertion', () => { it('sanitizes */ in diagnostic messages', () => { const dir = createTempDir(); - // The .parse() diagnostic message doesn't contain */, but we verify the comment is well-formed + // The handler diagnostic message doesn't contain */, but we verify the comment is well-formed const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `const a = CallToolRequestSchema.parse(data);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(FooSchema, async () => ({}));`, `` ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -167,10 +170,10 @@ describe('comment insertion', () => { // Import rewrite adds new import lines (splitting into multiple packages), // then handler transform emits actionRequired. The comment must land at the correct post-shift line. const input = [ - `import { McpServer, CallToolRequestSchema } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `import { McpServer, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/server/mcp.js';`, ``, `const server = new McpServer({ name: 'test', version: '1.0' });`, - `const a = CallToolRequestSchema.parse(data);`, + `server.setRequestHandler(FooSchema, async () => ({}));`, `` ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -181,16 +184,18 @@ describe('comment insertion', () => { const lines = output.split('\n'); const commentIdx = lines.findIndex(l => l.includes(CODEMOD_ERROR_PREFIX)); expect(commentIdx).toBeGreaterThan(-1); - // The comment should be directly above the parse() line (which may have moved) + // The comment should be directly above the handler line (which may have moved) const nextLine = lines[commentIdx + 1]!; - expect(nextLine).toContain('.parse(data)'); + expect(nextLine).toContain('setRequestHandler'); }); it('merges same-line diagnostics into a single comment', () => { const dir = createTempDir(); + // Two custom-schema handler registrations on the SAME physical line -> two same-line diagnostics const input = [ - `import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `const a = CallToolRequestSchema.parse(data1); const b = ListToolsRequestSchema.parse(data2);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(FooSchema, async () => ({})); server.setRequestHandler(BarSchema, async () => ({}));`, `` ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -207,9 +212,10 @@ describe('comment insertion', () => { it('skips comment insertion when target line is inside a template literal', () => { const dir = createTempDir(); const input = [ - "import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';", + "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';", + "const server = new McpServer({ name: 'test', version: '1.0' });", 'const msg = `', - ' Result: ${CallToolRequestSchema.parse(data).method}', + ' Result: ${server.setRequestHandler(FooSchema, async () => ({}))}', '`;', '' ].join('\n'); @@ -230,10 +236,11 @@ describe('comment insertion', () => { const dir = createTempDir(); // TemplateMiddle: text between two ${} spans const input = [ - "import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';", + "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';", + "const server = new McpServer({ name: 'test', version: '1.0' });", 'const msg = `${somePrefix}', - ' A: ${CallToolRequestSchema.parse(d1)}', - ' B: ${ListToolsRequestSchema.parse(d2)}', + ' A: ${server.setRequestHandler(FooSchema, async () => ({}))}', + ' B: ${server.setRequestHandler(BarSchema, async () => ({}))}', '`;', '' ].join('\n'); @@ -249,11 +256,12 @@ describe('comment insertion', () => { it('still inserts comment when diagnostic line merely contains a template literal', () => { const dir = createTempDir(); - // The .parse() and template are on the same line, but lineStart is at "const", + // The handler call and template are on the same line, but lineStart is at "server", // which is outside the template literal. const input = [ - "import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';", - 'const a = CallToolRequestSchema.parse(`template ${data}`);', + "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';", + "const server = new McpServer({ name: 'test', version: '1.0' });", + 'server.setRequestHandler(FooSchema, async () => ({ msg: `template ${data}` }));', '' ].join('\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -272,8 +280,9 @@ describe('comment insertion', () => { it('handles CRLF line endings without corrupting the file', () => { const dir = createTempDir(); const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `const a = CallToolRequestSchema.parse(data);`, + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(FooSchema, async () => ({}));`, `` ].join('\r\n'); writeFileSync(path.join(dir, 'server.ts'), input); @@ -286,6 +295,6 @@ describe('comment insertion', () => { const commentIdx = lines.findIndex(l => l.includes(CODEMOD_ERROR_PREFIX)); expect(commentIdx).toBeGreaterThan(-1); expect(lines[commentIdx]!.trim()).toMatch(/^\/\*.*\*\/$/); - expect(lines[commentIdx + 1]).toContain('.parse(data)'); + expect(lines[commentIdx + 1]).toContain('setRequestHandler'); }); }); diff --git a/packages/codemod/test/detectFormatter.test.ts b/packages/codemod/test/detectFormatter.test.ts new file mode 100644 index 0000000000..493cc3b574 --- /dev/null +++ b/packages/codemod/test/detectFormatter.test.ts @@ -0,0 +1,153 @@ +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { describe, it, expect, afterEach } from 'vitest'; + +import { detectFormatter } from '../src/utils/detectFormatter'; + +let tempDir: string; + +function createTempDir(): string { + tempDir = mkdtempSync(path.join(tmpdir(), 'mcp-codemod-formatter-')); + return tempDir; +} + +function writePkg(dir: string, pkg: Record): void { + writeFileSync(path.join(dir, 'package.json'), JSON.stringify(pkg)); +} + +afterEach(() => { + if (tempDir) { + rmSync(tempDir, { recursive: true, force: true }); + } +}); + +describe('detectFormatter', () => { + it('returns null when no formatter is configured', () => { + const dir = createTempDir(); + writePkg(dir, { devDependencies: { typescript: '^5' } }); + + expect(detectFormatter(dir)).toBeNull(); + }); + + it('detects Prettier from a config file', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'prettier.config.mjs'), 'export default {};'); + + const result = detectFormatter(dir); + expect(result?.name).toBe('Prettier'); + expect(result?.bin).toBe('prettier'); + expect(result?.writeArgs).toEqual(['--write']); + }); + + it('detects Prettier from the "prettier" key in package.json', () => { + const dir = createTempDir(); + writePkg(dir, { prettier: { singleQuote: false } }); + + expect(detectFormatter(dir)?.name).toBe('Prettier'); + }); + + it('detects Prettier from devDependencies', () => { + const dir = createTempDir(); + writePkg(dir, { devDependencies: { prettier: '^3' } }); + + expect(detectFormatter(dir)?.name).toBe('Prettier'); + }); + + it('detects Biome from biome.json', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'biome.json'), '{}'); + + const result = detectFormatter(dir); + expect(result?.name).toBe('Biome'); + expect(result?.bin).toBe('biome'); + expect(result?.writeArgs).toEqual(['format', '--write']); + }); + + it('does not detect dprint — a lone dprint.json yields null', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'dprint.json'), '{}'); + + expect(detectFormatter(dir)).toBeNull(); + }); + + it('detects ESLint when only ESLint is configured', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'eslint.config.js'), 'export default [];'); + + const result = detectFormatter(dir); + expect(result?.name).toBe('ESLint'); + expect(result?.bin).toBe('eslint'); + expect(result?.writeArgs).toEqual(['--fix']); + }); + + it('prefers Prettier over ESLint when both are configured (the common prettier-plugin case)', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'eslint.config.js'), 'export default [];'); + writeFileSync(path.join(dir, 'prettier.config.mjs'), 'export default {};'); + + expect(detectFormatter(dir)?.name).toBe('Prettier'); + }); + + it('prefers Biome over Prettier when both are configured', () => { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'biome.json'), '{}'); + writeFileSync(path.join(dir, 'prettier.config.mjs'), 'export default {};'); + + expect(detectFormatter(dir)?.name).toBe('Biome'); + }); + + it('walks up directory levels to find the formatter (monorepo layout)', () => { + const dir = createTempDir(); + const src = path.join(dir, 'packages', 'mcp', 'src'); + mkdirSync(src, { recursive: true }); + writeFileSync(path.join(dir, 'prettier.config.mjs'), 'export default {};'); + + expect(detectFormatter(src)?.name).toBe('Prettier'); + }); + + it('stops at the .git boundary and does not detect config above the repo root', () => { + const dir = createTempDir(); + const src = path.join(dir, 'project', 'src'); + mkdirSync(src, { recursive: true }); + mkdirSync(path.join(dir, 'project', '.git'), { recursive: true }); + // Config lives above the repo root — must not be picked up. + writeFileSync(path.join(dir, 'prettier.config.mjs'), 'export default {};'); + + expect(detectFormatter(src)).toBeNull(); + }); + + it('does not match a user-level $HOME config for a non-git project (stops at $HOME)', () => { + const home = createTempDir(); + const projectSrc = path.join(home, 'projects', 'app', 'src'); + mkdirSync(projectSrc, { recursive: true }); + // A user-level config sits at $HOME, above a non-git project — it must never be read as the + // project's config (the walk must stop before ascending into $HOME). + writeFileSync(path.join(home, 'prettier.config.mjs'), 'export default {};'); + + expect(detectFormatter(projectSrc, home)).toBeNull(); + }); + + it('reads the project root directly under $HOME but never $HOME itself', () => { + const home = createTempDir(); + const projectRoot = path.join(home, 'app'); + const src = path.join(projectRoot, 'src'); + mkdirSync(src, { recursive: true }); + // A higher-precedence formatter configured at $HOME must NOT shadow the project's own. + writeFileSync(path.join(home, 'biome.json'), '{}'); + writeFileSync(path.join(projectRoot, 'eslint.config.js'), 'export default [];'); + + // Only the project's ESLint is detected; $HOME's Biome is never read. + expect(detectFormatter(src, home)?.name).toBe('ESLint'); + }); + + it('detects a project config below $HOME (the boundary only blocks $HOME and above)', () => { + const home = createTempDir(); + const projectRoot = path.join(home, 'projects', 'app'); + const src = path.join(projectRoot, 'src'); + mkdirSync(src, { recursive: true }); + writeFileSync(path.join(projectRoot, 'biome.json'), '{}'); + + expect(detectFormatter(src, home)?.name).toBe('Biome'); + }); +}); diff --git a/packages/codemod/test/integration.test.ts b/packages/codemod/test/integration.test.ts index 18942bfcfa..557b533173 100644 --- a/packages/codemod/test/integration.test.ts +++ b/packages/codemod/test/integration.test.ts @@ -3,10 +3,10 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import { describe, it, expect, afterEach } from 'vitest'; -import { getMigration } from '../src/migrations/index.js'; -import { run } from '../src/runner.js'; -import { DiagnosticLevel } from '../src/types.js'; -import type { Migration, Transform } from '../src/types.js'; +import { getMigration } from '../src/migrations/index'; +import { run } from '../src/runner'; +import { DiagnosticLevel } from '../src/types'; +import type { Migration, Transform } from '../src/types'; const migration = getMigration('v1-to-v2')!; @@ -379,6 +379,70 @@ describe('integration', () => { expect(pkgJson.dependencies['express']).toBe('^4.0.0'); }); + it('package.json: does not add core when every schema import is rewritten away', () => { + // The dominant v1 pattern: a `*Schema` constant used ONLY as a setRequestHandler first arg. + // importPaths routes it to @modelcontextprotocol/core (recording the package), but + // handlerRegistration then rewrites the call to a method string and deletes the now-unused + // import. No core import survives, so package.json must NOT gain a core dependency. + const dir = createTempDir(); + writePkgJson(dir, { dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }); + writeFileSync( + path.join(dir, 'server.ts'), + [ + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, + `const server = new McpServer({ name: 'test', version: '1.0' });`, + `server.setRequestHandler(CallToolRequestSchema, async () => ({ content: [] }));`, + `` + ].join('\n') + ); + + const result = run(migration, { targetDir: dir }); + + // The schema usage was rewritten and its import deleted. + const output = readFileSync(path.join(dir, 'server.ts'), 'utf8'); + expect(output).toContain("setRequestHandler('tools/call'"); + expect(output).not.toContain('core'); + + // So core must not be added; the package actually imported (server) still is. + expect(result.packageJsonChanges).toBeDefined(); + expect(result.packageJsonChanges!.added).toContain('@modelcontextprotocol/server'); + expect(result.packageJsonChanges!.added).not.toContain('@modelcontextprotocol/core'); + + const pkgJson = JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8')); + expect(pkgJson.dependencies['@modelcontextprotocol/core']).toBeUndefined(); + expect(pkgJson.dependencies['@modelcontextprotocol/server']).toBeDefined(); + }); + + it('package.json: still adds core when a schema import survives as a value', () => { + // Guard against over-correcting: a schema used as a value (e.g. `.parse(...)`) keeps its import, + // so core remains a real dependency and must still be added. + const dir = createTempDir(); + writePkgJson(dir, { dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }); + writeFileSync( + path.join(dir, 'lib.ts'), + [ + `import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';`, + `export function parseResult(x: unknown) {`, + ` return CallToolResultSchema.parse(x);`, + `}`, + `` + ].join('\n') + ); + + const result = run(migration, { targetDir: dir }); + + const output = readFileSync(path.join(dir, 'lib.ts'), 'utf8'); + expect(output).toContain('@modelcontextprotocol/core'); + expect(output).toContain('CallToolResultSchema.parse'); + + expect(result.packageJsonChanges).toBeDefined(); + expect(result.packageJsonChanges!.added).toContain('@modelcontextprotocol/core'); + + const pkgJson = JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8')); + expect(pkgJson.dependencies['@modelcontextprotocol/core']).toBeDefined(); + }); + it('does not modify package.json in dry-run mode', () => { const dir = createTempDir(); writePkgJson(dir, { diff --git a/packages/codemod/test/packageJsonUpdater.test.ts b/packages/codemod/test/packageJsonUpdater.test.ts index 27227efd15..9b1e993e2f 100644 --- a/packages/codemod/test/packageJsonUpdater.test.ts +++ b/packages/codemod/test/packageJsonUpdater.test.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import { afterEach, describe, expect, it } from 'vitest'; -import { updatePackageJson } from '../src/utils/packageJsonUpdater.js'; +import { updatePackageJson } from '../src/utils/packageJsonUpdater'; let tempDir: string; @@ -145,7 +145,7 @@ describe('updatePackageJson', () => { expect(deps['@modelcontextprotocol/server']).toBeUndefined(); }); - it('filters out @modelcontextprotocol/core (private package)', () => { + it('filters out @modelcontextprotocol/core-internal (private package)', () => { const dir = createTempDir(); writePkgJson(dir, { dependencies: { @@ -153,15 +153,15 @@ describe('updatePackageJson', () => { } }); - const result = updatePackageJson(dir, new Set(['@modelcontextprotocol/core', '@modelcontextprotocol/server']), false); + const result = updatePackageJson(dir, new Set(['@modelcontextprotocol/core-internal', '@modelcontextprotocol/server']), false); expect(result).toBeDefined(); - expect(result!.added).not.toContain('@modelcontextprotocol/core'); + expect(result!.added).not.toContain('@modelcontextprotocol/core-internal'); expect(result!.added).toContain('@modelcontextprotocol/server'); const pkg = readPkgJson(dir); const deps = pkg.dependencies as Record; - expect(deps['@modelcontextprotocol/core']).toBeUndefined(); + expect(deps['@modelcontextprotocol/core-internal']).toBeUndefined(); }); it('preserves 4-space indentation', () => { diff --git a/packages/codemod/test/projectAnalyzer.test.ts b/packages/codemod/test/projectAnalyzer.test.ts index 0f69eacf79..222894aef7 100644 --- a/packages/codemod/test/projectAnalyzer.test.ts +++ b/packages/codemod/test/projectAnalyzer.test.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import { describe, it, expect, afterEach } from 'vitest'; -import { analyzeProject } from '../src/utils/projectAnalyzer.js'; +import { analyzeProject, resolveTypesPackage } from '../src/utils/projectAnalyzer'; let tempDir: string; @@ -115,7 +115,7 @@ describe('analyzeProject', () => { expect(result.projectType).toBe('server'); }); - it('returns unknown for v1 SDK package (falls through to per-file resolution)', () => { + it('returns unknown for a v1 SDK package with no source signal', () => { const dir = createTempDir(); writeFileSync( path.join(dir, 'package.json'), @@ -127,4 +127,97 @@ describe('analyzeProject', () => { const result = analyzeProject(dir); expect(result.projectType).toBe('unknown'); }); + + describe('source inference for v1 (pre-split) projects', () => { + function v1Project(files: Record): string { + const dir = createTempDir(); + writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } })); + mkdirSync(path.join(dir, 'src'), { recursive: true }); + for (const [name, content] of Object.entries(files)) { + writeFileSync(path.join(dir, 'src', name), content); + } + return dir; + } + + it('infers client from sdk/client subpath usage', () => { + const dir = v1Project({ 'a.ts': `import { Client } from '@modelcontextprotocol/sdk/client/index.js';` }); + expect(analyzeProject(dir).projectType).toBe('client'); + }); + + it('infers server from sdk/server subpath usage', () => { + const dir = v1Project({ 'a.ts': `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';` }); + expect(analyzeProject(dir).projectType).toBe('server'); + }); + + it('infers both when client and server subpaths are used across files', () => { + const dir = v1Project({ + 'client.ts': `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, + 'server.ts': `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';` + }); + expect(analyzeProject(dir).projectType).toBe('both'); + }); + + it('infers from an extensionless / bare sdk subpath specifier', () => { + const dir = v1Project({ 'a.ts': `import { McpServer } from '@modelcontextprotocol/sdk/server';` }); + expect(analyzeProject(dir).projectType).toBe('server'); + }); + + it('stays unknown when only shared paths are imported', () => { + const dir = v1Project({ 'a.ts': `import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';` }); + expect(analyzeProject(dir).projectType).toBe('unknown'); + }); + + it('ignores an import path that appears only in a comment (not a quoted specifier)', () => { + // A real client import plus a comment mentioning the server subpath. A whole-file substring + // scan would flip this to "both"; the quote-anchored match keeps it "client". + const dir = v1Project({ + 'a.ts': [ + `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, + `// previously imported from @modelcontextprotocol/sdk/server/mcp.js`, + '' + ].join('\n') + }); + expect(analyzeProject(dir).projectType).toBe('client'); + }); + + it('infers from source even without a package.json', () => { + const dir = createTempDir(); + mkdirSync(path.join(dir, 'src'), { recursive: true }); + writeFileSync(path.join(dir, 'src', 'a.ts'), `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`); + expect(analyzeProject(path.join(dir, 'src')).projectType).toBe('client'); + }); + + it('ignores node_modules when scanning source', () => { + const dir = v1Project({ 'a.ts': `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';` }); + mkdirSync(path.join(dir, 'node_modules', 'pkg'), { recursive: true }); + writeFileSync( + path.join(dir, 'node_modules', 'pkg', 'index.ts'), + `import { Client } from '@modelcontextprotocol/sdk/client/index.js';` + ); + // Only the server import in src counts; the client import under node_modules is skipped. + expect(analyzeProject(dir).projectType).toBe('server'); + }); + }); +}); + +describe('resolveTypesPackage', () => { + it('emits an info note (not a warning) for a both-project ambiguous file', () => { + const sink = { filePath: 'f.ts', line: 1, diagnostics: [] as import('../src/types').Diagnostic[] }; + const target = resolveTypesPackage({ projectType: 'both' }, false, false, sink); + expect(target).toBe('@modelcontextprotocol/server'); + expect(sink.diagnostics).toHaveLength(1); + expect(sink.diagnostics[0]!.level).toBe('info'); + }); + + it('emits an action-required warning for a genuinely unknown project', () => { + const sink = { filePath: 'f.ts', line: 1, diagnostics: [] as import('../src/types').Diagnostic[] }; + resolveTypesPackage({ projectType: 'unknown' }, false, false, sink); + expect(sink.diagnostics).toHaveLength(1); + expect(sink.diagnostics[0]!.level).toBe('warning'); + }); + + it('resolves by per-file signal regardless of project type', () => { + expect(resolveTypesPackage({ projectType: 'both' }, true, false)).toBe('@modelcontextprotocol/client'); + expect(resolveTypesPackage({ projectType: 'unknown' }, false, true)).toBe('@modelcontextprotocol/server'); + }); }); diff --git a/packages/codemod/test/v1-to-v2/authSchemaNames.test.ts b/packages/codemod/test/v1-to-v2/authSchemaNames.test.ts new file mode 100644 index 0000000000..2fd4631c2d --- /dev/null +++ b/packages/codemod/test/v1-to-v2/authSchemaNames.test.ts @@ -0,0 +1,36 @@ +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +import { AUTH_SCHEMA_NAMES, AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT } from '../../src/migrations/v1-to-v2/mappings/authSchemaNames'; + +describe('AUTH_SCHEMA_NAMES (codemod auth schema-routing allowlist)', () => { + it('routes only auth schemas that @modelcontextprotocol/core exports (drift guard)', () => { + // The import transform routes a `*Schema` symbol from sdk/shared/auth.js to core only when + // its name is in AUTH_SCHEMA_NAMES, so EVERY name here MUST be exported by core — otherwise + // the rewritten import would have no exported member. AUTH_SCHEMA_NAMES is the v1 auth-schema set, + // a SUBSET of core's auth exports: core may export more (v2-only schemas such as + // IdJagTokenExchangeResponseSchema) that v1 never had and the codemod never encounters. Read + // core's barrel directly (the `export { … } from '…/core-internal/auth'` block) so they cannot drift. + const src = readFileSync(fileURLToPath(new URL('../../../core/src/index.ts', import.meta.url)), 'utf8'); + const closeIdx = src.indexOf("} from '@modelcontextprotocol/core-internal/auth'"); + const openIdx = src.lastIndexOf('export {', closeIdx); + const block = src.slice(openIdx + 'export {'.length, closeIdx); + const coreAuthExports = new Set([...block.matchAll(/\b(\w+Schema)\b/g)].map(m => m[1])); + + const notExportedByCore = [...AUTH_SCHEMA_NAMES].filter(name => !coreAuthExports.has(name)); + expect(notExportedByCore).toEqual([]); + // The v1 auth-schema set is frozen; pin its size so an accidental add/remove is caught. + expect(AUTH_SCHEMA_NAMES.size).toBe(11); + }); + + it('keeps the no-v2-home auth schemas OUT of the routing allowlist', () => { + // SafeUrlSchema/OptionalSafeUrlSchema have no public v2 export, so they must NOT be routed to + // core (the import transform flags them instead). Guard the two sets stay disjoint. + for (const name of AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT) { + expect(AUTH_SCHEMA_NAMES.has(name)).toBe(false); + } + expect([...AUTH_SCHEMA_NAMES_NO_V2_PUBLIC_EXPORT].sort()).toEqual(['OptionalSafeUrlSchema', 'SafeUrlSchema']); + }); +}); diff --git a/packages/codemod/test/v1-to-v2/specSchemaNames.test.ts b/packages/codemod/test/v1-to-v2/specSchemaNames.test.ts new file mode 100644 index 0000000000..2a5aca1267 --- /dev/null +++ b/packages/codemod/test/v1-to-v2/specSchemaNames.test.ts @@ -0,0 +1,21 @@ +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +import { SPEC_SCHEMA_NAMES } from '../../src/migrations/v1-to-v2/mappings/specSchemaNames'; + +describe('SPEC_SCHEMA_NAMES (codemod schema-routing allowlist)', () => { + it("matches @modelcontextprotocol/core's exported schema set exactly (drift guard)", () => { + // The import transform routes a `*Schema` symbol from sdk/types.js to core only when the + // symbol's (rename-resolved) name is in this set. It must therefore equal core's actual + // public exports: a name missing here would be misrouted to client/server (which export no Zod + // schema values), and a name here that core does not export would produce a broken import. + // Read core's barrel directly so the two cannot silently drift. + const src = readFileSync(fileURLToPath(new URL('../../../core/src/index.ts', import.meta.url)), 'utf8'); + const block = src.slice(src.indexOf('export {') + 'export {'.length, src.indexOf('} from')); + const coreExports = [...new Set([...block.matchAll(/\b(\w+Schema)\b/g)].map(m => m[1]))].sort(); + expect([...SPEC_SCHEMA_NAMES].sort()).toEqual(coreExports); + expect(coreExports.length).toBeGreaterThanOrEqual(154); + }); +}); diff --git a/packages/codemod/test/v1-to-v2/transforms/contextTypes.test.ts b/packages/codemod/test/v1-to-v2/transforms/contextTypes.test.ts index ac8ea1b235..039fcf559d 100644 --- a/packages/codemod/test/v1-to-v2/transforms/contextTypes.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/contextTypes.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { contextTypesTransform } from '../../../src/migrations/v1-to-v2/transforms/contextTypes.js'; -import type { TransformContext } from '../../../src/types.js'; +import { contextTypesTransform } from '../../../src/migrations/v1-to-v2/transforms/contextTypes'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; diff --git a/packages/codemod/test/v1-to-v2/transforms/handlerRegistration.test.ts b/packages/codemod/test/v1-to-v2/transforms/handlerRegistration.test.ts index e4602910de..443814d7a5 100644 --- a/packages/codemod/test/v1-to-v2/transforms/handlerRegistration.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/handlerRegistration.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { handlerRegistrationTransform } from '../../../src/migrations/v1-to-v2/transforms/handlerRegistration.js'; -import type { TransformContext } from '../../../src/types.js'; +import { handlerRegistrationTransform } from '../../../src/migrations/v1-to-v2/transforms/handlerRegistration'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; @@ -93,7 +93,7 @@ describe('handler-registration transform', () => { it('does not replace schema identifiers from non-MCP packages', () => { const input = [ - `import { CallToolRequestSchema } from './local-schemas.js';`, + `import { CallToolRequestSchema } from './local-schemas';`, `server.setRequestHandler(CallToolRequestSchema, async (request) => {`, ` return { content: [] };`, `});`, @@ -106,14 +106,14 @@ describe('handler-registration transform', () => { it('does not rewrite local import when aliased MCP import has same export name', () => { const input = [ - `import { CallToolRequestSchema } from './local-schemas.js';`, + `import { CallToolRequestSchema } from './local-schemas';`, `import { CallToolRequestSchema as McpSchema } from '@modelcontextprotocol/sdk/types.js';`, `server.setRequestHandler(CallToolRequestSchema, async () => ({ content: [] }));`, `validateSchema(McpSchema);`, '' ].join('\n'); const result = applyTransform(input); - expect(result).toContain("from './local-schemas.js'"); + expect(result).toContain("from './local-schemas'"); expect(result).toContain('setRequestHandler(CallToolRequestSchema'); expect(result).not.toContain("'tools/call'"); }); @@ -219,6 +219,41 @@ describe('handler-registration transform', () => { expect(result).not.toContain('ElicitationCompleteNotificationSchema'); }); + it('emits a tasks-removed diagnostic for GetTaskRequestSchema (does NOT rewrite to tasks/get)', () => { + const input = [ + `import { GetTaskRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, + `server.setRequestHandler(GetTaskRequestSchema, async () => ({}));`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = handlerRegistrationTransform.apply(sourceFile, ctx); + const text = sourceFile.getFullText(); + expect(text).not.toContain("'tasks/get'"); + expect(text).toContain('setRequestHandler(GetTaskRequestSchema'); + expect(result.changesCount).toBe(0); + expect(result.diagnostics.length).toBe(1); + expect(result.diagnostics[0]!.message).toContain('Task handler registration'); + expect(result.diagnostics[0]!.message).toContain('SEP-2663'); + }); + + it('emits a tasks-removed diagnostic for TaskStatusNotificationSchema (does NOT rewrite)', () => { + const input = [ + `import { TaskStatusNotificationSchema } from '@modelcontextprotocol/sdk/types.js';`, + `client.setNotificationHandler(TaskStatusNotificationSchema, async () => {});`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = handlerRegistrationTransform.apply(sourceFile, ctx); + const text = sourceFile.getFullText(); + expect(text).not.toContain("'notifications/tasks/status'"); + expect(text).toContain('setNotificationHandler(TaskStatusNotificationSchema'); + expect(result.changesCount).toBe(0); + expect(result.diagnostics.length).toBe(1); + expect(result.diagnostics[0]!.message).toContain('Task handler registration'); + }); + it('does not emit diagnostic when first arg is a string literal (v2 style)', () => { const input = [`server.setRequestHandler('tools/call', async (request) => {`, ` return { content: [] };`, `});`, ''].join('\n'); const project = new Project({ useInMemoryFileSystem: true }); diff --git a/packages/codemod/test/v1-to-v2/transforms/importPaths.test.ts b/packages/codemod/test/v1-to-v2/transforms/importPaths.test.ts index 74fd5f3cb7..4cd43967c0 100644 --- a/packages/codemod/test/v1-to-v2/transforms/importPaths.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/importPaths.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { importPathsTransform } from '../../../src/migrations/v1-to-v2/transforms/importPaths.js'; -import type { TransformContext } from '../../../src/types.js'; +import { importPathsTransform } from '../../../src/migrations/v1-to-v2/transforms/importPaths'; +import type { TransformContext } from '../../../src/types'; function applyTransform(code: string, context: TransformContext = { projectType: 'both' }): string { const project = new Project({ useInMemoryFileSystem: true }); @@ -74,25 +74,364 @@ describe('import-paths transform', () => { expect(result.diagnostics[0]!.message).toContain('SSEServerTransport is deprecated'); }); - it('resolves sdk/types.js based on sibling client imports', () => { + it('resolves a sdk/types.js TYPE import based on sibling client imports', () => { const input = [ `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, - `import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';`, + `import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';`, '' ].join('\n'); const result = applyTransform(input, { projectType: 'both' }); expect(result).toContain(`from "@modelcontextprotocol/client"`); + expect(result).toContain('CallToolResult'); + expect(result).not.toContain('@modelcontextprotocol/core'); + }); + + it('resolves a sdk/types.js TYPE import based on sibling server imports', () => { + const input = [ + `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, + `import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'both' }); + expect(result).toContain(`from "@modelcontextprotocol/server"`); + expect(result).toContain('CallToolResult'); + }); + + it('routes *Schema imports from sdk/types.js to @modelcontextprotocol/core', () => { + const input = `import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); expect(result).toContain('CallToolResultSchema'); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('routes schemas to core regardless of client/server sibling context', () => { + // The only sibling is a client import, but the schema must still go to core. + const input = [ + `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, + `import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'both' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + expect(result).toContain('ListToolsResultSchema'); }); - it('resolves sdk/types.js based on sibling server imports', () => { + it('splits a mixed type + schema import: type resolves by context, schema to core', () => { const input = [ `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';`, - `import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';`, + `import { CallToolResult, CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';`, '' ].join('\n'); const result = applyTransform(input, { projectType: 'both' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + expect(result).toContain(`from "@modelcontextprotocol/server"`); + expect(result).toContain('CallToolResult'); + expect(result).toContain('CallToolResultSchema'); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('splits an aliased types.js import: schema constant to core, aliased type to server', () => { + // The presence of an alias (`Tool as SDKTool`) must not force the whole import into one package; + // each symbol still routes to its correct v2 target, with the alias preserved. + const input = [ + `import { CreateMessageRequestSchema, ClientCapabilities, Tool as SDKTool } from '@modelcontextprotocol/sdk/types.js';`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toMatch(/import\s*\{[^}]*\bCreateMessageRequestSchema\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/core["']/); + expect(result).toMatch(/import\s*\{[^}]*\bClientCapabilities\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/server["']/); + expect(result).toContain('Tool as SDKTool'); + // the schema constant must NOT end up imported from @modelcontextprotocol/server + expect(result).not.toMatch(/import\s*\{[^}]*CreateMessageRequestSchema[^}]*\}\s*from\s*["']@modelcontextprotocol\/server["']/); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('does not emit a "mixes symbols" diagnostic for an aliased mixed import (it splits instead)', () => { + const input = `import { CreateMessageRequestSchema, Tool as SDKTool } from '@modelcontextprotocol/sdk/types.js';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + expect(result.diagnostics.some(d => d.message.includes('mixes symbols'))).toBe(false); + }); + + it('preserves a leading file-header comment when rewriting the first SDK import', () => { + const input = [ + `/**`, + ` * Web-standard transport for MCP.`, + ` */`, + `import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';`, + `import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain('Web-standard transport for MCP.'); + expect(result).toContain('@modelcontextprotocol/server'); + expect(result).not.toContain('@modelcontextprotocol/sdk/'); + }); + + it('does not duplicate a multi-block leading header (blank line) when rewriting the first import in place', () => { + // The first SDK import is a namespace import, so it is rewritten in place (setModuleSpecifier) and + // its leading comments survive. The header is two // blocks separated by a BLANK line. A `\n`-join + // of the comment ranges loses that blank line, so the survival check would mis-fire and re-insert + // the header — duplicating it. The captured text must match the file's bytes exactly. + const input = [ + `// Copyright ACME`, + ``, + `// Notes about the types module`, + `import * as types from '@modelcontextprotocol/sdk/types.js';`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'server' }); + expect(result.split('// Copyright ACME').length - 1).toBe(1); + expect(result).toContain('@modelcontextprotocol/server'); + }); + + it('does not duplicate a CRLF leading header when rewriting the first import in place', () => { + // Same in-place rewrite, but the two // header lines are separated by CRLF. A `\n`-join never + // matches the file's `\r\n`, so the survival check would mis-fire and duplicate the header. + const input = `// Copyright ACME\r\n// Licensed MIT\r\n\r\nimport * as types from '@modelcontextprotocol/sdk/types.js';\r\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result.split('// Copyright ACME').length - 1).toBe(1); + expect(result).toContain('@modelcontextprotocol/server'); + }); + + it('routes OAuth *Schema from sdk/shared/auth.js to core; the TYPE resolves by context', () => { + // OAuthTokensSchema is a Zod schema re-exported by core (AUTH_SCHEMA_NAMES), so route it + // there — `OAuthTokensSchema.parse(...)` keeps working. OAuthTokens (the type) has no schema-name + // match and resolves by context to @modelcontextprotocol/client. + const input = [ + `import { OAuthTokensSchema, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';`, + `const t = OAuthTokensSchema.parse(raw);`, + `let x: OAuthTokens;`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'client' }); + expect(result).toMatch(/import\s*\{[^}]*\bOAuthTokensSchema\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/core["']/); + expect(result).toMatch(/import\s*\{[^}]*\bOAuthTokens\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/client["']/); + expect(result).toContain('OAuthTokensSchema.parse(raw)'); + expect(result).not.toContain('@modelcontextprotocol/sdk/shared/auth'); + }); + + it('does not emit a project-type note when every symbol routes to core (both project)', () => { + // A types.js import of nothing but `*Schema` constants routes entirely to core, so the + // context package is never used — resolveTypesPackage must not be called, and no "both"-project + // info note should be emitted. + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile( + 'test.ts', + `import { CallToolResultSchema, ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';\n` + ); + const result = importPathsTransform.apply(sourceFile, { projectType: 'both' }); + expect(result.diagnostics.some(d => /both client and server|determine project type/i.test(d.message))).toBe(false); + expect(sourceFile.getFullText()).toContain('@modelcontextprotocol/core'); + expect(sourceFile.getFullText()).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('does not warn about project type when an auth-schema-only import routes entirely to core (unknown project)', () => { + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile( + 'test.ts', + `import { OAuthTokensSchema, OAuthMetadataSchema } from '@modelcontextprotocol/sdk/shared/auth.js';\n` + ); + const result = importPathsTransform.apply(sourceFile, { projectType: 'unknown' }); + expect(result.diagnostics.some(d => /determine project type/i.test(d.message))).toBe(false); + expect(sourceFile.getFullText()).toContain('@modelcontextprotocol/core'); + }); + + it('still warns about project type when a non-schema symbol falls through to context (unknown project)', () => { + // Control: `Tool` is a type with no schema-name match, so it falls through to context resolution — + // the warning must still fire (lazy resolution must not suppress genuine fall-throughs). + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile( + 'test.ts', + `import { CallToolResultSchema, Tool } from '@modelcontextprotocol/sdk/types.js';\n` + ); + const result = importPathsTransform.apply(sourceFile, { projectType: 'unknown' }); + expect(result.diagnostics.some(d => /determine project type/i.test(d.message))).toBe(true); + }); + + it('splits a mixed default + named schema import — schema to core, default to context', () => { + // The named `CallToolResultSchema` must route to core even though a default import is present; + // the default binding (which can't be split) moves to the context package. Pre-fix the whole import + // moved to context and the schema silently became a "no exported member" error. + const result = applyTransform(`import sdk, { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';\n`, { + projectType: 'server' + }); + expect(result).toMatch(/import\s*\{[^}]*\bCallToolResultSchema\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/core["']/); + expect(result).toMatch(/import\s+sdk\s+from\s*["']@modelcontextprotocol\/server["']/); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('does not rewrite schema .parse() usages (migrates as an import-path swap)', () => { + const input = [ + `import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';`, + `const r = CallToolResultSchema.parse(value);`, + '' + ].join('\n'); + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain('CallToolResultSchema.parse(value)'); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + }); + + it('routes elicitation primitive *Schema TYPE names from sdk/types.js by context, not to core', () => { + // These names END in `Schema` but are TYPES; their Zod constant is `SchemaSchema`. They + // must resolve to the context package (where the types live), never to core (which only + // exports the `*SchemaSchema` constants) — otherwise the codemod emits a broken import. + const elicitationTypeNames = [ + 'BooleanSchema', + 'StringSchema', + 'NumberSchema', + 'EnumSchema', + 'SingleSelectEnumSchema', + 'MultiSelectEnumSchema', + 'TitledSingleSelectEnumSchema', + 'UntitledSingleSelectEnumSchema', + 'TitledMultiSelectEnumSchema', + 'UntitledMultiSelectEnumSchema', + 'LegacyTitledEnumSchema' + ]; + for (const typeName of elicitationTypeNames) { + const input = `import { ${typeName} } from '@modelcontextprotocol/sdk/types.js';\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result, typeName).toContain(`from "@modelcontextprotocol/server"`); + expect(result, typeName).not.toContain('@modelcontextprotocol/core'); + expect(result, typeName).toContain(typeName); + } + }); + + it('splits a primitive-schema TYPE from its matching schema CONSTANT (BooleanSchema vs BooleanSchemaSchema)', () => { + // They differ only by a trailing `Schema`, which the suffix heuristic could not distinguish. + // The constant goes to core; the type resolves by context. + const input = `import { BooleanSchema, BooleanSchemaSchema } from '@modelcontextprotocol/sdk/types.js';\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + expect(result).toContain('BooleanSchemaSchema'); expect(result).toContain(`from "@modelcontextprotocol/server"`); + expect(result).toMatch(/BooleanSchema\b/); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('routes a renamed spec schema (JSONRPCErrorSchema) from sdk/types.js to core', () => { + // JSONRPCErrorSchema → JSONRPCErrorResponseSchema, a core export. Membership is checked + // against the rename-resolved name; the symbolRenames transform applies the rename afterward, + // so importPaths alone leaves the name unchanged but routes it to core. + const input = `import { JSONRPCErrorSchema } from '@modelcontextprotocol/sdk/types.js';\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + expect(result).toContain('JSONRPCErrorSchema'); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('routes JSONRPCResponseSchema (result-only in v1) from sdk/types.js to core', () => { + // v1's JSONRPCResponseSchema validated only result responses; v2 reuses the name for a union. + // The rename to JSONRPCResultResponseSchema (a core export) preserves v1 behavior; importPaths + // routes it to core against the rename-resolved name (symbolRenames applies the rename after). + const input = `import { JSONRPCResponseSchema } from '@modelcontextprotocol/sdk/types.js';\n`; + const result = applyTransform(input, { projectType: 'server' }); + expect(result).toContain(`from "@modelcontextprotocol/core"`); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + expect(result).not.toContain(`from "@modelcontextprotocol/server"`); + }); + + it('flags a SafeUrlSchema import from sdk/shared/auth.js (no public v2 equivalent)', () => { + // SafeUrlSchema/OptionalSafeUrlSchema were internal URL field-validators in v1; v2's core + // deliberately does not re-export them, so there is no v2 home — emit guidance instead of silently + // routing to a package that has no such export. + const input = `import { SafeUrlSchema, OptionalSafeUrlSchema } from '@modelcontextprotocol/sdk/shared/auth.js';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const messages = result.diagnostics.map(d => d.message); + expect(messages.some(m => m.includes('SafeUrlSchema') && m.includes('no public v2 equivalent'))).toBe(true); + expect(messages.some(m => m.includes('OptionalSafeUrlSchema') && m.includes('no public v2 equivalent'))).toBe(true); + }); + + it('flags a star re-export of sdk/types.js that drops the moved schema constants', () => { + // `export * from '…/types.js'` cannot be routed per-symbol, so the Zod *Schema constants (now in + // core) silently disappear from the re-exporting barrel. Surface that for the user. + const input = `export * from '@modelcontextprotocol/sdk/types.js';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const messages = result.diagnostics.map(d => d.message).join('\n'); + expect(messages).toContain('@modelcontextprotocol/core'); + expect(messages).toMatch(/Star re-export/i); + }); + + it('flags a star re-export of sdk/shared/auth.js (schema constants move to core)', () => { + const input = `export * from '@modelcontextprotocol/sdk/shared/auth.js';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + expect(result.diagnostics.map(d => d.message).join('\n')).toContain('@modelcontextprotocol/core'); + }); + + it('emits a split diagnostic for a re-export mixing a spec schema and a *Schema type (no silent breakage)', () => { + // The `*Schema` suffix would have routed BooleanSchema to core silently (no such export); + // membership routing instead surfaces the mismatch so the user splits the re-export manually. + const input = `export { CallToolResultSchema, BooleanSchema } from '@modelcontextprotocol/sdk/types.js';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + expect(result.diagnostics.some(d => d.message.includes('mixes symbols') && d.message.includes('Split'))).toBe(true); + }); + + it('flags *Schema accesses through a namespace import of sdk/types.js (cannot be split)', () => { + const input = [ + `import * as types from '@modelcontextprotocol/sdk/types.js';`, + `const r = types.CallToolResultSchema.parse(value);`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const messages = result.diagnostics.map(d => d.message).join('\n'); + // The namespace can't be split, so the schema can't be auto-routed — but the user must be told. + expect(messages).toContain('@modelcontextprotocol/core'); + expect(messages).toContain('CallToolResultSchema'); + // The namespace import itself still moves to the context package (its types live there). + // (setModuleSpecifier preserves the original quote style, so match quote-agnostically.) + expect(sourceFile.getFullText()).toContain('@modelcontextprotocol/server'); + }); + + it('suggests the v2 (rename-resolved) name in the namespace schema-access diagnostic', () => { + // JSONRPCErrorSchema is re-exported by core as JSONRPCErrorResponseSchema; the suggested + // import must use the v2 name (the v1 name has no exported member), and mention the rename. + const input = [ + `import * as types from '@modelcontextprotocol/sdk/types.js';`, + `const r = types.JSONRPCErrorSchema.safeParse(value);`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const msg = result.diagnostics.map(d => d.message).join('\n'); + expect(msg).toContain("import { JSONRPCErrorResponseSchema } from '@modelcontextprotocol/core'"); + expect(msg).toContain('JSONRPCErrorSchema → JSONRPCErrorResponseSchema'); + expect(msg).not.toContain('import { JSONRPCErrorSchema } from'); + }); + + it('does not flag a namespace import of sdk/types.js that only accesses types', () => { + const input = [`import * as types from '@modelcontextprotocol/sdk/types.js';`, `const t: types.CallToolResult = value;`, ''].join( + '\n' + ); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + expect(result.diagnostics.map(d => d.message).join('\n')).not.toContain('@modelcontextprotocol/core'); + }); + + it('resolves extensionless sdk/types (no .js suffix) the same as sdk/types.js', () => { + const input = `import { CallToolResult } from '@modelcontextprotocol/sdk/types';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const output = sourceFile.getFullText(); + expect(output).toContain(`from "@modelcontextprotocol/server"`); + expect(output).toContain('CallToolResult'); + expect(output).not.toContain('@modelcontextprotocol/sdk'); + expect(result.diagnostics.map(d => d.message).join('\n')).not.toContain('Unknown SDK import path'); }); it('preserves type-only imports separately', () => { @@ -371,6 +710,17 @@ describe('import-paths transform', () => { expect(result.diagnostics.some(d => d.message.includes('SSEServerTransport is deprecated'))).toBe(true); }); + it('resolves extensionless sdk/types re-export (no .js suffix)', () => { + const input = `export { CallToolResult } from '@modelcontextprotocol/sdk/types';\n`; + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); + const output = sourceFile.getFullText(); + expect(output).toContain('@modelcontextprotocol/server'); + expect(output).not.toContain('@modelcontextprotocol/sdk'); + expect(result.diagnostics.map(d => d.message).join('\n')).not.toContain('Unknown SDK export path'); + }); + it('includes server-legacy in usedPackages for SSE import', () => { const project = new Project({ useInMemoryFileSystem: true }); const sourceFile = project.createSourceFile( @@ -437,7 +787,7 @@ describe('import-paths transform', () => { expect(result.diagnostics[0]!.message).toContain('RequestHandlerExtra'); }); - it('emits warning for aliased import mixing symbols from different v2 packages', () => { + it('splits an aliased import mixing symbols from different v2 packages (no longer bails)', () => { const input = [ `import { StreamableHTTPServerTransport as T, EventStore } from '@modelcontextprotocol/sdk/server/streamableHttp.js';`, '' @@ -445,8 +795,13 @@ describe('import-paths transform', () => { const project = new Project({ useInMemoryFileSystem: true }); const sourceFile = project.createSourceFile('test.ts', input); const result = importPathsTransform.apply(sourceFile, { projectType: 'server' }); - expect(result.diagnostics.length).toBeGreaterThan(0); - expect(result.diagnostics.some(d => d.message.includes('mixes symbols') && d.message.includes('Split'))).toBe(true); + const output = sourceFile.getFullText(); + // transport (aliased + renamed) → /node; companion type → /server + expect(output).toContain('NodeStreamableHTTPServerTransport as T'); + expect(output).toContain('@modelcontextprotocol/node'); + expect(output).toMatch(/import\s*\{[^}]*\bEventStore\b[^}]*\}\s*from\s*["']@modelcontextprotocol\/server["']/); + expect(output).not.toContain('@modelcontextprotocol/sdk'); + expect(result.diagnostics.some(d => d.message.includes('mixes symbols'))).toBe(false); }); it('emits warning for re-export mixing symbols from different v2 packages', () => { diff --git a/packages/codemod/test/v1-to-v2/transforms/mcpServerApi.test.ts b/packages/codemod/test/v1-to-v2/transforms/mcpServerApi.test.ts index e775a0c5ff..c9392aa830 100644 --- a/packages/codemod/test/v1-to-v2/transforms/mcpServerApi.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/mcpServerApi.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { mcpServerApiTransform } from '../../../src/migrations/v1-to-v2/transforms/mcpServerApi.js'; -import type { TransformContext } from '../../../src/types.js'; +import { mcpServerApiTransform } from '../../../src/migrations/v1-to-v2/transforms/mcpServerApi'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; const MCP_IMPORT = `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n`; diff --git a/packages/codemod/test/v1-to-v2/transforms/mockPaths.test.ts b/packages/codemod/test/v1-to-v2/transforms/mockPaths.test.ts index 2922618986..ed613ddc2f 100644 --- a/packages/codemod/test/v1-to-v2/transforms/mockPaths.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/mockPaths.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { mockPathsTransform } from '../../../src/migrations/v1-to-v2/transforms/mockPaths.js'; -import type { TransformContext } from '../../../src/types.js'; +import { mockPathsTransform } from '../../../src/migrations/v1-to-v2/transforms/mockPaths'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; @@ -63,6 +63,19 @@ describe('mock-paths transform', () => { expect(result).toContain(`'@modelcontextprotocol/server'`); expect(result).not.toContain('@modelcontextprotocol/sdk'); }); + + it('rewrites extensionless sdk/types path (no .js suffix)', () => { + const input = [ + `vi.doMock('@modelcontextprotocol/sdk/types', async importOriginal => {`, + ` const original = await importOriginal();`, + ` return { ...original, isInitializeRequest: mockFn };`, + `});`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain(`'@modelcontextprotocol/server'`); + expect(result).not.toContain('@modelcontextprotocol/sdk'); + }); }); describe('vi.mock', () => { @@ -325,6 +338,190 @@ describe('mock-paths transform', () => { }); }); + describe('schema constant routing (schemaSymbolTarget)', () => { + it('routes a vi.mock factory of only spec *Schema constants to core', () => { + const input = [`vi.mock('@modelcontextprotocol/sdk/types.js', () => ({`, ` CallToolResultSchema: vi.fn()`, `}));`, ''].join( + '\n' + ); + const result = applyTransform(input); + expect(result).toContain(`'@modelcontextprotocol/core'`); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + // The schema constant lives in core, never the context (server) package. + expect(result).not.toContain(`'@modelcontextprotocol/server'`); + }); + + it('routes a vi.mock factory of only auth *Schema constants to core', () => { + const input = [ + `vi.mock('@modelcontextprotocol/sdk/shared/auth.js', () => ({`, + ` OAuthTokensSchema: vi.fn()`, + `}));`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain(`'@modelcontextprotocol/core'`); + expect(result).not.toContain('@modelcontextprotocol/sdk/shared/auth'); + }); + + it('routes a destructured dynamic import of only *Schema constants to core', () => { + const input = [`const { CallToolResultSchema } = await import('@modelcontextprotocol/sdk/types.js');`, ''].join('\n'); + const result = applyTransform(input); + expect(result).toContain(`import('@modelcontextprotocol/core')`); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('renames JSONRPCResponseSchema and routes it to core in a mock factory', () => { + const input = [`vi.mock('@modelcontextprotocol/sdk/types.js', () => ({`, ` JSONRPCResponseSchema: vi.fn()`, `}));`, ''].join( + '\n' + ); + const result = applyTransform(input); + expect(result).toContain(`'@modelcontextprotocol/core'`); + expect(result).toContain('JSONRPCResultResponseSchema'); + expect(result).not.toMatch(/(? { + const input = [ + `vi.mock('@modelcontextprotocol/sdk/types.js', () => ({`, + ` CallToolResultSchema: vi.fn(),`, + ` McpError: vi.fn()`, + `}));`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect(result.diagnostics.some(d => d.message.includes('mixes symbols that belong to different v2 packages'))).toBe(true); + }); + + it('flags a destructured dynamic import mixing a *Schema constant and a type', () => { + const input = [`const { CallToolResultSchema, McpError } = await import('@modelcontextprotocol/sdk/types.js');`, ''].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect(result.diagnostics.some(d => d.message.includes('belong to different v2 packages'))).toBe(true); + }); + + it('routes a destructured .then() param of only *Schema constants to core', () => { + const input = [ + `import('@modelcontextprotocol/sdk/types.js').then(({ CallToolResultSchema }) => CallToolResultSchema.parse(value));`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain(`import('@modelcontextprotocol/core')`); + expect(result).not.toContain('@modelcontextprotocol/sdk/types'); + }); + + it('renames a *Schema in a destructured .then() param and routes it to core', () => { + const input = [ + `import('@modelcontextprotocol/sdk/types.js').then(({ JSONRPCResponseSchema }) => JSONRPCResponseSchema.parse(value));`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain(`import('@modelcontextprotocol/core')`); + expect(result).toContain('JSONRPCResultResponseSchema'); + }); + + it('flags a destructured .then() param mixing a *Schema constant and a type', () => { + const input = [ + `import('@modelcontextprotocol/sdk/types.js').then(({ CallToolResultSchema, McpError }) => CallToolResultSchema.parse(value));`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect(result.diagnostics.some(d => d.message.includes('belong to different v2 packages'))).toBe(true); + }); + }); + + describe('lazy context resolution (no spurious project-type diagnostic)', () => { + it('does not warn about project type for a schema-only vi.mock factory (unknown project)', () => { + // The factory routes entirely to core, so the context package is never used — resolveTypesPackage + // must not emit a "could not determine project type" warning. + const input = [`vi.mock('@modelcontextprotocol/sdk/types.js', () => ({`, ` CallToolResultSchema: vi.fn()`, `}));`, ''].join( + '\n' + ); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, { projectType: 'unknown' }); + expect(result.diagnostics.some(d => /determine project type/i.test(d.message))).toBe(false); + expect(sourceFile.getFullText()).toContain('@modelcontextprotocol/core'); + }); + + it('does not emit a both-project note for a schema-only destructured dynamic import (both project)', () => { + const input = [`const { OAuthTokensSchema } = await import('@modelcontextprotocol/sdk/shared/auth.js');`, ''].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, { projectType: 'both' }); + expect(result.diagnostics.some(d => /both client and server|determine project type/i.test(d.message))).toBe(false); + expect(sourceFile.getFullText()).toContain('@modelcontextprotocol/core'); + }); + + it('still warns about project type for a non-schema vi.mock factory (unknown project)', () => { + // Control: isInitializeRequest is a guard (not a schema constant), so the factory falls through to + // context resolution — the warning must still fire (lazy resolution must not suppress real fall-throughs). + const input = [`vi.mock('@modelcontextprotocol/sdk/types.js', () => ({`, ` isInitializeRequest: vi.fn()`, `}));`, ''].join( + '\n' + ); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, { projectType: 'unknown' }); + expect(result.diagnostics.some(d => /determine project type/i.test(d.message))).toBe(true); + }); + }); + + describe('non-destructured / .then dynamic import schema access (schemaSymbolTarget)', () => { + it('flags schema access on a non-destructured awaited dynamic import (types.js)', () => { + const input = [ + `const mod = await import('@modelcontextprotocol/sdk/types.js');`, + `const r = mod.CallToolResultSchema.parse(value);`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect( + result.diagnostics.some(d => d.message.includes('@modelcontextprotocol/core') && d.message.includes('CallToolResultSchema')) + ).toBe(true); + }); + + it('flags schema access in a .then() chain (shared/auth.js)', () => { + const input = [`import('@modelcontextprotocol/sdk/shared/auth.js').then(m => m.OAuthTokensSchema.parse(value));`, ''].join( + '\n' + ); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect( + result.diagnostics.some(d => d.message.includes('@modelcontextprotocol/core') && d.message.includes('OAuthTokensSchema')) + ).toBe(true); + }); + + it('notes the rename for a renamed schema accessed in a .then() chain', () => { + const input = [`import('@modelcontextprotocol/sdk/types.js').then(m => m.JSONRPCResponseSchema.parse(value));`, ''].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect( + result.diagnostics.some( + d => d.message.includes('JSONRPCResponseSchema') && d.message.includes('JSONRPCResultResponseSchema') + ) + ).toBe(true); + }); + + it('does not flag a non-destructured dynamic import with no schema access', () => { + // Control: `mod` is only used for a guard (not a schema constant), so no schema-moved-to-core note. + const input = [ + `const mod = await import('@modelcontextprotocol/sdk/types.js');`, + `const ok = mod.isInitializeRequest(value);`, + '' + ].join('\n'); + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile('test.ts', input); + const result = mockPathsTransform.apply(sourceFile, ctx); + expect(result.diagnostics.some(d => d.message.includes('moved to @modelcontextprotocol/core'))).toBe(false); + }); + }); + describe('validator subpath rewrites', () => { it('rewrites vi.mock of validator provider to the subpath', () => { const input = [ diff --git a/packages/codemod/test/v1-to-v2/transforms/removedApis.test.ts b/packages/codemod/test/v1-to-v2/transforms/removedApis.test.ts index b2ba1995e3..bf1001978a 100644 --- a/packages/codemod/test/v1-to-v2/transforms/removedApis.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/removedApis.test.ts @@ -1,9 +1,9 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { removedApisTransform } from '../../../src/migrations/v1-to-v2/transforms/removedApis.js'; -import type { TransformContext } from '../../../src/types.js'; -import { DiagnosticLevel } from '../../../src/types.js'; +import { removedApisTransform } from '../../../src/migrations/v1-to-v2/transforms/removedApis'; +import type { TransformContext } from '../../../src/types'; +import { DiagnosticLevel } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; diff --git a/packages/codemod/test/v1-to-v2/transforms/schemaParamRemoval.test.ts b/packages/codemod/test/v1-to-v2/transforms/schemaParamRemoval.test.ts index d2d6c86482..5f65411b5e 100644 --- a/packages/codemod/test/v1-to-v2/transforms/schemaParamRemoval.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/schemaParamRemoval.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { schemaParamRemovalTransform } from '../../../src/migrations/v1-to-v2/transforms/schemaParamRemoval.js'; -import type { TransformContext } from '../../../src/types.js'; +import { schemaParamRemovalTransform } from '../../../src/migrations/v1-to-v2/transforms/schemaParamRemoval'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'client' }; @@ -130,4 +130,40 @@ describe('schema-param-removal transform', () => { const result = applyTransform(input); expect(result).not.toMatch(/import.*CallToolResultSchema/); }); + + it('removes a literal undefined schema slot from callTool when an options argument follows', () => { + const input = [ + `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, + `const result = await client.callTool({ name: 'add', arguments: { a: 1 } }, undefined, { onprogress: cb });`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain("client.callTool({ name: 'add', arguments: { a: 1 } }, { onprogress: cb })"); + expect(result).not.toContain(', undefined,'); + }); + + it('removes a literal undefined schema slot from request when an options argument follows', () => { + const input = [ + `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`, + `const result = await client.request({ method: 'tools/call', params: {} }, undefined, { timeout: 5000 });`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain("client.request({ method: 'tools/call', params: {} }, { timeout: 5000 })"); + expect(result).not.toContain(', undefined,'); + }); + + it('does not strip undefined from request()/callTool() in a file with no MCP imports', () => { + // `request`/`callTool` are common non-MCP method names; without an MCP signal in the file the + // codemod must not touch them, or it would shift `someHttpClient.request(payload, undefined, opts)`. + const input = [`const r = await someHttpClient.request(payload, undefined, { timeout: 5000 });`, ''].join('\n'); + const result = applyTransform(input); + expect(result).toContain('someHttpClient.request(payload, undefined, { timeout: 5000 })'); + }); + + it('leaves a 2-arg callTool(params, undefined) unchanged (already valid as options in v2)', () => { + const input = [`await client.callTool({ name: 'add' }, undefined);`, ''].join('\n'); + const result = applyTransform(input); + expect(result).toContain('undefined'); + }); }); diff --git a/packages/codemod/test/v1-to-v2/transforms/specSchemaAccess.test.ts b/packages/codemod/test/v1-to-v2/transforms/specSchemaAccess.test.ts deleted file mode 100644 index 2c7f592e1f..0000000000 --- a/packages/codemod/test/v1-to-v2/transforms/specSchemaAccess.test.ts +++ /dev/null @@ -1,517 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { Project } from 'ts-morph'; - -import { specSchemaAccessTransform } from '../../../src/migrations/v1-to-v2/transforms/specSchemaAccess.js'; -import type { TransformContext } from '../../../src/types.js'; - -const ctx: TransformContext = { projectType: 'server' }; - -function applyTransform(code: string) { - const project = new Project({ useInMemoryFileSystem: true }); - const sourceFile = project.createSourceFile('test.ts', code); - const result = specSchemaAccessTransform.apply(sourceFile, ctx); - return { text: sourceFile.getFullText(), result }; -} - -describe('spec-schema-access transform', () => { - describe('auto-transform: .safeParse(v).success → isSpecType.X(v)', () => { - it('rewrites XSchema.safeParse(v).success to isSpecType.X(v)', () => { - const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/server';`, - `const valid = CallToolRequestSchema.safeParse(data).success;`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('isSpecType.CallToolRequest(data)'); - expect(text).not.toContain('safeParse'); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('handles safeParse().success in if-condition', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `if (ToolSchema.safeParse(obj).success) { doSomething(); }`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('isSpecType.Tool(obj)'); - expect(text).not.toContain('safeParse'); - }); - - it('adds isSpecType import when transforming safeParse().success', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const ok = CallToolResultSchema.safeParse(x).success;`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('isSpecType'); - expect(text).toMatch(/import.*isSpecType.*from/); - }); - }); - - describe('auto-transform: value position → specTypeSchemas.X', () => { - it('replaces schema passed as function arg with specTypeSchemas.X', () => { - const input = [ - `import { ListToolsRequestSchema } from '@modelcontextprotocol/server';`, - `validate(ListToolsRequestSchema);`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.ListToolsRequest'); - expect(result.changesCount).toBeGreaterThan(0); - expect(result.diagnostics.length).toBeGreaterThan(0); - expect(result.diagnostics[0]!.message).toContain('StandardSchemaV1'); - }); - - it('adds specTypeSchemas import', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const s = ToolSchema;`, ''].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('specTypeSchemas.Tool'); - expect(text).toMatch(/import.*specTypeSchemas.*from/); - }); - }); - - describe('auto-transform: captured safeParse result', () => { - it('rewrites captured safeParse call and result property accesses', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (parsed.success) { return parsed.data; }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain("specTypeSchemas.CallToolResult['~standard'].validate(data)"); - expect(text).toContain('parsed.issues === undefined'); - expect(text).toContain('parsed.value'); - expect(text).not.toContain('safeParse'); - expect(text).not.toContain('parsed.success'); - expect(text).not.toContain('parsed.data'); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('rewrites result properties assigned to variables (const isValid = parsed.success)', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `const isValid = parsed.success;`, - `const result = parsed.data;`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('parsed.issues === undefined'); - expect(text).toContain('parsed.value'); - expect(text).not.toContain('parsed.success'); - expect(text).not.toContain('parsed.data'); - }); - - it('rewrites .error to .issues', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const result = ToolSchema.safeParse(raw);`, - `if (!result.success) { console.log(result.error); }`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('result.issues'); - expect(text).not.toContain('result.error'); - }); - - it('handles ternary pattern: x.success ? x.data : fallback', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(toolResult);`, - `return parsed.success ? parsed.data : undefined;`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain("specTypeSchemas.CallToolResult['~standard'].validate(toolResult)"); - expect(text).toContain('(parsed.issues === undefined) ? parsed.value : undefined'); - }); - - it('adds specTypeSchemas import', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const r = ToolSchema.safeParse(v);`, - `r.success;`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toMatch(/import.*specTypeSchemas.*from/); - }); - - it('rewrites .error.issues to .issues (unwrap double nesting)', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (!parsed.success) { console.log(parsed.error.issues); }`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('parsed.issues'); - expect(text).not.toContain('parsed.issues.issues'); - expect(text).not.toContain('parsed.error'); - }); - - it('rewrites .error.message to issues map expression', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (!parsed.success) { console.log(parsed.error.message); }`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).not.toContain('parsed.error'); - expect(text).not.toContain('parsed.issues.message'); - expect(text).toContain("parsed.issues?.map(i => i.message).join(', ')"); - }); - - it('emits diagnostic for .error.format() instead of silently rewriting', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/server';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (!parsed.success) { console.log(parsed.error.format()); }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('parsed.error.format()'); - expect(text).not.toContain('parsed.issues()'); - expect(result.diagnostics.some(d => d.message.includes('no StandardSchema equivalent'))).toBe(true); - }); - - it('rewrites bare .error to .issues (unchanged behavior)', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const result = ToolSchema.safeParse(raw);`, - `if (!result.success) { console.log(result.error); }`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('result.issues'); - expect(text).not.toContain('result.error'); - }); - - it('does not rewrite same-named variable in sibling function', () => { - const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';`, - `function validate(d: unknown) {`, - ` const result = CallToolRequestSchema.safeParse(d);`, - ` return result.success;`, - `}`, - `async function callApi(client: any) {`, - ` const result = await client.get('/api');`, - ` return result.data;`, - `}`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('result.issues === undefined'); - expect(text).toContain('return result.data'); - expect(text).not.toContain('return result.value'); - }); - - it('rewrites non-captured safeParse (bare expression) to validate()', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `ToolSchema.safeParse(data);`, ''].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain("specTypeSchemas.Tool['~standard'].validate(data)"); - expect(text).not.toMatch(/import\s*\{[^}]*ToolSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - expect(result.diagnostics.length).toBe(1); - }); - }); - - describe('guardrails: non-MCP schemas are NOT touched', () => { - it('does not rewrite safeParse on user-defined schema with same name from local import', () => { - const input = [ - `import { CallToolResultSchema } from './mySchemas';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (parsed.success) { return parsed.data; }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('CallToolResultSchema.safeParse'); - expect(text).toContain('parsed.success'); - expect(text).toContain('parsed.data'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - - it('does not rewrite safeParse on user zod schema not from MCP', () => { - const input = [ - `import { z } from 'zod';`, - `const MySchema = z.object({ name: z.string() });`, - `const parsed = MySchema.safeParse(data);`, - `if (parsed.success) { return parsed.data; }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('MySchema.safeParse'); - expect(text).toContain('parsed.success'); - expect(text).toContain('parsed.data'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - - it('does not rewrite safeParse on non-spec schema name from MCP import', () => { - const input = [ - `import { SomeRandomSchema } from '@modelcontextprotocol/server';`, - `const parsed = SomeRandomSchema.safeParse(data);`, - `if (parsed.success) { return parsed.data; }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('SomeRandomSchema.safeParse'); - expect(text).toContain('parsed.success'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - - it('does not rewrite safeParse on npm package schema with matching name', () => { - const input = [ - `import { CallToolResultSchema } from 'some-other-package';`, - `const parsed = CallToolResultSchema.safeParse(data);`, - `if (parsed.success) { return parsed.data; }`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('CallToolResultSchema.safeParse'); - expect(text).toContain('parsed.success'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - }); - - describe('auto-transform: generic property access → specTypeSchemas.X', () => { - it('replaces schema identifier in .parseAsync() call', () => { - const input = [ - `import { OAuthTokensSchema } from '@modelcontextprotocol/server';`, - `const tokens = await OAuthTokensSchema.parseAsync(data);`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.OAuthTokens.parseAsync(data)'); - expect(text).not.toMatch(/import\s*\{[^}]*OAuthTokensSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - expect(result.diagnostics.length).toBeGreaterThan(0); - }); - - it('replaces schema identifier in .or() call', () => { - const input = [ - `import { ServerNotificationSchema } from '@modelcontextprotocol/server';`, - `const union = ServerNotificationSchema.or(otherSchema);`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.ServerNotification.or(otherSchema)'); - expect(text).not.toMatch(/import\s*\{[^}]*ServerNotificationSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('replaces schema identifier in .extend() call', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const extended = ToolSchema.extend({ extra: z.string() });`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.Tool.extend'); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('adds specTypeSchemas import for generic property access', () => { - const input = [ - `import { OAuthTokensSchema } from '@modelcontextprotocol/server';`, - `const tokens = await OAuthTokensSchema.parseAsync(data);`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toMatch(/import.*specTypeSchemas.*from/); - }); - }); - - describe('.parse(v)', () => { - it('rewrites discarded parse() to the validate() primitive', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `ToolSchema.parse(raw);`, ''].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain("specTypeSchemas.Tool['~standard'].validate(raw)"); - expect(text).not.toMatch(/import\s*\{[^}]*ToolSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('swaps the identifier (import stays resolvable) when the parse() result is used', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const tool = ToolSchema.parse(raw);`, ''].join( - '\n' - ); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.Tool.parse(raw)'); - expect(text).not.toMatch(/import\s*\{[^}]*ToolSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - expect(result.diagnostics[0]!.message).toContain('specTypeSchemas.Tool'); - }); - }); - - describe('diagnostic: z.infer', () => { - it('emits diagnostic for typeof in type position', () => { - const input = [ - `import { CallToolResultSchema } from '@modelcontextprotocol/client';`, - `type Result = typeof CallToolResultSchema;`, - '' - ].join('\n'); - const { result } = applyTransform(input); - expect(result.diagnostics.length).toBe(1); - expect(result.diagnostics[0]!.message).toContain('CallToolResult'); - }); - }); - - describe('no-op cases', () => { - it('does nothing for non-MCP imports', () => { - const input = [`import { CallToolRequestSchema } from './local';`, `CallToolRequestSchema.safeParse(data);`, ''].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('CallToolRequestSchema.safeParse'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - - it('does nothing for non-spec schema names', () => { - const input = [`import { SomeRandomSchema } from '@modelcontextprotocol/server';`, `SomeRandomSchema.parse(data);`, ''].join( - '\n' - ); - const { text, result } = applyTransform(input); - expect(text).toContain('SomeRandomSchema.parse'); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - - it('does nothing when no remaining references', () => { - const input = [`import { CallToolRequestSchema } from '@modelcontextprotocol/server';`, ''].join('\n'); - const { result } = applyTransform(input); - expect(result.changesCount).toBe(0); - expect(result.diagnostics.length).toBe(0); - }); - }); - - describe('import cleanup after transform', () => { - it('removes original schema import after all refs are auto-transformed', () => { - const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/server';`, - `const valid = CallToolRequestSchema.safeParse(data).success;`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('isSpecType.CallToolRequest(data)'); - expect(text).not.toMatch(/import\s*\{[^}]*CallToolRequestSchema[^}]*\}/); - }); - - it('removes the schema import even when a ref falls back to a parse()/safeParse() rewrite', () => { - const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/server';`, - `const valid = CallToolRequestSchema.safeParse(data).success;`, - `const parsed = CallToolRequestSchema.parse(data);`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).toContain('isSpecType.CallToolRequest(data)'); - expect(text).toContain('specTypeSchemas.CallToolRequest.parse(data)'); - expect(text).not.toMatch(/import\s*\{[^}]*CallToolRequestSchema[^}]*\}/); - }); - - it('removes schema specifier from import that also has other symbols', () => { - const input = [ - `import { CallToolRequestSchema, McpError } from '@modelcontextprotocol/server';`, - `const valid = CallToolRequestSchema.safeParse(data).success;`, - `throw new McpError(1, 'fail');`, - '' - ].join('\n'); - const { text } = applyTransform(input); - expect(text).not.toMatch(/import\s*\{[^}]*CallToolRequestSchema[^}]*\}/); - expect(text).toContain('McpError'); - expect(text).toContain(`@modelcontextprotocol/server`); - }); - }); - - describe('parent-kind guards', () => { - it('emits diagnostic for re-exported schema (ExportSpecifier)', () => { - const input = [ - `import { CallToolRequestSchema } from '@modelcontextprotocol/server';`, - `export { CallToolRequestSchema };`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('export { CallToolRequestSchema }'); - expect(result.diagnostics.some(d => d.message.includes('Re-export'))).toBe(true); - expect(result.changesCount).toBe(0); - }); - - it('expands shorthand property assignment and removes import', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const schemas = { ToolSchema };`, ''].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain("'ToolSchema': specTypeSchemas.Tool"); - expect(text).not.toMatch(/import\s*\{[^}]*ToolSchema[^}]*\}/); - expect(result.changesCount).toBeGreaterThan(0); - }); - - it('skips PropertyAssignment name-node (non-shorthand)', () => { - const input = [ - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const schemas = { ToolSchema: myValidator };`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('ToolSchema: myValidator'); - expect(result.changesCount).toBe(0); - }); - - it('skips BindingElement property-name', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const { ToolSchema: local } = obj;`, ''].join( - '\n' - ); - const { text, result } = applyTransform(input); - expect(text).toContain('ToolSchema: local'); - expect(result.changesCount).toBe(0); - }); - - it('skips PropertyAccessExpression name-node (obj.ToolSchema)', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const x = registry.ToolSchema;`, ''].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('registry.ToolSchema'); - expect(text).not.toContain('specTypeSchemas'); - expect(result.changesCount).toBe(0); - }); - - it('does not emit z.infer diagnostic for runtime typeof (TypeOfExpression)', () => { - const input = [`import { ToolSchema } from '@modelcontextprotocol/server';`, `const kind = typeof ToolSchema;`, ''].join('\n'); - const { result } = applyTransform(input); - expect(result.diagnostics.every(d => !d.message.includes('z.infer'))).toBe(true); - }); - }); - - describe('namespace imports', () => { - it('does not crash when file has namespace import from same package', () => { - const input = [ - `import * as types from '@modelcontextprotocol/server';`, - `import { ToolSchema } from '@modelcontextprotocol/server';`, - `const s = ToolSchema;`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain('specTypeSchemas.Tool'); - expect(result.changesCount).toBeGreaterThan(0); - }); - }); - - describe('aliased imports', () => { - it('handles aliased import and auto-transforms captured safeParse', () => { - const input = [ - `import { CallToolRequestSchema as CTRS } from '@modelcontextprotocol/server';`, - `const result = CTRS.safeParse(data);`, - `result.success;`, - '' - ].join('\n'); - const { text, result } = applyTransform(input); - expect(text).toContain("specTypeSchemas.CallToolRequest['~standard'].validate(data)"); - expect(text).not.toContain('CTRS.safeParse'); - expect(result.changesCount).toBeGreaterThan(0); - expect(result.diagnostics[0]!.message).toContain('specTypeSchemas.CallToolRequest'); - }); - }); -}); diff --git a/packages/codemod/test/v1-to-v2/transforms/symbolRenames.test.ts b/packages/codemod/test/v1-to-v2/transforms/symbolRenames.test.ts index d6ef103de6..c877d029fa 100644 --- a/packages/codemod/test/v1-to-v2/transforms/symbolRenames.test.ts +++ b/packages/codemod/test/v1-to-v2/transforms/symbolRenames.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; import { Project } from 'ts-morph'; -import { symbolRenamesTransform } from '../../../src/migrations/v1-to-v2/transforms/symbolRenames.js'; -import type { TransformContext } from '../../../src/types.js'; +import { symbolRenamesTransform } from '../../../src/migrations/v1-to-v2/transforms/symbolRenames'; +import type { TransformContext } from '../../../src/types'; const ctx: TransformContext = { projectType: 'server' }; @@ -44,6 +44,34 @@ describe('symbol-renames transform', () => { expect(result).toContain('isJSONRPCResultResponse'); }); + it('renames JSONRPCResponseSchema to JSONRPCResultResponseSchema (result-only in v1)', () => { + // v1's JSONRPCResponseSchema validated only result responses; v2 reuses the name for a union that + // also accepts errors. Rename to the result-only schema to preserve v1 parse/safeParse behavior. + const input = [ + `import { JSONRPCResponseSchema } from '@modelcontextprotocol/sdk/types.js';`, + `const r = JSONRPCResponseSchema.parse(value);`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain('JSONRPCResultResponseSchema.parse(value)'); + expect(result).not.toMatch(/(? { + // v1's JSONRPCResponse type was the result-only response; v2 reuses the name for a + // result|error union (Infer). Leaving the type unrenamed would + // silently widen a migrated v1 type import — mirror the schema/guard renames. + const input = [ + `import type { JSONRPCResponse } from '@modelcontextprotocol/server';`, + `function handle(r: JSONRPCResponse) { return r; }`, + '' + ].join('\n'); + const result = applyTransform(input); + expect(result).toContain('import type { JSONRPCResultResponse }'); + expect(result).toContain('r: JSONRPCResultResponse'); + expect(result).not.toMatch(/(? { const input = [ `import { ResourceReference } from '@modelcontextprotocol/sdk/types.js';`, @@ -303,7 +331,7 @@ describe('symbol-renames transform', () => { it('does not rename RequestHandlerExtra from non-MCP imports', () => { const input = [ - `import type { RequestHandlerExtra } from './my-local-types.js';`, + `import type { RequestHandlerExtra } from './my-local-types';`, `type MyHandler = (extra: RequestHandlerExtra) => void;`, '' ].join('\n'); diff --git a/packages/core-internal/CHANGELOG.md b/packages/core-internal/CHANGELOG.md new file mode 100644 index 0000000000..b1212d74db --- /dev/null +++ b/packages/core-internal/CHANGELOG.md @@ -0,0 +1,180 @@ +# @modelcontextprotocol/core-internal + +## 2.0.0-alpha.2 + +### Major Changes + +- [#2128](https://github.com/modelcontextprotocol/typescript-sdk/pull/2128) [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6) Thanks [@felixweinberger](https://github.com/felixweinberger)! - SEP-2663: remove + 2025-11 experimental tasks (TaskManager, experimental.tasks.\* accessors). Tasks are now Extensions Track. + +### Minor Changes + +- [#2049](https://github.com/modelcontextprotocol/typescript-sdk/pull/2049) [`4f226c1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/4f226c1e35200616d62f1d7e46a2daa33d91172a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add `SdkHttpError` subclass + with typed `.status` / `.statusText` accessors for HTTP transport failures. `StreamableHTTPClientTransport` now throws `SdkHttpError` (which extends `SdkError`) for non-OK HTTP responses; `SSEClientTransport` throws `SdkHttpError` for 401-after-reauth (circuit breaker). + +- [#1974](https://github.com/modelcontextprotocol/typescript-sdk/pull/1974) [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add custom (non-spec) + method support: a 3-arg `setRequestHandler(method, schemas, handler)` / `setNotificationHandler(method, schemas, handler)` form for vendor-prefixed methods, and a `request(req, resultSchema)` overload (also on `ctx.mcpReq.send`) for typed custom-method results. Spec-method + calls are unchanged. + + Response result-schema validation failure now rejects with `SdkError(InvalidResult)` instead of a raw `ZodError`. Adds `SdkErrorCode.InvalidResult`. + +- [#2248](https://github.com/modelcontextprotocol/typescript-sdk/pull/2248) [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Restore the 2025-11-25 + task wire types that were removed together with the task feature: the task schemas and inferred types, task members of the request/result/notification unions, the `task` request-params augmentation, the `tasks` capability key, the `isTaskAugmentedRequestParams` guard, and + `RELATED_TASK_META_KEY`. The task feature itself remains removed — servers do not advertise the `tasks` capability and inbound `tasks/*` requests receive `-32601` — but the wire surface stays so SDKs interoperate cleanly with peers on the 2025-11-25 revision. + +- [#2088](https://github.com/modelcontextprotocol/typescript-sdk/pull/2088) [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Bundle automatic JSON Schema + validator defaults in `@modelcontextprotocol/client` and `@modelcontextprotocol/server` runtime shims. + + Client and server pick the right validator automatically based on the runtime: the Node shim uses AJV, the browser/workerd shim uses `@cfworker/json-schema`. Both backends are bundled into the shim chunks that select them, so the default code path needs no extra installs — + `import { McpServer } from '@modelcontextprotocol/server'` does not pull `ajv` or `@cfworker/json-schema` into the root entry chunk. + + The named validator classes remain part of the public surface for consumers who want to customize the built-in backend (pre-register schemas by `$id`, register custom AJV formats, switch dialects, change `@cfworker/json-schema` draft). They are exposed through explicit + subpaths so they do not bloat the root index chunk: + - `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/ajv'` + - `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/cf-worker'` + + Importing from one of these subpaths means the corresponding peer dep (`ajv` + `ajv-formats`, or `@cfworker/json-schema`) must be in your `package.json`. The shim keeps its own vendored copy for the default path, so a project can use the subpath in some files and rely on the + default in others. + + The `jsonSchemaValidator` interface remains the public extension point for replacing validation entirely with a custom implementation. + +### Patch Changes + +- [#1901](https://github.com/modelcontextprotocol/typescript-sdk/pull/1901) [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab) Thanks [@felixweinberger](https://github.com/felixweinberger)! - + `registerTool`/`registerPrompt` accept a raw Zod shape (`{ field: z.string() }`) for `inputSchema`/`outputSchema`/`argsSchema` in addition to a wrapped Standard Schema. Raw shapes are auto-wrapped with `z.object()`. The raw-shape overloads are `@deprecated`; prefer wrapping + with `z.object()`. + + Also widens the `completable()` constraint from `StandardSchemaWithJSON` to `StandardSchemaV1` so v1's `completable(z.string(), fn)` continues to work. + +- [#2268](https://github.com/modelcontextprotocol/typescript-sdk/pull/2268) [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Mark the roots, sampling, and + logging runtime APIs as `@deprecated` per SEP-2577 (deprecated as of protocol version 2026-07-28; functional for at least twelve months). Annotates `Server.createMessage`/`listRoots`/`sendLoggingMessage`, `McpServer.sendLoggingMessage`, + `Client.setLoggingLevel`/`sendRootsListChanged`, the `ServerContext.mcpReq.log`/`requestSampling` helpers, and the `roots`/`sampling`/`logging` capability schema fields. JSDoc/docs only — no behavior change. + +- [#2270](https://github.com/modelcontextprotocol/typescript-sdk/pull/2270) [`78fbe27`](https://github.com/modelcontextprotocol/typescript-sdk/commit/78fbe2736d72be4841072b359b3a2b8c6f97cd5c) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add reserved trace context + `_meta` key constants (`TRACEPARENT_META_KEY`, `TRACESTATE_META_KEY`, `BAGGAGE_META_KEY`) per SEP-414, plus docs and a passthrough regression test. The spec reserves the unprefixed `_meta` keys `traceparent`, `tracestate`, and `baggage` (W3C Trace Context / W3C Baggage formats) + for distributed tracing; the SDK passes them through untouched. + +- [#2252](https://github.com/modelcontextprotocol/typescript-sdk/pull/2252) [`8d55531`](https://github.com/modelcontextprotocol/typescript-sdk/commit/8d55531dabd5aa2de8864d691520cd6c6fe77541) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add per-revision spec + reference types (2025-11-25 and 2026-07-28) with split comparison tests, and the 2026-07-28 wire contract surface: request-meta key constants, `RequestMetaEnvelopeSchema`, `server/discover` shapes, the typed `-32004` error, the `-32003` code constant, and a `resultType` + passthrough on the base result. Types and constants only — no behavior changes. + +- [#2275](https://github.com/modelcontextprotocol/typescript-sdk/pull/2275) [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add a configurable + `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or + `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/core-internal` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`. + +- [#1976](https://github.com/modelcontextprotocol/typescript-sdk/pull/1976) [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - refactor: subclasses + override `_wrapHandler` hook instead of redeclaring `setRequestHandler`. + +- [#1768](https://github.com/modelcontextprotocol/typescript-sdk/pull/1768) [`866c08d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/866c08d3640c5213f80c3b4220e24c42acfc2db8) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Allow additional JSON + Schema properties in elicitInput's requestedSchema type by adding .catchall(z.unknown()), matching the pattern used by inputSchema. This fixes type incompatibility when using Zod v4's .toJSONSchema() output which includes extra properties like $schema and additionalProperties. + +- [#1895](https://github.com/modelcontextprotocol/typescript-sdk/pull/1895) [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Fix runtime crash on + `tools/list` when a tool's `inputSchema` comes from zod 4.0–4.1. The SDK requires `~standard.jsonSchema` (StandardJSONSchemaV1, added in zod 4.2.0); previously a missing `jsonSchema` crashed at `undefined[io]`. `standardSchemaToJsonSchema` now detects zod 4 schemas lacking + `jsonSchema` and falls back to the SDK-bundled `z.toJSONSchema()`, emitting a one-time console warning. zod 3 schemas (which the bundled zod 4 converter cannot introspect) and non-zod schema libraries without `jsonSchema` get a clear error pointing to `fromJsonSchema()`. The + workspace zod catalog is also bumped to `^4.2.0`. + +## 2.0.0-alpha.1 + +### Minor Changes + +- [#1673](https://github.com/modelcontextprotocol/typescript-sdk/pull/1673) [`462c3fc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/462c3fc47dffac908d2ba27784d47ff010fa065e) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - refactor: extract task + orchestration from Protocol into TaskManager + + **Breaking changes:** + - `taskStore`, `taskMessageQueue`, `defaultTaskPollInterval`, and `maxTaskQueueSize` moved from `ProtocolOptions` to `capabilities.tasks` on `ClientOptions`/`ServerOptions` + +- [#1389](https://github.com/modelcontextprotocol/typescript-sdk/pull/1389) [`108f2f3`](https://github.com/modelcontextprotocol/typescript-sdk/commit/108f2f3ab6a1267587c7c4f900b6eca3cc2dae51) Thanks [@DePasqualeOrg](https://github.com/DePasqualeOrg)! - Fix error handling for + unknown tools and resources per MCP spec. + + **Tools:** Unknown or disabled tool calls now return JSON-RPC protocol errors with code `-32602` (InvalidParams) instead of `CallToolResult` with `isError: true`. Callers who checked `result.isError` for unknown tools should catch rejected promises instead. + + **Resources:** Unknown resource reads now return error code `-32002` (ResourceNotFound) instead of `-32602` (InvalidParams). + + Added `ProtocolErrorCode.ResourceNotFound`. + +- [#1689](https://github.com/modelcontextprotocol/typescript-sdk/pull/1689) [`0784be1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0784be1a67fb3cc2aba0182d88151264f4ea73c8) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Support Standard Schema + for tool and prompt schemas + + Tool and prompt registration now accepts any schema library that implements the [Standard Schema spec](https://standardschema.dev/): Zod v4, Valibot, ArkType, and others. `RegisteredTool.inputSchema`, `RegisteredTool.outputSchema`, and `RegisteredPrompt.argsSchema` now use + `StandardSchemaWithJSON` (requires both `~standard.validate` and `~standard.jsonSchema`) instead of the Zod-specific `AnySchema` type. + + **Zod v4 schemas continue to work unchanged** — Zod v4 implements the required interfaces natively. + + ```typescript + import { type } from 'arktype'; + + server.registerTool( + 'greet', + { + inputSchema: type({ name: 'string' }) + }, + async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}!` }] }) + ); + ``` + + For raw JSON Schema (e.g. TypeBox output), use the new `fromJsonSchema` adapter: + + ```typescript + import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core-internal'; + + server.registerTool( + 'greet', + { + inputSchema: fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } } }, new AjvJsonSchemaValidator()) + }, + handler + ); + ``` + + **Breaking changes:** + - `experimental.tasks.getTaskResult()` no longer accepts a `resultSchema` parameter. Returns `GetTaskPayloadResult` (a loose `Result`); cast to the expected type at the call site. + - Removed unused exports from `@modelcontextprotocol/core-internal`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` + instead. + - `completable()` remains Zod-specific (it relies on Zod's `.shape` introspection). + +### Patch Changes + +- [#1735](https://github.com/modelcontextprotocol/typescript-sdk/pull/1735) [`a2e5037`](https://github.com/modelcontextprotocol/typescript-sdk/commit/a2e503733f6f3eea3a79a80bdc1b3cdd743f8bb3) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Abort in-flight request + handlers when the connection closes. Previously, request handlers would continue running after the transport disconnected, wasting resources and preventing proper cleanup. Also fixes `InMemoryTransport.close()` firing `onclose` twice on the initiating side. + +- [#1574](https://github.com/modelcontextprotocol/typescript-sdk/pull/1574) [`379392d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/379392d04460ee2cbeecae374901fae21e525031) Thanks [@olaservo](https://github.com/olaservo)! - Add missing `size` field to + `ResourceSchema` to match the MCP specification + +- [#1363](https://github.com/modelcontextprotocol/typescript-sdk/pull/1363) [`0a75810`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0a75810b26e24bae6b9cfb41e12ac770aeaa1da4) Thanks [@DevJanderson](https://github.com/DevJanderson)! - Fix ReDoS vulnerability in + UriTemplate regex patterns (CVE-2026-0621) + +- [#1761](https://github.com/modelcontextprotocol/typescript-sdk/pull/1761) [`01954e6`](https://github.com/modelcontextprotocol/typescript-sdk/commit/01954e621afe525cc3c1bbe8d781e44734cf81c2) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Convert remaining + capability-assertion throws to `SdkError(SdkErrorCode.CapabilityNotSupported, ...)`. Follow-up to #1454 which missed `Client.assertCapability()`, the task capability helpers in `experimental/tasks/helpers.ts`, and the sampling/elicitation capability checks in + `experimental/tasks/server.ts`. + +- [#1790](https://github.com/modelcontextprotocol/typescript-sdk/pull/1790) [`89fb094`](https://github.com/modelcontextprotocol/typescript-sdk/commit/89fb0947b487b37f9bfcc2a2486dcd33d3922f8e) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Consolidate per-request + cleanup in `_requestWithSchema` into a single `.finally()` block. This fixes an abort signal listener leak (listeners accumulated when a caller reused one `AbortSignal` across requests) and two cases where `_responseHandlers` entries leaked on send-failure paths. + +- [#1486](https://github.com/modelcontextprotocol/typescript-sdk/pull/1486) [`65bbcea`](https://github.com/modelcontextprotocol/typescript-sdk/commit/65bbceab773277f056a9d3e385e7e7d8cef54f9b) Thanks [@localden](https://github.com/localden)! - Fix InMemoryTaskStore to enforce + session isolation. Previously, sessionId was accepted but ignored on all TaskStore methods, allowing any session to enumerate, read, and mutate tasks created by other sessions. The store now persists sessionId at creation time and enforces ownership on all reads and writes. + +- [#1766](https://github.com/modelcontextprotocol/typescript-sdk/pull/1766) [`48aba0d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/48aba0d3c3b2ee04c442934095b663d19e07a3b3) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add explicit + `| undefined` to optional properties on the `Transport` interface and `TransportSendOptions` (`onclose`, `onerror`, `onmessage`, `sessionId`, `setProtocolVersion`, `setSupportedProtocolVersions`, `onresumptiontoken`). + + This fixes TS2420 errors for consumers using `exactOptionalPropertyTypes: true` without `skipLibCheck`, where the emitted `.d.ts` for implementing classes included `| undefined` but the interface did not. + + Workaround for older SDK versions: enable `skipLibCheck: true` in your tsconfig. + +- [#1419](https://github.com/modelcontextprotocol/typescript-sdk/pull/1419) [`dcf708d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/dcf708d892b7ca5f137c74109d42cdeb05e2ee3a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - remove deprecated .tool, + .prompt, .resource method signatures + +- [#1534](https://github.com/modelcontextprotocol/typescript-sdk/pull/1534) [`69a0626`](https://github.com/modelcontextprotocol/typescript-sdk/commit/69a062693f61e024d7a366db0c3e3ba74ff59d8e) Thanks [@josefaidt](https://github.com/josefaidt)! - remove npm references, use pnpm + +- [#1534](https://github.com/modelcontextprotocol/typescript-sdk/pull/1534) [`69a0626`](https://github.com/modelcontextprotocol/typescript-sdk/commit/69a062693f61e024d7a366db0c3e3ba74ff59d8e) Thanks [@josefaidt](https://github.com/josefaidt)! - clean up package manager usage, all + pnpm + +- [#1796](https://github.com/modelcontextprotocol/typescript-sdk/pull/1796) [`d6a02c8`](https://github.com/modelcontextprotocol/typescript-sdk/commit/d6a02c85c0514658c27615398a3003aadce80fb0) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Ensure + `standardSchemaToJsonSchema` emits `type: "object"` at the root, fixing discriminated-union tool/prompt schemas that previously produced `{oneOf: [...]}` without the MCP-required top-level type. Also throws a clear error when given an explicitly non-object schema (e.g. + `z.string()`). Fixes #1643. + +- [#1419](https://github.com/modelcontextprotocol/typescript-sdk/pull/1419) [`dcf708d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/dcf708d892b7ca5f137c74109d42cdeb05e2ee3a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - deprecated .tool, .prompt, + .resource method removal + +- [#1762](https://github.com/modelcontextprotocol/typescript-sdk/pull/1762) [`64897f7`](https://github.com/modelcontextprotocol/typescript-sdk/commit/64897f78ce78f736b027dfecd1b4326c8c6678c7) Thanks [@felixweinberger](https://github.com/felixweinberger)! - + `ReadBuffer.readMessage()` now silently skips non-JSON lines instead of throwing `SyntaxError`. This prevents noisy `onerror` callbacks when hot-reload tools (tsx, nodemon) write debug output like "Gracefully restarting..." to stdout. Lines that parse as JSON but fail JSONRPC + schema validation still throw. diff --git a/packages/core-internal/eslint.config.mjs b/packages/core-internal/eslint.config.mjs new file mode 100644 index 0000000000..64a6c212c0 --- /dev/null +++ b/packages/core-internal/eslint.config.mjs @@ -0,0 +1,54 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default [ + ...baseConfig, + { + // Wire-layer isolation, outbound direction: nothing outside src/wire/ may + // reach into a wire revision module. The wire layer's only public surface + // is src/wire/codec.ts (the WireCodec interface) and src/wire/bootstrap.ts. + // test/wire/layeringInvariants.test.ts re-derives the same invariant with + // zero exceptions. Type-only imports are exempted at the lint layer (a + // type-only crossing is erased at runtime), but the test allows none. + files: ['src/**/*.ts'], + ignores: ['src/wire/**'], + rules: { + '@typescript-eslint/no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['**/wire/rev*', '**/wire/rev*/**', '@modelcontextprotocol/core-internal/wire/rev*'], + allowTypeImports: true, + message: 'Wire revision modules are codec-private. Route through src/wire/codec.ts (WireCodec) instead.' + } + ] + } + ] + } + }, + { + // Wire-layer isolation, inbound direction: wire revision modules are frozen, + // self-contained schema sets — they must not import the public-layer schema + // module at runtime. A change to types/schemas.ts must never alter what a + // codec emits or accepts on the wire. Type-only imports stay permitted. + files: ['src/wire/rev*/**/*.ts'], + rules: { + '@typescript-eslint/no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['**/types/schemas', '**/types/schemas.js'], + allowTypeImports: true, + message: + 'Wire revision modules must be self-contained. Freeze a copy of the schema into the ' + + 'rev*/ directory instead of importing the mutable public-layer types/schemas.ts.' + } + ] + } + ] + } + } +]; diff --git a/packages/core-internal/package.json b/packages/core-internal/package.json new file mode 100644 index 0000000000..6fbfbfec90 --- /dev/null +++ b/packages/core-internal/package.json @@ -0,0 +1,100 @@ +{ + "name": "@modelcontextprotocol/core-internal", + "private": true, + "version": "2.0.0-alpha.2", + "description": "Model Context Protocol implementation for TypeScript - Core package", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=20" + }, + "keywords": [ + "modelcontextprotocol", + "mcp", + "core" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs" + }, + "./types": { + "types": "./src/exports/types/index.ts", + "import": "./src/exports/types/index.ts" + }, + "./public": { + "types": "./src/exports/public/index.ts", + "import": "./src/exports/public/index.ts" + }, + "./validators/ajv": { + "types": "./src/validators/ajvProvider.ts", + "import": "./src/validators/ajvProvider.ts" + }, + "./validators/cfWorker": { + "types": "./src/validators/cfWorkerProvider.ts", + "import": "./src/validators/cfWorkerProvider.ts" + } + }, + "scripts": { + "typecheck": "tsgo -p tsconfig.json --noEmit", + "lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .", + "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", + "check": "pnpm run typecheck && pnpm run lint", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "json-schema-typed": "catalog:runtimeShared", + "zod": "catalog:runtimeShared" + }, + "peerDependencies": { + "@cfworker/json-schema": "catalog:runtimeShared", + "ajv": "catalog:runtimeShared", + "ajv-formats": "catalog:runtimeShared", + "zod": "catalog:runtimeShared" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "ajv": { + "optional": true + }, + "ajv-formats": { + "optional": true + }, + "zod": { + "optional": false + } + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@cfworker/json-schema": "catalog:runtimeShared", + "ajv": "catalog:runtimeShared", + "ajv-formats": "catalog:runtimeShared", + "@eslint/js": "catalog:devTools", + "@types/content-type": "catalog:devTools", + "@types/cors": "catalog:devTools", + "@types/cross-spawn": "catalog:devTools", + "@types/eventsource": "catalog:devTools", + "@types/express": "catalog:devTools", + "@types/express-serve-static-core": "catalog:devTools", + "@typescript/native-preview": "catalog:devTools", + "eslint": "catalog:devTools", + "eslint-config-prettier": "catalog:devTools", + "eslint-plugin-n": "catalog:devTools", + "prettier": "catalog:devTools", + "typescript": "catalog:devTools", + "typescript-eslint": "catalog:devTools", + "vitest": "catalog:devTools" + } +} diff --git a/packages/core/src/auth/errors.ts b/packages/core-internal/src/auth/errors.ts similarity index 98% rename from packages/core/src/auth/errors.ts rename to packages/core-internal/src/auth/errors.ts index 7aba02640d..6977ae0e57 100644 --- a/packages/core/src/auth/errors.ts +++ b/packages/core-internal/src/auth/errors.ts @@ -1,4 +1,4 @@ -import type { OAuthErrorResponse } from '../shared/auth.js'; +import type { OAuthErrorResponse } from '../shared/auth'; /** * OAuth error codes as defined by {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 | RFC 6749} diff --git a/packages/core/src/errors/sdkErrors.examples.ts b/packages/core-internal/src/errors/sdkErrors.examples.ts similarity index 99% rename from packages/core/src/errors/sdkErrors.examples.ts rename to packages/core-internal/src/errors/sdkErrors.examples.ts index d80fd6e756..c828d443ec 100644 --- a/packages/core/src/errors/sdkErrors.examples.ts +++ b/packages/core-internal/src/errors/sdkErrors.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { SdkError, SdkErrorCode, SdkHttpError } from './sdkErrors.js'; +import { SdkError, SdkErrorCode, SdkHttpError } from './sdkErrors'; /** * Example: Throwing and catching SDK errors. diff --git a/packages/core/src/errors/sdkErrors.ts b/packages/core-internal/src/errors/sdkErrors.ts similarity index 100% rename from packages/core/src/errors/sdkErrors.ts rename to packages/core-internal/src/errors/sdkErrors.ts diff --git a/packages/core/src/exports/public/index.ts b/packages/core-internal/src/exports/public/index.ts similarity index 77% rename from packages/core/src/exports/public/index.ts rename to packages/core-internal/src/exports/public/index.ts index c7cc53e0cb..10a357bb04 100644 --- a/packages/core/src/exports/public/index.ts +++ b/packages/core-internal/src/exports/public/index.ts @@ -1,24 +1,25 @@ /** - * Curated public API exports for @modelcontextprotocol/core. + * Curated public API exports for @modelcontextprotocol/core-internal. * * This module defines the stable, public-facing API surface. Client and server * packages re-export from here so that end users only see supported symbols. * * Internal utilities (Protocol class, stdio parsing, schema helpers, etc.) - * remain available via the internal barrel (@modelcontextprotocol/core) for + * remain available via the internal barrel (@modelcontextprotocol/core-internal) for * use by client/server packages. */ // Auth error classes -export { OAuthError, OAuthErrorCode } from '../../auth/errors.js'; +export { OAuthError, OAuthErrorCode } from '../../auth/errors'; // SDK error types (local errors that never cross the wire) -export type { SdkHttpErrorData } from '../../errors/sdkErrors.js'; -export { SdkError, SdkErrorCode, SdkHttpError } from '../../errors/sdkErrors.js'; +export type { SdkHttpErrorData } from '../../errors/sdkErrors'; +export { SdkError, SdkErrorCode, SdkHttpError } from '../../errors/sdkErrors'; // Auth TypeScript types (NOT Zod schemas like OAuthMetadataSchema) export type { AuthorizationServerMetadata, + IdJagTokenExchangeResponse, OAuthClientInformation, OAuthClientInformationFull, OAuthClientInformationMixed, @@ -33,13 +34,13 @@ export type { OpenIdProviderMetadata, StoredOAuthClientInformation, StoredOAuthTokens -} from '../../shared/auth.js'; +} from '../../shared/auth'; // Auth utilities -export { checkResourceAllowed, resourceUrlFromServerUrl } from '../../shared/authUtils.js'; +export { checkResourceAllowed, resourceUrlFromServerUrl } from '../../shared/authUtils'; // Metadata utilities -export { getDisplayName } from '../../shared/metadataUtils.js'; +export { getDisplayName } from '../../shared/metadataUtils'; // Protocol types (NOT the Protocol class itself or mergeCapabilities) export type { @@ -51,25 +52,25 @@ export type { RequestHandlerSchemas, RequestOptions, ServerContext -} from '../../shared/protocol.js'; -export { DEFAULT_REQUEST_TIMEOUT_MSEC } from '../../shared/protocol.js'; +} from '../../shared/protocol'; +export { DEFAULT_REQUEST_TIMEOUT_MSEC } from '../../shared/protocol'; // stdio message framing utilities (for custom transport authors) -export { deserializeMessage, ReadBuffer, serializeMessage, STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../shared/stdio.js'; +export { deserializeMessage, ReadBuffer, serializeMessage, STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../shared/stdio'; // Transport types (NOT normalizeHeaders) -export type { FetchLike, Transport, TransportSendOptions } from '../../shared/transport.js'; -export { createFetchWithInit } from '../../shared/transport.js'; -export { InMemoryTransport } from '../../util/inMemory.js'; +export type { FetchLike, Transport, TransportSendOptions } from '../../shared/transport'; +export { createFetchWithInit } from '../../shared/transport'; +export { InMemoryTransport } from '../../util/inMemory'; // URI Template -export type { Variables } from '../../shared/uriTemplate.js'; -export { UriTemplate } from '../../shared/uriTemplate.js'; +export type { Variables } from '../../shared/uriTemplate'; +export { UriTemplate } from '../../shared/uriTemplate'; // Types — all TypeScript types (standalone interfaces + schema-derived). // This is the one intentional `export *`: types.ts contains only spec-derived TS // types, and every type there should be public. See comment in types.ts. -export * from '../../types/types.js'; +export * from '../../types/types'; // Constants export { @@ -91,13 +92,13 @@ export { SUPPORTED_PROTOCOL_VERSIONS, TRACEPARENT_META_KEY, TRACESTATE_META_KEY -} from '../../types/constants.js'; +} from '../../types/constants'; // Protocol-era helpers -export type { ProtocolEra } from '../../shared/protocolEras.js'; +export type { ProtocolEra } from '../../shared/protocolEras'; // Enums -export { ProtocolErrorCode } from '../../types/enums.js'; +export { ProtocolErrorCode } from '../../types/enums'; // Error classes export { @@ -106,7 +107,7 @@ export { ResourceNotFoundError, UnsupportedProtocolVersionError, UrlElicitationRequiredError -} from '../../types/errors.js'; +} from '../../types/errors'; // Type guards and message parsing export { @@ -123,16 +124,16 @@ export { isJSONRPCResultResponse, isTaskAugmentedRequestParams, parseJSONRPCMessage -} from '../../types/guards.js'; +} from '../../types/guards'; // Validator types and classes -export type { SpecTypeName, SpecTypes } from '../../types/specTypeSchema.js'; -export { isSpecType, specTypeSchemas } from '../../types/specTypeSchema.js'; -export type { StandardSchemaV1, StandardSchemaV1Sync, StandardSchemaWithJSON } from '../../util/standardSchema.js'; +export type { SpecTypeName, SpecTypes } from '../../types/specTypeSchema'; +export { isSpecType, specTypeSchemas } from '../../types/specTypeSchema'; +export type { StandardSchemaV1, StandardSchemaV1Sync, StandardSchemaWithJSON } from '../../util/standardSchema'; // Validator providers are type-only here — import the runtime classes from the explicit // `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths to customise. -export type { AjvJsonSchemaValidator } from '../../validators/ajvProvider.js'; -export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from '../../validators/cfWorkerProvider.js'; +export type { AjvJsonSchemaValidator } from '../../validators/ajvProvider'; +export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from '../../validators/cfWorkerProvider'; // fromJsonSchema is intentionally NOT exported here — the server and client packages // provide runtime-aware wrappers that default to the appropriate validator via _shims. -export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from '../../validators/types.js'; +export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from '../../validators/types'; diff --git a/packages/core-internal/src/exports/types/index.ts b/packages/core-internal/src/exports/types/index.ts new file mode 100644 index 0000000000..cfd18a47ce --- /dev/null +++ b/packages/core-internal/src/exports/types/index.ts @@ -0,0 +1 @@ +export type * from '../../types/index'; diff --git a/packages/core-internal/src/index.ts b/packages/core-internal/src/index.ts new file mode 100644 index 0000000000..ab66a038b9 --- /dev/null +++ b/packages/core-internal/src/index.ts @@ -0,0 +1,40 @@ +export * from './auth/errors'; +export * from './errors/sdkErrors'; +export * from './shared/auth'; +export * from './shared/authUtils'; +export * from './shared/clientCapabilityRequirements'; +export * from './shared/envelope'; +export * from './shared/inboundClassification'; +export * from './shared/inputRequired'; +export * from './shared/inputRequiredDriver'; +export * from './shared/inputRequiredEngine'; +export * from './shared/mcpParamHeaders'; +export * from './shared/metadataUtils'; +export * from './shared/protocol'; +export * from './shared/protocolEras'; +export * from './shared/resultCacheHints'; +export * from './shared/stdio'; +export * from './shared/toolNameValidation'; +export * from './shared/transport'; +export * from './shared/uriTemplate'; +export * from './types/index'; +export * from './util/inMemory'; +// Wire-codec internals: the version→codec resolver the sibling packages need +// (era state itself lives on Protocol and is written through the +// package-internal write hook exported by shared/protocol.ts), plus the +// internal modern-revision literal so sibling packages can name the era a +// 2026-only seam runs in. NOTHING per-revision (registries, codec objects, +// per-revision schemas) is ever exported on this barrel — sibling packages +// reach the wire layer ONLY through `codecForVersion`'s function-only +// `WireCodec` surface. +export * from './util/schema'; +export * from './util/standardSchema'; +export * from './util/zodCompat'; +export { codecForVersion, MODERN_WIRE_REVISION } from './wire/codec'; + +// Validator providers are type-only here — import the runtime classes from the explicit +// `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths to customise. +export type { AjvJsonSchemaValidator } from './validators/ajvProvider'; +export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from './validators/cfWorkerProvider'; +export * from './validators/fromJsonSchema'; +export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './validators/types'; diff --git a/packages/core/src/shared/auth.ts b/packages/core-internal/src/shared/auth.ts similarity index 100% rename from packages/core/src/shared/auth.ts rename to packages/core-internal/src/shared/auth.ts diff --git a/packages/core/src/shared/authUtils.ts b/packages/core-internal/src/shared/authUtils.ts similarity index 100% rename from packages/core/src/shared/authUtils.ts rename to packages/core-internal/src/shared/authUtils.ts diff --git a/packages/core/src/shared/clientCapabilityRequirements.ts b/packages/core-internal/src/shared/clientCapabilityRequirements.ts similarity index 99% rename from packages/core/src/shared/clientCapabilityRequirements.ts rename to packages/core-internal/src/shared/clientCapabilityRequirements.ts index 59b3d5086f..b85a57b3f5 100644 --- a/packages/core/src/shared/clientCapabilityRequirements.ts +++ b/packages/core-internal/src/shared/clientCapabilityRequirements.ts @@ -25,7 +25,7 @@ * All three share {@linkcode missingClientCapabilities}; the per-method * requirement table below feeds call site 1 only. */ -import type { ClientCapabilities } from '../types/types.js'; +import type { ClientCapabilities } from '../types/types'; /** * Inbound request methods whose processing structurally requires a client diff --git a/packages/core/src/shared/envelope.ts b/packages/core-internal/src/shared/envelope.ts similarity index 96% rename from packages/core/src/shared/envelope.ts rename to packages/core-internal/src/shared/envelope.ts index 05fd71b9d0..08eaae6029 100644 --- a/packages/core/src/shared/envelope.ts +++ b/packages/core-internal/src/shared/envelope.ts @@ -19,9 +19,9 @@ * mapping live in the wire layer (the 2026-era codec's `validateEnvelopeMeta`). * This module never reaches into a per-revision wire module directly. */ -import { PROTOCOL_VERSION_META_KEY } from '../types/constants.js'; -import type { EnvelopeIssue } from '../wire/codec.js'; -import { codecForVersion, MODERN_WIRE_REVISION } from '../wire/codec.js'; +import { PROTOCOL_VERSION_META_KEY } from '../types/constants'; +import type { EnvelopeIssue } from '../wire/codec'; +import { codecForVersion, MODERN_WIRE_REVISION } from '../wire/codec'; // Re-export from the wire layer (the canonical home): the issue shape is part // of the function-only WireCodec contract. Imported above for the local return diff --git a/packages/core/src/shared/inboundClassification.ts b/packages/core-internal/src/shared/inboundClassification.ts similarity index 99% rename from packages/core/src/shared/inboundClassification.ts rename to packages/core-internal/src/shared/inboundClassification.ts index ca3cf9bda5..bffaae0645 100644 --- a/packages/core/src/shared/inboundClassification.ts +++ b/packages/core-internal/src/shared/inboundClassification.ts @@ -63,19 +63,19 @@ * `settled` flag on {@linkcode InboundLadderRejection} stays available to mark * a cell provisional again while such a change is in flight. */ -import { PROTOCOL_VERSION_META_KEY } from '../types/constants.js'; -import { ProtocolErrorCode } from '../types/enums.js'; -import { ProtocolError, UnsupportedProtocolVersionError } from '../types/errors.js'; -import { isJSONRPCErrorResponse, isJSONRPCNotification, isJSONRPCRequest, isJSONRPCResultResponse } from '../types/guards.js'; -import type { JSONRPCNotification, JSONRPCRequest, MessageClassification } from '../types/types.js'; -import { envelopeClaimVersion, hasEnvelopeClaim, requestMetaOf, validateEnvelopeMeta } from './envelope.js'; +import { PROTOCOL_VERSION_META_KEY } from '../types/constants'; +import { ProtocolErrorCode } from '../types/enums'; +import { ProtocolError, UnsupportedProtocolVersionError } from '../types/errors'; +import { isJSONRPCErrorResponse, isJSONRPCNotification, isJSONRPCRequest, isJSONRPCResultResponse } from '../types/guards'; +import type { JSONRPCNotification, JSONRPCRequest, MessageClassification } from '../types/types'; +import { envelopeClaimVersion, hasEnvelopeClaim, requestMetaOf, validateEnvelopeMeta } from './envelope'; // Value encoding is shared between the standard `Mcp-Name` header and the // custom `Mcp-Param-*` headers; the codec module already imports the // `HeaderMismatch` constant and rejection type from here, so this is a benign // two-module cycle (both sides only consume the other's exports inside // function bodies, never at module-evaluation time). -import { decodeMcpParamValue } from './mcpParamHeaders.js'; -import { isModernProtocolVersion } from './protocolEras.js'; +import { decodeMcpParamValue } from './mcpParamHeaders'; +import { isModernProtocolVersion } from './protocolEras'; /* ------------------------------------------------------------------------ * * Classifier input diff --git a/packages/core/src/shared/inputRequired.ts b/packages/core-internal/src/shared/inputRequired.ts similarity index 98% rename from packages/core/src/shared/inputRequired.ts rename to packages/core-internal/src/shared/inputRequired.ts index dfd2cac05f..43781d8990 100644 --- a/packages/core/src/shared/inputRequired.ts +++ b/packages/core-internal/src/shared/inputRequired.ts @@ -16,7 +16,7 @@ * discriminator, and hand-built result literals are equally legal — the * server seam re-checks the at-least-one rule for them. */ -import { isInputRequiredResult } from '../types/guards.js'; +import { isInputRequiredResult } from '../types/guards'; import type { CreateMessageRequestParams, ElicitRequestFormParams, @@ -26,8 +26,8 @@ import type { InputRequests, InputRequiredResult, InputResponses -} from '../types/types.js'; -import type { StandardSchemaV1 } from '../util/standardSchema.js'; +} from '../types/types'; +import type { StandardSchemaV1 } from '../util/standardSchema'; /** The shape accepted by {@linkcode inputRequired}. */ export interface InputRequiredSpec { diff --git a/packages/core/src/shared/inputRequiredDriver.ts b/packages/core-internal/src/shared/inputRequiredDriver.ts similarity index 98% rename from packages/core/src/shared/inputRequiredDriver.ts rename to packages/core-internal/src/shared/inputRequiredDriver.ts index 7142f20175..d754b544f9 100644 --- a/packages/core/src/shared/inputRequiredDriver.ts +++ b/packages/core-internal/src/shared/inputRequiredDriver.ts @@ -18,9 +18,9 @@ * every wire leg unchanged, and `maxTotalTimeout` bounds the whole flow by * shrinking the budget passed to each leg — no new timer system. */ -import { SdkError, SdkErrorCode } from '../errors/sdkErrors.js'; -import { isInputRequiredResult } from '../types/guards.js'; -import type { Progress } from '../types/types.js'; +import { SdkError, SdkErrorCode } from '../errors/sdkErrors'; +import { isInputRequiredResult } from '../types/guards'; +import type { Progress } from '../types/types'; /** * Whether the multi-round-trip driver fulfils `input_required` results diff --git a/packages/core/src/shared/inputRequiredEngine.ts b/packages/core-internal/src/shared/inputRequiredEngine.ts similarity index 96% rename from packages/core/src/shared/inputRequiredEngine.ts rename to packages/core-internal/src/shared/inputRequiredEngine.ts index b98ad54653..b665edbbde 100644 --- a/packages/core/src/shared/inputRequiredEngine.ts +++ b/packages/core-internal/src/shared/inputRequiredEngine.ts @@ -12,18 +12,18 @@ * `allowInputRequired` request option and the `inputResponses`/`requestState`/ * `droppedInputResponseKeys` context fields), and the named extension point. */ -import { SdkError, SdkErrorCode } from '../errors/sdkErrors.js'; -import type { InputRequiredResult, JSONRPCRequest, RequestMeta, Result } from '../types/types.js'; -import type { StandardSchemaV1 } from '../util/standardSchema.js'; -import type { WireCodec } from '../wire/codec.js'; +import { SdkError, SdkErrorCode } from '../errors/sdkErrors'; +import type { InputRequiredResult, JSONRPCRequest, RequestMeta, Result } from '../types/types'; +import type { StandardSchemaV1 } from '../util/standardSchema'; +import type { WireCodec } from '../wire/codec'; import type { InputRequiredDriverHooks, InputRequiredPayload, InputRequiredRetryLegOptions, ResolvedInputRequiredDriverConfig -} from './inputRequiredDriver.js'; -import { runInputRequiredDriver } from './inputRequiredDriver.js'; -import type { BaseContext, NonCompleteResultFlow, RequestOptions } from './protocol.js'; +} from './inputRequiredDriver'; +import { runInputRequiredDriver } from './inputRequiredDriver'; +import type { BaseContext, NonCompleteResultFlow, RequestOptions } from './protocol'; function isPlainObject(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); diff --git a/packages/core/src/shared/mcpParamHeaders.ts b/packages/core-internal/src/shared/mcpParamHeaders.ts similarity index 99% rename from packages/core/src/shared/mcpParamHeaders.ts rename to packages/core-internal/src/shared/mcpParamHeaders.ts index 87884a5408..493cf50aeb 100644 --- a/packages/core/src/shared/mcpParamHeaders.ts +++ b/packages/core-internal/src/shared/mcpParamHeaders.ts @@ -20,8 +20,8 @@ * - draft/server/tools.mdx § "x-mcp-header" (the schema-extension property and * its constraints) */ -import type { InboundLadderRejection } from './inboundClassification.js'; -import { HEADER_MISMATCH_ERROR_CODE } from './inboundClassification.js'; +import type { InboundLadderRejection } from './inboundClassification'; +import { HEADER_MISMATCH_ERROR_CODE } from './inboundClassification'; /* ------------------------------------------------------------------------ * * Declaration scan diff --git a/packages/core/src/shared/metadataUtils.ts b/packages/core-internal/src/shared/metadataUtils.ts similarity index 94% rename from packages/core/src/shared/metadataUtils.ts rename to packages/core-internal/src/shared/metadataUtils.ts index 1b11660e86..0836b4394a 100644 --- a/packages/core/src/shared/metadataUtils.ts +++ b/packages/core-internal/src/shared/metadataUtils.ts @@ -1,4 +1,4 @@ -import type { BaseMetadata } from '../types/index.js'; +import type { BaseMetadata } from '../types/index'; /** * Utilities for working with {@linkcode BaseMetadata} objects. diff --git a/packages/core/src/shared/protocol.examples.ts b/packages/core-internal/src/shared/protocol.examples.ts similarity index 94% rename from packages/core/src/shared/protocol.examples.ts rename to packages/core-internal/src/shared/protocol.examples.ts index ba3a701a2f..0ae10e6d08 100644 --- a/packages/core/src/shared/protocol.examples.ts +++ b/packages/core-internal/src/shared/protocol.examples.ts @@ -9,7 +9,7 @@ import * as z from 'zod/v4'; -import type { BaseContext, Protocol } from './protocol.js'; +import type { BaseContext, Protocol } from './protocol'; /** * Example: registering a handler for a custom (non-spec) request method. diff --git a/packages/core/src/shared/protocol.ts b/packages/core-internal/src/shared/protocol.ts similarity index 99% rename from packages/core/src/shared/protocol.ts rename to packages/core-internal/src/shared/protocol.ts index b141c98f03..08cc100477 100644 --- a/packages/core/src/shared/protocol.ts +++ b/packages/core-internal/src/shared/protocol.ts @@ -1,4 +1,4 @@ -import { SdkError, SdkErrorCode } from '../errors/sdkErrors.js'; +import { SdkError, SdkErrorCode } from '../errors/sdkErrors'; import type { AuthInfo, CancelledNotification, @@ -31,7 +31,7 @@ import type { Result, ResultTypeMap, ServerCapabilities -} from '../types/index.js'; +} from '../types/index'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, @@ -44,14 +44,14 @@ import { ProtocolError, ProtocolErrorCode, SUPPORTED_PROTOCOL_VERSIONS -} from '../types/index.js'; -import type { StandardSchemaV1 } from '../util/standardSchema.js'; -import { isStandardSchema, validateStandardSchema } from '../util/standardSchema.js'; -import { bootstrapOutboundCodec } from '../wire/bootstrap.js'; -import type { LiftedWireMaterial, WireCodec } from '../wire/codec.js'; -import { classifiedWireEra, codecForVersion, isSpecNotificationMethod, isSpecRequestMethod, MODERN_WIRE_REVISION } from '../wire/codec.js'; -import { manualInputRequiredValue, partitionInputResponses } from './inputRequiredEngine.js'; -import type { Transport, TransportSendOptions } from './transport.js'; +} from '../types/index'; +import type { StandardSchemaV1 } from '../util/standardSchema'; +import { isStandardSchema, validateStandardSchema } from '../util/standardSchema'; +import { bootstrapOutboundCodec } from '../wire/bootstrap'; +import type { LiftedWireMaterial, WireCodec } from '../wire/codec'; +import { classifiedWireEra, codecForVersion, isSpecNotificationMethod, isSpecRequestMethod, MODERN_WIRE_REVISION } from '../wire/codec'; +import { manualInputRequiredValue, partitionInputResponses } from './inputRequiredEngine'; +import type { Transport, TransportSendOptions } from './transport'; /** * Callback for progress notifications. diff --git a/packages/core/src/shared/protocolEras.ts b/packages/core-internal/src/shared/protocolEras.ts similarity index 100% rename from packages/core/src/shared/protocolEras.ts rename to packages/core-internal/src/shared/protocolEras.ts diff --git a/packages/core/src/shared/resultCacheHints.ts b/packages/core-internal/src/shared/resultCacheHints.ts similarity index 100% rename from packages/core/src/shared/resultCacheHints.ts rename to packages/core-internal/src/shared/resultCacheHints.ts diff --git a/packages/core/src/shared/stdio.ts b/packages/core-internal/src/shared/stdio.ts similarity index 94% rename from packages/core/src/shared/stdio.ts rename to packages/core-internal/src/shared/stdio.ts index ffadff6c86..8bd794b87b 100644 --- a/packages/core/src/shared/stdio.ts +++ b/packages/core-internal/src/shared/stdio.ts @@ -1,5 +1,5 @@ -import type { JSONRPCMessage } from '../types/index.js'; -import { JSONRPCMessageSchema } from '../types/index.js'; +import type { JSONRPCMessage } from '../types/index'; +import { JSONRPCMessageSchema } from '../types/index'; export const STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024; diff --git a/packages/core/src/shared/toolNameValidation.ts b/packages/core-internal/src/shared/toolNameValidation.ts similarity index 100% rename from packages/core/src/shared/toolNameValidation.ts rename to packages/core-internal/src/shared/toolNameValidation.ts diff --git a/packages/core/src/shared/transport.ts b/packages/core-internal/src/shared/transport.ts similarity index 99% rename from packages/core/src/shared/transport.ts rename to packages/core-internal/src/shared/transport.ts index ce64b67fdd..226f6ab0bd 100644 --- a/packages/core/src/shared/transport.ts +++ b/packages/core-internal/src/shared/transport.ts @@ -1,4 +1,4 @@ -import type { JSONRPCMessage, MessageExtraInfo, RequestId } from '../types/index.js'; +import type { JSONRPCMessage, MessageExtraInfo, RequestId } from '../types/index'; export type FetchLike = (url: string | URL, init?: RequestInit) => Promise; diff --git a/packages/core/src/shared/uriTemplate.ts b/packages/core-internal/src/shared/uriTemplate.ts similarity index 100% rename from packages/core/src/shared/uriTemplate.ts rename to packages/core-internal/src/shared/uriTemplate.ts diff --git a/packages/core/src/types/README.md b/packages/core-internal/src/types/README.md similarity index 88% rename from packages/core/src/types/README.md rename to packages/core-internal/src/types/README.md index 6d235ec8ae..fda450e8e9 100644 --- a/packages/core/src/types/README.md +++ b/packages/core-internal/src/types/README.md @@ -3,7 +3,7 @@ The `spec.types..ts` files in this directory are vendored, verbatim copies of the MCP specification's normative `schema.ts`, one file per protocol revision. Each file is generated by `pnpm run fetch:spec-types [version] [sha]` (`scripts/fetch-spec-types.ts`): the upstream schema is fetched at a specific spec commit, a provenance header recording that commit is prepended, and the result is formatted with the project's prettier config — no other transformation. -They are reference-only test oracles: the comparison suites in `packages/core/test/spec.types..test.ts` check the SDK's own types against them. They are not exported from any barrel and must never be imported by runtime code. +They are reference-only test oracles: the comparison suites in `packages/core-internal/test/spec.types..test.ts` check the SDK's own types against them. They are not exported from any barrel and must never be imported by runtime code. ## Lifecycle policy @@ -20,7 +20,7 @@ They are reference-only test oracles: the comparison suites in `packages/core/te 4. **Generated twins update atomically with their anchor.** If artifacts derived from an anchor (for example vendored JSON schemas or generated validators) are checked into this repository, any refresh that changes the anchor must regenerate those artifacts in the same commit. The anchor and its derived twins must never be out of sync at any commit on `main`. - **This clause is OPERATIVE.** The vendored twins are the per-revision `schema.json` copies under `packages/core/test/corpus/schema-twins/` (`.schema.json` + `manifest.json` recording the source commit and content hashes). They are TEST-ONLY oracles consumed by the + **This clause is OPERATIVE.** The vendored twins are the per-revision `schema.json` copies under `packages/core-internal/test/corpus/schema-twins/` (`.schema.json` + `manifest.json` recording the source commit and content hashes). They are TEST-ONLY oracles consumed by the schema-twin conformance lock (`test/wire/schemaTwinConformance.test.ts`) — never bundled, never imported by runtime code, and the JSON Schema engines stay optional peer dependencies. A refresh of `spec.types..ts` must copy the matching upstream `schema//schema.json` (same spec commit) over the twin and update `manifest.json` in the same commit; the spec example corpus manifest (`test/corpus/fixtures//manifest.json`) records its own source commit and follows the same atomicity rule when the examples are re-vendored. The conformance lock failing after an anchor-only refresh is the desired loud signal of a missed twin update. diff --git a/packages/core/src/types/constants.ts b/packages/core-internal/src/types/constants.ts similarity index 100% rename from packages/core/src/types/constants.ts rename to packages/core-internal/src/types/constants.ts diff --git a/packages/core/src/types/enums.ts b/packages/core-internal/src/types/enums.ts similarity index 100% rename from packages/core/src/types/enums.ts rename to packages/core-internal/src/types/enums.ts diff --git a/packages/core/src/types/errors.ts b/packages/core-internal/src/types/errors.ts similarity index 99% rename from packages/core/src/types/errors.ts rename to packages/core-internal/src/types/errors.ts index 4cf8fc9036..8f268c3a8c 100644 --- a/packages/core/src/types/errors.ts +++ b/packages/core-internal/src/types/errors.ts @@ -1,10 +1,10 @@ -import { ProtocolErrorCode } from './enums.js'; +import { ProtocolErrorCode } from './enums'; import type { ClientCapabilities, ElicitRequestURLParams, MissingRequiredClientCapabilityErrorData, UnsupportedProtocolVersionErrorData -} from './types.js'; +} from './types'; /** * Protocol errors are JSON-RPC errors that cross the wire as error responses. diff --git a/packages/core/src/types/guards.ts b/packages/core-internal/src/types/guards.ts similarity index 99% rename from packages/core/src/types/guards.ts rename to packages/core-internal/src/types/guards.ts index 0a5f4b7cd4..a0d575054e 100644 --- a/packages/core/src/types/guards.ts +++ b/packages/core-internal/src/types/guards.ts @@ -9,7 +9,7 @@ import { JSONRPCResponseSchema, JSONRPCResultResponseSchema, TaskAugmentedRequestParamsSchema -} from './schemas.js'; +} from './schemas'; import type { CallToolResult, CompleteRequest, @@ -25,7 +25,7 @@ import type { JSONRPCResponse, JSONRPCResultResponse, TaskAugmentedRequestParams -} from './types.js'; +} from './types'; /** * Validates and parses an unknown value as a JSON-RPC message. diff --git a/packages/core-internal/src/types/index.ts b/packages/core-internal/src/types/index.ts new file mode 100644 index 0000000000..46dd118f11 --- /dev/null +++ b/packages/core-internal/src/types/index.ts @@ -0,0 +1,9 @@ +// Internal barrel — re-exports everything for use within the SDK packages. +// The public API is defined in @modelcontextprotocol/core-internal/public (see exports/public/index.ts). +export * from './constants'; +export * from './enums'; +export * from './errors'; +export * from './guards'; +export * from './schemas'; +export * from './specTypeSchema'; +export * from './types'; diff --git a/packages/core/src/types/schemas.ts b/packages/core-internal/src/types/schemas.ts similarity index 99% rename from packages/core/src/types/schemas.ts rename to packages/core-internal/src/types/schemas.ts index 9ea3048416..21960a6176 100644 --- a/packages/core/src/types/schemas.ts +++ b/packages/core-internal/src/types/schemas.ts @@ -1,7 +1,7 @@ import * as z from 'zod/v4'; -import { JSONRPC_VERSION, RELATED_TASK_META_KEY, SUBSCRIPTION_ID_META_KEY } from './constants.js'; -import type { JSONArray, JSONObject, JSONValue } from './types.js'; +import { JSONRPC_VERSION, RELATED_TASK_META_KEY, SUBSCRIPTION_ID_META_KEY } from './constants'; +import type { JSONArray, JSONObject, JSONValue } from './types'; export const JSONValueSchema: z.ZodType = z.lazy(() => z.union([z.string(), z.number(), z.boolean(), z.null(), z.record(z.string(), JSONValueSchema), z.array(JSONValueSchema)]) diff --git a/packages/core/src/types/spec.types.2025-11-25.ts b/packages/core-internal/src/types/spec.types.2025-11-25.ts similarity index 100% rename from packages/core/src/types/spec.types.2025-11-25.ts rename to packages/core-internal/src/types/spec.types.2025-11-25.ts diff --git a/packages/core/src/types/spec.types.2026-07-28.ts b/packages/core-internal/src/types/spec.types.2026-07-28.ts similarity index 100% rename from packages/core/src/types/spec.types.2026-07-28.ts rename to packages/core-internal/src/types/spec.types.2026-07-28.ts diff --git a/packages/core/src/types/specTypeSchema.examples.ts b/packages/core-internal/src/types/specTypeSchema.examples.ts similarity index 94% rename from packages/core/src/types/specTypeSchema.examples.ts rename to packages/core-internal/src/types/specTypeSchema.examples.ts index 8e991d4f94..c05f65e62d 100644 --- a/packages/core/src/types/specTypeSchema.examples.ts +++ b/packages/core-internal/src/types/specTypeSchema.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { isSpecType, specTypeSchemas } from './specTypeSchema.js'; +import { isSpecType, specTypeSchemas } from './specTypeSchema'; declare const untrusted: unknown; declare const value: unknown; diff --git a/packages/core/src/types/specTypeSchema.ts b/packages/core-internal/src/types/specTypeSchema.ts similarity index 98% rename from packages/core/src/types/specTypeSchema.ts rename to packages/core-internal/src/types/specTypeSchema.ts index c3cc3e0e74..f7a109cbd5 100644 --- a/packages/core/src/types/specTypeSchema.ts +++ b/packages/core-internal/src/types/specTypeSchema.ts @@ -1,6 +1,7 @@ import type * as z from 'zod/v4'; import { + IdJagTokenExchangeResponseSchema, OAuthClientInformationFullSchema, OAuthClientInformationSchema, OAuthClientMetadataSchema, @@ -12,9 +13,9 @@ import { OAuthTokensSchema, OpenIdProviderDiscoveryMetadataSchema, OpenIdProviderMetadataSchema -} from '../shared/auth.js'; -import type { StandardSchemaV1, StandardSchemaV1Sync } from '../util/standardSchema.js'; -import * as schemas from './schemas.js'; +} from '../shared/auth'; +import type { StandardSchemaV1, StandardSchemaV1Sync } from '../util/standardSchema'; +import * as schemas from './schemas'; /** * Explicit allowlist of protocol Zod schemas that correspond to a public spec type in `types.ts`. @@ -194,6 +195,7 @@ const SPEC_SCHEMA_KEYS = [ ] as const satisfies readonly (keyof typeof schemas)[]; const authSchemas = { + IdJagTokenExchangeResponseSchema, OAuthClientInformationFullSchema, OAuthClientInformationSchema, OAuthClientMetadataSchema, diff --git a/packages/core/src/types/types.ts b/packages/core-internal/src/types/types.ts similarity index 99% rename from packages/core/src/types/types.ts rename to packages/core-internal/src/types/types.ts index d61b43bd04..2338ff3013 100644 --- a/packages/core/src/types/types.ts +++ b/packages/core-internal/src/types/types.ts @@ -14,7 +14,7 @@ import type { METHOD_NOT_FOUND, PARSE_ERROR, PROTOCOL_VERSION_META_KEY -} from './constants.js'; +} from './constants'; import type { AnnotationsSchema, AudioContentSchema, @@ -173,7 +173,7 @@ import type { UnsubscribeRequestSchema, UntitledMultiSelectEnumSchemaSchema, UntitledSingleSelectEnumSchemaSchema -} from './schemas.js'; +} from './schemas'; /* JSON types */ export type JSONValue = string | number | boolean | null | JSONObject | JSONArray; diff --git a/packages/core/src/util/inMemory.ts b/packages/core-internal/src/util/inMemory.ts similarity index 95% rename from packages/core/src/util/inMemory.ts rename to packages/core-internal/src/util/inMemory.ts index 4e79932094..3afd2b1ac7 100644 --- a/packages/core/src/util/inMemory.ts +++ b/packages/core-internal/src/util/inMemory.ts @@ -1,6 +1,6 @@ -import { SdkError, SdkErrorCode } from '../errors/sdkErrors.js'; -import type { Transport } from '../shared/transport.js'; -import type { AuthInfo, JSONRPCMessage, RequestId } from '../types/index.js'; +import { SdkError, SdkErrorCode } from '../errors/sdkErrors'; +import type { Transport } from '../shared/transport'; +import type { AuthInfo, JSONRPCMessage, RequestId } from '../types/index'; interface QueuedMessage { message: JSONRPCMessage; diff --git a/packages/core/src/util/schema.ts b/packages/core-internal/src/util/schema.ts similarity index 100% rename from packages/core/src/util/schema.ts rename to packages/core-internal/src/util/schema.ts diff --git a/packages/core/src/util/standardSchema.ts b/packages/core-internal/src/util/standardSchema.ts similarity index 100% rename from packages/core/src/util/standardSchema.ts rename to packages/core-internal/src/util/standardSchema.ts diff --git a/packages/core/src/util/zodCompat.ts b/packages/core-internal/src/util/zodCompat.ts similarity index 96% rename from packages/core/src/util/zodCompat.ts rename to packages/core-internal/src/util/zodCompat.ts index 3bb208809c..249dba5154 100644 --- a/packages/core/src/util/zodCompat.ts +++ b/packages/core-internal/src/util/zodCompat.ts @@ -6,8 +6,8 @@ import * as z from 'zod/v4'; -import type { StandardSchemaWithJSON } from './standardSchema.js'; -import { isStandardSchema } from './standardSchema.js'; +import type { StandardSchemaWithJSON } from './standardSchema'; +import { isStandardSchema } from './standardSchema'; function isZodV4Schema(v: unknown): v is z.ZodType { // `_zod` is the v4 internal namespace property. Zod v3 schemas have `_def` diff --git a/packages/core/src/validators/ajvProvider.examples.ts b/packages/core-internal/src/validators/ajvProvider.examples.ts similarity index 99% rename from packages/core/src/validators/ajvProvider.examples.ts rename to packages/core-internal/src/validators/ajvProvider.examples.ts index 7258c20291..e139dc5eab 100644 --- a/packages/core/src/validators/ajvProvider.examples.ts +++ b/packages/core-internal/src/validators/ajvProvider.examples.ts @@ -9,7 +9,7 @@ import { Ajv2020 } from 'ajv/dist/2020.js'; -import { addFormats, AjvJsonSchemaValidator } from './ajvProvider.js'; +import { addFormats, AjvJsonSchemaValidator } from './ajvProvider'; /** * Example: Default AJV instance. diff --git a/packages/core/src/validators/ajvProvider.ts b/packages/core-internal/src/validators/ajvProvider.ts similarity index 99% rename from packages/core/src/validators/ajvProvider.ts rename to packages/core-internal/src/validators/ajvProvider.ts index 59c7c87952..2d1d948721 100644 --- a/packages/core/src/validators/ajvProvider.ts +++ b/packages/core-internal/src/validators/ajvProvider.ts @@ -5,7 +5,7 @@ import { Ajv2020 } from 'ajv/dist/2020.js'; import _addFormats from 'ajv-formats'; -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types.js'; +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types'; /** * Canonical 2020-12 `$schema` URIs (http + https variants, trailing-`#` stripped). When a schema diff --git a/packages/core/src/validators/cfWorkerProvider.examples.ts b/packages/core-internal/src/validators/cfWorkerProvider.examples.ts similarity index 93% rename from packages/core/src/validators/cfWorkerProvider.examples.ts rename to packages/core-internal/src/validators/cfWorkerProvider.examples.ts index c166c18dd6..facc971b0c 100644 --- a/packages/core/src/validators/cfWorkerProvider.examples.ts +++ b/packages/core-internal/src/validators/cfWorkerProvider.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { CfWorkerJsonSchemaValidator } from './cfWorkerProvider.js'; +import { CfWorkerJsonSchemaValidator } from './cfWorkerProvider'; /** * Example: Default configuration (draft 2020-12, shortcircuit on). diff --git a/packages/core/src/validators/cfWorkerProvider.ts b/packages/core-internal/src/validators/cfWorkerProvider.ts similarity index 98% rename from packages/core/src/validators/cfWorkerProvider.ts rename to packages/core-internal/src/validators/cfWorkerProvider.ts index dde545fe59..8af5ff6393 100644 --- a/packages/core/src/validators/cfWorkerProvider.ts +++ b/packages/core-internal/src/validators/cfWorkerProvider.ts @@ -10,7 +10,7 @@ import { Validator } from '@cfworker/json-schema'; -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types.js'; +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types'; /** * JSON Schema draft version supported by `@cfworker/json-schema`. diff --git a/packages/core/src/validators/fromJsonSchema.examples.ts b/packages/core-internal/src/validators/fromJsonSchema.examples.ts similarity index 88% rename from packages/core/src/validators/fromJsonSchema.examples.ts rename to packages/core-internal/src/validators/fromJsonSchema.examples.ts index af72b5b036..7df661c545 100644 --- a/packages/core/src/validators/fromJsonSchema.examples.ts +++ b/packages/core-internal/src/validators/fromJsonSchema.examples.ts @@ -6,8 +6,8 @@ * @module */ -import { fromJsonSchema } from './fromJsonSchema.js'; -import type { jsonSchemaValidator } from './types.js'; +import { fromJsonSchema } from './fromJsonSchema'; +import type { jsonSchemaValidator } from './types'; declare const validator: jsonSchemaValidator; diff --git a/packages/core/src/validators/fromJsonSchema.ts b/packages/core-internal/src/validators/fromJsonSchema.ts similarity index 98% rename from packages/core/src/validators/fromJsonSchema.ts rename to packages/core-internal/src/validators/fromJsonSchema.ts index 4b7a6f11a3..696d1f29e9 100644 --- a/packages/core/src/validators/fromJsonSchema.ts +++ b/packages/core-internal/src/validators/fromJsonSchema.ts @@ -1,5 +1,5 @@ -import type { StandardSchemaV1, StandardSchemaWithJSON } from '../util/standardSchema.js'; -import type { JsonSchemaType, jsonSchemaValidator } from './types.js'; +import type { StandardSchemaV1, StandardSchemaWithJSON } from '../util/standardSchema'; +import type { JsonSchemaType, jsonSchemaValidator } from './types'; /** * Wrap a raw JSON Schema object as a {@linkcode StandardSchemaWithJSON} so it can be diff --git a/packages/core/src/validators/types.examples.ts b/packages/core-internal/src/validators/types.examples.ts similarity index 97% rename from packages/core/src/validators/types.examples.ts rename to packages/core-internal/src/validators/types.examples.ts index b6cd760695..2066a8aff3 100644 --- a/packages/core/src/validators/types.examples.ts +++ b/packages/core-internal/src/validators/types.examples.ts @@ -7,7 +7,7 @@ * @module */ -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from './types.js'; +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from './types'; // Stub for hypothetical schema validation function declare function isValid(schema: JsonSchemaType, input: unknown): boolean; diff --git a/packages/core/src/validators/types.ts b/packages/core-internal/src/validators/types.ts similarity index 100% rename from packages/core/src/validators/types.ts rename to packages/core-internal/src/validators/types.ts diff --git a/packages/core/src/wire/bootstrap.ts b/packages/core-internal/src/wire/bootstrap.ts similarity index 94% rename from packages/core/src/wire/bootstrap.ts rename to packages/core-internal/src/wire/bootstrap.ts index 5ae43bb39d..413c8d23d4 100644 --- a/packages/core/src/wire/bootstrap.ts +++ b/packages/core-internal/src/wire/bootstrap.ts @@ -24,8 +24,8 @@ * present on the 2025 era, absent from the 2026 era (the modern keepalive * story is owned by the negotiation milestones). */ -import type { WireCodec } from './codec.js'; -import { codecForVersion, MODERN_WIRE_REVISION } from './codec.js'; +import type { WireCodec } from './codec'; +import { codecForVersion, MODERN_WIRE_REVISION } from './codec'; export function bootstrapOutboundCodec(method: string): WireCodec | undefined { switch (method) { diff --git a/packages/core/src/wire/codec.ts b/packages/core-internal/src/wire/codec.ts similarity index 98% rename from packages/core/src/wire/codec.ts rename to packages/core-internal/src/wire/codec.ts index 4e777dc12b..9efb9a12f3 100644 --- a/packages/core/src/wire/codec.ts +++ b/packages/core-internal/src/wire/codec.ts @@ -41,8 +41,8 @@ * nothing per-revision is public surface, and nothing here may ever be * exported from `core/public`. */ -import type { SdkError } from '../errors/sdkErrors.js'; -import { isModernProtocolVersion } from '../shared/protocolEras.js'; +import type { SdkError } from '../errors/sdkErrors'; +import { isModernProtocolVersion } from '../shared/protocolEras'; import type { CallToolResult, ClientCapabilities, @@ -58,9 +58,9 @@ import type { RequestTypeMap, Result, ResultTypeMap -} from '../types/types.js'; -import { rev2025Codec } from './rev2025-11-25/codec.js'; -import { rev2026Codec } from './rev2026-07-28/codec.js'; +} from '../types/types'; +import { rev2025Codec } from './rev2025-11-25/codec'; +import { rev2026Codec } from './rev2026-07-28/codec'; /** Wire eras with distinct vocabulary. */ export type WireEra = '2025-11-25' | '2026-07-28'; diff --git a/packages/core/src/wire/rev2025-11-25/codec.ts b/packages/core-internal/src/wire/rev2025-11-25/codec.ts similarity index 97% rename from packages/core/src/wire/rev2025-11-25/codec.ts rename to packages/core-internal/src/wire/rev2025-11-25/codec.ts index b542b6cb06..ed30e9c67b 100644 --- a/packages/core/src/wire/rev2025-11-25/codec.ts +++ b/packages/core-internal/src/wire/rev2025-11-25/codec.ts @@ -28,12 +28,12 @@ */ import type * as z from 'zod/v4'; -import type { CallToolResult, Result } from '../../types/types.js'; -import type { DecodedResult, EnvelopeIssue, LiftedWireMaterial, OutboundEnvelopeMaterial, ValidateOutcome, WireCodec } from '../codec.js'; -import { appendTextFallbackForNonObject } from '../textFallback.js'; -import { isNonObjectJsonSchemaRoot, wrapOutputSchemaForLegacy } from './legacyWrap.js'; -import { getNotificationSchema, getRequestSchema, getResultSchema, hasNotificationMethod2025, hasRequestMethod2025 } from './registry.js'; -import { CreateMessageResultSchema, CreateMessageResultWithToolsSchema } from './schemas.js'; +import type { CallToolResult, Result } from '../../types/types'; +import type { DecodedResult, EnvelopeIssue, LiftedWireMaterial, OutboundEnvelopeMaterial, ValidateOutcome, WireCodec } from '../codec'; +import { appendTextFallbackForNonObject } from '../textFallback'; +import { isNonObjectJsonSchemaRoot, wrapOutputSchemaForLegacy } from './legacyWrap'; +import { getNotificationSchema, getRequestSchema, getResultSchema, hasNotificationMethod2025, hasRequestMethod2025 } from './registry'; +import { CreateMessageResultSchema, CreateMessageResultWithToolsSchema } from './schemas'; function isPlainObject(value: unknown): value is Record { return value !== null && typeof value === 'object' && !Array.isArray(value); diff --git a/packages/core/src/wire/rev2025-11-25/legacyWrap.ts b/packages/core-internal/src/wire/rev2025-11-25/legacyWrap.ts similarity index 100% rename from packages/core/src/wire/rev2025-11-25/legacyWrap.ts rename to packages/core-internal/src/wire/rev2025-11-25/legacyWrap.ts diff --git a/packages/core/src/wire/rev2025-11-25/registry.ts b/packages/core-internal/src/wire/rev2025-11-25/registry.ts similarity index 98% rename from packages/core/src/wire/rev2025-11-25/registry.ts rename to packages/core-internal/src/wire/rev2025-11-25/registry.ts index 478485fa23..f2878d429e 100644 --- a/packages/core/src/wire/rev2025-11-25/registry.ts +++ b/packages/core-internal/src/wire/rev2025-11-25/registry.ts @@ -23,8 +23,8 @@ */ import type * as z from 'zod/v4'; -import type { NotificationMethod, NotificationTypeMap, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types.js'; -import type { ClientNotificationSchema, ClientRequestSchema, ServerNotificationSchema, ServerRequestSchema } from './schemas.js'; +import type { NotificationMethod, NotificationTypeMap, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types'; +import type { ClientNotificationSchema, ClientRequestSchema, ServerNotificationSchema, ServerRequestSchema } from './schemas'; import { CallToolRequestSchema, CallToolResultSchema, @@ -70,7 +70,7 @@ import { TaskStatusNotificationSchema, ToolListChangedNotificationSchema, UnsubscribeRequestSchema -} from './schemas.js'; +} from './schemas'; /* The era's wire vocabulary, derived from the wire role unions in * `./schemas.ts` (the same unions the registries used to be built from at diff --git a/packages/core/src/wire/rev2025-11-25/schemas.ts b/packages/core-internal/src/wire/rev2025-11-25/schemas.ts similarity index 99% rename from packages/core/src/wire/rev2025-11-25/schemas.ts rename to packages/core-internal/src/wire/rev2025-11-25/schemas.ts index 12041e2bb5..935e3b74cc 100644 --- a/packages/core/src/wire/rev2025-11-25/schemas.ts +++ b/packages/core-internal/src/wire/rev2025-11-25/schemas.ts @@ -27,7 +27,7 @@ */ import * as z from 'zod/v4'; -import type { JSONObject, JSONValue } from '../../types/types.js'; +import type { JSONObject, JSONValue } from '../../types/types'; /* ─────────────────────────────────────────────────────────────────────────── * Building blocks diff --git a/packages/core/src/wire/rev2025-11-25/wireTypes.ts b/packages/core-internal/src/wire/rev2025-11-25/wireTypes.ts similarity index 99% rename from packages/core/src/wire/rev2025-11-25/wireTypes.ts rename to packages/core-internal/src/wire/rev2025-11-25/wireTypes.ts index ee36905fe6..73aad99818 100644 --- a/packages/core/src/wire/rev2025-11-25/wireTypes.ts +++ b/packages/core-internal/src/wire/rev2025-11-25/wireTypes.ts @@ -65,8 +65,8 @@ import type { SubscribeRequest, Tool, UnsubscribeRequest -} from '../../types/types.js'; -import type { SamplingMessageSchema as Frozen2025SamplingMessageSchema } from './schemas.js'; +} from '../../types/types'; +import type { SamplingMessageSchema as Frozen2025SamplingMessageSchema } from './schemas'; /** The 2025 anchor types blob values as bare `object`. */ type ObjectMap = { [key: string]: object }; diff --git a/packages/core/src/wire/rev2026-07-28/codec.ts b/packages/core-internal/src/wire/rev2026-07-28/codec.ts similarity index 96% rename from packages/core/src/wire/rev2026-07-28/codec.ts rename to packages/core-internal/src/wire/rev2026-07-28/codec.ts index 6b6713d7e0..d76d41024e 100644 --- a/packages/core/src/wire/rev2026-07-28/codec.ts +++ b/packages/core-internal/src/wire/rev2026-07-28/codec.ts @@ -27,25 +27,20 @@ */ import type * as z from 'zod/v4'; -import { SdkError, SdkErrorCode } from '../../errors/sdkErrors.js'; -import { - CLIENT_CAPABILITIES_META_KEY, - CLIENT_INFO_META_KEY, - LOG_LEVEL_META_KEY, - PROTOCOL_VERSION_META_KEY -} from '../../types/constants.js'; -import type { CallToolResult, Result } from '../../types/types.js'; -import type { DecodedResult, EnvelopeIssue, LiftedWireMaterial, OutboundEnvelopeMaterial, ValidateOutcome, WireCodec } from '../codec.js'; -import { appendTextFallbackForNonObject } from '../textFallback.js'; -import { fillCacheFields, stampResultType } from './encodeContract.js'; -import { getInputRequestSchema2026, getInputResponseSchema2026 } from './inputRequired.js'; +import { SdkError, SdkErrorCode } from '../../errors/sdkErrors'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, LOG_LEVEL_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../types/constants'; +import type { CallToolResult, Result } from '../../types/types'; +import type { DecodedResult, EnvelopeIssue, LiftedWireMaterial, OutboundEnvelopeMaterial, ValidateOutcome, WireCodec } from '../codec'; +import { appendTextFallbackForNonObject } from '../textFallback'; +import { fillCacheFields, stampResultType } from './encodeContract'; +import { getInputRequestSchema2026, getInputResponseSchema2026 } from './inputRequired'; import { getNotificationSchema2026, getRequestSchema2026, getResultSchema2026, hasNotificationMethod2026, hasRequestMethod2026 -} from './registry.js'; +} from './registry'; import { CallToolResultSchema, CompleteResultSchema, @@ -57,7 +52,7 @@ import { ListToolsResultSchema, ReadResourceResultSchema, RequestMetaEnvelopeSchema -} from './schemas.js'; +} from './schemas'; function isPlainObject(value: unknown): value is Record { return value !== null && typeof value === 'object' && !Array.isArray(value); diff --git a/packages/core/src/wire/rev2026-07-28/encodeContract.ts b/packages/core-internal/src/wire/rev2026-07-28/encodeContract.ts similarity index 95% rename from packages/core/src/wire/rev2026-07-28/encodeContract.ts rename to packages/core-internal/src/wire/rev2026-07-28/encodeContract.ts index de8f09a951..df3e71b5d0 100644 --- a/packages/core/src/wire/rev2026-07-28/encodeContract.ts +++ b/packages/core-internal/src/wire/rev2026-07-28/encodeContract.ts @@ -21,17 +21,17 @@ * Ordering matters and is pinned by tests: the stamp runs before the fill, so * an `input_required` result is never given cache fields. */ -import type { CacheHint } from '../../shared/resultCacheHints.js'; +import type { CacheHint } from '../../shared/resultCacheHints'; import { cacheHintFallbackOf, isCacheableResultMethod, isValidCacheScope, isValidCacheTtlMs, RESULT_CACHE_HINT_FALLBACK -} from '../../shared/resultCacheHints.js'; -import { ProtocolErrorCode } from '../../types/enums.js'; -import { ProtocolError } from '../../types/errors.js'; -import type { Result } from '../../types/types.js'; +} from '../../shared/resultCacheHints'; +import { ProtocolErrorCode } from '../../types/enums'; +import { ProtocolError } from '../../types/errors'; +import type { Result } from '../../types/types'; /** The default cache policy when neither the handler nor configuration provides one. */ export const DEFAULT_CACHE_TTL_MS = 0; diff --git a/packages/core/src/wire/rev2026-07-28/inputRequired.ts b/packages/core-internal/src/wire/rev2026-07-28/inputRequired.ts similarity index 98% rename from packages/core/src/wire/rev2026-07-28/inputRequired.ts rename to packages/core-internal/src/wire/rev2026-07-28/inputRequired.ts index 365a178d73..615cf5fd38 100644 --- a/packages/core/src/wire/rev2026-07-28/inputRequired.ts +++ b/packages/core-internal/src/wire/rev2026-07-28/inputRequired.ts @@ -20,14 +20,14 @@ */ import * as z from 'zod/v4'; -import type { RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types.js'; +import type { RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types'; import { CreateMessageRequestParamsSchema, CreateMessageResultSchema, ElicitRequestParamsSchema, ElicitResultSchema, ListRootsResultSchema -} from './schemas.js'; +} from './schemas'; /** The embedded input-request methods of the 2026-07-28 revision. */ export const INPUT_REQUEST_METHODS_2026 = ['elicitation/create', 'sampling/createMessage', 'roots/list'] as const; diff --git a/packages/core/src/wire/rev2026-07-28/registry.ts b/packages/core-internal/src/wire/rev2026-07-28/registry.ts similarity index 97% rename from packages/core/src/wire/rev2026-07-28/registry.ts rename to packages/core-internal/src/wire/rev2026-07-28/registry.ts index 969c719bbd..c515b58a4e 100644 --- a/packages/core/src/wire/rev2026-07-28/registry.ts +++ b/packages/core-internal/src/wire/rev2026-07-28/registry.ts @@ -29,9 +29,9 @@ */ import type * as z from 'zod/v4'; -import type { NotificationMethod, NotificationTypeMap, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types.js'; -import type { Rev2026NotificationMethod, Rev2026RequestMethod } from './schemas.js'; -import { dispatchRequestSchemas, dispatchResultSchemas, notificationSchemas2026 } from './schemas.js'; +import type { NotificationMethod, NotificationTypeMap, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../types/types'; +import type { Rev2026NotificationMethod, Rev2026RequestMethod } from './schemas'; +import { dispatchRequestSchemas, dispatchResultSchemas, notificationSchemas2026 } from './schemas'; /** The 2026-era request-method set (registry membership = the deletion story). */ export function hasRequestMethod2026(method: string): method is Rev2026RequestMethod { diff --git a/packages/core/src/wire/rev2026-07-28/schemas.ts b/packages/core-internal/src/wire/rev2026-07-28/schemas.ts similarity index 99% rename from packages/core/src/wire/rev2026-07-28/schemas.ts rename to packages/core-internal/src/wire/rev2026-07-28/schemas.ts index 240a75d655..02a1663142 100644 --- a/packages/core/src/wire/rev2026-07-28/schemas.ts +++ b/packages/core-internal/src/wire/rev2026-07-28/schemas.ts @@ -24,13 +24,8 @@ */ import * as z from 'zod/v4'; -import { - CLIENT_CAPABILITIES_META_KEY, - CLIENT_INFO_META_KEY, - LOG_LEVEL_META_KEY, - PROTOCOL_VERSION_META_KEY -} from '../../types/constants.js'; -import type { JSONObject, JSONValue } from '../../types/types.js'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, LOG_LEVEL_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../types/constants'; +import type { JSONObject, JSONValue } from '../../types/types'; /* ════════════════════════════════════════════════════════════════════════════ * Frozen neutral-layer building blocks diff --git a/packages/core/src/wire/textFallback.ts b/packages/core-internal/src/wire/textFallback.ts similarity index 95% rename from packages/core/src/wire/textFallback.ts rename to packages/core-internal/src/wire/textFallback.ts index 5518453480..40f4fa30ee 100644 --- a/packages/core/src/wire/textFallback.ts +++ b/packages/core-internal/src/wire/textFallback.ts @@ -1,4 +1,4 @@ -import type { CallToolResult } from '../types/types.js'; +import type { CallToolResult } from '../types/types'; /** * SEP-2106 §4.3 TextContent auto-append, era-agnostic, called from BOTH diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool-with-progress-token.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool-with-progress-token.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool-with-progress-token.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool-with-progress-token.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolRequest/call-tool.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/is-error.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/is-error.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/is-error.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/is-error.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/structured.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/structured.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/structured.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/structured.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/text.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/text.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CallToolResult/text.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CallToolResult/text.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CancelledNotification/cancelled.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CancelledNotification/cancelled.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CancelledNotification/cancelled.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CancelledNotification/cancelled.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CompleteRequest/complete.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CompleteRequest/complete.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CompleteRequest/complete.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CompleteRequest/complete.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CompleteResult/complete-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CompleteResult/complete-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CompleteResult/complete-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CompleteResult/complete-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CreateMessageRequest/create-message.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CreateMessageRequest/create-message.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CreateMessageRequest/create-message.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CreateMessageRequest/create-message.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CreateMessageResult/create-message-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CreateMessageResult/create-message-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CreateMessageResult/create-message-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CreateMessageResult/create-message-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/CreateTaskResult/create-task.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/CreateTaskResult/create-task.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/CreateTaskResult/create-task.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/CreateTaskResult/create-task.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ElicitRequest/form.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ElicitRequest/form.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ElicitRequest/form.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ElicitRequest/form.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ElicitResult/accept.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ElicitResult/accept.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ElicitResult/accept.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ElicitResult/accept.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/EmptyResult/empty.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/EmptyResult/empty.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/EmptyResult/empty.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/EmptyResult/empty.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/GetPromptRequest/get-prompt.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/GetPromptRequest/get-prompt.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/GetPromptRequest/get-prompt.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/GetPromptRequest/get-prompt.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/GetPromptResult/get-prompt-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/GetPromptResult/get-prompt-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/GetPromptResult/get-prompt-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/GetPromptResult/get-prompt-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/GetTaskRequest/get-task.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/GetTaskRequest/get-task.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/GetTaskRequest/get-task.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/GetTaskRequest/get-task.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/InitializeRequest/initialize.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/InitializeRequest/initialize.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/InitializeRequest/initialize.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/InitializeRequest/initialize.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/InitializeResult/initialize-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/InitializeResult/initialize-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/InitializeResult/initialize-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/InitializeResult/initialize-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/InitializedNotification/initialized.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/InitializedNotification/initialized.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/InitializedNotification/initialized.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/InitializedNotification/initialized.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/JSONRPCErrorResponse/error-envelope.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCErrorResponse/error-envelope.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/JSONRPCErrorResponse/error-envelope.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCErrorResponse/error-envelope.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/JSONRPCRequest/request-envelope.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCRequest/request-envelope.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/JSONRPCRequest/request-envelope.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCRequest/request-envelope.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/JSONRPCResultResponse/result-envelope.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCResultResponse/result-envelope.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/JSONRPCResultResponse/result-envelope.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/JSONRPCResultResponse/result-envelope.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListPromptsResult/list-prompts-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListPromptsResult/list-prompts-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListPromptsResult/list-prompts-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListPromptsResult/list-prompts-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListResourceTemplatesResult/list-templates-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourceTemplatesResult/list-templates-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListResourceTemplatesResult/list-templates-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourceTemplatesResult/list-templates-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListResourcesRequest/list-resources.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourcesRequest/list-resources.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListResourcesRequest/list-resources.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourcesRequest/list-resources.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListResourcesResult/list-resources-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourcesResult/list-resources-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListResourcesResult/list-resources-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListResourcesResult/list-resources-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListRootsRequest/list-roots.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListRootsRequest/list-roots.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListRootsRequest/list-roots.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListRootsRequest/list-roots.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListRootsResult/list-roots-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListRootsResult/list-roots-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListRootsResult/list-roots-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListRootsResult/list-roots-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListToolsRequest/list-tools.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListToolsRequest/list-tools.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListToolsRequest/list-tools.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListToolsRequest/list-tools.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ListToolsResult/list-tools-result.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ListToolsResult/list-tools-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ListToolsResult/list-tools-result.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ListToolsResult/list-tools-result.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/LoggingMessageNotification/log-message.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/LoggingMessageNotification/log-message.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/LoggingMessageNotification/log-message.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/LoggingMessageNotification/log-message.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/PingRequest/ping.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/PingRequest/ping.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/PingRequest/ping.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/PingRequest/ping.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ProgressNotification/progress.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ProgressNotification/progress.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ProgressNotification/progress.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ProgressNotification/progress.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/PromptListChangedNotification/prompt-list-changed.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/PromptListChangedNotification/prompt-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/PromptListChangedNotification/prompt-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/PromptListChangedNotification/prompt-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ReadResourceRequest/read-resource.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceRequest/read-resource.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ReadResourceRequest/read-resource.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceRequest/read-resource.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ReadResourceResult/blob.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceResult/blob.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ReadResourceResult/blob.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceResult/blob.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ReadResourceResult/text.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceResult/text.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ReadResourceResult/text.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ReadResourceResult/text.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ResourceListChangedNotification/resource-list-changed.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ResourceListChangedNotification/resource-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ResourceListChangedNotification/resource-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ResourceListChangedNotification/resource-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ResourceUpdatedNotification/resource-updated.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ResourceUpdatedNotification/resource-updated.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ResourceUpdatedNotification/resource-updated.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ResourceUpdatedNotification/resource-updated.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/RootsListChangedNotification/roots-list-changed.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/RootsListChangedNotification/roots-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/RootsListChangedNotification/roots-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/RootsListChangedNotification/roots-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/SetLevelRequest/set-level.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/SetLevelRequest/set-level.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/SetLevelRequest/set-level.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/SetLevelRequest/set-level.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/SubscribeRequest/subscribe.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/SubscribeRequest/subscribe.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/SubscribeRequest/subscribe.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/SubscribeRequest/subscribe.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/TaskAugmentedRequestParams/task-augmented-call-params.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/TaskAugmentedRequestParams/task-augmented-call-params.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/TaskAugmentedRequestParams/task-augmented-call-params.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/TaskAugmentedRequestParams/task-augmented-call-params.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/TaskStatusNotification/task-status.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/TaskStatusNotification/task-status.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/TaskStatusNotification/task-status.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/TaskStatusNotification/task-status.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/ToolListChangedNotification/tool-list-changed.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/ToolListChangedNotification/tool-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/ToolListChangedNotification/tool-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/ToolListChangedNotification/tool-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2025-11-25/UnsubscribeRequest/unsubscribe.json b/packages/core-internal/test/corpus/fixtures/2025-11-25/UnsubscribeRequest/unsubscribe.json similarity index 100% rename from packages/core/test/corpus/fixtures/2025-11-25/UnsubscribeRequest/unsubscribe.json rename to packages/core-internal/test/corpus/fixtures/2025-11-25/UnsubscribeRequest/unsubscribe.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/AudioContent/audio-wav-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/AudioContent/audio-wav-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/AudioContent/audio-wav-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/AudioContent/audio-wav-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/BlobResourceContents/image-file-contents.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/BlobResourceContents/image-file-contents.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/BlobResourceContents/image-file-contents.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/BlobResourceContents/image-file-contents.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/BooleanSchema/boolean-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/BooleanSchema/boolean-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/BooleanSchema/boolean-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/BooleanSchema/boolean-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolRequest/call-tool-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequest/call-tool-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolRequest/call-tool-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequest/call-tool-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolRequestParams/get-weather-tool-call-params.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequestParams/get-weather-tool-call-params.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolRequestParams/get-weather-tool-call-params.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequestParams/get-weather-tool-call-params.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolRequestParams/tool-call-params-with-progress-token.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequestParams/tool-call-params-with-progress-token.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolRequestParams/tool-call-params-with-progress-token.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolRequestParams/tool-call-params-with-progress-token.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/invalid-tool-input-error.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/invalid-tool-input-error.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/invalid-tool-input-error.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/invalid-tool-input-error.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-array-structured-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-array-structured-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-array-structured-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-array-structured-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-structured-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-structured-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-structured-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-structured-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-unstructured-text.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-unstructured-text.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-unstructured-text.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResult/result-with-unstructured-text.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CallToolResultResponse/call-tool-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResultResponse/call-tool-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CallToolResultResponse/call-tool-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CallToolResultResponse/call-tool-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CancelledNotification/user-requested-cancellation.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CancelledNotification/user-requested-cancellation.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CancelledNotification/user-requested-cancellation.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CancelledNotification/user-requested-cancellation.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CancelledNotificationParams/user-requested-cancellation.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CancelledNotificationParams/user-requested-cancellation.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CancelledNotificationParams/user-requested-cancellation.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CancelledNotificationParams/user-requested-cancellation.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-and-url-mode-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-and-url-mode-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-and-url-mode-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-and-url-mode-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-only-implicit.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-only-implicit.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-only-implicit.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/elicitation-form-only-implicit.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/extensions-ui-mime-types.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/extensions-ui-mime-types.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/extensions-ui-mime-types.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/extensions-ui-mime-types.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/roots-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/roots-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/roots-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/roots-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-context-inclusion-support-deprecated.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-context-inclusion-support-deprecated.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-context-inclusion-support-deprecated.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-context-inclusion-support-deprecated.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-tool-use-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-tool-use-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-tool-use-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ClientCapabilities/sampling-tool-use-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteRequest/completion-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequest/completion-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteRequest/completion-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequest/completion-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion-with-context.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion-with-context.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion-with-context.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion-with-context.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteRequestParams/prompt-argument-completion.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteResult/multiple-completion-values-with-more-available.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResult/multiple-completion-values-with-more-available.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteResult/multiple-completion-values-with-more-available.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResult/multiple-completion-values-with-more-available.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteResult/single-completion-value.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResult/single-completion-value.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteResult/single-completion-value.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResult/single-completion-value.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CompleteResultResponse/completion-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResultResponse/completion-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CompleteResultResponse/completion-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CompleteResultResponse/completion-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequest/sampling-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequest/sampling-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequest/sampling-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequest/sampling-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/basic-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/basic-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/basic-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/basic-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/follow-up-with-tool-results.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/follow-up-with-tool-results.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/follow-up-with-tool-results.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/follow-up-with-tool-results.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/request-with-tools.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/request-with-tools.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/request-with-tools.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageRequestParams/request-with-tools.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/final-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/final-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/final-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/final-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/text-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/text-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/text-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/text-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/tool-use-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/tool-use-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/CreateMessageResult/tool-use-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/CreateMessageResult/tool-use-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/DiscoverRequest/server-discover-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverRequest/server-discover-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/DiscoverRequest/server-discover-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverRequest/server-discover-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/DiscoverResult/server-capabilities-discovery.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverResult/server-capabilities-discovery.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/DiscoverResult/server-capabilities-discovery.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverResult/server-capabilities-discovery.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/DiscoverResultResponse/discover-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverResultResponse/discover-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/DiscoverResultResponse/discover-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/DiscoverResultResponse/discover-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitRequest/elicitation-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequest/elicitation-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitRequest/elicitation-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequest/elicitation-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-multiple-fields.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-multiple-fields.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-multiple-fields.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-multiple-fields.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-single-field.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-single-field.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-single-field.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestFormParams/elicit-single-field.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestURLParams/elicit-sensitive-data.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestURLParams/elicit-sensitive-data.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitRequestURLParams/elicit-sensitive-data.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitRequestURLParams/elicit-sensitive-data.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/accept-url-mode-no-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/accept-url-mode-no-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/accept-url-mode-no-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/accept-url-mode-no-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/input-multiple-fields.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/input-multiple-fields.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/input-multiple-fields.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/input-multiple-fields.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/input-single-field.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/input-single-field.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ElicitResult/input-single-field.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ElicitResult/input-single-field.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/EmbeddedResource/embedded-file-resource-with-annotations.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/EmbeddedResource/embedded-file-resource-with-annotations.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/EmbeddedResource/embedded-file-resource-with-annotations.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/EmbeddedResource/embedded-file-resource-with-annotations.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/GetPromptRequest/get-prompt-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptRequest/get-prompt-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/GetPromptRequest/get-prompt-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptRequest/get-prompt-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/GetPromptRequestParams/get-code-review-prompt.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptRequestParams/get-code-review-prompt.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/GetPromptRequestParams/get-code-review-prompt.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptRequestParams/get-code-review-prompt.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/GetPromptResult/code-review-prompt.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptResult/code-review-prompt.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/GetPromptResult/code-review-prompt.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptResult/code-review-prompt.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/GetPromptResultResponse/get-prompt-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptResultResponse/get-prompt-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/GetPromptResultResponse/get-prompt-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/GetPromptResultResponse/get-prompt-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/HeaderMismatchError/header-mismatch.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/HeaderMismatchError/header-mismatch.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/HeaderMismatchError/header-mismatch.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/HeaderMismatchError/header-mismatch.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ImageContent/image-png-content-with-annotations.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ImageContent/image-png-content-with-annotations.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ImageContent/image-png-content-with-annotations.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ImageContent/image-png-content-with-annotations.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InputRequests/elicitation-and-sampling-input-requests.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequests/elicitation-and-sampling-input-requests.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InputRequests/elicitation-and-sampling-input-requests.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequests/elicitation-and-sampling-input-requests.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-elicitation-and-sampling-and-request-state.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-elicitation-and-sampling-and-request-state.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-elicitation-and-sampling-and-request-state.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-elicitation-and-sampling-and-request-state.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-request-state-only.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-request-state-only.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-request-state-only.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InputRequiredResult/input-required-result-with-request-state-only.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InputResponses/elicitation-and-sampling-input-responses.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InputResponses/elicitation-and-sampling-input-responses.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InputResponses/elicitation-and-sampling-input-responses.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InputResponses/elicitation-and-sampling-input-responses.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InternalError/unexpected-error.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InternalError/unexpected-error.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InternalError/unexpected-error.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InternalError/unexpected-error.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-cursor.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-cursor.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-cursor.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-cursor.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-tool-arguments.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-tool-arguments.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-tool-arguments.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/invalid-tool-arguments.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-prompt.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-prompt.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-prompt.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-prompt.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-tool.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-tool.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-tool.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/InvalidParamsError/unknown-tool.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListPromptsRequest/list-prompts-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsRequest/list-prompts-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListPromptsRequest/list-prompts-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsRequest/list-prompts-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListPromptsResult/prompts-list-with-cursor-and-ttl.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsResult/prompts-list-with-cursor-and-ttl.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListPromptsResult/prompts-list-with-cursor-and-ttl.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsResult/prompts-list-with-cursor-and-ttl.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListPromptsResultResponse/list-prompts-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsResultResponse/list-prompts-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListPromptsResultResponse/list-prompts-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListPromptsResultResponse/list-prompts-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesRequest/list-resource-templates-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesRequest/list-resource-templates-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesRequest/list-resource-templates-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesRequest/list-resource-templates-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResult/resource-templates-list-with-cursor-and-ttl.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResult/resource-templates-list-with-cursor-and-ttl.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResult/resource-templates-list-with-cursor-and-ttl.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResult/resource-templates-list-with-cursor-and-ttl.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResultResponse/list-resource-templates-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResultResponse/list-resource-templates-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResultResponse/list-resource-templates-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourceTemplatesResultResponse/list-resource-templates-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourcesRequest/list-resources-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesRequest/list-resources-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourcesRequest/list-resources-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesRequest/list-resources-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourcesResult/resources-list-with-cursor-and-ttl.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesResult/resources-list-with-cursor-and-ttl.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourcesResult/resources-list-with-cursor-and-ttl.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesResult/resources-list-with-cursor-and-ttl.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListResourcesResultResponse/list-resources-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesResultResponse/list-resources-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListResourcesResultResponse/list-resources-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListResourcesResultResponse/list-resources-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListRootsRequest/list-roots-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsRequest/list-roots-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListRootsRequest/list-roots-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsRequest/list-roots-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListRootsResult/multiple-root-directories.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsResult/multiple-root-directories.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListRootsResult/multiple-root-directories.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsResult/multiple-root-directories.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListRootsResult/single-root-directory.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsResult/single-root-directory.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListRootsResult/single-root-directory.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListRootsResult/single-root-directory.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListToolsRequest/list-tools-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsRequest/list-tools-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListToolsRequest/list-tools-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsRequest/list-tools-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListToolsResult/tools-list-with-cursor-and-ttl.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsResult/tools-list-with-cursor-and-ttl.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListToolsResult/tools-list-with-cursor-and-ttl.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsResult/tools-list-with-cursor-and-ttl.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ListToolsResultResponse/list-tools-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsResultResponse/list-tools-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ListToolsResultResponse/list-tools-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ListToolsResultResponse/list-tools-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/LoggingMessageNotification/log-database-connection-failed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/LoggingMessageNotification/log-database-connection-failed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/LoggingMessageNotification/log-database-connection-failed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/LoggingMessageNotification/log-database-connection-failed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/LoggingMessageNotificationParams/log-database-connection-failed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/LoggingMessageNotificationParams/log-database-connection-failed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/LoggingMessageNotificationParams/log-database-connection-failed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/LoggingMessageNotificationParams/log-database-connection-failed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/MethodNotFoundError/prompts-not-supported.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/MethodNotFoundError/prompts-not-supported.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/MethodNotFoundError/prompts-not-supported.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/MethodNotFoundError/prompts-not-supported.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/MissingRequiredClientCapabilityError/missing-elicitation-capability.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/MissingRequiredClientCapabilityError/missing-elicitation-capability.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/MissingRequiredClientCapabilityError/missing-elicitation-capability.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/MissingRequiredClientCapabilityError/missing-elicitation-capability.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ModelPreferences/with-hints-and-priorities.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ModelPreferences/with-hints-and-priorities.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ModelPreferences/with-hints-and-priorities.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ModelPreferences/with-hints-and-priorities.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/NumberSchema/number-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/NumberSchema/number-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/NumberSchema/number-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/NumberSchema/number-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/PaginatedRequestParams/list-with-cursor.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/PaginatedRequestParams/list-with-cursor.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/PaginatedRequestParams/list-with-cursor.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/PaginatedRequestParams/list-with-cursor.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ParseError/invalid-json.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ParseError/invalid-json.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ParseError/invalid-json.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ParseError/invalid-json.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ProgressNotification/progress-message.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ProgressNotification/progress-message.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ProgressNotification/progress-message.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ProgressNotification/progress-message.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ProgressNotificationParams/progress-message.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ProgressNotificationParams/progress-message.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ProgressNotificationParams/progress-message.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ProgressNotificationParams/progress-message.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/PromptListChangedNotification/prompts-list-changed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/PromptListChangedNotification/prompts-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/PromptListChangedNotification/prompts-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/PromptListChangedNotification/prompts-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ReadResourceRequest/read-resource-request.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceRequest/read-resource-request.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ReadResourceRequest/read-resource-request.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceRequest/read-resource-request.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResult/file-resource-contents.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResult/file-resource-contents.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResult/file-resource-contents.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResult/file-resource-contents.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response-with-ttl.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response-with-ttl.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response-with-ttl.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response-with-ttl.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ReadResourceResultResponse/read-resource-result-response.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Resource/file-resource-with-annotations.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Resource/file-resource-with-annotations.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Resource/file-resource-with-annotations.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Resource/file-resource-with-annotations.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ResourceLink/file-resource-link.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceLink/file-resource-link.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ResourceLink/file-resource-link.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceLink/file-resource-link.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ResourceListChangedNotification/resources-list-changed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceListChangedNotification/resources-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ResourceListChangedNotification/resources-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceListChangedNotification/resources-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotification/file-resource-updated-notification.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotification/file-resource-updated-notification.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotification/file-resource-updated-notification.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotification/file-resource-updated-notification.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotificationParams/file-resource-updated.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotificationParams/file-resource-updated.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotificationParams/file-resource-updated.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ResourceUpdatedNotificationParams/file-resource-updated.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Root/project-directory.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Root/project-directory.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Root/project-directory.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Root/project-directory.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/SamplingMessage/multiple-content-blocks.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/SamplingMessage/multiple-content-blocks.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/SamplingMessage/multiple-content-blocks.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/SamplingMessage/multiple-content-blocks.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/SamplingMessage/single-content-block.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/SamplingMessage/single-content-block.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/SamplingMessage/single-content-block.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/SamplingMessage/single-content-block.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/completions-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/completions-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/completions-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/completions-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/extensions-tasks.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/extensions-tasks.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/extensions-tasks.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/extensions-tasks.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/logging-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/logging-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/logging-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/logging-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-list-changed-notifications.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-list-changed-notifications.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-list-changed-notifications.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-list-changed-notifications.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/prompts-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-all-notifications.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-all-notifications.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-all-notifications.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-all-notifications.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-list-changed-notifications-only.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-list-changed-notifications-only.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-list-changed-notifications-only.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-list-changed-notifications-only.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-subscription-to-individual-resource-updates-only.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-subscription-to-individual-resource-updates-only.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-subscription-to-individual-resource-updates-only.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/resources-subscription-to-individual-resource-updates-only.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-list-changed-notifications.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-list-changed-notifications.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-list-changed-notifications.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-list-changed-notifications.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-minimum-baseline-support.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-minimum-baseline-support.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-minimum-baseline-support.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ServerCapabilities/tools-minimum-baseline-support.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/StringSchema/email-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/StringSchema/email-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/StringSchema/email-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/StringSchema/email-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsAcknowledgedNotification/listen-acknowledged.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsAcknowledgedNotification/listen-acknowledged.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsAcknowledgedNotification/listen-acknowledged.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsAcknowledgedNotification/listen-acknowledged.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsListenRequest/listen-for-list-changes.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsListenRequest/listen-for-list-changes.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsListenRequest/listen-for-list-changes.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsListenRequest/listen-for-list-changes.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsListenResult/listen-closed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsListenResult/listen-closed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/SubscriptionsListenResult/listen-closed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/SubscriptionsListenResult/listen-closed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/TextContent/text-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/TextContent/text-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/TextContent/text-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/TextContent/text-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/TextResourceContents/text-file-contents.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/TextResourceContents/text-file-contents.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/TextResourceContents/text-file-contents.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/TextResourceContents/text-file-contents.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/TitledMultiSelectEnumSchema/titled-color-multi-select-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/TitledMultiSelectEnumSchema/titled-color-multi-select-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/TitledMultiSelectEnumSchema/titled-color-multi-select-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/TitledMultiSelectEnumSchema/titled-color-multi-select-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/TitledSingleSelectEnumSchema/titled-color-select-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/TitledSingleSelectEnumSchema/titled-color-select-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/TitledSingleSelectEnumSchema/titled-color-select-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/TitledSingleSelectEnumSchema/titled-color-select-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/tool-with-array-output-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/tool-with-array-output-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/tool-with-array-output-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/tool-with-array-output-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/tool-with-composition-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/tool-with-composition-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/tool-with-composition-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/tool-with-composition-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/with-default-2020-12-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-default-2020-12-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/with-default-2020-12-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-default-2020-12-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/with-explicit-draft-07-input-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-explicit-draft-07-input-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/with-explicit-draft-07-input-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-explicit-draft-07-input-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/with-no-parameters.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-no-parameters.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/with-no-parameters.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-no-parameters.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/Tool/with-output-schema-for-structured-content.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-output-schema-for-structured-content.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/Tool/with-output-schema-for-structured-content.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/Tool/with-output-schema-for-structured-content.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ToolListChangedNotification/tools-list-changed.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ToolListChangedNotification/tools-list-changed.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ToolListChangedNotification/tools-list-changed.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ToolListChangedNotification/tools-list-changed.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ToolResultContent/get-weather-tool-result.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ToolResultContent/get-weather-tool-result.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ToolResultContent/get-weather-tool-result.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ToolResultContent/get-weather-tool-result.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/ToolUseContent/get-weather-tool-use.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/ToolUseContent/get-weather-tool-use.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/ToolUseContent/get-weather-tool-use.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/ToolUseContent/get-weather-tool-use.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/UnsupportedProtocolVersionError/unsupported-version.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/UnsupportedProtocolVersionError/unsupported-version.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/UnsupportedProtocolVersionError/unsupported-version.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/UnsupportedProtocolVersionError/unsupported-version.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/UntitledMultiSelectEnumSchema/color-multi-select-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/UntitledMultiSelectEnumSchema/color-multi-select-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/UntitledMultiSelectEnumSchema/color-multi-select-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/UntitledMultiSelectEnumSchema/color-multi-select-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/UntitledSingleSelectEnumSchema/color-select-schema.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/UntitledSingleSelectEnumSchema/color-select-schema.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/UntitledSingleSelectEnumSchema/color-select-schema.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/UntitledSingleSelectEnumSchema/color-select-schema.json diff --git a/packages/core/test/corpus/fixtures/2026-07-28/manifest.json b/packages/core-internal/test/corpus/fixtures/2026-07-28/manifest.json similarity index 100% rename from packages/core/test/corpus/fixtures/2026-07-28/manifest.json rename to packages/core-internal/test/corpus/fixtures/2026-07-28/manifest.json diff --git a/packages/core/test/corpus/fixtures/rejection/batch-array-body.json b/packages/core-internal/test/corpus/fixtures/rejection/batch-array-body.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/batch-array-body.json rename to packages/core-internal/test/corpus/fixtures/rejection/batch-array-body.json diff --git a/packages/core/test/corpus/fixtures/rejection/error-response-unknown-id.json b/packages/core-internal/test/corpus/fixtures/rejection/error-response-unknown-id.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/error-response-unknown-id.json rename to packages/core-internal/test/corpus/fixtures/rejection/error-response-unknown-id.json diff --git a/packages/core/test/corpus/fixtures/rejection/invalid-spec-params.json b/packages/core-internal/test/corpus/fixtures/rejection/invalid-spec-params.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/invalid-spec-params.json rename to packages/core-internal/test/corpus/fixtures/rejection/invalid-spec-params.json diff --git a/packages/core/test/corpus/fixtures/rejection/notification-invalid-spec-params.json b/packages/core-internal/test/corpus/fixtures/rejection/notification-invalid-spec-params.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/notification-invalid-spec-params.json rename to packages/core-internal/test/corpus/fixtures/rejection/notification-invalid-spec-params.json diff --git a/packages/core/test/corpus/fixtures/rejection/notification-unknown-method.json b/packages/core-internal/test/corpus/fixtures/rejection/notification-unknown-method.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/notification-unknown-method.json rename to packages/core-internal/test/corpus/fixtures/rejection/notification-unknown-method.json diff --git a/packages/core/test/corpus/fixtures/rejection/null-request-id.json b/packages/core-internal/test/corpus/fixtures/rejection/null-request-id.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/null-request-id.json rename to packages/core-internal/test/corpus/fixtures/rejection/null-request-id.json diff --git a/packages/core/test/corpus/fixtures/rejection/request-extra-top-level-key.json b/packages/core-internal/test/corpus/fixtures/rejection/request-extra-top-level-key.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/request-extra-top-level-key.json rename to packages/core-internal/test/corpus/fixtures/rejection/request-extra-top-level-key.json diff --git a/packages/core/test/corpus/fixtures/rejection/result-not-an-object.json b/packages/core-internal/test/corpus/fixtures/rejection/result-not-an-object.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/result-not-an-object.json rename to packages/core-internal/test/corpus/fixtures/rejection/result-not-an-object.json diff --git a/packages/core/test/corpus/fixtures/rejection/result-response-unknown-id.json b/packages/core-internal/test/corpus/fixtures/rejection/result-response-unknown-id.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/result-response-unknown-id.json rename to packages/core-internal/test/corpus/fixtures/rejection/result-response-unknown-id.json diff --git a/packages/core/test/corpus/fixtures/rejection/unknown-request-method.json b/packages/core-internal/test/corpus/fixtures/rejection/unknown-request-method.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/unknown-request-method.json rename to packages/core-internal/test/corpus/fixtures/rejection/unknown-request-method.json diff --git a/packages/core/test/corpus/fixtures/rejection/unregistered-spec-method.json b/packages/core-internal/test/corpus/fixtures/rejection/unregistered-spec-method.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/unregistered-spec-method.json rename to packages/core-internal/test/corpus/fixtures/rejection/unregistered-spec-method.json diff --git a/packages/core/test/corpus/fixtures/rejection/valid-tools-call.json b/packages/core-internal/test/corpus/fixtures/rejection/valid-tools-call.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/valid-tools-call.json rename to packages/core-internal/test/corpus/fixtures/rejection/valid-tools-call.json diff --git a/packages/core/test/corpus/fixtures/rejection/wrong-jsonrpc-version.json b/packages/core-internal/test/corpus/fixtures/rejection/wrong-jsonrpc-version.json similarity index 100% rename from packages/core/test/corpus/fixtures/rejection/wrong-jsonrpc-version.json rename to packages/core-internal/test/corpus/fixtures/rejection/wrong-jsonrpc-version.json diff --git a/packages/core/test/corpus/schema-twins/2025-11-25.schema.json b/packages/core-internal/test/corpus/schema-twins/2025-11-25.schema.json similarity index 100% rename from packages/core/test/corpus/schema-twins/2025-11-25.schema.json rename to packages/core-internal/test/corpus/schema-twins/2025-11-25.schema.json diff --git a/packages/core/test/corpus/schema-twins/2026-07-28.schema.json b/packages/core-internal/test/corpus/schema-twins/2026-07-28.schema.json similarity index 100% rename from packages/core/test/corpus/schema-twins/2026-07-28.schema.json rename to packages/core-internal/test/corpus/schema-twins/2026-07-28.schema.json diff --git a/packages/core/test/corpus/schema-twins/manifest.json b/packages/core-internal/test/corpus/schema-twins/manifest.json similarity index 94% rename from packages/core/test/corpus/schema-twins/manifest.json rename to packages/core-internal/test/corpus/schema-twins/manifest.json index d5f56f2134..5f7e6f56c8 100644 --- a/packages/core/test/corpus/schema-twins/manifest.json +++ b/packages/core-internal/test/corpus/schema-twins/manifest.json @@ -1,5 +1,5 @@ { - "comment": "Vendored schema.json twins (TEST-ONLY conformance oracles; never bundled, never runtime). RAW upstream bytes - never reformat: each file is locked to the sha256/bytes below by schemaTwinConformance. Refresh via `pnpm fetch:schema-twins [sha]`, ATOMICALLY with the matching spec.types anchor (see packages/core/src/types/README.md lifecycle rule 4).", + "comment": "Vendored schema.json twins (TEST-ONLY conformance oracles; never bundled, never runtime). RAW upstream bytes - never reformat: each file is locked to the sha256/bytes below by schemaTwinConformance. Refresh via `pnpm fetch:schema-twins [sha]`, ATOMICALLY with the matching spec.types anchor (see packages/core-internal/src/types/README.md lifecycle rule 4).", "source": { "repository": "modelcontextprotocol/modelcontextprotocol", "commit": "f68d864a813754e188c6df52dcc5772a12f96c63" diff --git a/packages/core/test/corpus/specCorpus.test.ts b/packages/core-internal/test/corpus/specCorpus.test.ts similarity index 97% rename from packages/core/test/corpus/specCorpus.test.ts rename to packages/core-internal/test/corpus/specCorpus.test.ts index 8184af7fca..64a5bd1fb2 100644 --- a/packages/core/test/corpus/specCorpus.test.ts +++ b/packages/core-internal/test/corpus/specCorpus.test.ts @@ -36,14 +36,14 @@ import { CreateMessageResultWithToolsSchema, JSONRPCErrorResponseSchema, JSONRPCResultResponseSchema -} from '../../src/types/schemas.js'; -import * as schemas from '../../src/types/schemas.js'; +} from '../../src/types/schemas'; +import * as schemas from '../../src/types/schemas'; // Era routing (Q1 increment 2): each corpus revision resolves through its own // wire-era module first — 2025 fixtures may use 2025-only vocabulary (tasks), // 2026 fixtures use 2026-only vocabulary (envelope, discover) — then falls // back to the shared neutral payload schemas. -import * as wire2025 from '../../src/wire/rev2025-11-25/schemas.js'; -import * as wire2026 from '../../src/wire/rev2026-07-28/schemas.js'; +import * as wire2025 from '../../src/wire/rev2025-11-25/schemas'; +import * as wire2026 from '../../src/wire/rev2026-07-28/schemas'; const FIXTURES_ROOT = join(__dirname, 'fixtures'); diff --git a/packages/core/test/corpus/specCorpusDispatch.test.ts b/packages/core-internal/test/corpus/specCorpusDispatch.test.ts similarity index 95% rename from packages/core/test/corpus/specCorpusDispatch.test.ts rename to packages/core-internal/test/corpus/specCorpusDispatch.test.ts index 88859aa71a..07cf164369 100644 --- a/packages/core/test/corpus/specCorpusDispatch.test.ts +++ b/packages/core-internal/test/corpus/specCorpusDispatch.test.ts @@ -23,10 +23,10 @@ import { join } from 'node:path'; import { describe, expect, test } from 'vitest'; -import { Protocol } from '../../src/shared/protocol.js'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import type { JSONRPCMessage } from '../../src/types/index.js'; +import { Protocol } from '../../src/shared/protocol'; +import type { BaseContext } from '../../src/shared/protocol'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import type { JSONRPCMessage } from '../../src/types/index'; const REJECTION_DIR = join(__dirname, 'fixtures', 'rejection'); diff --git a/packages/core/test/errors/sdkHttpError.test.ts b/packages/core-internal/test/errors/sdkHttpError.test.ts similarity index 99% rename from packages/core/test/errors/sdkHttpError.test.ts rename to packages/core-internal/test/errors/sdkHttpError.test.ts index b217483580..421a51d6c6 100644 --- a/packages/core/test/errors/sdkHttpError.test.ts +++ b/packages/core-internal/test/errors/sdkHttpError.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { SdkError, SdkErrorCode, SdkHttpError } from '../../src/index.js'; +import { SdkError, SdkErrorCode, SdkHttpError } from '../../src/index'; describe('SdkHttpError', () => { it('exposes status and statusText via getters', () => { diff --git a/packages/core/test/inMemory.test.ts b/packages/core-internal/test/inMemory.test.ts similarity index 98% rename from packages/core/test/inMemory.test.ts rename to packages/core-internal/test/inMemory.test.ts index 46332eaa20..0dc72fd32f 100644 --- a/packages/core/test/inMemory.test.ts +++ b/packages/core-internal/test/inMemory.test.ts @@ -1,5 +1,5 @@ -import type { AuthInfo, JSONRPCMessage } from '../src/types/index.js'; -import { InMemoryTransport } from '../src/util/inMemory.js'; +import type { AuthInfo, JSONRPCMessage } from '../src/types/index'; +import { InMemoryTransport } from '../src/util/inMemory'; describe('InMemoryTransport', () => { let clientTransport: InMemoryTransport; diff --git a/packages/core/test/packageTopologyPins.test.ts b/packages/core-internal/test/packageTopologyPins.test.ts similarity index 94% rename from packages/core/test/packageTopologyPins.test.ts rename to packages/core-internal/test/packageTopologyPins.test.ts index 9a12a303b6..4df0188232 100644 --- a/packages/core/test/packageTopologyPins.test.ts +++ b/packages/core-internal/test/packageTopologyPins.test.ts @@ -50,6 +50,10 @@ const PUBLIC_PACKAGES: Record { // of packages is itself published surface. A new package must be added // to PUBLIC_PACKAGES here deliberately (or pinned as private below) — // otherwise it would ship to npm without any pin applying to it. - expect(discoverManifestDirs()).toEqual([...Object.keys(PUBLIC_PACKAGES), 'core'].sort()); + expect(discoverManifestDirs()).toEqual([...Object.keys(PUBLIC_PACKAGES), 'core-internal'].sort()); }); }); describe('internal packages stay private', () => { - test('@modelcontextprotocol/core is private (bundled into client/server dists)', () => { - const manifest = readManifest('core'); - expect(manifest.name).toBe('@modelcontextprotocol/core'); + test('@modelcontextprotocol/core-internal is private (bundled into client/server dists)', () => { + const manifest = readManifest('core-internal'); + expect(manifest.name).toBe('@modelcontextprotocol/core-internal'); expect(manifest.private).toBe(true); }); diff --git a/packages/core/test/shared/auth.test.ts b/packages/core-internal/test/shared/auth.test.ts similarity index 99% rename from packages/core/test/shared/auth.test.ts rename to packages/core-internal/test/shared/auth.test.ts index 39ba0cf7e0..4561d8fb11 100644 --- a/packages/core/test/shared/auth.test.ts +++ b/packages/core-internal/test/shared/auth.test.ts @@ -4,7 +4,7 @@ import { OpenIdProviderMetadataSchema, OptionalSafeUrlSchema, SafeUrlSchema -} from '../../src/shared/auth.js'; +} from '../../src/shared/auth'; describe('SafeUrlSchema', () => { it('accepts valid HTTPS URLs', () => { diff --git a/packages/core/test/shared/authUtils.test.ts b/packages/core-internal/test/shared/authUtils.test.ts similarity index 99% rename from packages/core/test/shared/authUtils.test.ts rename to packages/core-internal/test/shared/authUtils.test.ts index 902cfe41df..312d1809ef 100644 --- a/packages/core/test/shared/authUtils.test.ts +++ b/packages/core-internal/test/shared/authUtils.test.ts @@ -1,4 +1,4 @@ -import { checkResourceAllowed, resourceUrlFromServerUrl } from '../../src/shared/authUtils.js'; +import { checkResourceAllowed, resourceUrlFromServerUrl } from '../../src/shared/authUtils'; describe('auth-utils', () => { describe('resourceUrlFromServerUrl', () => { diff --git a/packages/core/test/shared/clientCapabilityRequirements.test.ts b/packages/core-internal/test/shared/clientCapabilityRequirements.test.ts similarity index 98% rename from packages/core/test/shared/clientCapabilityRequirements.test.ts rename to packages/core-internal/test/shared/clientCapabilityRequirements.test.ts index ff25edc6e2..04e17a74da 100644 --- a/packages/core/test/shared/clientCapabilityRequirements.test.ts +++ b/packages/core-internal/test/shared/clientCapabilityRequirements.test.ts @@ -14,8 +14,8 @@ import { REQUIRED_CLIENT_CAPABILITIES_BY_METHOD, requiredClientCapabilitiesForInputRequest, requiredClientCapabilitiesForRequest -} from '../../src/shared/clientCapabilityRequirements.js'; -import { rev2026RequestMethods } from '../../src/wire/rev2026-07-28/registry.js'; +} from '../../src/shared/clientCapabilityRequirements'; +import { rev2026RequestMethods } from '../../src/wire/rev2026-07-28/registry'; describe('missingClientCapabilities', () => { test('an undeclared capability view (no envelope, empty session state) misses everything required — the structural clean refusal', () => { diff --git a/packages/core/test/shared/customMethods.test.ts b/packages/core-internal/test/shared/customMethods.test.ts similarity index 97% rename from packages/core/test/shared/customMethods.test.ts rename to packages/core-internal/test/shared/customMethods.test.ts index ae902cd749..f3c6b612f3 100644 --- a/packages/core/test/shared/customMethods.test.ts +++ b/packages/core-internal/test/shared/customMethods.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it } from 'vitest'; import { z } from 'zod/v4'; -import { Protocol } from '../../src/shared/protocol.js'; -import type { BaseContext, JSONRPCRequest, Result, StandardSchemaV1 } from '../../src/exports/public/index.js'; -import { ProtocolError } from '../../src/types/index.js'; -import { SdkErrorCode } from '../../src/errors/sdkErrors.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; +import { Protocol } from '../../src/shared/protocol'; +import type { BaseContext, JSONRPCRequest, Result, StandardSchemaV1 } from '../../src/exports/public/index'; +import { ProtocolError } from '../../src/types/index'; +import { SdkErrorCode } from '../../src/errors/sdkErrors'; +import { InMemoryTransport } from '../../src/util/inMemory'; class TestProtocol extends Protocol { protected buildContext(ctx: BaseContext): BaseContext { diff --git a/packages/core/test/shared/errorHttpStatusMatrix.test.ts b/packages/core-internal/test/shared/errorHttpStatusMatrix.test.ts similarity index 98% rename from packages/core/test/shared/errorHttpStatusMatrix.test.ts rename to packages/core-internal/test/shared/errorHttpStatusMatrix.test.ts index fb5344a1bb..d053f9eae8 100644 --- a/packages/core/test/shared/errorHttpStatusMatrix.test.ts +++ b/packages/core-internal/test/shared/errorHttpStatusMatrix.test.ts @@ -23,8 +23,8 @@ */ import { describe, expect, test } from 'vitest'; -import { HEADER_MISMATCH_ERROR_CODE, httpStatusForErrorCode, LADDER_ERROR_HTTP_STATUS } from '../../src/shared/inboundClassification.js'; -import { ProtocolErrorCode } from '../../src/types/enums.js'; +import { HEADER_MISMATCH_ERROR_CODE, httpStatusForErrorCode, LADDER_ERROR_HTTP_STATUS } from '../../src/shared/inboundClassification'; +import { ProtocolErrorCode } from '../../src/types/enums'; describe('the status matrix — pinned cells', () => { const PINNED_LADDER_CELLS: ReadonlyArray<{ code: number; status: number; cell: string }> = [ diff --git a/packages/core/test/shared/inboundClassification.test.ts b/packages/core-internal/test/shared/inboundClassification.test.ts similarity index 99% rename from packages/core/test/shared/inboundClassification.test.ts rename to packages/core-internal/test/shared/inboundClassification.test.ts index 5108b8e6cf..16017d7562 100644 --- a/packages/core/test/shared/inboundClassification.test.ts +++ b/packages/core-internal/test/shared/inboundClassification.test.ts @@ -12,10 +12,10 @@ */ import { describe, expect, test } from 'vitest'; -import { hasEnvelopeClaim, validateEnvelopeMeta } from '../../src/shared/envelope.js'; -import type { InboundHttpRequest, InboundLegacyRoute } from '../../src/shared/inboundClassification.js'; -import { classifyInboundRequest, modernOnlyStrictRejection } from '../../src/shared/inboundClassification.js'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants.js'; +import { hasEnvelopeClaim, validateEnvelopeMeta } from '../../src/shared/envelope'; +import type { InboundHttpRequest, InboundLegacyRoute } from '../../src/shared/inboundClassification'; +import { classifyInboundRequest, modernOnlyStrictRejection } from '../../src/shared/inboundClassification'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants'; const MODERN_REVISION = '2026-07-28'; diff --git a/packages/core/test/shared/inboundLadderCellSheet.test.ts b/packages/core-internal/test/shared/inboundLadderCellSheet.test.ts similarity index 99% rename from packages/core/test/shared/inboundLadderCellSheet.test.ts rename to packages/core-internal/test/shared/inboundLadderCellSheet.test.ts index 87c28bec3d..78613d4940 100644 --- a/packages/core/test/shared/inboundLadderCellSheet.test.ts +++ b/packages/core-internal/test/shared/inboundLadderCellSheet.test.ts @@ -19,15 +19,15 @@ */ import { describe, expect, test } from 'vitest'; -import type { InboundHttpRequest, InboundLadderRejection } from '../../src/shared/inboundClassification.js'; +import type { InboundHttpRequest, InboundLadderRejection } from '../../src/shared/inboundClassification'; import { classifyInboundRequest, httpStatusForErrorCode, INBOUND_VALIDATION_LADDER, LADDER_ERROR_HTTP_STATUS, modernOnlyStrictRejection -} from '../../src/shared/inboundClassification.js'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants.js'; +} from '../../src/shared/inboundClassification'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants'; const MODERN_REVISION = '2026-07-28'; diff --git a/packages/core/test/shared/inputRequired.test.ts b/packages/core-internal/test/shared/inputRequired.test.ts similarity index 97% rename from packages/core/test/shared/inputRequired.test.ts rename to packages/core-internal/test/shared/inputRequired.test.ts index 421ed67309..2bce27fcf1 100644 --- a/packages/core/test/shared/inputRequired.test.ts +++ b/packages/core-internal/test/shared/inputRequired.test.ts @@ -7,9 +7,9 @@ import { describe, expect, test } from 'vitest'; import * as z from 'zod/v4'; -import { acceptedContent, inputRequired, withInputRequired } from '../../src/shared/inputRequired.js'; -import { isInputRequiredResult } from '../../src/types/guards.js'; -import { validateStandardSchema } from '../../src/util/standardSchema.js'; +import { acceptedContent, inputRequired, withInputRequired } from '../../src/shared/inputRequired'; +import { isInputRequiredResult } from '../../src/types/guards'; +import { validateStandardSchema } from '../../src/util/standardSchema'; describe('inputRequired() builder', () => { test('builds a plain discriminated value (no brand) from inputRequests', () => { diff --git a/packages/core/test/shared/inputRequiredDriver.test.ts b/packages/core-internal/test/shared/inputRequiredDriver.test.ts similarity index 99% rename from packages/core/test/shared/inputRequiredDriver.test.ts rename to packages/core-internal/test/shared/inputRequiredDriver.test.ts index 6f49311060..2d4ec5d138 100644 --- a/packages/core/test/shared/inputRequiredDriver.test.ts +++ b/packages/core-internal/test/shared/inputRequiredDriver.test.ts @@ -7,7 +7,7 @@ */ import { describe, expect, test, vi } from 'vitest'; -import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors.js'; +import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors'; import { buildInputRequiredRetryParams, DEFAULT_INPUT_REQUIRED_AUTO_FULFILL, @@ -15,7 +15,7 @@ import { REQUEST_STATE_ONLY_LEG_PACING_MS, resolveInputRequiredDriverConfig, runInputRequiredDriver -} from '../../src/shared/inputRequiredDriver.js'; +} from '../../src/shared/inputRequiredDriver'; const ELICIT_ENTRY = { method: 'elicitation/create', params: { mode: 'form', message: 'Name?' } }; diff --git a/packages/core/test/shared/inputRequiredEngine.test.ts b/packages/core-internal/test/shared/inputRequiredEngine.test.ts similarity index 95% rename from packages/core/test/shared/inputRequiredEngine.test.ts rename to packages/core-internal/test/shared/inputRequiredEngine.test.ts index 2ba089808c..d747b7ca10 100644 --- a/packages/core/test/shared/inputRequiredEngine.test.ts +++ b/packages/core-internal/test/shared/inputRequiredEngine.test.ts @@ -6,11 +6,7 @@ */ import { describe, expect, test } from 'vitest'; -import { - buildRetryLegRequestOptions, - partitionInputResponses, - synthesizeInputRequestContext -} from '../../src/shared/inputRequiredEngine.js'; +import { buildRetryLegRequestOptions, partitionInputResponses, synthesizeInputRequestContext } from '../../src/shared/inputRequiredEngine'; describe('per-retry-leg request options whitelist', () => { test('only the whitelisted fields carry over — resumption tokens and the related-request id never do', () => { diff --git a/packages/core/test/shared/inputRequiredFunnel.test.ts b/packages/core-internal/test/shared/inputRequiredFunnel.test.ts similarity index 95% rename from packages/core/test/shared/inputRequiredFunnel.test.ts rename to packages/core-internal/test/shared/inputRequiredFunnel.test.ts index c08904ed7e..d12b526bd1 100644 --- a/packages/core/test/shared/inputRequiredFunnel.test.ts +++ b/packages/core-internal/test/shared/inputRequiredFunnel.test.ts @@ -11,12 +11,12 @@ import { describe, expect, test } from 'vitest'; import * as z from 'zod/v4'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol.js'; -import type { JSONRPCRequest } from '../../src/types/index.js'; -import { isInputRequiredResult } from '../../src/types/guards.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol'; +import type { JSONRPCRequest } from '../../src/types/index'; +import { isInputRequiredResult } from '../../src/types/guards'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} diff --git a/packages/core/test/shared/mcpParamHeaders.test.ts b/packages/core-internal/test/shared/mcpParamHeaders.test.ts similarity index 99% rename from packages/core/test/shared/mcpParamHeaders.test.ts rename to packages/core-internal/test/shared/mcpParamHeaders.test.ts index e4e3bca6be..13d8ea582f 100644 --- a/packages/core/test/shared/mcpParamHeaders.test.ts +++ b/packages/core-internal/test/shared/mcpParamHeaders.test.ts @@ -10,7 +10,7 @@ */ import { describe, expect, test } from 'vitest'; -import { HEADER_MISMATCH_ERROR_CODE } from '../../src/shared/inboundClassification.js'; +import { HEADER_MISMATCH_ERROR_CODE } from '../../src/shared/inboundClassification'; import { buildMcpParamHeaders, decodeMcpParamValue, @@ -21,7 +21,7 @@ import { scanXMcpHeaderDeclarations, validateMcpParamHeaders, X_MCP_HEADER_KEY -} from '../../src/shared/mcpParamHeaders.js'; +} from '../../src/shared/mcpParamHeaders'; /* ------------------------------------------------------------------------ * * Value encoding (spec table) diff --git a/packages/core/test/shared/protocol.test.ts b/packages/core-internal/test/shared/protocol.test.ts similarity index 99% rename from packages/core/test/shared/protocol.test.ts rename to packages/core-internal/test/shared/protocol.test.ts index dbfc314d53..2ecdc40adc 100644 --- a/packages/core/test/shared/protocol.test.ts +++ b/packages/core-internal/test/shared/protocol.test.ts @@ -3,9 +3,9 @@ import { vi } from 'vitest'; import * as z from 'zod/v4'; import type { ZodType } from 'zod/v4'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { mergeCapabilities, Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol.js'; -import type { Transport, TransportSendOptions } from '../../src/shared/transport.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { mergeCapabilities, Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol'; +import type { Transport, TransportSendOptions } from '../../src/shared/transport'; import type { ClientCapabilities, JSONRPCErrorResponse, @@ -19,11 +19,11 @@ import type { RequestId, Result, ServerCapabilities -} from '../../src/types/index.js'; -import { ProtocolError, ProtocolErrorCode } from '../../src/types/index.js'; -import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec.js'; +} from '../../src/types/index'; +import { ProtocolError, ProtocolErrorCode } from '../../src/types/index'; +import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec'; // Test Protocol subclass for testing class TestProtocolImpl extends Protocol { diff --git a/packages/core/test/shared/protocolDropInboundHook.test.ts b/packages/core-internal/test/shared/protocolDropInboundHook.test.ts similarity index 96% rename from packages/core/test/shared/protocolDropInboundHook.test.ts rename to packages/core-internal/test/shared/protocolDropInboundHook.test.ts index 40b99452d8..a718be8a02 100644 --- a/packages/core/test/shared/protocolDropInboundHook.test.ts +++ b/packages/core-internal/test/shared/protocolDropInboundHook.test.ts @@ -13,17 +13,17 @@ */ import { describe, expect, it } from 'vitest'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol } from '../../src/shared/protocol.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol } from '../../src/shared/protocol'; import type { JSONRPCErrorResponse, JSONRPCMessage, JSONRPCNotification, JSONRPCRequest, JSONRPCResultResponse -} from '../../src/types/index.js'; -import { isJSONRPCResultResponse } from '../../src/types/index.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; +} from '../../src/types/index'; +import { isJSONRPCResultResponse } from '../../src/types/index'; +import { InMemoryTransport } from '../../src/util/inMemory'; class HookedProtocol extends Protocol { /** Messages the hook was consulted for (in order). */ diff --git a/packages/core/test/shared/protocolEras.test.ts b/packages/core-internal/test/shared/protocolEras.test.ts similarity index 96% rename from packages/core/test/shared/protocolEras.test.ts rename to packages/core-internal/test/shared/protocolEras.test.ts index c01c97fdad..49e0dadb94 100644 --- a/packages/core/test/shared/protocolEras.test.ts +++ b/packages/core-internal/test/shared/protocolEras.test.ts @@ -6,8 +6,8 @@ import { legacyProtocolVersions, modernProtocolVersions, SUPPORTED_MODERN_PROTOCOL_VERSIONS -} from '../../src/shared/protocolEras.js'; -import { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from '../../src/types/constants.js'; +} from '../../src/shared/protocolEras'; +import { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from '../../src/types/constants'; describe('protocol era helpers', () => { test('every released (legacy-list) version is classified legacy', () => { diff --git a/packages/core/test/shared/protocolTransportHandling.test.ts b/packages/core-internal/test/shared/protocolTransportHandling.test.ts similarity index 95% rename from packages/core/test/shared/protocolTransportHandling.test.ts rename to packages/core-internal/test/shared/protocolTransportHandling.test.ts index 23e3dad76b..731914265b 100644 --- a/packages/core/test/shared/protocolTransportHandling.test.ts +++ b/packages/core-internal/test/shared/protocolTransportHandling.test.ts @@ -1,9 +1,9 @@ import { beforeEach, describe, expect, test } from 'vitest'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol } from '../../src/shared/protocol.js'; -import type { Transport } from '../../src/shared/transport.js'; -import type { EmptyResult, JSONRPCMessage, Notification, Request, Result } from '../../src/types/index.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol } from '../../src/shared/protocol'; +import type { Transport } from '../../src/shared/transport'; +import type { EmptyResult, JSONRPCMessage, Notification, Request, Result } from '../../src/types/index'; // Mock Transport class class MockTransport implements Transport { diff --git a/packages/core/test/shared/rawResultTypeFirst.test.ts b/packages/core-internal/test/shared/rawResultTypeFirst.test.ts similarity index 97% rename from packages/core/test/shared/rawResultTypeFirst.test.ts rename to packages/core-internal/test/shared/rawResultTypeFirst.test.ts index 51fb40211f..3e44c48ed7 100644 --- a/packages/core/test/shared/rawResultTypeFirst.test.ts +++ b/packages/core-internal/test/shared/rawResultTypeFirst.test.ts @@ -25,11 +25,11 @@ */ import { describe, expect, test } from 'vitest'; -import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors.js'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol.js'; -import type { JSONRPCRequest } from '../../src/types/index.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; +import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol'; +import type { JSONRPCRequest } from '../../src/types/index'; +import { InMemoryTransport } from '../../src/util/inMemory'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} @@ -201,7 +201,7 @@ describe('raw-first resultType handling — 2025 era (strip-on-lift, Q1-SD3 ii)' describe('decode step 2 — the wire-exact schema lookup is own-key only', () => { test("a prototype-chain method name (e.g. 'constructor') skips the wire-exact parse instead of throwing", async () => { - const { rev2026Codec } = await import('../../src/wire/rev2026-07-28/codec.js'); + const { rev2026Codec } = await import('../../src/wire/rev2026-07-28/codec'); // A bare object-prototype hit would surface Function (not a schema) // and throw a TypeError out of the decode hop. The lookup must treat // non-own keys exactly like unknown methods: no wire-exact parse, diff --git a/packages/core/test/shared/standardHeaderValidation.test.ts b/packages/core-internal/test/shared/standardHeaderValidation.test.ts similarity index 98% rename from packages/core/test/shared/standardHeaderValidation.test.ts rename to packages/core-internal/test/shared/standardHeaderValidation.test.ts index 935bd66ad7..8a150375a9 100644 --- a/packages/core/test/shared/standardHeaderValidation.test.ts +++ b/packages/core-internal/test/shared/standardHeaderValidation.test.ts @@ -19,10 +19,10 @@ */ import { describe, expect, test } from 'vitest'; -import type { InboundHttpRequest, InboundLadderRejection, InboundModernRoute } from '../../src/shared/inboundClassification.js'; -import { classifyInboundRequest, MCP_NAME_HEADER_SOURCE, validateStandardRequestHeaders } from '../../src/shared/inboundClassification.js'; -import { encodeMcpParamValue } from '../../src/shared/mcpParamHeaders.js'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants.js'; +import type { InboundHttpRequest, InboundLadderRejection, InboundModernRoute } from '../../src/shared/inboundClassification'; +import { classifyInboundRequest, MCP_NAME_HEADER_SOURCE, validateStandardRequestHeaders } from '../../src/shared/inboundClassification'; +import { encodeMcpParamValue } from '../../src/shared/mcpParamHeaders'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '../../src/types/constants'; const MODERN = '2026-07-28'; const ENVELOPE = { diff --git a/packages/core/test/shared/stdio.test.ts b/packages/core-internal/test/shared/stdio.test.ts similarity index 98% rename from packages/core/test/shared/stdio.test.ts rename to packages/core-internal/test/shared/stdio.test.ts index ec00f1c2f0..f8d27a4c1f 100644 --- a/packages/core/test/shared/stdio.test.ts +++ b/packages/core-internal/test/shared/stdio.test.ts @@ -1,5 +1,5 @@ -import { ReadBuffer, STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../src/shared/stdio.js'; -import type { JSONRPCMessage } from '../../src/types/index.js'; +import { ReadBuffer, STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../src/shared/stdio'; +import type { JSONRPCMessage } from '../../src/types/index'; const testMessage: JSONRPCMessage = { jsonrpc: '2.0', diff --git a/packages/core/test/shared/toolNameValidation.test.ts b/packages/core-internal/test/shared/toolNameValidation.test.ts similarity index 99% rename from packages/core/test/shared/toolNameValidation.test.ts rename to packages/core-internal/test/shared/toolNameValidation.test.ts index 131cbbc5f6..5628b731ca 100644 --- a/packages/core/test/shared/toolNameValidation.test.ts +++ b/packages/core-internal/test/shared/toolNameValidation.test.ts @@ -1,7 +1,7 @@ import type { MockInstance } from 'vitest'; import { vi } from 'vitest'; -import { issueToolNameWarning, validateAndWarnToolName, validateToolName } from '../../src/shared/toolNameValidation.js'; +import { issueToolNameWarning, validateAndWarnToolName, validateToolName } from '../../src/shared/toolNameValidation'; // Spy on console.warn to capture output let warnSpy: MockInstance; diff --git a/packages/core/test/shared/traceContextMeta.test.ts b/packages/core-internal/test/shared/traceContextMeta.test.ts similarity index 96% rename from packages/core/test/shared/traceContextMeta.test.ts rename to packages/core-internal/test/shared/traceContextMeta.test.ts index ff8c0bbf9e..312fbca6e3 100644 --- a/packages/core/test/shared/traceContextMeta.test.ts +++ b/packages/core-internal/test/shared/traceContextMeta.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from 'vitest'; import { z } from 'zod/v4'; -import { Protocol } from '../../src/shared/protocol.js'; -import type { BaseContext } from '../../src/exports/public/index.js'; -import { BAGGAGE_META_KEY, TRACEPARENT_META_KEY, TRACESTATE_META_KEY } from '../../src/exports/public/index.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; +import { Protocol } from '../../src/shared/protocol'; +import type { BaseContext } from '../../src/exports/public/index'; +import { BAGGAGE_META_KEY, TRACEPARENT_META_KEY, TRACESTATE_META_KEY } from '../../src/exports/public/index'; +import { InMemoryTransport } from '../../src/util/inMemory'; class TestProtocol extends Protocol { protected buildContext(ctx: BaseContext): BaseContext { diff --git a/packages/core/test/shared/transport.test.ts b/packages/core-internal/test/shared/transport.test.ts similarity index 99% rename from packages/core/test/shared/transport.test.ts rename to packages/core-internal/test/shared/transport.test.ts index bdef03a5ec..2a17ac0643 100644 --- a/packages/core/test/shared/transport.test.ts +++ b/packages/core-internal/test/shared/transport.test.ts @@ -1,4 +1,4 @@ -import { createFetchWithInit, type FetchLike, normalizeHeaders } from '../../src/shared/transport.js'; +import { createFetchWithInit, type FetchLike, normalizeHeaders } from '../../src/shared/transport'; describe('normalizeHeaders', () => { test('returns empty object for undefined', () => { diff --git a/packages/core/test/shared/typedMapAlignment.test.ts b/packages/core-internal/test/shared/typedMapAlignment.test.ts similarity index 95% rename from packages/core/test/shared/typedMapAlignment.test.ts rename to packages/core-internal/test/shared/typedMapAlignment.test.ts index 1cd836d3db..eacf493e4d 100644 --- a/packages/core/test/shared/typedMapAlignment.test.ts +++ b/packages/core-internal/test/shared/typedMapAlignment.test.ts @@ -18,14 +18,14 @@ */ import { describe, expect, test } from 'vitest'; -import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors.js'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol } from '../../src/shared/protocol.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import type { JSONRPCRequest } from '../../src/types/index.js'; +import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol } from '../../src/shared/protocol'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import type { JSONRPCRequest } from '../../src/types/index'; // Post-relocation home (Q1 increment-2 step 1): the runtime registries live // behind the per-era wire-codec interface now. -import { getResultSchema } from '../../src/wire/rev2025-11-25/registry.js'; +import { getResultSchema } from '../../src/wire/rev2025-11-25/registry'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} diff --git a/packages/core/test/shared/uriTemplate.test.ts b/packages/core-internal/test/shared/uriTemplate.test.ts similarity index 99% rename from packages/core/test/shared/uriTemplate.test.ts rename to packages/core-internal/test/shared/uriTemplate.test.ts index 3954901c4f..bfc3237872 100644 --- a/packages/core/test/shared/uriTemplate.test.ts +++ b/packages/core-internal/test/shared/uriTemplate.test.ts @@ -1,4 +1,4 @@ -import { UriTemplate } from '../../src/shared/uriTemplate.js'; +import { UriTemplate } from '../../src/shared/uriTemplate'; describe('UriTemplate', () => { describe('isTemplate', () => { diff --git a/packages/core/test/shared/wireOnlyLift.test.ts b/packages/core-internal/test/shared/wireOnlyLift.test.ts similarity index 97% rename from packages/core/test/shared/wireOnlyLift.test.ts rename to packages/core-internal/test/shared/wireOnlyLift.test.ts index 32a8eb5302..4ce1395ae1 100644 --- a/packages/core/test/shared/wireOnlyLift.test.ts +++ b/packages/core-internal/test/shared/wireOnlyLift.test.ts @@ -17,17 +17,17 @@ import { describe, expect, expectTypeOf, test } from 'vitest'; import * as z from 'zod/v4'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol } from '../../src/shared/protocol.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import type { JSONRPCMessage, JSONRPCRequest, RequestMetaEnvelope, Result } from '../../src/types/index.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol } from '../../src/shared/protocol'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import type { JSONRPCMessage, JSONRPCRequest, RequestMetaEnvelope, Result } from '../../src/types/index'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, LOG_LEVEL_META_KEY, PROTOCOL_VERSION_META_KEY, RELATED_TASK_META_KEY -} from '../../src/types/index.js'; +} from '../../src/types/index'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} diff --git a/packages/core/test/shared/wrapHandler.test.ts b/packages/core-internal/test/shared/wrapHandler.test.ts similarity index 93% rename from packages/core/test/shared/wrapHandler.test.ts rename to packages/core-internal/test/shared/wrapHandler.test.ts index 452b58194f..06a5045ecd 100644 --- a/packages/core/test/shared/wrapHandler.test.ts +++ b/packages/core-internal/test/shared/wrapHandler.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { Protocol } from '../../src/shared/protocol.js'; -import type { BaseContext, JSONRPCRequest, Result } from '../../src/exports/public/index.js'; +import { Protocol } from '../../src/shared/protocol'; +import type { BaseContext, JSONRPCRequest, Result } from '../../src/exports/public/index'; class TestProtocol extends Protocol { protected buildContext(ctx: BaseContext): BaseContext { diff --git a/packages/core/test/spec.types.2025-11-25.test.ts b/packages/core-internal/test/spec.types.2025-11-25.test.ts similarity index 99% rename from packages/core/test/spec.types.2025-11-25.test.ts rename to packages/core-internal/test/spec.types.2025-11-25.test.ts index 9bbf5606a6..a3e7a13f5c 100644 --- a/packages/core/test/spec.types.2025-11-25.test.ts +++ b/packages/core-internal/test/spec.types.2025-11-25.test.ts @@ -15,13 +15,13 @@ import fs from 'node:fs'; import path from 'node:path'; -import type * as SpecTypes from '../src/types/spec.types.2025-11-25.js'; -import type * as SDKTypes from '../src/types/index.js'; +import type * as SpecTypes from '../src/types/spec.types.2025-11-25'; +import type * as SDKTypes from '../src/types/index'; // The era-faithful 2025 wire role unions (Q1 increment 2): the NEUTRAL role // aggregates no longer carry task vocabulary — the 2025-era wire module does. // Role-union comparisons against this FROZEN revision's anchor therefore // target the wire-era artifacts. -import type * as Wire2025 from '../src/wire/rev2025-11-25/schemas.js'; +import type * as Wire2025 from '../src/wire/rev2025-11-25/schemas'; import type { Wire2025ClientCapabilities, Wire2025ClientRequestView, @@ -36,7 +36,7 @@ import type { Wire2025ServerCapabilities, Wire2025ServerRequestView, Wire2025Tool -} from '../src/wire/rev2025-11-25/wireTypes.js'; +} from '../src/wire/rev2025-11-25/wireTypes'; import type * as z4 from 'zod/v4'; // SEP-2106 adjudication: the public/neutral SDK types widen `structuredContent` (`unknown`) diff --git a/packages/core/test/spec.types.2026-07-28.test.ts b/packages/core-internal/test/spec.types.2026-07-28.test.ts similarity index 99% rename from packages/core/test/spec.types.2026-07-28.test.ts rename to packages/core-internal/test/spec.types.2026-07-28.test.ts index fc58dd0e73..4b55f9b20f 100644 --- a/packages/core/test/spec.types.2026-07-28.test.ts +++ b/packages/core-internal/test/spec.types.2026-07-28.test.ts @@ -23,10 +23,10 @@ import { LATEST_PROTOCOL_VERSION, MISSING_REQUIRED_CLIENT_CAPABILITY, UNSUPPORTED_PROTOCOL_VERSION -} from '../src/types/spec.types.2026-07-28.js'; -import type * as SpecTypes from '../src/types/spec.types.2026-07-28.js'; -import type * as SDKTypes from '../src/types/index.js'; -import type * as Wire2026 from '../src/wire/rev2026-07-28/schemas.js'; +} from '../src/types/spec.types.2026-07-28'; +import type * as SpecTypes from '../src/types/spec.types.2026-07-28'; +import type * as SDKTypes from '../src/types/index'; +import type * as Wire2026 from '../src/wire/rev2026-07-28/schemas'; import type * as z4 from 'zod/v4'; import { CLIENT_CAPABILITIES_META_KEY, @@ -34,7 +34,7 @@ import { LOG_LEVEL_META_KEY, PROTOCOL_VERSION_META_KEY, ProtocolErrorCode -} from '../src/types/index.js'; +} from '../src/types/index'; /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/packages/core/test/types.capabilities.test.ts b/packages/core-internal/test/types.capabilities.test.ts similarity index 99% rename from packages/core/test/types.capabilities.test.ts rename to packages/core-internal/test/types.capabilities.test.ts index 1f66184525..18e7d9745c 100644 --- a/packages/core/test/types.capabilities.test.ts +++ b/packages/core-internal/test/types.capabilities.test.ts @@ -1,4 +1,4 @@ -import { ClientCapabilitiesSchema, InitializeRequestParamsSchema } from '../src/types/index.js'; +import { ClientCapabilitiesSchema, InitializeRequestParamsSchema } from '../src/types/index'; describe('ClientCapabilitiesSchema backwards compatibility', () => { describe('ElicitationCapabilitySchema preprocessing', () => { diff --git a/packages/core/test/types.test.ts b/packages/core-internal/test/types.test.ts similarity index 99% rename from packages/core/test/types.test.ts rename to packages/core-internal/test/types.test.ts index c56f83990b..ba7adca0fb 100644 --- a/packages/core/test/types.test.ts +++ b/packages/core-internal/test/types.test.ts @@ -26,13 +26,13 @@ import { ToolResultContentSchema, ToolSchema, ToolUseContentSchema -} from '../src/types/index.js'; +} from '../src/types/index'; // Wire-era modules (Q1 increment 2): the per-request envelope lives in the // 2026-era schemas; the era-faithful 2025 role unions (incl. tasks) live in // the 2025-era schemas. -import { getRequestSchema } from '../src/wire/rev2025-11-25/registry.js'; -import { ClientRequestSchema as Wire2025ClientRequestSchema } from '../src/wire/rev2025-11-25/schemas.js'; -import { RequestMetaEnvelopeSchema } from '../src/wire/rev2026-07-28/schemas.js'; +import { getRequestSchema } from '../src/wire/rev2025-11-25/registry'; +import { ClientRequestSchema as Wire2025ClientRequestSchema } from '../src/wire/rev2025-11-25/schemas'; +import { RequestMetaEnvelopeSchema } from '../src/wire/rev2026-07-28/schemas'; describe('Types', () => { test('should have correct latest protocol version', () => { diff --git a/packages/core/test/types/crossBundleErrorRecognition.test.ts b/packages/core-internal/test/types/crossBundleErrorRecognition.test.ts similarity index 96% rename from packages/core/test/types/crossBundleErrorRecognition.test.ts rename to packages/core-internal/test/types/crossBundleErrorRecognition.test.ts index c6f1377e99..edb959173e 100644 --- a/packages/core/test/types/crossBundleErrorRecognition.test.ts +++ b/packages/core-internal/test/types/crossBundleErrorRecognition.test.ts @@ -17,11 +17,11 @@ */ import { describe, expect, test } from 'vitest'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol } from '../../src/shared/protocol.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import type { JSONRPCRequest } from '../../src/types/index.js'; -import { ProtocolError, ProtocolErrorCode, UnsupportedProtocolVersionError, UrlElicitationRequiredError } from '../../src/types/index.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol } from '../../src/shared/protocol'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import type { JSONRPCRequest } from '../../src/types/index'; +import { ProtocolError, ProtocolErrorCode, UnsupportedProtocolVersionError, UrlElicitationRequiredError } from '../../src/types/index'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} diff --git a/packages/core/test/types/discoverWiring.test.ts b/packages/core-internal/test/types/discoverWiring.test.ts similarity index 94% rename from packages/core/test/types/discoverWiring.test.ts rename to packages/core-internal/test/types/discoverWiring.test.ts index b17b96101c..ea0c1f409b 100644 --- a/packages/core/test/types/discoverWiring.test.ts +++ b/packages/core-internal/test/types/discoverWiring.test.ts @@ -8,10 +8,10 @@ */ import { describe, expect, expectTypeOf, test } from 'vitest'; -import { ClientRequestSchema, DiscoverResultSchema, ServerResultSchema } from '../../src/types/index.js'; -import type { DiscoverResult, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../src/types/index.js'; -import { getRequestSchema, getResultSchema } from '../../src/wire/rev2025-11-25/registry.js'; -import { getRequestSchema2026, getResultSchema2026 } from '../../src/wire/rev2026-07-28/registry.js'; +import { ClientRequestSchema, DiscoverResultSchema, ServerResultSchema } from '../../src/types/index'; +import type { DiscoverResult, RequestMethod, RequestTypeMap, ResultTypeMap } from '../../src/types/index'; +import { getRequestSchema, getResultSchema } from '../../src/wire/rev2025-11-25/registry'; +import { getRequestSchema2026, getResultSchema2026 } from '../../src/wire/rev2026-07-28/registry'; describe('server/discover typed-funnel wiring (LC-02)', () => { test('ClientRequestSchema accepts a server/discover request', () => { diff --git a/packages/core/test/types/errorSurfacePins.test.ts b/packages/core-internal/test/types/errorSurfacePins.test.ts similarity index 99% rename from packages/core/test/types/errorSurfacePins.test.ts rename to packages/core-internal/test/types/errorSurfacePins.test.ts index 7191cf5e19..59a207791f 100644 --- a/packages/core/test/types/errorSurfacePins.test.ts +++ b/packages/core-internal/test/types/errorSurfacePins.test.ts @@ -12,7 +12,7 @@ */ import { describe, expect, test } from 'vitest'; -import { SdkError, SdkErrorCode, SdkHttpError } from '../../src/errors/sdkErrors.js'; +import { SdkError, SdkErrorCode, SdkHttpError } from '../../src/errors/sdkErrors'; import { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, INTERNAL_ERROR, @@ -28,8 +28,8 @@ import { ResourceNotFoundError, UnsupportedProtocolVersionError, UrlElicitationRequiredError -} from '../../src/types/index.js'; -import { STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../src/shared/stdio.js'; +} from '../../src/types/index'; +import { STDIO_DEFAULT_MAX_BUFFER_SIZE } from '../../src/shared/stdio'; describe('ProtocolErrorCode', () => { test('numeric values are frozen wire ABI', () => { diff --git a/packages/core/test/types/errors.test.ts b/packages/core-internal/test/types/errors.test.ts similarity index 95% rename from packages/core/test/types/errors.test.ts rename to packages/core-internal/test/types/errors.test.ts index 0b04ada841..f3cbf89636 100644 --- a/packages/core/test/types/errors.test.ts +++ b/packages/core-internal/test/types/errors.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { ProtocolErrorCode } from '../../src/types/enums.js'; -import { ProtocolError, UnsupportedProtocolVersionError } from '../../src/types/errors.js'; +import { ProtocolErrorCode } from '../../src/types/enums'; +import { ProtocolError, UnsupportedProtocolVersionError } from '../../src/types/errors'; describe('UnsupportedProtocolVersionError', () => { const data = { supported: ['2025-11-25', '2025-06-18'], requested: '2026-07-28' }; diff --git a/packages/core/test/types/guards.test.ts b/packages/core-internal/test/types/guards.test.ts similarity index 96% rename from packages/core/test/types/guards.test.ts rename to packages/core-internal/test/types/guards.test.ts index 117e9ecda7..fe96b64dd3 100644 --- a/packages/core/test/types/guards.test.ts +++ b/packages/core-internal/test/types/guards.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { JSONRPC_VERSION } from '../../src/types/constants.js'; -import { isCallToolResult, isJSONRPCErrorResponse, isJSONRPCResponse, isJSONRPCResultResponse } from '../../src/types/guards.js'; +import { JSONRPC_VERSION } from '../../src/types/constants'; +import { isCallToolResult, isJSONRPCErrorResponse, isJSONRPCResponse, isJSONRPCResultResponse } from '../../src/types/guards'; describe('isJSONRPCResponse', () => { it('returns true for a valid result response', () => { diff --git a/packages/core/test/types/missingClientCapabilityError.test.ts b/packages/core-internal/test/types/missingClientCapabilityError.test.ts similarity index 97% rename from packages/core/test/types/missingClientCapabilityError.test.ts rename to packages/core-internal/test/types/missingClientCapabilityError.test.ts index ce121ff8a9..e9a97375ca 100644 --- a/packages/core/test/types/missingClientCapabilityError.test.ts +++ b/packages/core-internal/test/types/missingClientCapabilityError.test.ts @@ -7,8 +7,8 @@ */ import { describe, expect, test } from 'vitest'; -import { ProtocolErrorCode } from '../../src/types/enums.js'; -import { MissingRequiredClientCapabilityError, ProtocolError } from '../../src/types/errors.js'; +import { ProtocolErrorCode } from '../../src/types/enums'; +import { MissingRequiredClientCapabilityError, ProtocolError } from '../../src/types/errors'; describe('MissingRequiredClientCapabilityError', () => { test('carries the -32021 code and the missing capabilities in data.requiredCapabilities', () => { diff --git a/packages/core/test/types/publicTypeShapes.test.ts b/packages/core-internal/test/types/publicTypeShapes.test.ts similarity index 97% rename from packages/core/test/types/publicTypeShapes.test.ts rename to packages/core-internal/test/types/publicTypeShapes.test.ts index 5358e80613..5efb1b05ce 100644 --- a/packages/core/test/types/publicTypeShapes.test.ts +++ b/packages/core-internal/test/types/publicTypeShapes.test.ts @@ -21,11 +21,11 @@ import type { SamplingMessageContentBlock, Tool, ToolResultContent -} from '../../src/types/types.js'; +} from '../../src/types/types'; import { CallToolResultSchema as Wire2025CallToolResultSchema, ToolSchema as Wire2025ToolSchema -} from '../../src/wire/rev2025-11-25/schemas.js'; +} from '../../src/wire/rev2025-11-25/schemas'; describe('SEP-2106 public-type widening', () => { it('CallToolResult.structuredContent is unknown', () => { diff --git a/packages/core/test/types/registryPins.test.ts b/packages/core-internal/test/types/registryPins.test.ts similarity index 98% rename from packages/core/test/types/registryPins.test.ts rename to packages/core-internal/test/types/registryPins.test.ts index b86a10b398..9af70927f2 100644 --- a/packages/core/test/types/registryPins.test.ts +++ b/packages/core-internal/test/types/registryPins.test.ts @@ -22,7 +22,7 @@ import { describe, expect, it } from 'vitest'; // Post-relocation home (Q1 increment-2 step 1): the pinned contents are // unchanged — only the module housing the registries moved. -import { getNotificationSchema, getRequestSchema, getResultSchema } from '../../src/wire/rev2025-11-25/registry.js'; +import { getNotificationSchema, getRequestSchema, getResultSchema } from '../../src/wire/rev2025-11-25/registry'; // The 2025 wire schemas are fully self-contained in the era's schema module: // every per-method schema the registry serves is a FROZEN 2025-11-25 copy so // the public/neutral layer can evolve (e.g. SEP-2106 widening) without @@ -73,7 +73,7 @@ import { TaskStatusNotificationSchema, ToolListChangedNotificationSchema, UnsubscribeRequestSchema -} from '../../src/wire/rev2025-11-25/schemas.js'; +} from '../../src/wire/rev2025-11-25/schemas'; /** The exact 2025-era request-method → schema map (today's wire surface, verbatim). */ const EXPECTED_REQUEST_SCHEMAS = { diff --git a/packages/core/test/types/schemaBoundaryPins.test.ts b/packages/core-internal/test/types/schemaBoundaryPins.test.ts similarity index 99% rename from packages/core/test/types/schemaBoundaryPins.test.ts rename to packages/core-internal/test/types/schemaBoundaryPins.test.ts index 8551b425d8..5dd6a11727 100644 --- a/packages/core/test/types/schemaBoundaryPins.test.ts +++ b/packages/core-internal/test/types/schemaBoundaryPins.test.ts @@ -25,7 +25,7 @@ import { JSONRPCRequestSchema, JSONRPCResultResponseSchema, ResultSchema -} from '../../src/types/index.js'; +} from '../../src/types/index'; // The per-request envelope is wire-only vocabulary and now lives in the // 2026-era wire module (Q1 increment 2); its accept/reject line is unchanged. import { @@ -33,7 +33,7 @@ import { ClientCapabilitiesSchema as Wire2026ClientCapabilitiesSchema, ListToolsResultSchema as Wire2026ListToolsResultSchema, RequestMetaEnvelopeSchema -} from '../../src/wire/rev2026-07-28/schemas.js'; +} from '../../src/wire/rev2026-07-28/schemas'; import type { CallToolResult, CompleteResult, @@ -45,7 +45,7 @@ import type { ListToolsResult, ReadResourceResult, ServerCapabilities -} from '../../src/types/index.js'; +} from '../../src/types/index'; /** Extract zod issue codes without depending on zod's generics. */ const issueCodes = (err: unknown): string[] => ((err as { issues?: Array<{ code: string }> }).issues ?? []).map(i => i.code); diff --git a/packages/core/test/types/specTypeSchema.test.ts b/packages/core-internal/test/types/specTypeSchema.test.ts similarity index 95% rename from packages/core/test/types/specTypeSchema.test.ts rename to packages/core-internal/test/types/specTypeSchema.test.ts index 7a077717cf..3266b09521 100644 --- a/packages/core/test/types/specTypeSchema.test.ts +++ b/packages/core-internal/test/types/specTypeSchema.test.ts @@ -1,9 +1,9 @@ import { describe, expect, expectTypeOf, it } from 'vitest'; -import type { OAuthMetadata, OAuthTokens } from '../../src/shared/auth.js'; -import * as schemas from '../../src/types/schemas.js'; -import type { SpecTypeName, SpecTypes } from '../../src/types/specTypeSchema.js'; -import { isSpecType, specTypeSchemas } from '../../src/types/specTypeSchema.js'; +import type { OAuthMetadata, OAuthTokens } from '../../src/shared/auth'; +import * as schemas from '../../src/types/schemas'; +import type { SpecTypeName, SpecTypes } from '../../src/types/specTypeSchema'; +import { isSpecType, specTypeSchemas } from '../../src/types/specTypeSchema'; import type { CallToolResult, ContentBlock, @@ -13,7 +13,7 @@ import type { JSONValue, ResourceTemplateType, Tool -} from '../../src/types/types.js'; +} from '../../src/types/types'; describe('specTypeSchemas', () => { it('returns a StandardSchemaV1Sync validator that accepts valid values', () => { @@ -180,10 +180,11 @@ describe('SPEC_SCHEMA_KEYS allowlist', () => { .filter(k => !INTERNAL_HELPER_SCHEMAS.includes(k)) .map(k => k.slice(0, -'Schema'.length)) .sort(); - // Auth schemas are sourced from shared/auth.ts, not schemas.ts, so filter them out of the - // observed side before comparing. + // Auth schemas are sourced from shared/auth.ts, not schemas.ts. Keep only the protocol entries + // (whose `*Schema` const lives in schemas.ts) so the comparison stays against schemas.ts — + // robust to new auth schemas (e.g. IdJagTokenExchangeResponse) without a name-prefix heuristic. const actual = Object.keys(isSpecType) - .filter(k => !k.startsWith('OAuth') && !k.startsWith('OpenId')) + .filter(k => `${k}Schema` in schemas) .sort(); expect(actual).toEqual(expected); }); diff --git a/packages/core/test/types/wireOnlyHiding.test.ts b/packages/core-internal/test/types/wireOnlyHiding.test.ts similarity index 99% rename from packages/core/test/types/wireOnlyHiding.test.ts rename to packages/core-internal/test/types/wireOnlyHiding.test.ts index 1a71e600cc..a29f1627a6 100644 --- a/packages/core/test/types/wireOnlyHiding.test.ts +++ b/packages/core-internal/test/types/wireOnlyHiding.test.ts @@ -45,8 +45,8 @@ import type { ResultTypeMap, Task, TaskAugmentedRequestParams -} from '../../src/types/types.js'; -import { CallToolResultSchema, ResultSchema } from '../../src/types/schemas.js'; +} from '../../src/types/types'; +import { CallToolResultSchema, ResultSchema } from '../../src/types/schemas'; /** Declared (non-index-signature) keys of T. */ type KnownKeyOf = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] }; diff --git a/packages/core/test/util/standardSchema.test.ts b/packages/core-internal/test/util/standardSchema.test.ts similarity index 99% rename from packages/core/test/util/standardSchema.test.ts rename to packages/core-internal/test/util/standardSchema.test.ts index 6c3de99d77..8856592ff0 100644 --- a/packages/core/test/util/standardSchema.test.ts +++ b/packages/core-internal/test/util/standardSchema.test.ts @@ -1,6 +1,6 @@ import * as z from 'zod/v4'; -import { standardSchemaToJsonSchema } from '../../src/util/standardSchema.js'; +import { standardSchemaToJsonSchema } from '../../src/util/standardSchema'; describe('standardSchemaToJsonSchema', () => { test('emits type:object for plain z.object schemas', () => { diff --git a/packages/core/test/util/standardSchema.zodFallback.test.ts b/packages/core-internal/test/util/standardSchema.zodFallback.test.ts similarity index 99% rename from packages/core/test/util/standardSchema.zodFallback.test.ts rename to packages/core-internal/test/util/standardSchema.zodFallback.test.ts index d825a3271d..f8862b08a3 100644 --- a/packages/core/test/util/standardSchema.zodFallback.test.ts +++ b/packages/core-internal/test/util/standardSchema.zodFallback.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import { standardSchemaToJsonSchema } from '../../src/util/standardSchema.js'; +import { standardSchemaToJsonSchema } from '../../src/util/standardSchema'; type SchemaArg = Parameters[0]; diff --git a/packages/core/test/util/zodCompat.test.ts b/packages/core-internal/test/util/zodCompat.test.ts similarity index 99% rename from packages/core/test/util/zodCompat.test.ts rename to packages/core-internal/test/util/zodCompat.test.ts index cf48be3d3b..5bdc229298 100644 --- a/packages/core/test/util/zodCompat.test.ts +++ b/packages/core-internal/test/util/zodCompat.test.ts @@ -1,8 +1,8 @@ import { vi } from 'vitest'; import * as z from 'zod/v4'; -import { standardSchemaToJsonSchema } from '../../src/util/standardSchema.js'; -import { isZodRawShape, normalizeRawShapeSchema } from '../../src/util/zodCompat.js'; +import { standardSchemaToJsonSchema } from '../../src/util/standardSchema'; +import { isZodRawShape, normalizeRawShapeSchema } from '../../src/util/zodCompat'; describe('isZodRawShape', () => { test('treats empty object as a raw shape (matches v1)', () => { diff --git a/packages/core/test/validators/validators.test.ts b/packages/core-internal/test/validators/validators.test.ts similarity index 99% rename from packages/core/test/validators/validators.test.ts rename to packages/core-internal/test/validators/validators.test.ts index 0ccf5ad9e4..3318b94d10 100644 --- a/packages/core/test/validators/validators.test.ts +++ b/packages/core-internal/test/validators/validators.test.ts @@ -9,9 +9,9 @@ import path from 'node:path'; import { vi } from 'vitest'; -import { Ajv, AjvJsonSchemaValidator } from '../../src/validators/ajvProvider.js'; -import { CfWorkerJsonSchemaValidator } from '../../src/validators/cfWorkerProvider.js'; -import type { JsonSchemaType } from '../../src/validators/types.js'; +import { Ajv, AjvJsonSchemaValidator } from '../../src/validators/ajvProvider'; +import { CfWorkerJsonSchemaValidator } from '../../src/validators/cfWorkerProvider'; +import type { JsonSchemaType } from '../../src/validators/types'; // Test with both AJV and CfWorker validators // AJV validator will use default configuration with format validation enabled @@ -554,7 +554,7 @@ describe('Missing dependencies', () => { }); // Attempting to import ajv-provider should fail - await expect(import('../../src/validators/ajvProvider.js')).rejects.toThrow(); + await expect(import('../../src/validators/ajvProvider')).rejects.toThrow(); }); it('should be able to import cfWorkerProvider when ajv is missing', async () => { @@ -568,7 +568,7 @@ describe('Missing dependencies', () => { }); // But cfWorkerProvider should import successfully - const cfworkerModule = await import('../../src/validators/cfWorkerProvider.js'); + const cfworkerModule = await import('../../src/validators/cfWorkerProvider'); expect(cfworkerModule.CfWorkerJsonSchemaValidator).toBeDefined(); // And should work correctly @@ -595,7 +595,7 @@ describe('Missing dependencies', () => { }); // Attempting to import cfWorkerProvider should fail - await expect(import('../../src/validators/cfWorkerProvider.js')).rejects.toThrow(); + await expect(import('../../src/validators/cfWorkerProvider')).rejects.toThrow(); }); it('should be able to import ajv-provider when @cfworker/json-schema is missing', async () => { @@ -605,7 +605,7 @@ describe('Missing dependencies', () => { }); // But ajv-provider should import successfully - const ajvModule = await import('../../src/validators/ajvProvider.js'); + const ajvModule = await import('../../src/validators/ajvProvider'); expect(ajvModule.AjvJsonSchemaValidator).toBeDefined(); // And should work correctly diff --git a/packages/core/test/wire/codec.test.ts b/packages/core-internal/test/wire/codec.test.ts similarity index 99% rename from packages/core/test/wire/codec.test.ts rename to packages/core-internal/test/wire/codec.test.ts index 7238b37d8d..7d3d34a971 100644 --- a/packages/core/test/wire/codec.test.ts +++ b/packages/core-internal/test/wire/codec.test.ts @@ -10,7 +10,7 @@ */ import { describe, expect, test } from 'vitest'; -import { codecForVersion, MODERN_WIRE_REVISION } from '../../src/wire/codec.js'; +import { codecForVersion, MODERN_WIRE_REVISION } from '../../src/wire/codec'; const MATERIAL = { protocolVersion: '2026-09-01', diff --git a/packages/core/test/wire/encodeContract.test.ts b/packages/core-internal/test/wire/encodeContract.test.ts similarity index 98% rename from packages/core/test/wire/encodeContract.test.ts rename to packages/core-internal/test/wire/encodeContract.test.ts index 984ec208e9..32c404010d 100644 --- a/packages/core/test/wire/encodeContract.test.ts +++ b/packages/core-internal/test/wire/encodeContract.test.ts @@ -23,19 +23,19 @@ import { CACHEABLE_RESULT_METHODS, cacheHintFallbackOf, RESULT_CACHE_HINT_FALLBACK -} from '../../src/shared/resultCacheHints.js'; -import { ProtocolError } from '../../src/types/errors.js'; -import type { Result } from '../../src/types/types.js'; -import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec.js'; -import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec.js'; -import { DiscoverResultSchema as Wire2026DiscoverResultSchema } from '../../src/wire/rev2026-07-28/schemas.js'; +} from '../../src/shared/resultCacheHints'; +import { ProtocolError } from '../../src/types/errors'; +import type { Result } from '../../src/types/types'; +import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec'; +import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec'; +import { DiscoverResultSchema as Wire2026DiscoverResultSchema } from '../../src/wire/rev2026-07-28/schemas'; import { DEFAULT_CACHE_SCOPE, DEFAULT_CACHE_TTL_MS, EXTENDED_RESULT_TYPE_METHODS, fillCacheFields, stampResultType -} from '../../src/wire/rev2026-07-28/encodeContract.js'; +} from '../../src/wire/rev2026-07-28/encodeContract'; const asResult = (value: Record): Result => value as unknown as Result; const fieldsOf = (value: Result): Record => value as unknown as Record; diff --git a/packages/core/test/wire/eraGates.test.ts b/packages/core-internal/test/wire/eraGates.test.ts similarity index 98% rename from packages/core/test/wire/eraGates.test.ts rename to packages/core-internal/test/wire/eraGates.test.ts index dac1ae70c9..8ecd642a1e 100644 --- a/packages/core/test/wire/eraGates.test.ts +++ b/packages/core-internal/test/wire/eraGates.test.ts @@ -35,11 +35,11 @@ */ import { describe, expect, test } from 'vitest'; -import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors.js'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol.js'; -import type { JSONRPCMessage, MessageClassification, Result } from '../../src/types/index.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; +import { SdkError, SdkErrorCode } from '../../src/errors/sdkErrors'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol'; +import type { JSONRPCMessage, MessageClassification, Result } from '../../src/types/index'; +import { InMemoryTransport } from '../../src/util/inMemory'; import * as z from 'zod/v4'; class TestProtocol extends Protocol { @@ -307,7 +307,7 @@ describe('the stamp seam and the never-stamp guarantee', () => { }); test('the 2025 codec encodeResult is the identity (same reference, nothing added)', async () => { - const { rev2025Codec } = await import('../../src/wire/rev2025-11-25/codec.js'); + const { rev2025Codec } = await import('../../src/wire/rev2025-11-25/codec'); const result = { content: [{ type: 'text', text: 'x' }] } as unknown as Result; expect(rev2025Codec.encodeResult('tools/call', result)).toBe(result); }); @@ -564,7 +564,7 @@ describe('outbound era gates — typed local error before the transport', () => describe('T6 width-leak killed at both roots', () => { test('2026 era: a task-shaped tools/call body can never parse as an empty success', async () => { - const { rev2026Codec } = await import('../../src/wire/rev2026-07-28/codec.js'); + const { rev2026Codec } = await import('../../src/wire/rev2026-07-28/codec'); // resultType present-and-complete but the body is task-shaped: the // wire-exact parse requires content — loud invalid, never {content: []}. const decoded = rev2026Codec.decodeResult('tools/call', { @@ -575,8 +575,8 @@ describe('T6 width-leak killed at both roots', () => { }); test('2025 era: with the content default gone, a bare task-shaped body fails the plain schema loudly', async () => { - const { rev2025Codec } = await import('../../src/wire/rev2025-11-25/codec.js'); - const { CallToolResultSchema } = await import('../../src/wire/rev2025-11-25/schemas.js'); + const { rev2025Codec } = await import('../../src/wire/rev2025-11-25/codec'); + const { CallToolResultSchema } = await import('../../src/wire/rev2025-11-25/schemas'); const decoded = rev2025Codec.decodeResult('tools/call', { task: { taskId: 't-1', status: 'working' } }); expect(decoded.kind).toBe('complete'); if (decoded.kind === 'complete') { @@ -590,7 +590,7 @@ describe('T6 width-leak killed at both roots', () => { // failure (surfaced as a typed INVALID_RESULT — see // test/shared/typedMapAlignment.test.ts). Task interop is the // explicit-schema overload, never a silent union member. - const { getResultSchema } = await import('../../src/wire/rev2025-11-25/registry.js'); + const { getResultSchema } = await import('../../src/wire/rev2025-11-25/registry'); const plain = getResultSchema('tools/call'); expect(plain).toBe(CallToolResultSchema); expect( diff --git a/packages/core/test/wire/layeringInvariants.test.ts b/packages/core-internal/test/wire/layeringInvariants.test.ts similarity index 98% rename from packages/core/test/wire/layeringInvariants.test.ts rename to packages/core-internal/test/wire/layeringInvariants.test.ts index 39f767d748..37c5ba29f9 100644 --- a/packages/core/test/wire/layeringInvariants.test.ts +++ b/packages/core-internal/test/wire/layeringInvariants.test.ts @@ -17,7 +17,7 @@ import { posix, sep } from 'node:path'; import { describe, expect, expectTypeOf, test } from 'vitest'; -import type { WireCodec } from '../../src/wire/codec.js'; +import type { WireCodec } from '../../src/wire/codec'; const SRC_ROOT = new URL('../../src/', import.meta.url); diff --git a/packages/core/test/wire/legacyWrap.test.ts b/packages/core-internal/test/wire/legacyWrap.test.ts similarity index 99% rename from packages/core/test/wire/legacyWrap.test.ts rename to packages/core-internal/test/wire/legacyWrap.test.ts index ed421c1210..dfca0fa6eb 100644 --- a/packages/core/test/wire/legacyWrap.test.ts +++ b/packages/core-internal/test/wire/legacyWrap.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { wrapOutputSchemaForLegacy } from '../../src/wire/rev2025-11-25/legacyWrap.js'; -import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec.js'; +import { wrapOutputSchemaForLegacy } from '../../src/wire/rev2025-11-25/legacyWrap'; +import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec'; /** Test helper: drill into a nested untyped object by path. */ function dig(node: unknown, ...path: ReadonlyArray): unknown { diff --git a/packages/core/test/wire/neutralKeyParity.test.ts b/packages/core-internal/test/wire/neutralKeyParity.test.ts similarity index 98% rename from packages/core/test/wire/neutralKeyParity.test.ts rename to packages/core-internal/test/wire/neutralKeyParity.test.ts index 316513541b..7a3b6112c7 100644 --- a/packages/core/test/wire/neutralKeyParity.test.ts +++ b/packages/core-internal/test/wire/neutralKeyParity.test.ts @@ -22,8 +22,8 @@ import { describe, expect, test } from 'vitest'; import type * as z4 from 'zod/v4'; -import type * as SDK from '../../src/types/index.js'; -import type * as Wire2026 from '../../src/wire/rev2026-07-28/schemas.js'; +import type * as SDK from '../../src/types/index'; +import type * as Wire2026 from '../../src/wire/rev2026-07-28/schemas'; /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/packages/core/test/wire/registryDiffOracle.test.ts b/packages/core-internal/test/wire/registryDiffOracle.test.ts similarity index 98% rename from packages/core/test/wire/registryDiffOracle.test.ts rename to packages/core-internal/test/wire/registryDiffOracle.test.ts index 6bdd2937c8..42b3bb7abf 100644 --- a/packages/core/test/wire/registryDiffOracle.test.ts +++ b/packages/core-internal/test/wire/registryDiffOracle.test.ts @@ -20,8 +20,8 @@ import path from 'node:path'; import { describe, expect, test } from 'vitest'; -import { rev2025NotificationMethods, rev2025RequestMethods } from '../../src/wire/rev2025-11-25/registry.js'; -import { rev2026NotificationMethods, rev2026RequestMethods } from '../../src/wire/rev2026-07-28/registry.js'; +import { rev2025NotificationMethods, rev2025RequestMethods } from '../../src/wire/rev2025-11-25/registry'; +import { rev2026NotificationMethods, rev2026RequestMethods } from '../../src/wire/rev2026-07-28/registry'; const ANCHORS = { '2025-11-25': path.resolve(__dirname, '../../src/types/spec.types.2025-11-25.ts'), diff --git a/packages/core/test/wire/rev2025FrozenShapes.test.ts b/packages/core-internal/test/wire/rev2025FrozenShapes.test.ts similarity index 97% rename from packages/core/test/wire/rev2025FrozenShapes.test.ts rename to packages/core-internal/test/wire/rev2025FrozenShapes.test.ts index c9178aa861..e678d091c2 100644 --- a/packages/core/test/wire/rev2025FrozenShapes.test.ts +++ b/packages/core-internal/test/wire/rev2025FrozenShapes.test.ts @@ -13,7 +13,7 @@ import { ListToolsResultSchema, ToolResultContentSchema, ToolSchema -} from '../../src/wire/rev2025-11-25/schemas.js'; +} from '../../src/wire/rev2025-11-25/schemas'; describe('frozen 2025-11-25 wire shapes (Q10-L2)', () => { it('CallToolResultSchema rejects non-object structuredContent', () => { diff --git a/packages/core/test/wire/schemaTwinConformance.test.ts b/packages/core-internal/test/wire/schemaTwinConformance.test.ts similarity index 98% rename from packages/core/test/wire/schemaTwinConformance.test.ts rename to packages/core-internal/test/wire/schemaTwinConformance.test.ts index e0f4b21dca..6d7945a425 100644 --- a/packages/core/test/wire/schemaTwinConformance.test.ts +++ b/packages/core-internal/test/wire/schemaTwinConformance.test.ts @@ -18,7 +18,7 @@ * blind to them). * * Twin refresh is ATOMIC with the matching anchor (lifecycle rule 4, - * packages/core/src/types/README.md); provenance in schema-twins/manifest.json. + * packages/core-internal/src/types/README.md); provenance in schema-twins/manifest.json. */ import { createHash } from 'node:crypto'; import { readdirSync, readFileSync, statSync } from 'node:fs'; diff --git a/packages/core/test/wire/stampingSuppression.test.ts b/packages/core-internal/test/wire/stampingSuppression.test.ts similarity index 98% rename from packages/core/test/wire/stampingSuppression.test.ts rename to packages/core-internal/test/wire/stampingSuppression.test.ts index 80af02aacc..707e43e0da 100644 --- a/packages/core/test/wire/stampingSuppression.test.ts +++ b/packages/core-internal/test/wire/stampingSuppression.test.ts @@ -23,13 +23,13 @@ */ import { describe, expect, test } from 'vitest'; -import type { BaseContext } from '../../src/shared/protocol.js'; -import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol.js'; -import { attachCacheHintFallback, CACHEABLE_RESULT_METHODS } from '../../src/shared/resultCacheHints.js'; -import type { JSONRPCMessage, MessageClassification, Result } from '../../src/types/index.js'; -import { InMemoryTransport } from '../../src/util/inMemory.js'; -import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec.js'; -import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec.js'; +import type { BaseContext } from '../../src/shared/protocol'; +import { Protocol, setNegotiatedProtocolVersion } from '../../src/shared/protocol'; +import { attachCacheHintFallback, CACHEABLE_RESULT_METHODS } from '../../src/shared/resultCacheHints'; +import type { JSONRPCMessage, MessageClassification, Result } from '../../src/types/index'; +import { InMemoryTransport } from '../../src/util/inMemory'; +import { rev2025Codec } from '../../src/wire/rev2025-11-25/codec'; +import { rev2026Codec } from '../../src/wire/rev2026-07-28/codec'; class TestProtocol extends Protocol { protected assertCapabilityForMethod(): void {} diff --git a/packages/core-internal/tsconfig.json b/packages/core-internal/tsconfig.json new file mode 100644 index 0000000000..a6838303e4 --- /dev/null +++ b/packages/core-internal/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "paths": { + "*": ["./*"], + "@modelcontextprotocol/eslint-config": ["./node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], + "@modelcontextprotocol/vitest-config": ["./node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + } + } +} diff --git a/packages/core-internal/vitest.config.js b/packages/core-internal/vitest.config.js new file mode 100644 index 0000000000..496fca3200 --- /dev/null +++ b/packages/core-internal/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index e25cd09faa..6c0e610989 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -4,103 +4,7 @@ ### Minor Changes -- [#1673](https://github.com/modelcontextprotocol/typescript-sdk/pull/1673) [`462c3fc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/462c3fc47dffac908d2ba27784d47ff010fa065e) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - refactor: extract task - orchestration from Protocol into TaskManager - - **Breaking changes:** - - `taskStore`, `taskMessageQueue`, `defaultTaskPollInterval`, and `maxTaskQueueSize` moved from `ProtocolOptions` to `capabilities.tasks` on `ClientOptions`/`ServerOptions` - -- [#1389](https://github.com/modelcontextprotocol/typescript-sdk/pull/1389) [`108f2f3`](https://github.com/modelcontextprotocol/typescript-sdk/commit/108f2f3ab6a1267587c7c4f900b6eca3cc2dae51) Thanks [@DePasqualeOrg](https://github.com/DePasqualeOrg)! - Fix error handling for - unknown tools and resources per MCP spec. - - **Tools:** Unknown or disabled tool calls now return JSON-RPC protocol errors with code `-32602` (InvalidParams) instead of `CallToolResult` with `isError: true`. Callers who checked `result.isError` for unknown tools should catch rejected promises instead. - - **Resources:** Unknown resource reads now return error code `-32002` (ResourceNotFound) instead of `-32602` (InvalidParams). - - Added `ProtocolErrorCode.ResourceNotFound`. - -- [#1689](https://github.com/modelcontextprotocol/typescript-sdk/pull/1689) [`0784be1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0784be1a67fb3cc2aba0182d88151264f4ea73c8) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Support Standard Schema - for tool and prompt schemas - - Tool and prompt registration now accepts any schema library that implements the [Standard Schema spec](https://standardschema.dev/): Zod v4, Valibot, ArkType, and others. `RegisteredTool.inputSchema`, `RegisteredTool.outputSchema`, and `RegisteredPrompt.argsSchema` now use - `StandardSchemaWithJSON` (requires both `~standard.validate` and `~standard.jsonSchema`) instead of the Zod-specific `AnySchema` type. - - **Zod v4 schemas continue to work unchanged** — Zod v4 implements the required interfaces natively. - - ```typescript - import { type } from 'arktype'; - - server.registerTool( - 'greet', - { - inputSchema: type({ name: 'string' }) - }, - async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}!` }] }) - ); - ``` - - For raw JSON Schema (e.g. TypeBox output), use the new `fromJsonSchema` adapter: - - ```typescript - import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core'; - - server.registerTool( - 'greet', - { - inputSchema: fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } } }, new AjvJsonSchemaValidator()) - }, - handler - ); - ``` - - **Breaking changes:** - - `experimental.tasks.getTaskResult()` no longer accepts a `resultSchema` parameter. Returns `GetTaskPayloadResult` (a loose `Result`); cast to the expected type at the call site. - - Removed unused exports from `@modelcontextprotocol/core`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` instead. - - `completable()` remains Zod-specific (it relies on Zod's `.shape` introspection). - -### Patch Changes - -- [#1735](https://github.com/modelcontextprotocol/typescript-sdk/pull/1735) [`a2e5037`](https://github.com/modelcontextprotocol/typescript-sdk/commit/a2e503733f6f3eea3a79a80bdc1b3cdd743f8bb3) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Abort in-flight request - handlers when the connection closes. Previously, request handlers would continue running after the transport disconnected, wasting resources and preventing proper cleanup. Also fixes `InMemoryTransport.close()` firing `onclose` twice on the initiating side. - -- [#1574](https://github.com/modelcontextprotocol/typescript-sdk/pull/1574) [`379392d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/379392d04460ee2cbeecae374901fae21e525031) Thanks [@olaservo](https://github.com/olaservo)! - Add missing `size` field to - `ResourceSchema` to match the MCP specification - -- [#1363](https://github.com/modelcontextprotocol/typescript-sdk/pull/1363) [`0a75810`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0a75810b26e24bae6b9cfb41e12ac770aeaa1da4) Thanks [@DevJanderson](https://github.com/DevJanderson)! - Fix ReDoS vulnerability in - UriTemplate regex patterns (CVE-2026-0621) - -- [#1761](https://github.com/modelcontextprotocol/typescript-sdk/pull/1761) [`01954e6`](https://github.com/modelcontextprotocol/typescript-sdk/commit/01954e621afe525cc3c1bbe8d781e44734cf81c2) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Convert remaining - capability-assertion throws to `SdkError(SdkErrorCode.CapabilityNotSupported, ...)`. Follow-up to #1454 which missed `Client.assertCapability()`, the task capability helpers in `experimental/tasks/helpers.ts`, and the sampling/elicitation capability checks in - `experimental/tasks/server.ts`. - -- [#1790](https://github.com/modelcontextprotocol/typescript-sdk/pull/1790) [`89fb094`](https://github.com/modelcontextprotocol/typescript-sdk/commit/89fb0947b487b37f9bfcc2a2486dcd33d3922f8e) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Consolidate per-request - cleanup in `_requestWithSchema` into a single `.finally()` block. This fixes an abort signal listener leak (listeners accumulated when a caller reused one `AbortSignal` across requests) and two cases where `_responseHandlers` entries leaked on send-failure paths. - -- [#1486](https://github.com/modelcontextprotocol/typescript-sdk/pull/1486) [`65bbcea`](https://github.com/modelcontextprotocol/typescript-sdk/commit/65bbceab773277f056a9d3e385e7e7d8cef54f9b) Thanks [@localden](https://github.com/localden)! - Fix InMemoryTaskStore to enforce - session isolation. Previously, sessionId was accepted but ignored on all TaskStore methods, allowing any session to enumerate, read, and mutate tasks created by other sessions. The store now persists sessionId at creation time and enforces ownership on all reads and writes. - -- [#1766](https://github.com/modelcontextprotocol/typescript-sdk/pull/1766) [`48aba0d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/48aba0d3c3b2ee04c442934095b663d19e07a3b3) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add explicit - `| undefined` to optional properties on the `Transport` interface and `TransportSendOptions` (`onclose`, `onerror`, `onmessage`, `sessionId`, `setProtocolVersion`, `setSupportedProtocolVersions`, `onresumptiontoken`). - - This fixes TS2420 errors for consumers using `exactOptionalPropertyTypes: true` without `skipLibCheck`, where the emitted `.d.ts` for implementing classes included `| undefined` but the interface did not. - - Workaround for older SDK versions: enable `skipLibCheck: true` in your tsconfig. - -- [#1419](https://github.com/modelcontextprotocol/typescript-sdk/pull/1419) [`dcf708d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/dcf708d892b7ca5f137c74109d42cdeb05e2ee3a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - remove deprecated .tool, - .prompt, .resource method signatures - -- [#1534](https://github.com/modelcontextprotocol/typescript-sdk/pull/1534) [`69a0626`](https://github.com/modelcontextprotocol/typescript-sdk/commit/69a062693f61e024d7a366db0c3e3ba74ff59d8e) Thanks [@josefaidt](https://github.com/josefaidt)! - remove npm references, use pnpm - -- [#1534](https://github.com/modelcontextprotocol/typescript-sdk/pull/1534) [`69a0626`](https://github.com/modelcontextprotocol/typescript-sdk/commit/69a062693f61e024d7a366db0c3e3ba74ff59d8e) Thanks [@josefaidt](https://github.com/josefaidt)! - clean up package manager usage, all - pnpm - -- [#1796](https://github.com/modelcontextprotocol/typescript-sdk/pull/1796) [`d6a02c8`](https://github.com/modelcontextprotocol/typescript-sdk/commit/d6a02c85c0514658c27615398a3003aadce80fb0) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Ensure - `standardSchemaToJsonSchema` emits `type: "object"` at the root, fixing discriminated-union tool/prompt schemas that previously produced `{oneOf: [...]}` without the MCP-required top-level type. Also throws a clear error when given an explicitly non-object schema (e.g. - `z.string()`). Fixes #1643. - -- [#1419](https://github.com/modelcontextprotocol/typescript-sdk/pull/1419) [`dcf708d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/dcf708d892b7ca5f137c74109d42cdeb05e2ee3a) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - deprecated .tool, .prompt, - .resource method removal - -- [#1762](https://github.com/modelcontextprotocol/typescript-sdk/pull/1762) [`64897f7`](https://github.com/modelcontextprotocol/typescript-sdk/commit/64897f78ce78f736b027dfecd1b4326c8c6678c7) Thanks [@felixweinberger](https://github.com/felixweinberger)! - - `ReadBuffer.readMessage()` now silently skips non-JSON lines instead of throwing `SyntaxError`. This prevents noisy `onerror` callbacks when hot-reload tools (tsx, nodemon) write debug output like "Gracefully restarting..." to stdout. Lines that parse as JSON but fail JSONRPC - schema validation still throw. +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add + `@modelcontextprotocol/core`: the public home for the MCP specification and OAuth/OpenID Zod schemas. It bundles the SDK's internal schema definitions and re-exports only the `*Schema` values, so consumers can validate protocol payloads (`Schema.parse(value)` / + `.safeParse(value)`) without depending on a package's internal barrel. Alongside the spec schemas it also re-exports the auth schemas v1 exposed from `@modelcontextprotocol/sdk/shared/auth.js` (e.g. `OAuthTokensSchema`, `OAuthMetadataSchema`, + `IdJagTokenExchangeResponseSchema`). Spec types, error classes, enums, and guards continue to live on `@modelcontextprotocol/server` and `@modelcontextprotocol/client`. diff --git a/packages/core/README.md b/packages/core/README.md new file mode 100644 index 0000000000..5da63a8f2a --- /dev/null +++ b/packages/core/README.md @@ -0,0 +1,40 @@ +# @modelcontextprotocol/core + +Canonical public home for the [Model Context Protocol](https://modelcontextprotocol.io) specification and OAuth/OpenID **Zod schemas**. + +These are the exact schema constants the SDK validates protocol and OAuth/OpenID payloads against internally. The `@modelcontextprotocol/server` and `@modelcontextprotocol/client` packages keep a Zod-free public surface, so this package exists as the supported place to import the +raw schemas when you need to validate or parse MCP messages yourself. + +## Install + +```sh +npm install @modelcontextprotocol/core +``` + +## Usage + +```ts +import { CallToolResultSchema } from '@modelcontextprotocol/core'; + +// Throws on invalid input; returns the typed result on success. +const result = CallToolResultSchema.parse(payload); + +// Or non-throwing: +const parsed = CallToolResultSchema.safeParse(payload); +if (parsed.success) { + // parsed.data is a fully typed CallToolResult +} +``` + +## Scope + +This package exports **only** Zod schema constants (`*Schema`), in two groups: + +- the MCP **spec** schemas — `CallToolResultSchema`, `ListToolsResultSchema`, …; and +- the **OAuth/OpenID** auth schemas — `OAuthTokensSchema`, `OAuthMetadataSchema`, `IdJagTokenExchangeResponseSchema`, … (the schemas v1 exposed from `@modelcontextprotocol/sdk/shared/auth.js`). + +The corresponding TypeScript types, error classes, enums, and type guards are part of the public API of [`@modelcontextprotocol/server`](https://www.npmjs.com/package/@modelcontextprotocol/server) and +[`@modelcontextprotocol/client`](https://www.npmjs.com/package/@modelcontextprotocol/client). + +> **Migrating from v1?** In v1 these schemas were imported from `@modelcontextprotocol/sdk/types.js` (spec schemas) and `@modelcontextprotocol/sdk/shared/auth.js` (OAuth/OpenID schemas). Point those `*Schema` imports at `@modelcontextprotocol/core` and your existing `.parse()` / +> `.safeParse()` calls keep working unchanged. diff --git a/packages/core/eslint.config.mjs b/packages/core/eslint.config.mjs index a142acd806..dd9e88588a 100644 --- a/packages/core/eslint.config.mjs +++ b/packages/core/eslint.config.mjs @@ -5,50 +5,8 @@ import baseConfig from '@modelcontextprotocol/eslint-config'; export default [ ...baseConfig, { - // Wire-layer isolation, outbound direction: nothing outside src/wire/ may - // reach into a wire revision module. The wire layer's only public surface - // is src/wire/codec.ts (the WireCodec interface) and src/wire/bootstrap.ts. - // test/wire/layeringInvariants.test.ts re-derives the same invariant with - // zero exceptions. Type-only imports are exempted at the lint layer (a - // type-only crossing is erased at runtime), but the test allows none. - files: ['src/**/*.ts'], - ignores: ['src/wire/**'], - rules: { - '@typescript-eslint/no-restricted-imports': [ - 'error', - { - patterns: [ - { - group: ['**/wire/rev*', '**/wire/rev*/**', '@modelcontextprotocol/core/wire/rev*'], - allowTypeImports: true, - message: 'Wire revision modules are codec-private. Route through src/wire/codec.ts (WireCodec) instead.' - } - ] - } - ] - } - }, - { - // Wire-layer isolation, inbound direction: wire revision modules are frozen, - // self-contained schema sets — they must not import the public-layer schema - // module at runtime. A change to types/schemas.ts must never alter what a - // codec emits or accepts on the wire. Type-only imports stay permitted. - files: ['src/wire/rev*/**/*.ts'], - rules: { - '@typescript-eslint/no-restricted-imports': [ - 'error', - { - patterns: [ - { - group: ['**/types/schemas', '**/types/schemas.js'], - allowTypeImports: true, - message: - 'Wire revision modules must be self-contained. Freeze a copy of the schema into the ' + - 'rev*/ directory instead of importing the mutable public-layer types/schemas.ts.' - } - ] - } - ] + settings: { + 'import/internal-regex': '^@modelcontextprotocol/core-internal' } } ]; diff --git a/packages/core/package.json b/packages/core/package.json index beb46ccb88..fabb970fc4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,8 +1,7 @@ { "name": "@modelcontextprotocol/core", - "private": true, "version": "2.0.0-alpha.1", - "description": "Model Context Protocol implementation for TypeScript - Core package", + "description": "Model Context Protocol for TypeScript — public Zod schemas (spec + OAuth/OpenID)", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", "homepage": "https://modelcontextprotocol.io", @@ -18,84 +17,45 @@ "keywords": [ "modelcontextprotocol", "mcp", - "core" + "schemas", + "zod" ], "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs" - }, - "./types": { - "types": "./src/exports/types/index.ts", - "import": "./src/exports/types/index.ts" - }, - "./public": { - "types": "./src/exports/public/index.ts", - "import": "./src/exports/public/index.ts" - }, - "./validators/ajv": { - "types": "./src/validators/ajvProvider.ts", - "import": "./src/validators/ajvProvider.ts" - }, - "./validators/cfWorker": { - "types": "./src/validators/cfWorkerProvider.ts", - "import": "./src/validators/cfWorkerProvider.ts" + "import": "./dist/index.js" } }, + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], "scripts": { "typecheck": "tsgo -p tsconfig.json --noEmit", + "build": "tsdown", + "build:watch": "tsdown --watch", + "prepack": "pnpm run build", "lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .", "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "pnpm run typecheck && pnpm run lint", "test": "vitest run", - "test:watch": "vitest", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "test:watch": "vitest" }, "dependencies": { - "json-schema-typed": "catalog:runtimeShared", - "zod": "catalog:runtimeShared" - }, - "peerDependencies": { - "@cfworker/json-schema": "catalog:runtimeShared", - "ajv": "catalog:runtimeShared", - "ajv-formats": "catalog:runtimeShared", "zod": "catalog:runtimeShared" }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "ajv": { - "optional": true - }, - "ajv-formats": { - "optional": true - }, - "zod": { - "optional": false - } - }, "devDependencies": { + "@eslint/js": "catalog:devTools", + "@modelcontextprotocol/core-internal": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", "@modelcontextprotocol/vitest-config": "workspace:^", - "@modelcontextprotocol/eslint-config": "workspace:^", - "@cfworker/json-schema": "catalog:runtimeShared", - "ajv": "catalog:runtimeShared", - "ajv-formats": "catalog:runtimeShared", - "@eslint/js": "catalog:devTools", - "@types/content-type": "catalog:devTools", - "@types/cors": "catalog:devTools", - "@types/cross-spawn": "catalog:devTools", - "@types/eventsource": "catalog:devTools", - "@types/express": "catalog:devTools", - "@types/express-serve-static-core": "catalog:devTools", "@typescript/native-preview": "catalog:devTools", "eslint": "catalog:devTools", "eslint-config-prettier": "catalog:devTools", "eslint-plugin-n": "catalog:devTools", "prettier": "catalog:devTools", - "tsx": "catalog:devTools", + "tsdown": "catalog:devTools", "typescript": "catalog:devTools", "typescript-eslint": "catalog:devTools", "vitest": "catalog:devTools" diff --git a/packages/core/src/exports/types/index.ts b/packages/core/src/exports/types/index.ts deleted file mode 100644 index b957a8874c..0000000000 --- a/packages/core/src/exports/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type * from '../../types/index.js'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0141475f26..2440232047 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,40 +1,204 @@ -export * from './auth/errors.js'; -export * from './errors/sdkErrors.js'; -export * from './shared/auth.js'; -export * from './shared/authUtils.js'; -export * from './shared/clientCapabilityRequirements.js'; -export * from './shared/envelope.js'; -export * from './shared/inboundClassification.js'; -export * from './shared/inputRequired.js'; -export * from './shared/inputRequiredDriver.js'; -export * from './shared/inputRequiredEngine.js'; -export * from './shared/mcpParamHeaders.js'; -export * from './shared/metadataUtils.js'; -export * from './shared/protocol.js'; -export * from './shared/protocolEras.js'; -export * from './shared/resultCacheHints.js'; -export * from './shared/stdio.js'; -export * from './shared/toolNameValidation.js'; -export * from './shared/transport.js'; -export * from './shared/uriTemplate.js'; -export * from './types/index.js'; -export * from './util/inMemory.js'; -// Wire-codec internals: the version→codec resolver the sibling packages need -// (era state itself lives on Protocol and is written through the -// package-internal write hook exported by shared/protocol.ts), plus the -// internal modern-revision literal so sibling packages can name the era a -// 2026-only seam runs in. NOTHING per-revision (registries, codec objects, -// per-revision schemas) is ever exported on this barrel — sibling packages -// reach the wire layer ONLY through `codecForVersion`'s function-only -// `WireCodec` surface. -export * from './util/schema.js'; -export * from './util/standardSchema.js'; -export * from './util/zodCompat.js'; -export { codecForVersion, MODERN_WIRE_REVISION } from './wire/codec.js'; +// @modelcontextprotocol/core +// +// Canonical public home for the Model Context Protocol specification + OAuth/OpenID Zod schemas. +// +// These are the exact schema constants the SDK validates against internally (defined in the +// private @modelcontextprotocol/core-internal package). This package bundles core-internal and re-exports ONLY the +// `*Schema` Zod values, so consumers can validate protocol/OAuth payloads directly — e.g. +// `CallToolResultSchema.parse(value)` / `.safeParse(value)` — without depending on core-internal's +// barrel. +// +// Scope: Zod schemas ONLY. The corresponding spec TypeScript types, error classes, enums, and +// type guards are part of the public API of @modelcontextprotocol/server and /client. +// +// Two groups, kept separate to mirror core-internal's own spec-vs-auth split, each bundled from a build-only +// subpath alias of core-internal (tsconfig.json + tsdown.config.ts): +// - SPEC schemas, from @modelcontextprotocol/core-internal/schemas (core-internal/src/types/schemas.ts): every +// `export const *Schema` EXCEPT internal helpers with no public spec type (e.g. +// BaseRequestParamsSchema). Mirrors core-internal's SPEC_SCHEMA_KEYS allowlist. +// - OAUTH/OPENID schemas, from @modelcontextprotocol/core-internal/auth (core-internal/src/shared/auth.ts). +// The coreSchemas test asserts both groups stay in sync with their core-internal source modules. +export { + AnnotationsSchema, + AudioContentSchema, + BaseMetadataSchema, + BlobResourceContentsSchema, + BooleanSchemaSchema, + CallToolRequestParamsSchema, + CallToolRequestSchema, + CallToolResultSchema, + CancelledNotificationParamsSchema, + CancelledNotificationSchema, + CancelTaskRequestSchema, + CancelTaskResultSchema, + ClientCapabilitiesSchema, + ClientNotificationSchema, + ClientRequestSchema, + ClientResultSchema, + CompatibilityCallToolResultSchema, + CompleteRequestParamsSchema, + CompleteRequestSchema, + CompleteResultSchema, + ContentBlockSchema, + CreateMessageRequestParamsSchema, + CreateMessageRequestSchema, + CreateMessageResultSchema, + CreateMessageResultWithToolsSchema, + CreateTaskResultSchema, + CursorSchema, + DiscoverRequestSchema, + DiscoverResultSchema, + ElicitationCompleteNotificationParamsSchema, + ElicitationCompleteNotificationSchema, + ElicitRequestFormParamsSchema, + ElicitRequestParamsSchema, + ElicitRequestSchema, + ElicitRequestURLParamsSchema, + ElicitResultSchema, + EmbeddedResourceSchema, + EmptyResultSchema, + EnumSchemaSchema, + GetPromptRequestParamsSchema, + GetPromptRequestSchema, + GetPromptResultSchema, + GetTaskPayloadRequestSchema, + GetTaskPayloadResultSchema, + GetTaskRequestSchema, + GetTaskResultSchema, + IconSchema, + IconsSchema, + ImageContentSchema, + ImplementationSchema, + InitializedNotificationSchema, + InitializeRequestParamsSchema, + InitializeRequestSchema, + InitializeResultSchema, + JSONArraySchema, + JSONObjectSchema, + JSONRPCErrorResponseSchema, + JSONRPCMessageSchema, + JSONRPCNotificationSchema, + JSONRPCRequestSchema, + JSONRPCResponseSchema, + JSONRPCResultResponseSchema, + JSONValueSchema, + LegacyTitledEnumSchemaSchema, + ListPromptsRequestSchema, + ListPromptsResultSchema, + ListResourcesRequestSchema, + ListResourcesResultSchema, + ListResourceTemplatesRequestSchema, + ListResourceTemplatesResultSchema, + ListRootsRequestSchema, + ListRootsResultSchema, + ListTasksRequestSchema, + ListTasksResultSchema, + ListToolsRequestSchema, + ListToolsResultSchema, + LoggingLevelSchema, + LoggingMessageNotificationParamsSchema, + LoggingMessageNotificationSchema, + ModelHintSchema, + ModelPreferencesSchema, + MultiSelectEnumSchemaSchema, + NotificationSchema, + NumberSchemaSchema, + PaginatedRequestParamsSchema, + PaginatedRequestSchema, + PaginatedResultSchema, + PingRequestSchema, + PrimitiveSchemaDefinitionSchema, + ProgressNotificationParamsSchema, + ProgressNotificationSchema, + ProgressSchema, + ProgressTokenSchema, + PromptArgumentSchema, + PromptListChangedNotificationSchema, + PromptMessageSchema, + PromptReferenceSchema, + PromptSchema, + ReadResourceRequestParamsSchema, + ReadResourceRequestSchema, + ReadResourceResultSchema, + RelatedTaskMetadataSchema, + RequestIdSchema, + RequestMetaSchema, + RequestSchema, + ResourceContentsSchema, + ResourceLinkSchema, + ResourceListChangedNotificationSchema, + ResourceRequestParamsSchema, + ResourceSchema, + ResourceTemplateReferenceSchema, + ResourceTemplateSchema, + ResourceUpdatedNotificationParamsSchema, + ResourceUpdatedNotificationSchema, + ResultSchema, + RoleSchema, + RootSchema, + RootsListChangedNotificationSchema, + SamplingContentSchema, + SamplingMessageContentBlockSchema, + SamplingMessageSchema, + ServerCapabilitiesSchema, + ServerNotificationSchema, + ServerRequestSchema, + ServerResultSchema, + SetLevelRequestParamsSchema, + SetLevelRequestSchema, + SingleSelectEnumSchemaSchema, + StringSchemaSchema, + SubscribeRequestParamsSchema, + SubscribeRequestSchema, + SubscriptionFilterSchema, + SubscriptionsAcknowledgedNotificationParamsSchema, + SubscriptionsAcknowledgedNotificationSchema, + SubscriptionsListenRequestParamsSchema, + SubscriptionsListenRequestSchema, + SubscriptionsListenResultMetaSchema, + SubscriptionsListenResultSchema, + TaskAugmentedRequestParamsSchema, + TaskCreationParamsSchema, + TaskMetadataSchema, + TaskSchema, + TaskStatusNotificationParamsSchema, + TaskStatusNotificationSchema, + TaskStatusSchema, + TextContentSchema, + TextResourceContentsSchema, + TitledMultiSelectEnumSchemaSchema, + TitledSingleSelectEnumSchemaSchema, + ToolAnnotationsSchema, + ToolChoiceSchema, + ToolExecutionSchema, + ToolListChangedNotificationSchema, + ToolResultContentSchema, + ToolSchema, + ToolUseContentSchema, + UnsubscribeRequestParamsSchema, + UnsubscribeRequestSchema, + UntitledMultiSelectEnumSchemaSchema, + UntitledSingleSelectEnumSchemaSchema +} from '@modelcontextprotocol/core-internal/schemas'; -// Validator providers are type-only here — import the runtime classes from the explicit -// `@modelcontextprotocol/{core,client,server}/validators/{ajv,cf-worker}` subpaths to customise. -export type { AjvJsonSchemaValidator } from './validators/ajvProvider.js'; -export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from './validators/cfWorkerProvider.js'; -export * from './validators/fromJsonSchema.js'; -export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './validators/types.js'; +// Auth schemas (OAuth / OpenID / IdJag) — kept as a SEPARATE group from the MCP spec schemas above, +// mirroring core-internal's own spec-vs-auth split (these live in core-internal/src/shared/auth.ts, not types/schemas.ts, +// and are registered as `authSchemas` in core-internal's specTypeSchema.ts). This group is EXACTLY core-internal's +// `authSchemas` set — every auth schema that has a public spec type (so `isSpecType.OAuthTokens`, +// `isSpecType.IdJagTokenExchangeResponse`, etc. exist). The typeless internal URL field-validators +// (SafeUrlSchema, OptionalSafeUrlSchema) are not auth schemas and stay out. The coreSchemas test +// asserts this group stays in sync with core-internal's `authSchemas`. +export { + IdJagTokenExchangeResponseSchema, + OAuthClientInformationFullSchema, + OAuthClientInformationSchema, + OAuthClientMetadataSchema, + OAuthClientRegistrationErrorSchema, + OAuthErrorResponseSchema, + OAuthMetadataSchema, + OAuthProtectedResourceMetadataSchema, + OAuthTokenRevocationRequestSchema, + OAuthTokensSchema, + OpenIdProviderDiscoveryMetadataSchema, + OpenIdProviderMetadataSchema +} from '@modelcontextprotocol/core-internal/auth'; diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts deleted file mode 100644 index c150aea737..0000000000 --- a/packages/core/src/types/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Internal barrel — re-exports everything for use within the SDK packages. -// The public API is defined in @modelcontextprotocol/core/public (see exports/public/index.ts). -export * from './constants.js'; -export * from './enums.js'; -export * from './errors.js'; -export * from './guards.js'; -export * from './schemas.js'; -export * from './specTypeSchema.js'; -export * from './types.js'; diff --git a/packages/core/test/coreSchemas.test.ts b/packages/core/test/coreSchemas.test.ts new file mode 100644 index 0000000000..85a0e08a09 --- /dev/null +++ b/packages/core/test/coreSchemas.test.ts @@ -0,0 +1,61 @@ +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +import * as core from '../src/index'; +import { CursorSchema, InitializeRequestSchema, OAuthTokensSchema } from '../src/index'; + +function readCore(relativePath: string): string { + return readFileSync(fileURLToPath(new URL(relativePath, import.meta.url)), 'utf8'); +} + +function exportedSchemaConsts(src: string, re: RegExp): string[] { + return [...src.matchAll(re)].map(m => m[1]).filter((name): name is string => name !== undefined && /^[A-Z]/.test(name)); +} + +describe('@modelcontextprotocol/core', () => { + it('re-exports spec + OAuth schemas as working Zod objects', () => { + // Round-trips valid/invalid values — proves the re-exports are real Zod schemas (not type-only + // aliases) and that `.parse`/`.safeParse` work, for both the spec and the OAuth group. + expect(CursorSchema.parse('abc')).toBe('abc'); + expect(InitializeRequestSchema.safeParse({}).success).toBe(false); + expect(OAuthTokensSchema.safeParse({}).success).toBe(false); + expect(OAuthTokensSchema.safeParse({ access_token: 'tok', token_type: 'Bearer' }).success).toBe(true); + }); + + it('re-exports exactly core’s spec + OAuth schemas — no internal helpers (drift guard)', () => { + // core's public surface is two SEPARATE groups, mirroring core-internal's own spec-vs-auth split: + // 1. spec `*Schema` constants from core-internal/src/types/schemas.ts (minus internal helpers with no + // public spec type — they must NOT leak), mirroring core-internal's SPEC_SCHEMA_KEYS allowlist; and + // 2. the auth `*Schema` constants registered in core-internal's `authSchemas` object (specTypeSchema.ts) + // — i.e. the auth schemas that have a public spec type. Reading that object directly (not a + // name prefix) is the source of truth, so a new auth schema added to core-internal is required here + // automatically; typeless internal helpers (SafeUrlSchema, OptionalSafeUrlSchema) stay out + // because they are not in `authSchemas`. + // Read the core-internal sources directly so the groups cannot silently drift. + const SPEC_INTERNAL_HELPERS = [ + 'BaseRequestParamsSchema', + 'ClientTasksCapabilitySchema', + 'ListChangedOptionsBaseSchema', + 'NotificationsParamsSchema', + 'ServerTasksCapabilitySchema' + ]; + const specSchemas = exportedSchemaConsts( + readCore('../../core-internal/src/types/schemas.ts'), + /^export const (\w+Schema)\b/gm + ).filter(name => !SPEC_INTERNAL_HELPERS.includes(name)); + const specTypeSrc = readCore('../../core-internal/src/types/specTypeSchema.ts'); + const authStart = specTypeSrc.indexOf('const authSchemas = {'); + const authObj = specTypeSrc.slice(authStart, specTypeSrc.indexOf('} as const', authStart)); + const authSchemas = exportedSchemaConsts(authObj, /\b(\w+Schema)\b/g); + + const expected = [...specSchemas, ...authSchemas].sort(); + const exported = Object.keys(core).sort(); + // Exact match, both directions: a new core spec/auth schema missing here fails (we forgot to + // re-export it), and any internal helper / non-spec symbol that leaks here also fails. + expect(exported).toEqual(expected); + expect(specSchemas.length).toBeGreaterThanOrEqual(154); + expect(authSchemas.length).toBe(12); + }); +}); diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index a6838303e4..e150389b59 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -5,8 +5,8 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/eslint-config": ["./node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], - "@modelcontextprotocol/vitest-config": ["./node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + "@modelcontextprotocol/core-internal/schemas": ["./node_modules/@modelcontextprotocol/core-internal/src/types/schemas.ts"], + "@modelcontextprotocol/core-internal/auth": ["./node_modules/@modelcontextprotocol/core-internal/src/shared/auth.ts"] } } } diff --git a/packages/core/tsdown.config.ts b/packages/core/tsdown.config.ts new file mode 100644 index 0000000000..464ae98615 --- /dev/null +++ b/packages/core/tsdown.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'tsdown'; + +// core re-exports ONLY the spec + OAuth Zod schemas from @modelcontextprotocol/core-internal (private, +// unpublished). Two BUILD-ONLY subpath aliases (not real core exports) point at core-internal's two schema +// modules, kept as separate sources: +// @modelcontextprotocol/core-internal/schemas → core-internal/src/types/schemas.ts (MCP spec schemas) +// @modelcontextprotocol/core-internal/auth → core-internal/src/shared/auth.ts (OAuth/OpenID schemas) +// Aliasing to these modules rather than core-internal's barrel keeps the bundled graph to just the schemas + +// the constants they use — never Protocol, transports, stdio, or the ajv/cfWorker validators. Both +// modules import only `zod/v4`, so the graph stays runtime-neutral; `platform: 'neutral'` makes a +// node-only dependency leaking in fail the build here instead of silently shipping. +export default defineConfig({ + failOnWarn: 'ci-only', + entry: ['src/index.ts'], + format: ['esm'], + outDir: 'dist', + clean: true, + sourcemap: true, + target: 'esnext', + platform: 'neutral', + dts: { + resolver: 'tsc', + compilerOptions: { + baseUrl: '.', + paths: { + '@modelcontextprotocol/core-internal/schemas': ['../core-internal/src/types/schemas.ts'], + '@modelcontextprotocol/core-internal/auth': ['../core-internal/src/shared/auth.ts'] + } + } + }, + noExternal: ['@modelcontextprotocol/core-internal/schemas', '@modelcontextprotocol/core-internal/auth'] +}); diff --git a/packages/core/typedoc.json b/packages/core/typedoc.json new file mode 100644 index 0000000000..08e5572417 --- /dev/null +++ b/packages/core/typedoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["src/index.ts"] +} diff --git a/packages/middleware/express/CHANGELOG.md b/packages/middleware/express/CHANGELOG.md index fb0fe43371..f3a3cd93bd 100644 --- a/packages/middleware/express/CHANGELOG.md +++ b/packages/middleware/express/CHANGELOG.md @@ -1,5 +1,31 @@ # @modelcontextprotocol/express +## 2.0.0-alpha.3 + +### Minor Changes + +- [#1907](https://github.com/modelcontextprotocol/typescript-sdk/pull/1907) [`7cccc2a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/7cccc2aca81f4cd961d2a0ef53e879f68a01df73) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add OAuth + Resource-Server glue to the Express adapter: `requireBearerAuth` middleware (token verification + RFC 6750 `WWW-Authenticate` challenges), `mcpAuthMetadataRouter` (serves RFC 9728 Protected Resource Metadata and mirrors RFC 8414 AS metadata at the resource origin), the + `getOAuthProtectedResourceMetadataUrl` helper, and the `OAuthTokenVerifier` interface. These restore the v1 `src/server/auth` Resource-Server pieces as first-class v2 API so MCP servers can plug into an external Authorization Server with a few lines of Express wiring. + +### Patch Changes + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- Updated dependencies [[`e8c7180`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e8c7180109b417eef5cc22b7e9d821ab1c119a69), [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4), + [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d), [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790), + [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9), [`c59dc3a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c59dc3aa1a633d27fbbe873f1a430483cf7440f8), + [`df4b6cc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/df4b6cc88d6f24fc857519cf506a7a039f532637), [`2c0c481`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2c0c481cb9dbfd15c8613f765c940a5f5bace94d), + [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1), [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52), + [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab), [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f), + [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd), [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6), + [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9), [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784), + [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1), [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2), + [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9), [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5)]: + - @modelcontextprotocol/server@2.0.0-alpha.3 + ## 2.0.0-alpha.2 ### Patch Changes diff --git a/packages/middleware/express/eslint.config.mjs b/packages/middleware/express/eslint.config.mjs index 03d5331344..2284c163a1 100644 --- a/packages/middleware/express/eslint.config.mjs +++ b/packages/middleware/express/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/(server|core)' + 'import/internal-regex': '^@modelcontextprotocol/server' } } ]; diff --git a/packages/middleware/express/package.json b/packages/middleware/express/package.json index b0b695344e..8b675f789b 100644 --- a/packages/middleware/express/package.json +++ b/packages/middleware/express/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/express", "private": false, - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Express adapters for the Model Context Protocol TypeScript server SDK - Express middleware", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/packages/middleware/express/src/auth/bearerAuth.ts b/packages/middleware/express/src/auth/bearerAuth.ts index 5f46be792e..b2230e0bb6 100644 --- a/packages/middleware/express/src/auth/bearerAuth.ts +++ b/packages/middleware/express/src/auth/bearerAuth.ts @@ -1,7 +1,7 @@ import { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/server'; import type { RequestHandler } from 'express'; -import type { OAuthTokenVerifier } from './types.js'; +import type { OAuthTokenVerifier } from './types'; /** * Options for {@link requireBearerAuth}. diff --git a/packages/middleware/express/src/express.examples.ts b/packages/middleware/express/src/express.examples.ts index 8d3f8e2ffc..42daa70064 100644 --- a/packages/middleware/express/src/express.examples.ts +++ b/packages/middleware/express/src/express.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { createMcpExpressApp } from './express.js'; +import { createMcpExpressApp } from './express'; /** * Example: Basic usage with default DNS rebinding protection. diff --git a/packages/middleware/express/src/express.ts b/packages/middleware/express/src/express.ts index 70d3881d0b..dd930f5713 100644 --- a/packages/middleware/express/src/express.ts +++ b/packages/middleware/express/src/express.ts @@ -1,8 +1,8 @@ import type { Express } from 'express'; import express from 'express'; -import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js'; -import { localhostOriginValidation, originValidation } from './middleware/originValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation'; +import { localhostOriginValidation, originValidation } from './middleware/originValidation'; /** * Options for creating an MCP Express application. diff --git a/packages/middleware/express/src/index.ts b/packages/middleware/express/src/index.ts index 941354d4ab..dd0c2ed617 100644 --- a/packages/middleware/express/src/index.ts +++ b/packages/middleware/express/src/index.ts @@ -1,10 +1,10 @@ -export * from './express.js'; -export * from './middleware/hostHeaderValidation.js'; -export * from './middleware/originValidation.js'; +export * from './express'; +export * from './middleware/hostHeaderValidation'; +export * from './middleware/originValidation'; // OAuth Resource-Server glue: bearer-token middleware + PRM/AS metadata router. -export type { BearerAuthMiddlewareOptions } from './auth/bearerAuth.js'; -export { requireBearerAuth } from './auth/bearerAuth.js'; -export type { AuthMetadataOptions } from './auth/metadataRouter.js'; -export { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from './auth/metadataRouter.js'; -export type { OAuthTokenVerifier } from './auth/types.js'; +export type { BearerAuthMiddlewareOptions } from './auth/bearerAuth'; +export { requireBearerAuth } from './auth/bearerAuth'; +export type { AuthMetadataOptions } from './auth/metadataRouter'; +export { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from './auth/metadataRouter'; +export type { OAuthTokenVerifier } from './auth/types'; diff --git a/packages/middleware/express/src/middleware/hostHeaderValidation.examples.ts b/packages/middleware/express/src/middleware/hostHeaderValidation.examples.ts index 2e00f48b65..0e0ca43549 100644 --- a/packages/middleware/express/src/middleware/hostHeaderValidation.examples.ts +++ b/packages/middleware/express/src/middleware/hostHeaderValidation.examples.ts @@ -9,7 +9,7 @@ import type { Express } from 'express'; -import { hostHeaderValidation, localhostHostValidation } from './hostHeaderValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from './hostHeaderValidation'; /** * Example: Using hostHeaderValidation middleware with custom allowed hosts. diff --git a/packages/middleware/express/test/auth/resourceServer.test.ts b/packages/middleware/express/test/auth/resourceServer.test.ts index e9ab4b617c..1214556e5e 100644 --- a/packages/middleware/express/test/auth/resourceServer.test.ts +++ b/packages/middleware/express/test/auth/resourceServer.test.ts @@ -6,9 +6,9 @@ import supertest from 'supertest'; import type { Mock } from 'vitest'; import { vi } from 'vitest'; -import type { OAuthTokenVerifier } from '../../src/auth/types.js'; -import { requireBearerAuth } from '../../src/auth/bearerAuth.js'; -import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from '../../src/auth/metadataRouter.js'; +import type { OAuthTokenVerifier } from '../../src/auth/types'; +import { requireBearerAuth } from '../../src/auth/bearerAuth'; +import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from '../../src/auth/metadataRouter'; // --------------------------------------------------------------------------- // requireBearerAuth diff --git a/packages/middleware/express/test/express.test.ts b/packages/middleware/express/test/express.test.ts index f4be9f998f..8f44ce0ee3 100644 --- a/packages/middleware/express/test/express.test.ts +++ b/packages/middleware/express/test/express.test.ts @@ -1,8 +1,8 @@ import type { NextFunction, Request, Response } from 'express'; import { vi } from 'vitest'; -import { createMcpExpressApp } from '../src/express.js'; -import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation.js'; +import { createMcpExpressApp } from '../src/express'; +import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation'; // Helper to create mock Express request/response/next function createMockReqResNext(host?: string) { diff --git a/packages/middleware/express/test/originValidation.test.ts b/packages/middleware/express/test/originValidation.test.ts index 5184adf0aa..cfcbaba806 100644 --- a/packages/middleware/express/test/originValidation.test.ts +++ b/packages/middleware/express/test/originValidation.test.ts @@ -2,8 +2,8 @@ import type { NextFunction, Request, Response } from 'express'; import supertest from 'supertest'; import { vi } from 'vitest'; -import { createMcpExpressApp } from '../src/express.js'; -import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation.js'; +import { createMcpExpressApp } from '../src/express'; +import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation'; // Helper to create mock Express request/response/next function createMockReqResNext(origin?: string) { diff --git a/packages/middleware/express/tsconfig.json b/packages/middleware/express/tsconfig.json index 0292cb0c22..11330e7a4a 100644 --- a/packages/middleware/express/tsconfig.json +++ b/packages/middleware/express/tsconfig.json @@ -7,11 +7,11 @@ "*": ["./*"], "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ] } } diff --git a/packages/middleware/fastify/CHANGELOG.md b/packages/middleware/fastify/CHANGELOG.md index 94d0a35749..1661e5b9d3 100644 --- a/packages/middleware/fastify/CHANGELOG.md +++ b/packages/middleware/fastify/CHANGELOG.md @@ -1,5 +1,25 @@ # @modelcontextprotocol/fastify +## 2.0.0-alpha.3 + +### Patch Changes + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- Updated dependencies [[`e8c7180`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e8c7180109b417eef5cc22b7e9d821ab1c119a69), [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4), + [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d), [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790), + [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9), [`c59dc3a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c59dc3aa1a633d27fbbe873f1a430483cf7440f8), + [`df4b6cc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/df4b6cc88d6f24fc857519cf506a7a039f532637), [`2c0c481`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2c0c481cb9dbfd15c8613f765c940a5f5bace94d), + [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1), [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52), + [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab), [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f), + [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd), [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6), + [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9), [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784), + [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1), [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2), + [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9), [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5)]: + - @modelcontextprotocol/server@2.0.0-alpha.3 + ## 2.0.0-alpha.2 ### Patch Changes diff --git a/packages/middleware/fastify/eslint.config.mjs b/packages/middleware/fastify/eslint.config.mjs index 03d5331344..2284c163a1 100644 --- a/packages/middleware/fastify/eslint.config.mjs +++ b/packages/middleware/fastify/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/(server|core)' + 'import/internal-regex': '^@modelcontextprotocol/server' } } ]; diff --git a/packages/middleware/fastify/package.json b/packages/middleware/fastify/package.json index de6df8f3bc..7afe78cc30 100644 --- a/packages/middleware/fastify/package.json +++ b/packages/middleware/fastify/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/fastify", "private": false, - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Fastify adapters for the Model Context Protocol TypeScript server SDK - Fastify middleware", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/packages/middleware/fastify/src/fastify.examples.ts b/packages/middleware/fastify/src/fastify.examples.ts index 36353ced7c..f3bd0318e8 100644 --- a/packages/middleware/fastify/src/fastify.examples.ts +++ b/packages/middleware/fastify/src/fastify.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { createMcpFastifyApp } from './fastify.js'; +import { createMcpFastifyApp } from './fastify'; /** * Example: Basic usage with default DNS rebinding protection. diff --git a/packages/middleware/fastify/src/fastify.ts b/packages/middleware/fastify/src/fastify.ts index cb5877c9a6..b010188250 100644 --- a/packages/middleware/fastify/src/fastify.ts +++ b/packages/middleware/fastify/src/fastify.ts @@ -1,8 +1,8 @@ import type { FastifyInstance } from 'fastify'; import Fastify from 'fastify'; -import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js'; -import { localhostOriginValidation, originValidation } from './middleware/originValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation'; +import { localhostOriginValidation, originValidation } from './middleware/originValidation'; /** * Options for creating an MCP Fastify application. diff --git a/packages/middleware/fastify/src/index.ts b/packages/middleware/fastify/src/index.ts index 61748e59a1..e4712af442 100644 --- a/packages/middleware/fastify/src/index.ts +++ b/packages/middleware/fastify/src/index.ts @@ -1,3 +1,3 @@ -export * from './fastify.js'; -export * from './middleware/hostHeaderValidation.js'; -export * from './middleware/originValidation.js'; +export * from './fastify'; +export * from './middleware/hostHeaderValidation'; +export * from './middleware/originValidation'; diff --git a/packages/middleware/fastify/src/middleware/hostHeaderValidation.examples.ts b/packages/middleware/fastify/src/middleware/hostHeaderValidation.examples.ts index cbf6645840..c1d35a77d8 100644 --- a/packages/middleware/fastify/src/middleware/hostHeaderValidation.examples.ts +++ b/packages/middleware/fastify/src/middleware/hostHeaderValidation.examples.ts @@ -9,7 +9,7 @@ import type { FastifyInstance } from 'fastify'; -import { hostHeaderValidation, localhostHostValidation } from './hostHeaderValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from './hostHeaderValidation'; /** * Example: Using hostHeaderValidation hook with custom allowed hosts. diff --git a/packages/middleware/fastify/test/fastify.test.ts b/packages/middleware/fastify/test/fastify.test.ts index a64e920934..d4a007bc3d 100644 --- a/packages/middleware/fastify/test/fastify.test.ts +++ b/packages/middleware/fastify/test/fastify.test.ts @@ -1,7 +1,7 @@ import Fastify from 'fastify'; -import { createMcpFastifyApp } from '../src/fastify.js'; -import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation.js'; +import { createMcpFastifyApp } from '../src/fastify'; +import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation'; describe('@modelcontextprotocol/fastify', () => { describe('hostHeaderValidation', () => { diff --git a/packages/middleware/fastify/test/originValidation.test.ts b/packages/middleware/fastify/test/originValidation.test.ts index 14dfc42beb..f18fe247b3 100644 --- a/packages/middleware/fastify/test/originValidation.test.ts +++ b/packages/middleware/fastify/test/originValidation.test.ts @@ -1,7 +1,7 @@ import Fastify from 'fastify'; -import { createMcpFastifyApp } from '../src/fastify.js'; -import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation.js'; +import { createMcpFastifyApp } from '../src/fastify'; +import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation'; describe('@modelcontextprotocol/fastify origin validation', () => { describe('originValidation', () => { diff --git a/packages/middleware/fastify/tsconfig.json b/packages/middleware/fastify/tsconfig.json index c92435851b..62f257e788 100644 --- a/packages/middleware/fastify/tsconfig.json +++ b/packages/middleware/fastify/tsconfig.json @@ -7,8 +7,8 @@ "*": ["./*"], "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ] } } diff --git a/packages/middleware/hono/CHANGELOG.md b/packages/middleware/hono/CHANGELOG.md index 7a9b246747..a621810ffb 100644 --- a/packages/middleware/hono/CHANGELOG.md +++ b/packages/middleware/hono/CHANGELOG.md @@ -1,5 +1,25 @@ # @modelcontextprotocol/hono +## 2.0.0-alpha.3 + +### Patch Changes + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- Updated dependencies [[`e8c7180`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e8c7180109b417eef5cc22b7e9d821ab1c119a69), [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4), + [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d), [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790), + [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9), [`c59dc3a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c59dc3aa1a633d27fbbe873f1a430483cf7440f8), + [`df4b6cc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/df4b6cc88d6f24fc857519cf506a7a039f532637), [`2c0c481`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2c0c481cb9dbfd15c8613f765c940a5f5bace94d), + [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1), [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52), + [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab), [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f), + [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd), [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6), + [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9), [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784), + [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1), [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2), + [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9), [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5)]: + - @modelcontextprotocol/server@2.0.0-alpha.3 + ## 2.0.0-alpha.2 ### Patch Changes diff --git a/packages/middleware/hono/eslint.config.mjs b/packages/middleware/hono/eslint.config.mjs index 03d5331344..2284c163a1 100644 --- a/packages/middleware/hono/eslint.config.mjs +++ b/packages/middleware/hono/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/(server|core)' + 'import/internal-regex': '^@modelcontextprotocol/server' } } ]; diff --git a/packages/middleware/hono/package.json b/packages/middleware/hono/package.json index f067aedf91..79b2d02de1 100644 --- a/packages/middleware/hono/package.json +++ b/packages/middleware/hono/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/hono", "private": false, - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Hono adapters for the Model Context Protocol TypeScript server SDK - Hono middleware", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/packages/middleware/hono/src/hono.ts b/packages/middleware/hono/src/hono.ts index 7d5405ce99..80237f7d4e 100644 --- a/packages/middleware/hono/src/hono.ts +++ b/packages/middleware/hono/src/hono.ts @@ -1,8 +1,8 @@ import type { Context } from 'hono'; import { Hono } from 'hono'; -import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js'; -import { localhostOriginValidation, originValidation } from './middleware/originValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation'; +import { localhostOriginValidation, originValidation } from './middleware/originValidation'; /** * Options for creating an MCP Hono application. diff --git a/packages/middleware/hono/src/index.ts b/packages/middleware/hono/src/index.ts index 177b54d5b3..201c8b7339 100644 --- a/packages/middleware/hono/src/index.ts +++ b/packages/middleware/hono/src/index.ts @@ -1,3 +1,3 @@ -export * from './hono.js'; -export * from './middleware/hostHeaderValidation.js'; -export * from './middleware/originValidation.js'; +export * from './hono'; +export * from './middleware/hostHeaderValidation'; +export * from './middleware/originValidation'; diff --git a/packages/middleware/hono/test/hono.test.ts b/packages/middleware/hono/test/hono.test.ts index a080f1ffb1..1c743277b0 100644 --- a/packages/middleware/hono/test/hono.test.ts +++ b/packages/middleware/hono/test/hono.test.ts @@ -2,8 +2,8 @@ import type { Context } from 'hono'; import { Hono } from 'hono'; import { vi } from 'vitest'; -import { createMcpHonoApp } from '../src/hono.js'; -import { hostHeaderValidation } from '../src/middleware/hostHeaderValidation.js'; +import { createMcpHonoApp } from '../src/hono'; +import { hostHeaderValidation } from '../src/middleware/hostHeaderValidation'; describe('@modelcontextprotocol/hono', () => { test('hostHeaderValidation blocks invalid Host and allows valid Host', async () => { diff --git a/packages/middleware/hono/test/originValidation.test.ts b/packages/middleware/hono/test/originValidation.test.ts index c395921d39..eb85cec1b2 100644 --- a/packages/middleware/hono/test/originValidation.test.ts +++ b/packages/middleware/hono/test/originValidation.test.ts @@ -1,8 +1,8 @@ import { Hono } from 'hono'; import { vi } from 'vitest'; -import { createMcpHonoApp } from '../src/hono.js'; -import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation.js'; +import { createMcpHonoApp } from '../src/hono'; +import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation'; describe('@modelcontextprotocol/hono origin validation', () => { test('originValidation blocks a disallowed Origin and allows an allowed Origin', async () => { diff --git a/packages/middleware/hono/tsconfig.json b/packages/middleware/hono/tsconfig.json index 0292cb0c22..11330e7a4a 100644 --- a/packages/middleware/hono/tsconfig.json +++ b/packages/middleware/hono/tsconfig.json @@ -7,11 +7,11 @@ "*": ["./*"], "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], - "@modelcontextprotocol/core": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts" + "@modelcontextprotocol/core-internal": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/index.ts" ], - "@modelcontextprotocol/core/public": [ - "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/exports/public/index.ts" + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" ] } } diff --git a/packages/middleware/node/CHANGELOG.md b/packages/middleware/node/CHANGELOG.md index 242614d4a3..b40fabe1c0 100644 --- a/packages/middleware/node/CHANGELOG.md +++ b/packages/middleware/node/CHANGELOG.md @@ -1,5 +1,29 @@ # @modelcontextprotocol/node +## 2.0.0-alpha.3 + +### Patch Changes + +- [#1896](https://github.com/modelcontextprotocol/typescript-sdk/pull/1896) [`5433f40`](https://github.com/modelcontextprotocol/typescript-sdk/commit/5433f405972ab943c4d68b0eacf6d79baf132824) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Mark `hono` peer + dependency as optional. `@modelcontextprotocol/node` only uses `getRequestListener` from `@hono/node-server` (Node HTTP ↔ Web Standard conversion), which does not require the `hono` framework at runtime. Consumers no longer need to install `hono` to use + `NodeStreamableHTTPServerTransport`. Note: `@hono/node-server` itself still declares `hono` as a hard peer, so package managers may emit a warning; this is upstream and harmless for `getRequestListener`-only usage. + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- Updated dependencies [[`e8c7180`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e8c7180109b417eef5cc22b7e9d821ab1c119a69), [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4), + [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d), [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790), + [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9), [`c59dc3a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c59dc3aa1a633d27fbbe873f1a430483cf7440f8), + [`df4b6cc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/df4b6cc88d6f24fc857519cf506a7a039f532637), [`2c0c481`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2c0c481cb9dbfd15c8613f765c940a5f5bace94d), + [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1), [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52), + [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab), [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f), + [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd), [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6), + [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9), [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784), + [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1), [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2), + [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9), [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5)]: + - @modelcontextprotocol/server@2.0.0-alpha.3 + ## 2.0.0-alpha.2 ### Patch Changes diff --git a/packages/middleware/node/eslint.config.mjs b/packages/middleware/node/eslint.config.mjs index 4f034f2235..dd9e88588a 100644 --- a/packages/middleware/node/eslint.config.mjs +++ b/packages/middleware/node/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/core' + 'import/internal-regex': '^@modelcontextprotocol/core-internal' } } ]; diff --git a/packages/middleware/node/package.json b/packages/middleware/node/package.json index 30fa7ed663..955f02eabe 100644 --- a/packages/middleware/node/package.json +++ b/packages/middleware/node/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/node", - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Model Context Protocol implementation for TypeScript - Node.js middleware", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -46,9 +46,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../../.prettierignore --write .", "check": "pnpm run typecheck && pnpm run lint", "test": "vitest run", - "test:watch": "vitest", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "test:watch": "vitest" }, "dependencies": { "@hono/node-server": "catalog:runtimeServerOnly" @@ -64,7 +62,7 @@ }, "devDependencies": { "@modelcontextprotocol/server": "workspace:^", - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/test-helpers": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", @@ -76,7 +74,6 @@ "eslint-plugin-n": "catalog:devTools", "prettier": "catalog:devTools", "tsdown": "catalog:devTools", - "tsx": "catalog:devTools", "typescript": "catalog:devTools", "typescript-eslint": "catalog:devTools", "vitest": "catalog:devTools" diff --git a/packages/middleware/node/src/index.ts b/packages/middleware/node/src/index.ts index 9cff39c82c..31cbc30c9e 100644 --- a/packages/middleware/node/src/index.ts +++ b/packages/middleware/node/src/index.ts @@ -1,11 +1,11 @@ -export * from './middleware/hostHeaderValidation.js'; -export * from './middleware/originValidation.js'; -export * from './streamableHttp.js'; +export * from './middleware/hostHeaderValidation'; +export * from './middleware/originValidation'; +export * from './streamableHttp'; export type { FetchLikeMcpHandler, NodeIncomingMessageLike, NodeMcpRequestHandler, NodeServerResponseLike, ToNodeHandlerOptions -} from './toNodeHandler.js'; -export { toNodeHandler } from './toNodeHandler.js'; +} from './toNodeHandler'; +export { toNodeHandler } from './toNodeHandler'; diff --git a/packages/middleware/node/src/streamableHttp.examples.ts b/packages/middleware/node/src/streamableHttp.examples.ts index fb4bef8417..4ac8778c92 100644 --- a/packages/middleware/node/src/streamableHttp.examples.ts +++ b/packages/middleware/node/src/streamableHttp.examples.ts @@ -12,7 +12,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http'; import { McpServer } from '@modelcontextprotocol/server'; -import { NodeStreamableHTTPServerTransport } from './streamableHttp.js'; +import { NodeStreamableHTTPServerTransport } from './streamableHttp'; /** * Example: Stateful Streamable HTTP transport (Node.js). diff --git a/packages/middleware/node/test/streamableHttp.test.ts b/packages/middleware/node/test/streamableHttp.test.ts index c427aa2eea..140717c6bb 100644 --- a/packages/middleware/node/test/streamableHttp.test.ts +++ b/packages/middleware/node/test/streamableHttp.test.ts @@ -11,14 +11,14 @@ import type { JSONRPCMessage, JSONRPCResultResponse, RequestId -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import type { EventId, EventStore, StreamId } from '@modelcontextprotocol/server'; import { McpServer } from '@modelcontextprotocol/server'; import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers'; import * as z from 'zod/v4'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { NodeStreamableHTTPServerTransport } from '../src/streamableHttp.js'; +import { NodeStreamableHTTPServerTransport } from '../src/streamableHttp'; async function getFreePort() { return new Promise(res => { diff --git a/packages/middleware/node/test/toNodeHandler.test.ts b/packages/middleware/node/test/toNodeHandler.test.ts index f80d96b2b8..3861f3afd2 100644 --- a/packages/middleware/node/test/toNodeHandler.test.ts +++ b/packages/middleware/node/test/toNodeHandler.test.ts @@ -10,14 +10,14 @@ */ import { Readable } from 'node:stream'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import type { McpRequestContext } from '@modelcontextprotocol/server'; import { createMcpHandler, McpServer } from '@modelcontextprotocol/server'; import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import type { NodeServerResponseLike } from '../src/toNodeHandler.js'; -import { toNodeHandler } from '../src/toNodeHandler.js'; +import type { NodeServerResponseLike } from '../src/toNodeHandler'; +import { toNodeHandler } from '../src/toNodeHandler'; const MODERN_REVISION = '2026-07-28'; diff --git a/packages/middleware/node/test/validation.test.ts b/packages/middleware/node/test/validation.test.ts index 01e98108e0..61273e76d5 100644 --- a/packages/middleware/node/test/validation.test.ts +++ b/packages/middleware/node/test/validation.test.ts @@ -2,8 +2,8 @@ import type { IncomingMessage, ServerResponse } from 'node:http'; import { vi } from 'vitest'; -import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation.js'; -import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation.js'; +import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation'; +import { localhostOriginValidation, originValidation } from '../src/middleware/originValidation'; function fakeReqRes(headers: Record) { const req = { headers } as unknown as IncomingMessage; diff --git a/packages/middleware/node/tsconfig.json b/packages/middleware/node/tsconfig.json index 0985895356..7cd442d0d4 100644 --- a/packages/middleware/node/tsconfig.json +++ b/packages/middleware/node/tsconfig.json @@ -7,8 +7,10 @@ "*": ["./*"], "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], "@modelcontextprotocol/test-helpers": ["./node_modules/@modelcontextprotocol/test-helpers/src/index.ts"] } } diff --git a/packages/middleware/node/tsdown.config.ts b/packages/middleware/node/tsdown.config.ts index f953bc65de..b6081802ff 100644 --- a/packages/middleware/node/tsdown.config.ts +++ b/packages/middleware/node/tsdown.config.ts @@ -28,7 +28,7 @@ export default defineConfig({ // consumers already have its types). `paths: {}` disables the dev source // mappings; `preserveSymlinks` keeps `node_modules` in the resolved path so // rolldown-plugin-dts recognises the dep as external instead of inlining the - // whole upstream type graph (which OOMs once core's surface gets large enough). + // whole upstream type graph (which OOMs once core-internal's surface gets large enough). // // TODO: drop this override once tsdown pulls rolldown-plugin-dts >=0.21.0 // (sxzz/rolldown-plugin-dts@03998d41 honours rolldown `external` before the diff --git a/packages/server-legacy/CHANGELOG.md b/packages/server-legacy/CHANGELOG.md new file mode 100644 index 0000000000..8a2be446a4 --- /dev/null +++ b/packages/server-legacy/CHANGELOG.md @@ -0,0 +1,8 @@ +# @modelcontextprotocol/server-legacy + +## 2.0.0-alpha.3 + +### Minor Changes + +- [#2206](https://github.com/modelcontextprotocol/typescript-sdk/pull/2206) [`e03bca9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e03bca90c1f925f80843dc27fb4eb2421408a0c1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add + @modelcontextprotocol/server-legacy package with frozen v1 SSE transport and OAuth Authorization Server helpers for migration from v1 to v2. diff --git a/packages/server-legacy/eslint.config.mjs b/packages/server-legacy/eslint.config.mjs index 4f034f2235..dd9e88588a 100644 --- a/packages/server-legacy/eslint.config.mjs +++ b/packages/server-legacy/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/core' + 'import/internal-regex': '^@modelcontextprotocol/core-internal' } } ]; diff --git a/packages/server-legacy/package.json b/packages/server-legacy/package.json index c320fe349d..6bf42d5155 100644 --- a/packages/server-legacy/package.json +++ b/packages/server-legacy/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/server-legacy", "private": false, - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Frozen v1 SSE transport and OAuth Authorization Server helpers for the Model Context Protocol TypeScript SDK. Deprecated; use StreamableHTTP and a dedicated OAuth server in production.", "deprecated": "This package is a frozen copy of v1's SSE transport and OAuth Authorization Server helpers for migration purposes only. Use StreamableHTTP from @modelcontextprotocol/server and a dedicated OAuth server in production. Will not receive new features.", "license": "MIT", @@ -80,7 +80,7 @@ } }, "devDependencies": { - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/vitest-config": "workspace:^", diff --git a/packages/server-legacy/src/auth/clients.ts b/packages/server-legacy/src/auth/clients.ts index f6aca1be92..0c9412ca18 100644 --- a/packages/server-legacy/src/auth/clients.ts +++ b/packages/server-legacy/src/auth/clients.ts @@ -1,4 +1,4 @@ -import type { OAuthClientInformationFull } from '@modelcontextprotocol/core'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/core-internal'; /** * Stores information about registered OAuth clients for this server. diff --git a/packages/server-legacy/src/auth/errors.ts b/packages/server-legacy/src/auth/errors.ts index eac277779c..236ed22d1b 100644 --- a/packages/server-legacy/src/auth/errors.ts +++ b/packages/server-legacy/src/auth/errors.ts @@ -1,4 +1,4 @@ -import type { OAuthErrorResponse } from '@modelcontextprotocol/core'; +import type { OAuthErrorResponse } from '@modelcontextprotocol/core-internal'; /** * Base class for all OAuth errors diff --git a/packages/server-legacy/src/auth/handlers/authorize.ts b/packages/server-legacy/src/auth/handlers/authorize.ts index adbfbfa053..d9c1508710 100644 --- a/packages/server-legacy/src/auth/handlers/authorize.ts +++ b/packages/server-legacy/src/auth/handlers/authorize.ts @@ -4,10 +4,10 @@ import type { Options as RateLimitOptions } from 'express-rate-limit'; import { rateLimit } from 'express-rate-limit'; import * as z from 'zod/v4'; -import { InvalidClientError, InvalidRequestError, OAuthError, ServerError, TooManyRequestsError } from '../errors.js'; -import { allowedMethods } from '../middleware/allowedMethods.js'; +import { InvalidClientError, InvalidRequestError, OAuthError, ServerError, TooManyRequestsError } from '../errors'; +import { allowedMethods } from '../middleware/allowedMethods'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -- AuthorizationParams referenced in JSDoc {@linkcode} -import type { AuthorizationParams, OAuthServerProvider } from '../provider.js'; +import type { AuthorizationParams, OAuthServerProvider } from '../provider'; export type AuthorizationHandlerOptions = { provider: OAuthServerProvider; diff --git a/packages/server-legacy/src/auth/handlers/metadata.ts b/packages/server-legacy/src/auth/handlers/metadata.ts index 529a6e57a8..e75b493320 100644 --- a/packages/server-legacy/src/auth/handlers/metadata.ts +++ b/packages/server-legacy/src/auth/handlers/metadata.ts @@ -1,9 +1,9 @@ -import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/core'; +import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/core-internal'; import cors from 'cors'; import type { RequestHandler } from 'express'; import express from 'express'; -import { allowedMethods } from '../middleware/allowedMethods.js'; +import { allowedMethods } from '../middleware/allowedMethods'; export function metadataHandler(metadata: OAuthMetadata | OAuthProtectedResourceMetadata): RequestHandler { // Nested router so we can configure middleware and restrict HTTP method diff --git a/packages/server-legacy/src/auth/handlers/register.ts b/packages/server-legacy/src/auth/handlers/register.ts index 6ca5324ebb..d180ff35f7 100644 --- a/packages/server-legacy/src/auth/handlers/register.ts +++ b/packages/server-legacy/src/auth/handlers/register.ts @@ -1,16 +1,16 @@ import crypto from 'node:crypto'; -import type { OAuthClientInformationFull } from '@modelcontextprotocol/core'; -import { OAuthClientMetadataSchema } from '@modelcontextprotocol/core'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/core-internal'; +import { OAuthClientMetadataSchema } from '@modelcontextprotocol/core-internal'; import cors from 'cors'; import type { RequestHandler } from 'express'; import express from 'express'; import type { Options as RateLimitOptions } from 'express-rate-limit'; import { rateLimit } from 'express-rate-limit'; -import type { OAuthRegisteredClientsStore } from '../clients.js'; -import { InvalidClientMetadataError, OAuthError, ServerError, TooManyRequestsError } from '../errors.js'; -import { allowedMethods } from '../middleware/allowedMethods.js'; +import type { OAuthRegisteredClientsStore } from '../clients'; +import { InvalidClientMetadataError, OAuthError, ServerError, TooManyRequestsError } from '../errors'; +import { allowedMethods } from '../middleware/allowedMethods'; export type ClientRegistrationHandlerOptions = { /** diff --git a/packages/server-legacy/src/auth/handlers/revoke.ts b/packages/server-legacy/src/auth/handlers/revoke.ts index 2a34a4449c..218d89beba 100644 --- a/packages/server-legacy/src/auth/handlers/revoke.ts +++ b/packages/server-legacy/src/auth/handlers/revoke.ts @@ -1,14 +1,14 @@ -import { OAuthTokenRevocationRequestSchema } from '@modelcontextprotocol/core'; +import { OAuthTokenRevocationRequestSchema } from '@modelcontextprotocol/core-internal'; import cors from 'cors'; import type { RequestHandler } from 'express'; import express from 'express'; import type { Options as RateLimitOptions } from 'express-rate-limit'; import { rateLimit } from 'express-rate-limit'; -import { InvalidRequestError, OAuthError, ServerError, TooManyRequestsError } from '../errors.js'; -import { allowedMethods } from '../middleware/allowedMethods.js'; -import { authenticateClient } from '../middleware/clientAuth.js'; -import type { OAuthServerProvider } from '../provider.js'; +import { InvalidRequestError, OAuthError, ServerError, TooManyRequestsError } from '../errors'; +import { allowedMethods } from '../middleware/allowedMethods'; +import { authenticateClient } from '../middleware/clientAuth'; +import type { OAuthServerProvider } from '../provider'; export type RevocationHandlerOptions = { provider: OAuthServerProvider; diff --git a/packages/server-legacy/src/auth/handlers/token.ts b/packages/server-legacy/src/auth/handlers/token.ts index 8a7683ab5d..e2552673d9 100644 --- a/packages/server-legacy/src/auth/handlers/token.ts +++ b/packages/server-legacy/src/auth/handlers/token.ts @@ -13,10 +13,10 @@ import { ServerError, TooManyRequestsError, UnsupportedGrantTypeError -} from '../errors.js'; -import { allowedMethods } from '../middleware/allowedMethods.js'; -import { authenticateClient } from '../middleware/clientAuth.js'; -import type { OAuthServerProvider } from '../provider.js'; +} from '../errors'; +import { allowedMethods } from '../middleware/allowedMethods'; +import { authenticateClient } from '../middleware/clientAuth'; +import type { OAuthServerProvider } from '../provider'; export type TokenHandlerOptions = { provider: OAuthServerProvider; diff --git a/packages/server-legacy/src/auth/index.ts b/packages/server-legacy/src/auth/index.ts index e864576096..5f9319364a 100644 --- a/packages/server-legacy/src/auth/index.ts +++ b/packages/server-legacy/src/auth/index.ts @@ -1,37 +1,37 @@ // Core router -export type { AuthMetadataOptions, AuthRouterOptions } from './router.js'; -export { createOAuthMetadata, getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, mcpAuthRouter } from './router.js'; +export type { AuthMetadataOptions, AuthRouterOptions } from './router'; +export { createOAuthMetadata, getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, mcpAuthRouter } from './router'; // Provider interfaces -export type { AuthorizationParams, OAuthServerProvider, OAuthTokenVerifier } from './provider.js'; +export type { AuthorizationParams, OAuthServerProvider, OAuthTokenVerifier } from './provider'; // Proxy provider -export type { ProxyEndpoints, ProxyOptions } from './providers/proxyProvider.js'; -export { ProxyOAuthServerProvider } from './providers/proxyProvider.js'; +export type { ProxyEndpoints, ProxyOptions } from './providers/proxyProvider'; +export { ProxyOAuthServerProvider } from './providers/proxyProvider'; // Client store -export type { OAuthRegisteredClientsStore } from './clients.js'; +export type { OAuthRegisteredClientsStore } from './clients'; // Handlers -export type { AuthorizationHandlerOptions } from './handlers/authorize.js'; -export { authorizationHandler, redirectUriMatches } from './handlers/authorize.js'; -export { metadataHandler } from './handlers/metadata.js'; -export type { ClientRegistrationHandlerOptions } from './handlers/register.js'; -export { clientRegistrationHandler } from './handlers/register.js'; -export type { RevocationHandlerOptions } from './handlers/revoke.js'; -export { revocationHandler } from './handlers/revoke.js'; -export type { TokenHandlerOptions } from './handlers/token.js'; -export { tokenHandler } from './handlers/token.js'; +export type { AuthorizationHandlerOptions } from './handlers/authorize'; +export { authorizationHandler, redirectUriMatches } from './handlers/authorize'; +export { metadataHandler } from './handlers/metadata'; +export type { ClientRegistrationHandlerOptions } from './handlers/register'; +export { clientRegistrationHandler } from './handlers/register'; +export type { RevocationHandlerOptions } from './handlers/revoke'; +export { revocationHandler } from './handlers/revoke'; +export type { TokenHandlerOptions } from './handlers/token'; +export { tokenHandler } from './handlers/token'; // Middleware -export { allowedMethods } from './middleware/allowedMethods.js'; -export type { BearerAuthMiddlewareOptions } from './middleware/bearerAuth.js'; -export { requireBearerAuth } from './middleware/bearerAuth.js'; -export type { ClientAuthenticationMiddlewareOptions } from './middleware/clientAuth.js'; -export { authenticateClient } from './middleware/clientAuth.js'; +export { allowedMethods } from './middleware/allowedMethods'; +export type { BearerAuthMiddlewareOptions } from './middleware/bearerAuth'; +export { requireBearerAuth } from './middleware/bearerAuth'; +export type { ClientAuthenticationMiddlewareOptions } from './middleware/clientAuth'; +export { authenticateClient } from './middleware/clientAuth'; // Error classes -export * from './errors.js'; +export * from './errors'; // Types -export type { AuthInfo } from './types.js'; +export type { AuthInfo } from './types'; diff --git a/packages/server-legacy/src/auth/middleware/allowedMethods.ts b/packages/server-legacy/src/auth/middleware/allowedMethods.ts index b24dac3f2e..b5ca41c8b6 100644 --- a/packages/server-legacy/src/auth/middleware/allowedMethods.ts +++ b/packages/server-legacy/src/auth/middleware/allowedMethods.ts @@ -1,6 +1,6 @@ import type { RequestHandler } from 'express'; -import { MethodNotAllowedError } from '../errors.js'; +import { MethodNotAllowedError } from '../errors'; /** * Middleware to handle unsupported HTTP methods with a 405 Method Not Allowed response. diff --git a/packages/server-legacy/src/auth/middleware/bearerAuth.ts b/packages/server-legacy/src/auth/middleware/bearerAuth.ts index b615b5bf48..14710221a2 100644 --- a/packages/server-legacy/src/auth/middleware/bearerAuth.ts +++ b/packages/server-legacy/src/auth/middleware/bearerAuth.ts @@ -1,8 +1,8 @@ import type { RequestHandler } from 'express'; -import { InsufficientScopeError, InvalidTokenError, OAuthError, ServerError } from '../errors.js'; -import type { OAuthTokenVerifier } from '../provider.js'; -import type { AuthInfo } from '../types.js'; +import { InsufficientScopeError, InvalidTokenError, OAuthError, ServerError } from '../errors'; +import type { OAuthTokenVerifier } from '../provider'; +import type { AuthInfo } from '../types'; export type BearerAuthMiddlewareOptions = { /** diff --git a/packages/server-legacy/src/auth/middleware/clientAuth.ts b/packages/server-legacy/src/auth/middleware/clientAuth.ts index f3f7a3896e..ad9d931253 100644 --- a/packages/server-legacy/src/auth/middleware/clientAuth.ts +++ b/packages/server-legacy/src/auth/middleware/clientAuth.ts @@ -1,9 +1,9 @@ -import type { OAuthClientInformationFull } from '@modelcontextprotocol/core'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/core-internal'; import type { RequestHandler } from 'express'; import * as z from 'zod/v4'; -import type { OAuthRegisteredClientsStore } from '../clients.js'; -import { InvalidClientError, InvalidRequestError, OAuthError, ServerError } from '../errors.js'; +import type { OAuthRegisteredClientsStore } from '../clients'; +import { InvalidClientError, InvalidRequestError, OAuthError, ServerError } from '../errors'; export type ClientAuthenticationMiddlewareOptions = { /** diff --git a/packages/server-legacy/src/auth/provider.ts b/packages/server-legacy/src/auth/provider.ts index e197491025..bdb3acb8c9 100644 --- a/packages/server-legacy/src/auth/provider.ts +++ b/packages/server-legacy/src/auth/provider.ts @@ -1,8 +1,8 @@ -import type { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core'; +import type { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; import type { Response } from 'express'; -import type { OAuthRegisteredClientsStore } from './clients.js'; -import type { AuthInfo } from './types.js'; +import type { OAuthRegisteredClientsStore } from './clients'; +import type { AuthInfo } from './types'; export type AuthorizationParams = { state?: string; diff --git a/packages/server-legacy/src/auth/providers/proxyProvider.ts b/packages/server-legacy/src/auth/providers/proxyProvider.ts index 495eab3c67..347589198a 100644 --- a/packages/server-legacy/src/auth/providers/proxyProvider.ts +++ b/packages/server-legacy/src/auth/providers/proxyProvider.ts @@ -1,11 +1,11 @@ -import type { FetchLike, OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core'; -import { OAuthClientInformationFullSchema, OAuthTokensSchema } from '@modelcontextprotocol/core'; +import type { FetchLike, OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; +import { OAuthClientInformationFullSchema, OAuthTokensSchema } from '@modelcontextprotocol/core-internal'; import type { Response } from 'express'; -import type { OAuthRegisteredClientsStore } from '../clients.js'; -import { ServerError } from '../errors.js'; -import type { AuthorizationParams, OAuthServerProvider } from '../provider.js'; -import type { AuthInfo } from '../types.js'; +import type { OAuthRegisteredClientsStore } from '../clients'; +import { ServerError } from '../errors'; +import type { AuthorizationParams, OAuthServerProvider } from '../provider'; +import type { AuthInfo } from '../types'; export type ProxyEndpoints = { authorizationUrl: string; diff --git a/packages/server-legacy/src/auth/router.ts b/packages/server-legacy/src/auth/router.ts index 02755cc7d7..866615540b 100644 --- a/packages/server-legacy/src/auth/router.ts +++ b/packages/server-legacy/src/auth/router.ts @@ -1,17 +1,17 @@ -import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/core'; +import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/core-internal'; import type { RequestHandler } from 'express'; import express from 'express'; -import type { AuthorizationHandlerOptions } from './handlers/authorize.js'; -import { authorizationHandler } from './handlers/authorize.js'; -import { metadataHandler } from './handlers/metadata.js'; -import type { ClientRegistrationHandlerOptions } from './handlers/register.js'; -import { clientRegistrationHandler } from './handlers/register.js'; -import type { RevocationHandlerOptions } from './handlers/revoke.js'; -import { revocationHandler } from './handlers/revoke.js'; -import type { TokenHandlerOptions } from './handlers/token.js'; -import { tokenHandler } from './handlers/token.js'; -import type { OAuthServerProvider } from './provider.js'; +import type { AuthorizationHandlerOptions } from './handlers/authorize'; +import { authorizationHandler } from './handlers/authorize'; +import { metadataHandler } from './handlers/metadata'; +import type { ClientRegistrationHandlerOptions } from './handlers/register'; +import { clientRegistrationHandler } from './handlers/register'; +import type { RevocationHandlerOptions } from './handlers/revoke'; +import { revocationHandler } from './handlers/revoke'; +import type { TokenHandlerOptions } from './handlers/token'; +import { tokenHandler } from './handlers/token'; +import type { OAuthServerProvider } from './provider'; // Check for dev mode flag that allows HTTP issuer URLs (for development/testing only) const allowInsecureIssuerUrl = diff --git a/packages/server-legacy/src/auth/types.ts b/packages/server-legacy/src/auth/types.ts index 3ccfcdc344..1168c8be9b 100644 --- a/packages/server-legacy/src/auth/types.ts +++ b/packages/server-legacy/src/auth/types.ts @@ -1 +1 @@ -export type { AuthInfo } from '@modelcontextprotocol/core'; +export type { AuthInfo } from '@modelcontextprotocol/core-internal'; diff --git a/packages/server-legacy/src/index.ts b/packages/server-legacy/src/index.ts index 0ce1af0fca..2e8fae62ae 100644 --- a/packages/server-legacy/src/index.ts +++ b/packages/server-legacy/src/index.ts @@ -1,2 +1,2 @@ -export * from './auth/index.js'; -export * from './sse/index.js'; +export * from './auth/index'; +export * from './sse/index'; diff --git a/packages/server-legacy/src/sse/index.ts b/packages/server-legacy/src/sse/index.ts index 108a3d884e..1fcbd3f6e5 100644 --- a/packages/server-legacy/src/sse/index.ts +++ b/packages/server-legacy/src/sse/index.ts @@ -1 +1 @@ -export { SSEServerTransport, type SSEServerTransportOptions } from './sse.js'; +export { SSEServerTransport, type SSEServerTransportOptions } from './sse'; diff --git a/packages/server-legacy/src/sse/sse.ts b/packages/server-legacy/src/sse/sse.ts index 7c9a4eab6f..6add66f9f9 100644 --- a/packages/server-legacy/src/sse/sse.ts +++ b/packages/server-legacy/src/sse/sse.ts @@ -2,8 +2,8 @@ import { randomUUID } from 'node:crypto'; import type { IncomingMessage, ServerResponse } from 'node:http'; import { TLSSocket } from 'node:tls'; -import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, Transport, TransportSendOptions } from '@modelcontextprotocol/core'; -import { JSONRPCMessageSchema } from '@modelcontextprotocol/core'; +import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, Transport, TransportSendOptions } from '@modelcontextprotocol/core-internal'; +import { JSONRPCMessageSchema } from '@modelcontextprotocol/core-internal'; import contentType from 'content-type'; import getRawBody from 'raw-body'; diff --git a/packages/server-legacy/test/auth/handlers/authorize.test.ts b/packages/server-legacy/test/auth/handlers/authorize.test.ts index 9a1edcff49..9f87a4ae6f 100644 --- a/packages/server-legacy/test/auth/handlers/authorize.test.ts +++ b/packages/server-legacy/test/auth/handlers/authorize.test.ts @@ -1,11 +1,11 @@ -import { authorizationHandler, AuthorizationHandlerOptions, redirectUriMatches } from '../../../src/auth/handlers/authorize.js'; -import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider.js'; -import { OAuthRegisteredClientsStore } from '../../../src/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/core'; +import { authorizationHandler, AuthorizationHandlerOptions, redirectUriMatches } from '../../../src/auth/handlers/authorize'; +import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider'; +import { OAuthRegisteredClientsStore } from '../../../src/auth/clients'; +import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/core-internal'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../../src/auth/types.js'; -import { InvalidTokenError } from '../../../src/auth/errors.js'; +import { AuthInfo } from '../../../src/auth/types'; +import { InvalidTokenError } from '../../../src/auth/errors'; describe('Authorization Handler', () => { // Mock client data diff --git a/packages/server-legacy/test/auth/handlers/metadata.test.ts b/packages/server-legacy/test/auth/handlers/metadata.test.ts index 875f3749cc..46f26b98d7 100644 --- a/packages/server-legacy/test/auth/handlers/metadata.test.ts +++ b/packages/server-legacy/test/auth/handlers/metadata.test.ts @@ -1,5 +1,5 @@ -import { metadataHandler } from '../../../src/auth/handlers/metadata.js'; -import { OAuthMetadata } from '@modelcontextprotocol/core'; +import { metadataHandler } from '../../../src/auth/handlers/metadata'; +import { OAuthMetadata } from '@modelcontextprotocol/core-internal'; import express from 'express'; import supertest from 'supertest'; diff --git a/packages/server-legacy/test/auth/handlers/register.test.ts b/packages/server-legacy/test/auth/handlers/register.test.ts index b2d01adb3b..295515a89a 100644 --- a/packages/server-legacy/test/auth/handlers/register.test.ts +++ b/packages/server-legacy/test/auth/handlers/register.test.ts @@ -1,6 +1,6 @@ -import { clientRegistrationHandler, ClientRegistrationHandlerOptions } from '../../../src/auth/handlers/register.js'; -import { OAuthRegisteredClientsStore } from '../../../src/auth/clients.js'; -import { OAuthClientInformationFull, OAuthClientMetadata } from '@modelcontextprotocol/core'; +import { clientRegistrationHandler, ClientRegistrationHandlerOptions } from '../../../src/auth/handlers/register'; +import { OAuthRegisteredClientsStore } from '../../../src/auth/clients'; +import { OAuthClientInformationFull, OAuthClientMetadata } from '@modelcontextprotocol/core-internal'; import express from 'express'; import supertest from 'supertest'; import { MockInstance } from 'vitest'; diff --git a/packages/server-legacy/test/auth/handlers/revoke.test.ts b/packages/server-legacy/test/auth/handlers/revoke.test.ts index 02bf86f4dd..eb4caf52f7 100644 --- a/packages/server-legacy/test/auth/handlers/revoke.test.ts +++ b/packages/server-legacy/test/auth/handlers/revoke.test.ts @@ -1,11 +1,11 @@ -import { revocationHandler, RevocationHandlerOptions } from '../../../src/auth/handlers/revoke.js'; -import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider.js'; -import { OAuthRegisteredClientsStore } from '../../../src/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core'; +import { revocationHandler, RevocationHandlerOptions } from '../../../src/auth/handlers/revoke'; +import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider'; +import { OAuthRegisteredClientsStore } from '../../../src/auth/clients'; +import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../../src/auth/types.js'; -import { InvalidTokenError } from '../../../src/auth/errors.js'; +import { AuthInfo } from '../../../src/auth/types'; +import { InvalidTokenError } from '../../../src/auth/errors'; import { MockInstance } from 'vitest'; describe('Revocation Handler', () => { diff --git a/packages/server-legacy/test/auth/handlers/token.test.ts b/packages/server-legacy/test/auth/handlers/token.test.ts index d298185cc3..ade2aca5ec 100644 --- a/packages/server-legacy/test/auth/handlers/token.test.ts +++ b/packages/server-legacy/test/auth/handlers/token.test.ts @@ -1,13 +1,13 @@ -import { tokenHandler, TokenHandlerOptions } from '../../../src/auth/handlers/token.js'; -import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider.js'; -import { OAuthRegisteredClientsStore } from '../../../src/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core'; +import { tokenHandler, TokenHandlerOptions } from '../../../src/auth/handlers/token'; +import { OAuthServerProvider, AuthorizationParams } from '../../../src/auth/provider'; +import { OAuthRegisteredClientsStore } from '../../../src/auth/clients'; +import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; import express, { Response } from 'express'; import supertest from 'supertest'; import * as pkceChallenge from 'pkce-challenge'; -import { InvalidGrantError, InvalidTokenError } from '../../../src/auth/errors.js'; -import { AuthInfo } from '../../../src/auth/types.js'; -import { ProxyOAuthServerProvider } from '../../../src/auth/providers/proxyProvider.js'; +import { InvalidGrantError, InvalidTokenError } from '../../../src/auth/errors'; +import { AuthInfo } from '../../../src/auth/types'; +import { ProxyOAuthServerProvider } from '../../../src/auth/providers/proxyProvider'; import { type Mock } from 'vitest'; // Mock pkce-challenge diff --git a/packages/server-legacy/test/auth/middleware/allowedMethods.test.ts b/packages/server-legacy/test/auth/middleware/allowedMethods.test.ts index 731e6e551b..833bb8a072 100644 --- a/packages/server-legacy/test/auth/middleware/allowedMethods.test.ts +++ b/packages/server-legacy/test/auth/middleware/allowedMethods.test.ts @@ -1,4 +1,4 @@ -import { allowedMethods } from '../../../src/auth/middleware/allowedMethods.js'; +import { allowedMethods } from '../../../src/auth/middleware/allowedMethods'; import express, { Request, Response } from 'express'; import request from 'supertest'; diff --git a/packages/server-legacy/test/auth/middleware/bearerAuth.test.ts b/packages/server-legacy/test/auth/middleware/bearerAuth.test.ts index cd2e0a7f92..58df280616 100644 --- a/packages/server-legacy/test/auth/middleware/bearerAuth.test.ts +++ b/packages/server-legacy/test/auth/middleware/bearerAuth.test.ts @@ -1,10 +1,10 @@ import { Request, Response } from 'express'; import { Mock } from 'vitest'; -import { requireBearerAuth } from '../../../src/auth/middleware/bearerAuth.js'; -import { AuthInfo } from '../../../src/auth/types.js'; -import { InsufficientScopeError, InvalidTokenError, CustomOAuthError, ServerError } from '../../../src/auth/errors.js'; -import { OAuthTokenVerifier } from '../../../src/auth/provider.js'; -import { createExpressResponseMock } from '../../helpers/http.js'; +import { requireBearerAuth } from '../../../src/auth/middleware/bearerAuth'; +import { AuthInfo } from '../../../src/auth/types'; +import { InsufficientScopeError, InvalidTokenError, CustomOAuthError, ServerError } from '../../../src/auth/errors'; +import { OAuthTokenVerifier } from '../../../src/auth/provider'; +import { createExpressResponseMock } from '../../helpers/http'; // Mock verifier const mockVerifyAccessToken = vi.fn(); diff --git a/packages/server-legacy/test/auth/middleware/clientAuth.test.ts b/packages/server-legacy/test/auth/middleware/clientAuth.test.ts index 4c7b0b6157..df21c5d205 100644 --- a/packages/server-legacy/test/auth/middleware/clientAuth.test.ts +++ b/packages/server-legacy/test/auth/middleware/clientAuth.test.ts @@ -1,6 +1,6 @@ -import { authenticateClient, ClientAuthenticationMiddlewareOptions } from '../../../src/auth/middleware/clientAuth.js'; -import { OAuthRegisteredClientsStore } from '../../../src/auth/clients.js'; -import { OAuthClientInformationFull } from '@modelcontextprotocol/core'; +import { authenticateClient, ClientAuthenticationMiddlewareOptions } from '../../../src/auth/middleware/clientAuth'; +import { OAuthRegisteredClientsStore } from '../../../src/auth/clients'; +import { OAuthClientInformationFull } from '@modelcontextprotocol/core-internal'; import express from 'express'; import supertest from 'supertest'; diff --git a/packages/server-legacy/test/auth/providers/proxyProvider.test.ts b/packages/server-legacy/test/auth/providers/proxyProvider.test.ts index e261925be4..7915435eac 100644 --- a/packages/server-legacy/test/auth/providers/proxyProvider.test.ts +++ b/packages/server-legacy/test/auth/providers/proxyProvider.test.ts @@ -1,10 +1,10 @@ import { Response } from 'express'; -import { ProxyOAuthServerProvider, ProxyOptions } from '../../../src/auth/providers/proxyProvider.js'; -import { AuthInfo } from '../../../src/auth/types.js'; -import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/core'; -import { ServerError } from '../../../src/auth/errors.js'; -import { InvalidTokenError } from '../../../src/auth/errors.js'; -import { InsufficientScopeError } from '../../../src/auth/errors.js'; +import { ProxyOAuthServerProvider, ProxyOptions } from '../../../src/auth/providers/proxyProvider'; +import { AuthInfo } from '../../../src/auth/types'; +import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/core-internal'; +import { ServerError } from '../../../src/auth/errors'; +import { InvalidTokenError } from '../../../src/auth/errors'; +import { InsufficientScopeError } from '../../../src/auth/errors'; import { type Mock } from 'vitest'; describe('Proxy OAuth Server Provider', () => { diff --git a/packages/server-legacy/test/auth/router.test.ts b/packages/server-legacy/test/auth/router.test.ts index b29f7509ad..83ad277af8 100644 --- a/packages/server-legacy/test/auth/router.test.ts +++ b/packages/server-legacy/test/auth/router.test.ts @@ -1,11 +1,11 @@ -import { mcpAuthRouter, AuthRouterOptions, mcpAuthMetadataRouter, AuthMetadataOptions } from '../../src/auth/router.js'; -import { OAuthServerProvider, AuthorizationParams } from '../../src/auth/provider.js'; -import { OAuthRegisteredClientsStore } from '../../src/auth/clients.js'; -import { OAuthClientInformationFull, OAuthMetadata, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core'; +import { mcpAuthRouter, AuthRouterOptions, mcpAuthMetadataRouter, AuthMetadataOptions } from '../../src/auth/router'; +import { OAuthServerProvider, AuthorizationParams } from '../../src/auth/provider'; +import { OAuthRegisteredClientsStore } from '../../src/auth/clients'; +import { OAuthClientInformationFull, OAuthMetadata, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/core-internal'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../src/auth/types.js'; -import { InvalidTokenError } from '../../src/auth/errors.js'; +import { AuthInfo } from '../../src/auth/types'; +import { InvalidTokenError } from '../../src/auth/errors'; describe('MCP Auth Router', () => { // Setup mock provider with full capabilities diff --git a/packages/server-legacy/test/sse/sse.test.ts b/packages/server-legacy/test/sse/sse.test.ts index 13d19640bb..212ad7f958 100644 --- a/packages/server-legacy/test/sse/sse.test.ts +++ b/packages/server-legacy/test/sse/sse.test.ts @@ -1,8 +1,8 @@ import http from 'node:http'; import { type Mocked } from 'vitest'; -import { SSEServerTransport } from '../../src/sse/sse.js'; -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; +import { SSEServerTransport } from '../../src/sse/sse'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; const createMockResponse = () => { const res = { diff --git a/packages/server-legacy/tsconfig.json b/packages/server-legacy/tsconfig.json index 18c1327cbc..e70d31d788 100644 --- a/packages/server-legacy/tsconfig.json +++ b/packages/server-legacy/tsconfig.json @@ -5,8 +5,8 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"] + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": ["./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts"] } } } diff --git a/packages/server-legacy/tsdown.config.ts b/packages/server-legacy/tsdown.config.ts index 458d92e8a0..2fff3afcd7 100644 --- a/packages/server-legacy/tsdown.config.ts +++ b/packages/server-legacy/tsdown.config.ts @@ -15,10 +15,10 @@ export default defineConfig({ compilerOptions: { baseUrl: '.', paths: { - '@modelcontextprotocol/core': ['../core/src/index.ts'], - '@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts'] + '@modelcontextprotocol/core-internal': ['../core-internal/src/index.ts'], + '@modelcontextprotocol/core-internal/public': ['../core-internal/src/exports/public/index.ts'] } } }, - noExternal: ['@modelcontextprotocol/core'] + noExternal: ['@modelcontextprotocol/core-internal'] }); diff --git a/packages/server/CHANGELOG.md b/packages/server/CHANGELOG.md index 3f27e84e5a..68e2c29c2e 100644 --- a/packages/server/CHANGELOG.md +++ b/packages/server/CHANGELOG.md @@ -1,5 +1,112 @@ # @modelcontextprotocol/server +## 2.0.0-alpha.3 + +### Major Changes + +- [#2128](https://github.com/modelcontextprotocol/typescript-sdk/pull/2128) [`c8d7401`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c8d7401b46f34b6c49b7cfb7b321714d0d4048f6) Thanks [@felixweinberger](https://github.com/felixweinberger)! - SEP-2663: remove + 2025-11 experimental tasks (TaskManager, experimental.tasks.\* accessors). Tasks are now Extensions Track. + +### Minor Changes + +- [#1974](https://github.com/modelcontextprotocol/typescript-sdk/pull/1974) [`db83829`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db83829c5bd5d6659c5e7b96638b11953b0e262d) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add custom (non-spec) + method support: a 3-arg `setRequestHandler(method, schemas, handler)` / `setNotificationHandler(method, schemas, handler)` form for vendor-prefixed methods, and a `request(req, resultSchema)` overload (also on `ctx.mcpReq.send`) for typed custom-method results. Spec-method + calls are unchanged. + + Response result-schema validation failure now rejects with `SdkError(InvalidResult)` instead of a raw `ZodError`. Adds `SdkErrorCode.InvalidResult`. + +- [#2353](https://github.com/modelcontextprotocol/typescript-sdk/pull/2353) [`c59dc3a`](https://github.com/modelcontextprotocol/typescript-sdk/commit/c59dc3aa1a633d27fbbe873f1a430483cf7440f8) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Support `icons` on the + high-level `McpServer.registerTool()` and `registerPrompt()` config objects (and on their `update()` methods). Tool and prompt icons now surface in `tools/list` and `prompts/list`. Resource, resource-template, and server-info (`Implementation`) icons already passed through. + This closes the gap with the MCP spec, which allows `icons` on tools, resources, resource templates, and prompts. + +- [#2354](https://github.com/modelcontextprotocol/typescript-sdk/pull/2354) [`0fb8406`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0fb8406d83a3578a12a605e1b43c352d565071b1) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add the v2 + `IdJagTokenExchangeResponse` type to the public API and register its schema as an MCP spec type. `IdJagTokenExchangeResponse` is now exported from `@modelcontextprotocol/client` and `@modelcontextprotocol/server`, `'IdJagTokenExchangeResponse'` joins the `SpecTypeName` union, + and `isSpecType.IdJagTokenExchangeResponse(value)` / `specTypeSchemas.IdJagTokenExchangeResponse` validate it by name — matching how the OAuth/OpenID auth schemas are already exposed. The Zod schema itself, `IdJagTokenExchangeResponseSchema`, is available from + `@modelcontextprotocol/core`. + +- [#2248](https://github.com/modelcontextprotocol/typescript-sdk/pull/2248) [`db28156`](https://github.com/modelcontextprotocol/typescript-sdk/commit/db28156a23032290b3ce3bae00a17544c4807b8f) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Restore the 2025-11-25 + task wire types that were removed together with the task feature: the task schemas and inferred types, task members of the request/result/notification unions, the `task` request-params augmentation, the `tasks` capability key, the `isTaskAugmentedRequestParams` guard, and + `RELATED_TASK_META_KEY`. The task feature itself remains removed — servers do not advertise the `tasks` capability and inbound `tasks/*` requests receive `-32601` — but the wire surface stays so SDKs interoperate cleanly with peers on the 2025-11-25 revision. + +- [#1887](https://github.com/modelcontextprotocol/typescript-sdk/pull/1887) [`96db044`](https://github.com/modelcontextprotocol/typescript-sdk/commit/96db044fe965f0b7d5109e6d68598eaddce961c9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Export `isSpecType` and + `specTypeSchemas` records for runtime validation of any MCP spec type by name. `isSpecType.ContentBlock(value)` is a type predicate; `specTypeSchemas.ContentBlock` is a `StandardSchemaV1Sync` validator — `validate()` returns the result synchronously. Guards are + standalone functions, so `arr.filter(isSpecType.ContentBlock)` works. Also export the `SpecTypeName`, `SpecTypes`, and `StandardSchemaV1Sync` types. + +- [#1871](https://github.com/modelcontextprotocol/typescript-sdk/pull/1871) [`9fc9070`](https://github.com/modelcontextprotocol/typescript-sdk/commit/9fc9070b7b8e18227127aaee9869f8809a87fdb1) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Move stdio transports + to a `./stdio` subpath export. Import `StdioClientTransport`, `getDefaultEnvironment`, `DEFAULT_INHERITED_ENV_VARS`, and `StdioServerParameters` from `@modelcontextprotocol/client/stdio`, and `StdioServerTransport` from `@modelcontextprotocol/server/stdio`. The + `@modelcontextprotocol/client` root entry no longer pulls in `node:child_process`, `node:stream`, or `cross-spawn`, fixing bundling for browser and Cloudflare Workers targets; the `@modelcontextprotocol/server` root entry drops its `node:stream` reference. Node.js, Bun, and + Deno consumers update the import path; runtime behavior is unchanged. + +### Patch Changes + +- [#2280](https://github.com/modelcontextprotocol/typescript-sdk/pull/2280) [`e8c7180`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e8c7180109b417eef5cc22b7e9d821ab1c119a69) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Bound the + protocol-version checks gating SSE resumability behavior (priming events and `closeSSEStream` callbacks) in the Streamable HTTP server transport. Previously an open-ended `>= '2025-11-25'` comparison let unknown future protocol version strings from an `initialize` request body + enable this behavior; the version must now also be one of the transport's supported protocol versions. Behavior for all currently supported protocol versions is unchanged. + +- [#1897](https://github.com/modelcontextprotocol/typescript-sdk/pull/1897) [`434b2f1`](https://github.com/modelcontextprotocol/typescript-sdk/commit/434b2f11ecec452f3dca0199f68afccd8b119dd4) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Stop bundling + `@cfworker/json-schema` into the main package barrel. Previously `CfWorkerJsonSchemaValidator` was re-exported from the core internal barrel, so tsdown inlined the `@cfworker/json-schema` dependency into every consumer's bundle even when it was never used. The named validator + classes are now reachable only via the explicit `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths and the runtime `_shims` conditional, so consumers that import only from the root entry point no longer ship the validator dep. + +- [#2269](https://github.com/modelcontextprotocol/typescript-sdk/pull/2269) [`e84c3e9`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e84c3e9ad040eb09299b1f99dd8bdd14251ae790) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Non-SEP draft spec conformance + fixes + - `McpServer` now eagerly installs list/read/call handlers for every primitive capability (`tools`, `resources`, `prompts`) declared in `ServerOptions.capabilities`. Per the draft spec, a server that declares a capability MUST respond to its list method (potentially with an + empty result) instead of returning "Method not found". Previously, handlers were only installed lazily on first registration, so a server constructed with e.g. `capabilities: { tools: {} }` and zero registered tools answered `tools/list` with `-32601`. Low-level `Server` + users remain responsible for registering handlers for declared capabilities (documented on `ServerOptions.capabilities`). + - Fixed pagination doc examples on `Client.listTools`/`listPrompts`/`listResources` to loop `while (cursor !== undefined)` instead of `while (cursor)` — per the draft spec, clients MUST NOT treat an empty-string cursor as the end of results. + +- [#1834](https://github.com/modelcontextprotocol/typescript-sdk/pull/1834) [`42cb6b2`](https://github.com/modelcontextprotocol/typescript-sdk/commit/42cb6b2b728347d8b58a0d1940b7e63366a29ab9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Export + `InMemoryTransport` for in-process testing. + +- [#1788](https://github.com/modelcontextprotocol/typescript-sdk/pull/1788) [`df4b6cc`](https://github.com/modelcontextprotocol/typescript-sdk/commit/df4b6cc88d6f24fc857519cf506a7a039f532637) Thanks [@claygeo](https://github.com/claygeo)! - Prevent stack overflow in + StreamableHTTPServerTransport.close() with re-entrant guard + +- [#1855](https://github.com/modelcontextprotocol/typescript-sdk/pull/1855) [`2c0c481`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2c0c481cb9dbfd15c8613f765c940a5f5bace94d) Thanks [@Christian-Sidak](https://github.com/Christian-Sidak)! - Add `| undefined` to + optional callback and function properties on `WebStandardStreamableHTTPServerTransportOptions` (`sessionIdGenerator`, `onsessioninitialized`, `onsessionclosed`) and corresponding private fields. + + This fixes TS2430 errors for consumers using `exactOptionalPropertyTypes: true` without `skipLibCheck`, where optional properties with function types need explicit `| undefined` to match their emitted declarations. + +- [#1898](https://github.com/modelcontextprotocol/typescript-sdk/pull/1898) [`2a7611d`](https://github.com/modelcontextprotocol/typescript-sdk/commit/2a7611d46b0d4f4e7bd4147c7a3ad3da00e57e52) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add top-level `types` + field (and `typesVersions` on client/server for their subpath exports) so consumers on legacy `moduleResolution: "node"` can resolve type declarations. The `exports` map remains the source of truth for `nodenext`/`bundler` resolution. The `typesVersions` map includes entries + for subpaths added by sibling PRs in this series (`zod-schemas`, `stdio`); those entries are no-ops until the corresponding `dist/*.d.mts` files exist. + +- [#1901](https://github.com/modelcontextprotocol/typescript-sdk/pull/1901) [`e15a8ef`](https://github.com/modelcontextprotocol/typescript-sdk/commit/e15a8ef3be19520d8159ae9f5b464ba3ac80a5ab) Thanks [@felixweinberger](https://github.com/felixweinberger)! - + `registerTool`/`registerPrompt` accept a raw Zod shape (`{ field: z.string() }`) for `inputSchema`/`outputSchema`/`argsSchema` in addition to a wrapped Standard Schema. Raw shapes are auto-wrapped with `z.object()`. The raw-shape overloads are `@deprecated`; prefer wrapping + with `z.object()`. + + Also widens the `completable()` constraint from `StandardSchemaWithJSON` to `StandardSchemaV1` so v1's `completable(z.string(), fn)` continues to work. + +- [#2268](https://github.com/modelcontextprotocol/typescript-sdk/pull/2268) [`49c0a71`](https://github.com/modelcontextprotocol/typescript-sdk/commit/49c0a711c8bf2d385f9e03b4f28ba0ff0d0db0bd) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Mark the roots, sampling, and + logging runtime APIs as `@deprecated` per SEP-2577 (deprecated as of protocol version 2026-07-28; functional for at least twelve months). Annotates `Server.createMessage`/`listRoots`/`sendLoggingMessage`, `McpServer.sendLoggingMessage`, + `Client.setLoggingLevel`/`sendRootsListChanged`, the `ServerContext.mcpReq.log`/`requestSampling` helpers, and the `roots`/`sampling`/`logging` capability schema fields. JSDoc/docs only — no behavior change. + +- [#2275](https://github.com/modelcontextprotocol/typescript-sdk/pull/2275) [`1b53a41`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1b53a415ea2c33aa11ac413fc9c2d68ccffde784) Thanks [@KKonstantinov](https://github.com/KKonstantinov)! - Add a configurable + `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or + `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/client` / `@modelcontextprotocol/server` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`. + +- [#2088](https://github.com/modelcontextprotocol/typescript-sdk/pull/2088) [`16d13ab`](https://github.com/modelcontextprotocol/typescript-sdk/commit/16d13abf78b5dba5de73dfa284325b13d4219bb2) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Bundle automatic JSON Schema + validator defaults in `@modelcontextprotocol/client` and `@modelcontextprotocol/server` runtime shims. + + Client and server pick the right validator automatically based on the runtime: the Node shim uses AJV, the browser/workerd shim uses `@cfworker/json-schema`. Both backends are bundled into the shim chunks that select them, so the default code path needs no extra installs — + `import { McpServer } from '@modelcontextprotocol/server'` does not pull `ajv` or `@cfworker/json-schema` into the root entry chunk. + + The named validator classes remain part of the public surface for consumers who want to customize the built-in backend (pre-register schemas by `$id`, register custom AJV formats, switch dialects, change `@cfworker/json-schema` draft). They are exposed through explicit + subpaths so they do not bloat the root index chunk: + - `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/ajv'` + - `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/cf-worker'` + + Importing from one of these subpaths means the corresponding peer dep (`ajv` + `ajv-formats`, or `@cfworker/json-schema`) must be in your `package.json`. The shim keeps its own vendored copy for the default path, so a project can use the subpath in some files and rely on the + default in others. + + The `jsonSchemaValidator` interface remains the public extension point for replacing validation entirely with a custom implementation. + +- [#1976](https://github.com/modelcontextprotocol/typescript-sdk/pull/1976) [`55b1f06`](https://github.com/modelcontextprotocol/typescript-sdk/commit/55b1f06cd4569e334f3435b7971f0446f1ef9be9) Thanks [@felixweinberger](https://github.com/felixweinberger)! - refactor: subclasses + override `_wrapHandler` hook instead of redeclaring `setRequestHandler`. + +- [#1895](https://github.com/modelcontextprotocol/typescript-sdk/pull/1895) [`b256546`](https://github.com/modelcontextprotocol/typescript-sdk/commit/b256546750277faeb7c886792aae5ed26e6904d5) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Fix runtime crash on + `tools/list` when a tool's `inputSchema` comes from zod 4.0–4.1. The SDK requires `~standard.jsonSchema` (StandardJSONSchemaV1, added in zod 4.2.0); previously a missing `jsonSchema` crashed at `undefined[io]`. `standardSchemaToJsonSchema` now detects zod 4 schemas lacking + `jsonSchema` and falls back to the SDK-bundled `z.toJSONSchema()`, emitting a one-time console warning. zod 3 schemas (which the bundled zod 4 converter cannot introspect) and non-zod schema libraries without `jsonSchema` get a clear error pointing to `fromJsonSchema()`. The + workspace zod catalog is also bumped to `^4.2.0`. + ## 2.0.0-alpha.2 ### Patch Changes @@ -51,7 +158,8 @@ For raw JSON Schema (e.g. TypeBox output), use the new `fromJsonSchema` adapter: ```typescript - import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core'; + import { fromJsonSchema } from '@modelcontextprotocol/server'; + import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv'; server.registerTool( 'greet', @@ -64,7 +172,8 @@ **Breaking changes:** - `experimental.tasks.getTaskResult()` no longer accepts a `resultSchema` parameter. Returns `GetTaskPayloadResult` (a loose `Result`); cast to the expected type at the call site. - - Removed unused exports from `@modelcontextprotocol/core`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` instead. + - Removed unused exports from `@modelcontextprotocol/core-internal`: `SchemaInput`, `schemaToJson`, `parseSchemaAsync`, `getSchemaShape`, `getSchemaDescription`, `isOptionalSchema`, `unwrapOptionalSchema`. Use the new `standardSchemaToJsonSchema` and `validateStandardSchema` + instead. - `completable()` remains Zod-specific (it relies on Zod's `.shape` introspection). ### Patch Changes diff --git a/packages/server/eslint.config.mjs b/packages/server/eslint.config.mjs index 4f034f2235..dd9e88588a 100644 --- a/packages/server/eslint.config.mjs +++ b/packages/server/eslint.config.mjs @@ -6,7 +6,7 @@ export default [ ...baseConfig, { settings: { - 'import/internal-regex': '^@modelcontextprotocol/core' + 'import/internal-regex': '^@modelcontextprotocol/core-internal' } } ]; diff --git a/packages/server/package.json b/packages/server/package.json index d7bce70fa4..76bbb7364e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/server", - "version": "2.0.0-alpha.2", + "version": "2.0.0-alpha.3", "description": "Model Context Protocol implementation for TypeScript - Server package", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -84,9 +84,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "pnpm run typecheck && pnpm run lint", "test": "vitest run", - "test:watch": "vitest", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "test:watch": "vitest" }, "dependencies": { "zod": "catalog:runtimeShared" @@ -96,7 +94,7 @@ "ajv": "catalog:runtimeShared", "ajv-formats": "catalog:runtimeShared", "@eslint/js": "catalog:devTools", - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/test-helpers": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", @@ -109,7 +107,6 @@ "prettier": "catalog:devTools", "supertest": "catalog:devTools", "tsdown": "catalog:devTools", - "tsx": "catalog:devTools", "typescript": "catalog:devTools", "typescript-eslint": "catalog:devTools", "vitest": "catalog:devTools" diff --git a/packages/server/src/fromJsonSchema.ts b/packages/server/src/fromJsonSchema.ts index 180ef2defc..c2db3fda44 100644 --- a/packages/server/src/fromJsonSchema.ts +++ b/packages/server/src/fromJsonSchema.ts @@ -1,5 +1,5 @@ -import type { JsonSchemaType, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core'; -import { fromJsonSchema as coreFromJsonSchema } from '@modelcontextprotocol/core'; +import type { JsonSchemaType, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core-internal'; +import { fromJsonSchema as coreFromJsonSchema } from '@modelcontextprotocol/core-internal'; import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims'; let _defaultValidator: jsonSchemaValidator | undefined; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 9b993eea1e..b419da882d 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -2,12 +2,12 @@ // // This file defines the complete public surface. It consists of: // - Package-specific exports: listed explicitly below (named imports) -// - Protocol-level types: re-exported from @modelcontextprotocol/core/public +// - Protocol-level types: re-exported from @modelcontextprotocol/core-internal/public // // Any new export added here becomes public API. Use named exports, not wildcards. -export type { CompletableSchema, CompleteCallback } from './server/completable.js'; -export { completable, isCompletable } from './server/completable.js'; +export type { CompletableSchema, CompleteCallback } from './server/completable'; +export { completable, isCompletable } from './server/completable'; export type { CreateMcpHandlerOptions, LegacyHttpHandler, @@ -15,8 +15,8 @@ export type { McpHttpHandler, McpRequestContext, McpServerFactory -} from './server/createMcpHandler.js'; -export { createMcpHandler, isLegacyRequest, legacyStatelessFallback } from './server/createMcpHandler.js'; +} from './server/createMcpHandler'; +export { createMcpHandler, isLegacyRequest, legacyStatelessFallback } from './server/createMcpHandler'; export type { AnyToolHandler, BaseToolCallback, @@ -31,23 +31,23 @@ export type { RegisteredTool, ResourceMetadata, ToolCallback -} from './server/mcp.js'; -export { McpServer, ResourceTemplate } from './server/mcp.js'; -export type { HostHeaderValidationResult } from './server/middleware/hostHeaderValidation.js'; -export { hostHeaderValidationResponse, localhostAllowedHostnames, validateHostHeader } from './server/middleware/hostHeaderValidation.js'; -export type { OriginValidationResult } from './server/middleware/originValidation.js'; -export { localhostAllowedOrigins, originValidationResponse, validateOriginHeader } from './server/middleware/originValidation.js'; -export type { PerRequestHTTPServerTransportOptions, PerRequestMessageExtra, PerRequestResponseMode } from './server/perRequestTransport.js'; -export { PerRequestHTTPServerTransport } from './server/perRequestTransport.js'; +} from './server/mcp'; +export { McpServer, ResourceTemplate } from './server/mcp'; +export type { HostHeaderValidationResult } from './server/middleware/hostHeaderValidation'; +export { hostHeaderValidationResponse, localhostAllowedHostnames, validateHostHeader } from './server/middleware/hostHeaderValidation'; +export type { OriginValidationResult } from './server/middleware/originValidation'; +export { localhostAllowedOrigins, originValidationResponse, validateOriginHeader } from './server/middleware/originValidation'; +export type { PerRequestHTTPServerTransportOptions, PerRequestMessageExtra, PerRequestResponseMode } from './server/perRequestTransport'; +export { PerRequestHTTPServerTransport } from './server/perRequestTransport'; // Opt-in HMAC sealing for the multi-round-trip requestState (SEP-2322): the // convenience codec consumers drop into ServerOptions.requestState.verify. -export type { RequestStateCodec, RequestStateCodecOptions } from './server/requestStateCodec.js'; -export { createRequestStateCodec } from './server/requestStateCodec.js'; -export type { ServerOptions } from './server/server.js'; -export { Server } from './server/server.js'; +export type { RequestStateCodec, RequestStateCodecOptions } from './server/requestStateCodec'; +export { createRequestStateCodec } from './server/requestStateCodec'; +export type { ServerOptions } from './server/server'; +export { Server } from './server/server'; // subscriptions/listen change-event sourcing seam (protocol revision 2026-07-28). -export type { ServerEvent, ServerEventBus, ServerNotifier } from './server/serverEventBus.js'; -export { InMemoryServerEventBus } from './server/serverEventBus.js'; +export type { ServerEvent, ServerEventBus, ServerNotifier } from './server/serverEventBus'; +export { InMemoryServerEventBus } from './server/serverEventBus'; // StdioServerTransport and the serveStdio entry are exported from the './stdio' subpath — server stdio // has only type-level Node imports (erased at compile time), but matching the client's `./stdio` subpath // gives consumers a consistent shape across packages. @@ -57,11 +57,11 @@ export type { HandleRequestOptions, StreamId, WebStandardStreamableHTTPServerTransportOptions -} from './server/streamableHttp.js'; -export { WebStandardStreamableHTTPServerTransport } from './server/streamableHttp.js'; +} from './server/streamableHttp'; +export { WebStandardStreamableHTTPServerTransport } from './server/streamableHttp'; // runtime-aware wrapper (shadows core/public's fromJsonSchema with optional validator) -export { fromJsonSchema } from './fromJsonSchema.js'; +export { fromJsonSchema } from './fromJsonSchema'; // Inbound HTTP request classification (dual-era serving): the body-primary era // predicate used by createMcpHandler, exported for hand-wired compositions. @@ -73,18 +73,18 @@ export type { InboundLegacyRouteReason, InboundModernRoute, InboundValidationRung -} from '@modelcontextprotocol/core'; -export { classifyInboundRequest } from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; +export { classifyInboundRequest } from '@modelcontextprotocol/core-internal'; // Cache hints for cacheable 2026-07-28 results (ServerOptions.cacheHints and // the registerResource cacheHint option). -export type { CacheHint, CacheScope } from '@modelcontextprotocol/core'; +export type { CacheHint, CacheScope } from '@modelcontextprotocol/core-internal'; // Multi round-trip requests (protocol revision 2026-07-28): the authoring // helpers a handler uses to request additional client input by returning an // input-required result instead of sending a server→client request. -export type { InputRequiredSpec } from '@modelcontextprotocol/core'; -export { acceptedContent, inputRequired } from '@modelcontextprotocol/core'; +export type { InputRequiredSpec } from '@modelcontextprotocol/core-internal'; +export { acceptedContent, inputRequired } from '@modelcontextprotocol/core-internal'; // re-export curated public API from core -export * from '@modelcontextprotocol/core/public'; +export * from '@modelcontextprotocol/core-internal/public'; diff --git a/packages/server/src/server/completable.examples.ts b/packages/server/src/server/completable.examples.ts index b0655d2438..925f24e2a3 100644 --- a/packages/server/src/server/completable.examples.ts +++ b/packages/server/src/server/completable.examples.ts @@ -9,8 +9,8 @@ import * as z from 'zod/v4'; -import { completable } from './completable.js'; -import { McpServer } from './mcp.js'; +import { completable } from './completable'; +import { McpServer } from './mcp'; /** * Example: Using completable() in a prompt registration. diff --git a/packages/server/src/server/completable.ts b/packages/server/src/server/completable.ts index 82300f7df1..b8ab7b6b68 100644 --- a/packages/server/src/server/completable.ts +++ b/packages/server/src/server/completable.ts @@ -1,4 +1,4 @@ -import type { StandardSchemaV1 } from '@modelcontextprotocol/core'; +import type { StandardSchemaV1 } from '@modelcontextprotocol/core-internal'; export const COMPLETABLE_SYMBOL: unique symbol = Symbol.for('mcp.completable'); diff --git a/packages/server/src/server/createMcpHandler.ts b/packages/server/src/server/createMcpHandler.ts index c1b0656873..b2e4828a2a 100644 --- a/packages/server/src/server/createMcpHandler.ts +++ b/packages/server/src/server/createMcpHandler.ts @@ -35,7 +35,7 @@ import type { InboundLegacyRoute, InboundModernRoute, RequestId -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { classifyInboundRequest, CLIENT_CAPABILITIES_META_KEY, @@ -54,17 +54,17 @@ import { UnsupportedProtocolVersionError, validateMcpParamHeaders, validateStandardRequestHeaders -} from '@modelcontextprotocol/core'; - -import { invoke } from './invoke.js'; -import { createListenRouter, DEFAULT_LISTEN_KEEPALIVE_MS, DEFAULT_MAX_SUBSCRIPTIONS } from './listenRouter.js'; -import { McpServer } from './mcp.js'; -import type { PerRequestResponseMode } from './perRequestTransport.js'; -import type { Server } from './server.js'; -import { installModernOnlyHandlers, seedClientIdentityFromEnvelope } from './server.js'; -import type { ServerEventBus, ServerNotifier } from './serverEventBus.js'; -import { createServerNotifier, InMemoryServerEventBus } from './serverEventBus.js'; -import { WebStandardStreamableHTTPServerTransport } from './streamableHttp.js'; +} from '@modelcontextprotocol/core-internal'; + +import { invoke } from './invoke'; +import { createListenRouter, DEFAULT_LISTEN_KEEPALIVE_MS, DEFAULT_MAX_SUBSCRIPTIONS } from './listenRouter'; +import { McpServer } from './mcp'; +import type { PerRequestResponseMode } from './perRequestTransport'; +import type { Server } from './server'; +import { installModernOnlyHandlers, seedClientIdentityFromEnvelope } from './server'; +import type { ServerEventBus, ServerNotifier } from './serverEventBus'; +import { createServerNotifier, InMemoryServerEventBus } from './serverEventBus'; +import { WebStandardStreamableHTTPServerTransport } from './streamableHttp'; /* ------------------------------------------------------------------------ * * Factory and handler types diff --git a/packages/server/src/server/invoke.ts b/packages/server/src/server/invoke.ts index f6c9c11359..6966968604 100644 --- a/packages/server/src/server/invoke.ts +++ b/packages/server/src/server/invoke.ts @@ -15,12 +15,12 @@ * (and installing modern-only handlers) is the calling entry's responsibility * and happens before this seam runs; the seam itself never writes era state. */ -import type { AuthInfo, JSONRPCNotification, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core'; +import type { AuthInfo, JSONRPCNotification, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core-internal'; -import type { McpServer } from './mcp.js'; -import type { PerRequestResponseMode } from './perRequestTransport.js'; -import { PerRequestHTTPServerTransport } from './perRequestTransport.js'; -import type { Server } from './server.js'; +import type { McpServer } from './mcp'; +import type { PerRequestResponseMode } from './perRequestTransport'; +import { PerRequestHTTPServerTransport } from './perRequestTransport'; +import type { Server } from './server'; /** Per-exchange context for {@linkcode invoke}. */ export interface InvokeContext { diff --git a/packages/server/src/server/listenRouter.ts b/packages/server/src/server/listenRouter.ts index 4bff1c2a70..5aaa948c43 100644 --- a/packages/server/src/server/listenRouter.ts +++ b/packages/server/src/server/listenRouter.ts @@ -23,11 +23,11 @@ * transport close carries no response and the client treats it as a * disconnect. */ -import type { JSONRPCRequest, RequestId, ServerCapabilities, SubscriptionFilter } from '@modelcontextprotocol/core'; -import { codecForVersion, MODERN_WIRE_REVISION, SUBSCRIPTION_ID_META_KEY } from '@modelcontextprotocol/core'; +import type { JSONRPCRequest, RequestId, ServerCapabilities, SubscriptionFilter } from '@modelcontextprotocol/core-internal'; +import { codecForVersion, MODERN_WIRE_REVISION, SUBSCRIPTION_ID_META_KEY } from '@modelcontextprotocol/core-internal'; -import type { ServerEventBus } from './serverEventBus.js'; -import { honoredSubset, listenFilterAccepts, serverEventToNotification } from './serverEventBus.js'; +import type { ServerEventBus } from './serverEventBus'; +import { honoredSubset, listenFilterAccepts, serverEventToNotification } from './serverEventBus'; /** Default SSE comment-frame keepalive interval for listen streams. */ export const DEFAULT_LISTEN_KEEPALIVE_MS = 15_000; @@ -394,7 +394,7 @@ export class StdioListenRouter { } } -function notificationToServerEvent(method: string, uri: string | undefined): import('./serverEventBus.js').ServerEvent { +function notificationToServerEvent(method: string, uri: string | undefined): import('./serverEventBus').ServerEvent { switch (method) { case 'notifications/tools/list_changed': { return { kind: 'tools_list_changed' }; diff --git a/packages/server/src/server/mcp.examples.ts b/packages/server/src/server/mcp.examples.ts index 740c1bf186..c4abb9ccb7 100644 --- a/packages/server/src/server/mcp.examples.ts +++ b/packages/server/src/server/mcp.examples.ts @@ -7,11 +7,11 @@ * @module */ -import type { CallToolResult } from '@modelcontextprotocol/core'; +import type { CallToolResult } from '@modelcontextprotocol/core-internal'; import * as z from 'zod/v4'; -import { McpServer } from './mcp.js'; -import { StdioServerTransport } from './stdio.js'; +import { McpServer } from './mcp'; +import { StdioServerTransport } from './stdio'; /** * Example: Creating a new McpServer. diff --git a/packages/server/src/server/mcp.ts b/packages/server/src/server/mcp.ts index bd499efa59..e0d10b5a8e 100644 --- a/packages/server/src/server/mcp.ts +++ b/packages/server/src/server/mcp.ts @@ -26,7 +26,7 @@ import type { ToolExecution, Transport, Variables -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { assertCompleteRequestPrompt, assertCompleteRequestResourceTemplate, @@ -43,12 +43,12 @@ import { UriTemplate, validateAndWarnToolName, validateStandardSchema -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import type * as z from 'zod/v4'; -import { getCompleter, isCompletable } from './completable.js'; -import type { ServerOptions } from './server.js'; -import { Server } from './server.js'; +import { getCompleter, isCompletable } from './completable'; +import type { ServerOptions } from './server'; +import { Server } from './server'; /** * High-level MCP server that provides a simpler API for working with resources, tools, and prompts. diff --git a/packages/server/src/server/middleware/hostHeaderValidation.examples.ts b/packages/server/src/server/middleware/hostHeaderValidation.examples.ts index fd49d97516..f46a04c570 100644 --- a/packages/server/src/server/middleware/hostHeaderValidation.examples.ts +++ b/packages/server/src/server/middleware/hostHeaderValidation.examples.ts @@ -7,7 +7,7 @@ * @module */ -import { validateHostHeader } from './hostHeaderValidation.js'; +import { validateHostHeader } from './hostHeaderValidation'; /** * Example: Validating a host header against allowed hosts. diff --git a/packages/server/src/server/perRequestTransport.ts b/packages/server/src/server/perRequestTransport.ts index 74eaaca51a..c9d24c6f63 100644 --- a/packages/server/src/server/perRequestTransport.ts +++ b/packages/server/src/server/perRequestTransport.ts @@ -39,7 +39,7 @@ import type { RequestId, Transport, TransportSendOptions -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { isJSONRPCErrorResponse, isJSONRPCRequest, @@ -47,7 +47,7 @@ import { LADDER_ERROR_HTTP_STATUS, SdkError, SdkErrorCode -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; /** * How the transport shapes its HTTP response for a request: diff --git a/packages/server/src/server/requestStateCodec.ts b/packages/server/src/server/requestStateCodec.ts index 5dee32d036..91433a144e 100644 --- a/packages/server/src/server/requestStateCodec.ts +++ b/packages/server/src/server/requestStateCodec.ts @@ -1,4 +1,4 @@ -import type { ServerContext } from '@modelcontextprotocol/core'; +import type { ServerContext } from '@modelcontextprotocol/core-internal'; /** * Options for {@linkcode createRequestStateCodec}. diff --git a/packages/server/src/server/serveStdio.ts b/packages/server/src/server/serveStdio.ts index a3fed9b4ee..d01067483f 100644 --- a/packages/server/src/server/serveStdio.ts +++ b/packages/server/src/server/serveStdio.ts @@ -56,7 +56,7 @@ import type { RequestId, Transport, TransportSendOptions -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { carriesValidModernEnvelopeClaim, envelopeClaimVersion, @@ -72,14 +72,14 @@ import { SUPPORTED_MODERN_PROTOCOL_VERSIONS, UnsupportedProtocolVersionError, validateEnvelopeMeta -} from '@modelcontextprotocol/core'; - -import type { McpServerFactory } from './createMcpHandler.js'; -import { DEFAULT_MAX_SUBSCRIPTIONS, StdioListenRouter } from './listenRouter.js'; -import { McpServer } from './mcp.js'; -import type { Server } from './server.js'; -import { installModernOnlyHandlers } from './server.js'; -import { StdioServerTransport } from './stdio.js'; +} from '@modelcontextprotocol/core-internal'; + +import type { McpServerFactory } from './createMcpHandler'; +import { DEFAULT_MAX_SUBSCRIPTIONS, StdioListenRouter } from './listenRouter'; +import { McpServer } from './mcp'; +import type { Server } from './server'; +import { installModernOnlyHandlers } from './server'; +import { StdioServerTransport } from './stdio'; /** Options for {@linkcode serveStdio}. */ export interface ServeStdioOptions { diff --git a/packages/server/src/server/server.ts b/packages/server/src/server/server.ts index 4142b789f6..dc15beea33 100644 --- a/packages/server/src/server/server.ts +++ b/packages/server/src/server/server.ts @@ -36,7 +36,7 @@ import type { ServerContext, ToolResultContent, ToolUseContent -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { assertValidCacheHint, attachCacheHintFallback, @@ -59,7 +59,7 @@ import { requiredClientCapabilitiesForInputRequest, SdkError, SdkErrorCode -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims'; /** diff --git a/packages/server/src/server/serverEventBus.ts b/packages/server/src/server/serverEventBus.ts index 20575a7455..3f97f62309 100644 --- a/packages/server/src/server/serverEventBus.ts +++ b/packages/server/src/server/serverEventBus.ts @@ -1,4 +1,4 @@ -import type { ServerCapabilities, SubscriptionFilter } from '@modelcontextprotocol/core'; +import type { ServerCapabilities, SubscriptionFilter } from '@modelcontextprotocol/core-internal'; /** * A change event a server publishes for delivery on open `subscriptions/listen` diff --git a/packages/server/src/server/stdio.examples.ts b/packages/server/src/server/stdio.examples.ts index de4603eaa7..6b51203b3b 100644 --- a/packages/server/src/server/stdio.examples.ts +++ b/packages/server/src/server/stdio.examples.ts @@ -7,8 +7,8 @@ * @module */ -import { McpServer } from './mcp.js'; -import { StdioServerTransport } from './stdio.js'; +import { McpServer } from './mcp'; +import { StdioServerTransport } from './stdio'; /** * Example: Basic stdio transport usage. diff --git a/packages/server/src/server/stdio.ts b/packages/server/src/server/stdio.ts index a790fc75a4..e8fda03257 100644 --- a/packages/server/src/server/stdio.ts +++ b/packages/server/src/server/stdio.ts @@ -1,7 +1,7 @@ import type { Readable, Writable } from 'node:stream'; -import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core'; -import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal'; +import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/core-internal'; import { process } from '@modelcontextprotocol/server/_shims'; /** diff --git a/packages/server/src/server/streamableHttp.examples.ts b/packages/server/src/server/streamableHttp.examples.ts index a805c1dcee..678c43c928 100644 --- a/packages/server/src/server/streamableHttp.examples.ts +++ b/packages/server/src/server/streamableHttp.examples.ts @@ -7,8 +7,8 @@ * @module */ -import { McpServer } from './mcp.js'; -import { WebStandardStreamableHTTPServerTransport } from './streamableHttp.js'; +import { McpServer } from './mcp'; +import { WebStandardStreamableHTTPServerTransport } from './streamableHttp'; /** * Example: Stateful Streamable HTTP transport (Web Standard). diff --git a/packages/server/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts index c63ab6e7e2..1f2cf94b00 100644 --- a/packages/server/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -7,7 +7,7 @@ * For Node.js Express/HTTP compatibility, use {@linkcode @modelcontextprotocol/node!NodeStreamableHTTPServerTransport | NodeStreamableHTTPServerTransport} which wraps this transport. */ -import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, RequestId, Transport } from '@modelcontextprotocol/core'; +import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, RequestId, Transport } from '@modelcontextprotocol/core-internal'; import { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, isInitializeRequest, @@ -16,7 +16,7 @@ import { isJSONRPCResultResponse, JSONRPCMessageSchema, SUPPORTED_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; export type StreamId = string; export type EventId = string; diff --git a/packages/server/src/shimsNode.ts b/packages/server/src/shimsNode.ts index 9354850b6e..6ec703659a 100644 --- a/packages/server/src/shimsNode.ts +++ b/packages/server/src/shimsNode.ts @@ -3,5 +3,5 @@ * * This file is selected via package.json export conditions when running in Node.js. */ -export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv'; +export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/ajv'; export { default as process } from 'node:process'; diff --git a/packages/server/src/shimsWorkerd.ts b/packages/server/src/shimsWorkerd.ts index dc23da8080..92e3bf0f17 100644 --- a/packages/server/src/shimsWorkerd.ts +++ b/packages/server/src/shimsWorkerd.ts @@ -3,7 +3,7 @@ * * This file is selected via package.json export conditions when running in workerd. */ -export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +export { CfWorkerJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; /** * Stub process object for non-Node.js environments. diff --git a/packages/server/src/stdio.ts b/packages/server/src/stdio.ts index deaa8468db..1d38a61a0d 100644 --- a/packages/server/src/stdio.ts +++ b/packages/server/src/stdio.ts @@ -6,6 +6,6 @@ // subpath gives consumers a consistent shape across packages. Import from // `@modelcontextprotocol/server/stdio` only in process-stdio runtimes (Node.js, Bun, Deno). -export type { ServeStdioOptions, StdioServerHandle } from './server/serveStdio.js'; -export { serveStdio } from './server/serveStdio.js'; -export { StdioServerTransport } from './server/stdio.js'; +export type { ServeStdioOptions, StdioServerHandle } from './server/serveStdio'; +export { serveStdio } from './server/serveStdio'; +export { StdioServerTransport } from './server/stdio'; diff --git a/packages/server/src/validators/ajv.ts b/packages/server/src/validators/ajv.ts index 31f0fed3b3..8bd1a78a8d 100644 --- a/packages/server/src/validators/ajv.ts +++ b/packages/server/src/validators/ajv.ts @@ -11,4 +11,4 @@ * const validator = new AjvJsonSchemaValidator(ajv); * ``` */ -export { addFormats, Ajv, AjvJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv'; +export { addFormats, Ajv, AjvJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/ajv'; diff --git a/packages/server/src/validators/cfWorker.ts b/packages/server/src/validators/cfWorker.ts index 2969b4dc9d..f1d9379afc 100644 --- a/packages/server/src/validators/cfWorker.ts +++ b/packages/server/src/validators/cfWorker.ts @@ -1,3 +1,3 @@ /** Customisation entry point for the `@cfworker/json-schema` validator. */ -export type { CfWorkerSchemaDraft } from '@modelcontextprotocol/core/validators/cfWorker'; -export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +export type { CfWorkerSchemaDraft } from '@modelcontextprotocol/core-internal/validators/cfWorker'; +export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; diff --git a/packages/server/test/server/cacheHints.test.ts b/packages/server/test/server/cacheHints.test.ts index d865062bf6..ac1579e070 100644 --- a/packages/server/test/server/cacheHints.test.ts +++ b/packages/server/test/server/cacheHints.test.ts @@ -9,21 +9,21 @@ * `{ ttlMs: 0, cacheScope: 'private' }`, * - and the era boundary: 2025-era responses never gain any of it. */ -import type { JSONRPCMessage, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, InMemoryTransport, PROTOCOL_VERSION_META_KEY, setNegotiatedProtocolVersion -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { invoke } from '../../src/server/invoke.js'; -import { McpServer, ResourceTemplate } from '../../src/server/mcp.js'; -import type { ServerOptions } from '../../src/server/server.js'; -import { installModernOnlyHandlers, Server } from '../../src/server/server.js'; +import { invoke } from '../../src/server/invoke'; +import { McpServer, ResourceTemplate } from '../../src/server/mcp'; +import type { ServerOptions } from '../../src/server/server'; +import { installModernOnlyHandlers, Server } from '../../src/server/server'; const MODERN_REVISION = '2026-07-28'; const MODERN: MessageClassification = { era: 'modern', revision: MODERN_REVISION }; diff --git a/packages/server/test/server/classificationCarrierPin.test.ts b/packages/server/test/server/classificationCarrierPin.test.ts index 00e135dd0f..4694f65abb 100644 --- a/packages/server/test/server/classificationCarrierPin.test.ts +++ b/packages/server/test/server/classificationCarrierPin.test.ts @@ -11,12 +11,12 @@ * claim where the envelope does not participate (the reserved keys are lifted * from `_meta`, exactly as for any legacy request carrying them). */ -import type { MessageExtraInfo } from '@modelcontextprotocol/core'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import type { MessageExtraInfo } from '@modelcontextprotocol/core-internal'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Server } from '../../src/server/server.js'; -import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { Server } from '../../src/server/server'; +import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp'; const MODERN = '2026-07-28'; diff --git a/packages/server/test/server/completable.test.ts b/packages/server/test/server/completable.test.ts index 9dfa7b42ba..79dc576f1d 100644 --- a/packages/server/test/server/completable.test.ts +++ b/packages/server/test/server/completable.test.ts @@ -1,7 +1,7 @@ import * as z from 'zod/v4'; import { describe, expect, it } from 'vitest'; -import { completable, getCompleter } from '../../src/server/completable.js'; +import { completable, getCompleter } from '../../src/server/completable'; describe('completable with Zod v4', () => { it('preserves types and values of underlying schema', () => { diff --git a/packages/server/test/server/createMcpHandler.test.ts b/packages/server/test/server/createMcpHandler.test.ts index fca9ac41ab..f3237221e0 100644 --- a/packages/server/test/server/createMcpHandler.test.ts +++ b/packages/server/test/server/createMcpHandler.test.ts @@ -7,14 +7,14 @@ * faces, the per-request era write + client-identity backfill, notification * routing, the response-mode knob, and close() teardown of the modern leg. */ -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import type { McpRequestContext } from '../../src/server/createMcpHandler.js'; -import { createMcpHandler, isLegacyRequest } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport.js'; +import type { McpRequestContext } from '../../src/server/createMcpHandler'; +import { createMcpHandler, isLegacyRequest } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; +import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport'; const MODERN_REVISION = '2026-07-28'; diff --git a/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts b/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts index 38d3463919..e6b6bad4e6 100644 --- a/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts +++ b/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts @@ -9,18 +9,18 @@ * temporary entry to the requirement table; the production behavior with the * empty table — every modern request passes the gate — is pinned too. */ -import type { ClientCapabilities } from '@modelcontextprotocol/core'; +import type { ClientCapabilities } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY, REQUIRED_CLIENT_CAPABILITIES_BY_METHOD -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { afterEach, describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { createMcpHandler } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { createMcpHandler } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; const MODERN_REVISION = '2026-07-28'; diff --git a/packages/server/test/server/createMcpHandlerListen.test.ts b/packages/server/test/server/createMcpHandlerListen.test.ts index 2dd3fa372c..46eec5fde0 100644 --- a/packages/server/test/server/createMcpHandlerListen.test.ts +++ b/packages/server/test/server/createMcpHandlerListen.test.ts @@ -12,11 +12,11 @@ import { CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY, SUBSCRIPTION_ID_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { createMcpHandler } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { createMcpHandler } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; const ENVELOPE = { [PROTOCOL_VERSION_META_KEY]: '2026-07-28', diff --git a/packages/server/test/server/createMcpHandlerStatelessLiteral.test.ts b/packages/server/test/server/createMcpHandlerStatelessLiteral.test.ts index 4aac72549e..bba2a3c959 100644 --- a/packages/server/test/server/createMcpHandlerStatelessLiteral.test.ts +++ b/packages/server/test/server/createMcpHandlerStatelessLiteral.test.ts @@ -10,12 +10,12 @@ * code -32000, and the literal substring `Unsupported protocol version`, with * the supported-versions suffix derived from `SUPPORTED_PROTOCOL_VERSIONS`. */ -import { SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core'; +import { SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { createMcpHandler } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { createMcpHandler } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; interface JSONRPCErrorBody { jsonrpc: string; diff --git a/packages/server/test/server/discover.test.ts b/packages/server/test/server/discover.test.ts index f4bdbc27c6..d1f1db73f6 100644 --- a/packages/server/test/server/discover.test.ts +++ b/packages/server/test/server/discover.test.ts @@ -19,7 +19,7 @@ * package-internal hook the entry will use, and the modern-era request shape * carries the required per-request `_meta` envelope. */ -import type { DiscoverResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core'; +import type { DiscoverResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, @@ -32,10 +32,10 @@ import { PROTOCOL_VERSION_META_KEY, setNegotiatedProtocolVersion, SUPPORTED_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { discoverAdvertisedCapabilities, Server } from '../../src/server/server.js'; +import { discoverAdvertisedCapabilities, Server } from '../../src/server/server'; const MODERN = '2026-07-28'; /** A supported list spanning both eras — what the constant becomes after a future bump. */ diff --git a/packages/server/test/server/eraParityErrorShapes.test.ts b/packages/server/test/server/eraParityErrorShapes.test.ts index a87b5b9b6e..19d0ce8b5e 100644 --- a/packages/server/test/server/eraParityErrorShapes.test.ts +++ b/packages/server/test/server/eraParityErrorShapes.test.ts @@ -5,7 +5,7 @@ * enumerated table of era-mandated differences. Anything outside that table * is a parity regression. */ -import type { CallToolResult, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core'; +import type { CallToolResult, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core-internal'; import { classifyInboundRequest, CLIENT_CAPABILITIES_META_KEY, @@ -13,13 +13,13 @@ import { PROTOCOL_VERSION_META_KEY, ProtocolError, setNegotiatedProtocolVersion -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport.js'; -import { Server } from '../../src/server/server.js'; -import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport'; +import { Server } from '../../src/server/server'; +import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp'; const MODERN_REVISION = '2026-07-28'; const MODERN: MessageClassification = { era: 'modern', revision: MODERN_REVISION }; diff --git a/packages/server/test/server/inputRequired.test.ts b/packages/server/test/server/inputRequired.test.ts index efce872842..ab6895abfe 100644 --- a/packages/server/test/server/inputRequired.test.ts +++ b/packages/server/test/server/inputRequired.test.ts @@ -26,7 +26,7 @@ import type { JSONRPCNotification, JSONRPCRequest, JSONRPCResultResponse -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { acceptedContent, CLIENT_CAPABILITIES_META_KEY, @@ -37,13 +37,13 @@ import { PROTOCOL_VERSION_META_KEY, setNegotiatedProtocolVersion, UrlElicitationRequiredError -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import { McpServer } from '../../src/server/mcp.js'; -import type { ServerOptions } from '../../src/server/server.js'; -import { Server } from '../../src/server/server.js'; +import { McpServer } from '../../src/server/mcp'; +import type { ServerOptions } from '../../src/server/server'; +import { Server } from '../../src/server/server'; const MODERN = '2026-07-28'; diff --git a/packages/server/test/server/invokeSeam.test.ts b/packages/server/test/server/invokeSeam.test.ts index 764bd99518..b1f35e33cb 100644 --- a/packages/server/test/server/invokeSeam.test.ts +++ b/packages/server/test/server/invokeSeam.test.ts @@ -7,19 +7,19 @@ * negotiated-version hook, standing in for the HTTP entry that will own that * write in production. */ -import type { JSONRPCNotification, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core'; +import type { JSONRPCNotification, JSONRPCRequest, MessageClassification } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY, setNegotiatedProtocolVersion -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { invoke } from '../../src/server/invoke.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { Server } from '../../src/server/server.js'; +import { invoke } from '../../src/server/invoke'; +import { McpServer } from '../../src/server/mcp'; +import { Server } from '../../src/server/server'; const MODERN_REVISION = '2026-07-28'; const MODERN: MessageClassification = { era: 'modern', revision: MODERN_REVISION }; diff --git a/packages/server/test/server/jsonSchemaValidatorOverride.test.ts b/packages/server/test/server/jsonSchemaValidatorOverride.test.ts index 729111d9a8..e5edf18398 100644 --- a/packages/server/test/server/jsonSchemaValidatorOverride.test.ts +++ b/packages/server/test/server/jsonSchemaValidatorOverride.test.ts @@ -1,7 +1,7 @@ -import type { JsonSchemaType, JsonSchemaValidatorResult, jsonSchemaValidator } from '@modelcontextprotocol/core'; -import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; -import { fromJsonSchema } from '../../src/fromJsonSchema.js'; -import { Server } from '../../src/server/server.js'; +import type { JsonSchemaType, JsonSchemaValidatorResult, jsonSchemaValidator } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; +import { fromJsonSchema } from '../../src/fromJsonSchema'; +import { Server } from '../../src/server/server'; class RecordingValidator implements jsonSchemaValidator { schemas: JsonSchemaType[] = []; diff --git a/packages/server/test/server/legacyDefaultServing.test.ts b/packages/server/test/server/legacyDefaultServing.test.ts index 877349894c..2d7d8d7560 100644 --- a/packages/server/test/server/legacyDefaultServing.test.ts +++ b/packages/server/test/server/legacyDefaultServing.test.ts @@ -7,12 +7,17 @@ * serving the 2026-07-28 revision on stdio goes through the `serveStdio` * entry (covered in `serveStdio.test.ts`). */ -import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest } from '@modelcontextprotocol/core'; -import { InMemoryTransport, isJSONRPCErrorResponse, isJSONRPCResultResponse, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest } from '@modelcontextprotocol/core-internal'; +import { + InMemoryTransport, + isJSONRPCErrorResponse, + isJSONRPCResultResponse, + LATEST_PROTOCOL_VERSION +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { McpServer } from '../../src/server/mcp.js'; +import { McpServer } from '../../src/server/mcp'; function buildServer() { const server = new McpServer( diff --git a/packages/server/test/server/legacyStatelessFallback.test.ts b/packages/server/test/server/legacyStatelessFallback.test.ts index a125168c78..50247ae6ab 100644 --- a/packages/server/test/server/legacyStatelessFallback.test.ts +++ b/packages/server/test/server/legacyStatelessFallback.test.ts @@ -6,9 +6,9 @@ import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import type { McpRequestContext } from '../../src/server/createMcpHandler.js'; -import { legacyStatelessFallback } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import type { McpRequestContext } from '../../src/server/createMcpHandler'; +import { legacyStatelessFallback } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; interface JSONRPCErrorBody { jsonrpc: string; diff --git a/packages/server/test/server/listOrdering.test.ts b/packages/server/test/server/listOrdering.test.ts index d5c793453e..f7ad16aa38 100644 --- a/packages/server/test/server/listOrdering.test.ts +++ b/packages/server/test/server/listOrdering.test.ts @@ -10,8 +10,8 @@ import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { invoke } from '../../src/server/invoke.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { invoke } from '../../src/server/invoke'; +import { McpServer } from '../../src/server/mcp'; const LEGACY = { classification: { era: 'legacy' as const } }; diff --git a/packages/server/test/server/lowLevelLegacyWrap.test.ts b/packages/server/test/server/lowLevelLegacyWrap.test.ts index 121057b4dc..286669d7a4 100644 --- a/packages/server/test/server/lowLevelLegacyWrap.test.ts +++ b/packages/server/test/server/lowLevelLegacyWrap.test.ts @@ -7,11 +7,11 @@ * structured content. Nothing in `mcp.ts` (or any server-side code) re-derives * the wrap — the only era branch is the codec. */ -import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest } from '@modelcontextprotocol/core'; -import { InMemoryTransport, isJSONRPCResultResponse, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, isJSONRPCResultResponse, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { Server } from '../../src/server/server.js'; +import { Server } from '../../src/server/server'; async function wire(server: Server) { const [peerTx, serverTx] = InMemoryTransport.createLinkedPair(); diff --git a/packages/server/test/server/mcp.compat.test.ts b/packages/server/test/server/mcp.compat.test.ts index 9adb866ff9..ae7a0438b5 100644 --- a/packages/server/test/server/mcp.compat.test.ts +++ b/packages/server/test/server/mcp.compat.test.ts @@ -1,10 +1,10 @@ -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; -import { InMemoryTransport, isStandardSchema, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, isStandardSchema, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; import { describe, expect, expectTypeOf, it, vi } from 'vitest'; import * as z from 'zod/v4'; -import { McpServer } from '../../src/index.js'; -import type { InferRawShape } from '../../src/server/mcp.js'; -import { completable } from '../../src/server/completable.js'; +import { McpServer } from '../../src/index'; +import type { InferRawShape } from '../../src/server/mcp'; +import { completable } from '../../src/server/completable'; describe('registerTool/registerPrompt accept raw Zod shape (auto-wrapped)', () => { it('registerTool accepts a raw shape for inputSchema and auto-wraps it', () => { diff --git a/packages/server/test/server/mcp.icons.test.ts b/packages/server/test/server/mcp.icons.test.ts index 42aba4fdd4..168a6977c0 100644 --- a/packages/server/test/server/mcp.icons.test.ts +++ b/packages/server/test/server/mcp.icons.test.ts @@ -1,7 +1,7 @@ -import type { Icon, JSONRPCMessage } from '@modelcontextprotocol/core'; -import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core'; +import type { Icon, JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; -import { McpServer, ResourceTemplate } from '../../src/index.js'; +import { McpServer, ResourceTemplate } from '../../src/index'; const ICONS: Icon[] = [ { src: 'https://example.com/icon.png', mimeType: 'image/png', sizes: ['48x48', '96x96'] }, diff --git a/packages/server/test/server/mcpParamValidation.test.ts b/packages/server/test/server/mcpParamValidation.test.ts index 0b8b02158a..531edf05b0 100644 --- a/packages/server/test/server/mcpParamValidation.test.ts +++ b/packages/server/test/server/mcpParamValidation.test.ts @@ -15,12 +15,12 @@ import { CLIENT_INFO_META_KEY, encodeMcpParamValue, PROTOCOL_VERSION_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; -import { fromJsonSchema } from '../../src/fromJsonSchema.js'; -import { createMcpHandler } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { fromJsonSchema } from '../../src/fromJsonSchema'; +import { createMcpHandler } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; const MODERN = '2026-07-28'; const ENVELOPE = { diff --git a/packages/server/test/server/originValidation.test.ts b/packages/server/test/server/originValidation.test.ts index e0a3d4ab43..e76a2f5c3f 100644 --- a/packages/server/test/server/originValidation.test.ts +++ b/packages/server/test/server/originValidation.test.ts @@ -4,7 +4,7 @@ */ import { describe, expect, it } from 'vitest'; -import { localhostAllowedOrigins, originValidationResponse, validateOriginHeader } from '../../src/server/middleware/originValidation.js'; +import { localhostAllowedOrigins, originValidationResponse, validateOriginHeader } from '../../src/server/middleware/originValidation'; describe('validateOriginHeader', () => { it('passes when no Origin header is present (non-browser clients)', () => { diff --git a/packages/server/test/server/perRequestStreaming.test.ts b/packages/server/test/server/perRequestStreaming.test.ts index ba56b6e543..6d350ed2ef 100644 --- a/packages/server/test/server/perRequestStreaming.test.ts +++ b/packages/server/test/server/perRequestStreaming.test.ts @@ -4,18 +4,18 @@ * forced response modes the entry-level knob will plug into, comment-frame * support, and disconnect-as-cancellation. */ -import type { CallToolResult, JSONRPCRequest, MessageClassification, ServerContext } from '@modelcontextprotocol/core'; +import type { CallToolResult, JSONRPCRequest, MessageClassification, ServerContext } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY, setNegotiatedProtocolVersion -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import type { PerRequestResponseMode } from '../../src/server/perRequestTransport.js'; -import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport.js'; -import { Server } from '../../src/server/server.js'; +import type { PerRequestResponseMode } from '../../src/server/perRequestTransport'; +import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport'; +import { Server } from '../../src/server/server'; const MODERN_REVISION = '2026-07-28'; const MODERN: MessageClassification = { era: 'modern', revision: MODERN_REVISION }; diff --git a/packages/server/test/server/perRequestTransport.test.ts b/packages/server/test/server/perRequestTransport.test.ts index 69a9088d7f..035e81b83b 100644 --- a/packages/server/test/server/perRequestTransport.test.ts +++ b/packages/server/test/server/perRequestTransport.test.ts @@ -4,7 +4,13 @@ * pre-handler rejections, auth-info pass-through, and the close/teardown * chain. */ -import type { CallToolResult, JSONRPCNotification, JSONRPCRequest, MessageClassification, ServerContext } from '@modelcontextprotocol/core'; +import type { + CallToolResult, + JSONRPCNotification, + JSONRPCRequest, + MessageClassification, + ServerContext +} from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, @@ -13,12 +19,12 @@ import { SdkError, SdkErrorCode, setNegotiatedProtocolVersion -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport.js'; -import { Server } from '../../src/server/server.js'; +import { PerRequestHTTPServerTransport } from '../../src/server/perRequestTransport'; +import { Server } from '../../src/server/server'; const MODERN_REVISION = '2026-07-28'; const MODERN: MessageClassification = { era: 'modern', revision: MODERN_REVISION }; diff --git a/packages/server/test/server/requestStateCodec.test.ts b/packages/server/test/server/requestStateCodec.test.ts index bc823c6690..d29b763e7d 100644 --- a/packages/server/test/server/requestStateCodec.test.ts +++ b/packages/server/test/server/requestStateCodec.test.ts @@ -4,11 +4,11 @@ * the seam-level wiring (`ServerOptions.requestState.verify`) is covered in * `inputRequired.test.ts`. */ -import type { ServerContext } from '@modelcontextprotocol/core'; +import type { ServerContext } from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; -import { createRequestStateCodec } from '../../src/server/requestStateCodec.js'; -import type { ServerOptions } from '../../src/server/server.js'; +import { createRequestStateCodec } from '../../src/server/requestStateCodec'; +import type { ServerOptions } from '../../src/server/server'; const KEY = crypto.getRandomValues(new Uint8Array(32)); diff --git a/packages/server/test/server/serveStdio.test.ts b/packages/server/test/server/serveStdio.test.ts index aced8d3b9f..a207a32bd2 100644 --- a/packages/server/test/server/serveStdio.test.ts +++ b/packages/server/test/server/serveStdio.test.ts @@ -27,7 +27,7 @@ import type { JSONRPCRequest, MessageExtraInfo, Transport -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, @@ -38,14 +38,14 @@ import { PROTOCOL_VERSION_META_KEY, SdkError, SdkErrorCode -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import type { McpServerFactory } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; -import type { ServeStdioOptions } from '../../src/server/serveStdio.js'; -import { serveStdio } from '../../src/server/serveStdio.js'; +import type { McpServerFactory } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; +import type { ServeStdioOptions } from '../../src/server/serveStdio'; +import { serveStdio } from '../../src/server/serveStdio'; const MODERN = '2026-07-28'; diff --git a/packages/server/test/server/serveStdioListen.test.ts b/packages/server/test/server/serveStdioListen.test.ts index af5e15c6ca..0edb634398 100644 --- a/packages/server/test/server/serveStdioListen.test.ts +++ b/packages/server/test/server/serveStdioListen.test.ts @@ -7,20 +7,20 @@ * graceful-close path (one empty `subscriptions/listen` result per * subscription id on `handle.close()`). */ -import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest, Transport } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest, Transport } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, InMemoryTransport, PROTOCOL_VERSION_META_KEY, SUBSCRIPTION_ID_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { StdioListenRouter } from '../../src/server/listenRouter.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { serveStdio } from '../../src/server/serveStdio.js'; +import { StdioListenRouter } from '../../src/server/listenRouter'; +import { McpServer } from '../../src/server/mcp'; +import { serveStdio } from '../../src/server/serveStdio'; const ENVELOPE = { [PROTOCOL_VERSION_META_KEY]: '2026-07-28', diff --git a/packages/server/test/server/server.test.ts b/packages/server/test/server/server.test.ts index 057bcfcbd9..f6c40602ae 100644 --- a/packages/server/test/server/server.test.ts +++ b/packages/server/test/server/server.test.ts @@ -1,12 +1,12 @@ -import type { CallToolResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core'; +import type { CallToolResult, JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/core-internal'; import { InitializeResultSchema, InMemoryTransport, isJSONRPCResultResponse, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; -import { Server } from '../../src/server/server.js'; +} from '@modelcontextprotocol/core-internal'; +import { Server } from '../../src/server/server'; /** An older protocol version the server supports out of the box. */ const OLDER_SUPPORTED_VERSION = '2025-03-26'; diff --git a/packages/server/test/server/serverEventBus.test.ts b/packages/server/test/server/serverEventBus.test.ts index 6f9feb1d7b..0c42974d9d 100644 --- a/packages/server/test/server/serverEventBus.test.ts +++ b/packages/server/test/server/serverEventBus.test.ts @@ -6,7 +6,7 @@ import { honoredSubset, listenFilterAccepts, serverEventToNotification -} from '../../src/server/serverEventBus.js'; +} from '../../src/server/serverEventBus'; describe('listenFilterAccepts', () => { it('accepts only the change types the filter explicitly opted in to', () => { diff --git a/packages/server/test/server/stdHeaderValidation.test.ts b/packages/server/test/server/stdHeaderValidation.test.ts index 3c7f9238ac..21b491f90a 100644 --- a/packages/server/test/server/stdHeaderValidation.test.ts +++ b/packages/server/test/server/stdHeaderValidation.test.ts @@ -18,12 +18,12 @@ import { CLIENT_INFO_META_KEY, encodeMcpParamValue, PROTOCOL_VERSION_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; -import { createMcpHandler } from '../../src/server/createMcpHandler.js'; -import { McpServer } from '../../src/server/mcp.js'; +import { createMcpHandler } from '../../src/server/createMcpHandler'; +import { McpServer } from '../../src/server/mcp'; const MODERN = '2026-07-28'; const ENVELOPE = { diff --git a/packages/server/test/server/stdio.test.ts b/packages/server/test/server/stdio.test.ts index be52951688..fe79e3679c 100644 --- a/packages/server/test/server/stdio.test.ts +++ b/packages/server/test/server/stdio.test.ts @@ -1,9 +1,9 @@ import { Readable, Writable } from 'node:stream'; -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; -import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/core-internal'; -import { StdioServerTransport } from '../../src/server/stdio.js'; +import { StdioServerTransport } from '../../src/server/stdio'; let input: Readable; let outputBuffer: ReadBuffer; diff --git a/packages/server/test/server/streamableHttp.test.ts b/packages/server/test/server/streamableHttp.test.ts index b95e8bafd1..beca451113 100644 --- a/packages/server/test/server/streamableHttp.test.ts +++ b/packages/server/test/server/streamableHttp.test.ts @@ -1,11 +1,11 @@ import { randomUUID } from 'node:crypto'; -import type { CallToolResult, JSONRPCErrorResponse, JSONRPCMessage } from '@modelcontextprotocol/core'; +import type { CallToolResult, JSONRPCErrorResponse, JSONRPCMessage } from '@modelcontextprotocol/core-internal'; import * as z from 'zod/v4'; -import { McpServer } from '../../src/server/mcp.js'; -import type { EventId, EventStore, StreamId } from '../../src/server/streamableHttp.js'; -import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { McpServer } from '../../src/server/mcp'; +import type { EventId, EventStore, StreamId } from '../../src/server/streamableHttp'; +import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp'; /** * Common test messages diff --git a/packages/server/test/server/streamableHttpFutureVersionGates.test.ts b/packages/server/test/server/streamableHttpFutureVersionGates.test.ts index ef1670444d..4abf9fb74d 100644 --- a/packages/server/test/server/streamableHttpFutureVersionGates.test.ts +++ b/packages/server/test/server/streamableHttpFutureVersionGates.test.ts @@ -1,10 +1,10 @@ import { randomUUID } from 'node:crypto'; -import type { JSONRPCMessage, MessageExtraInfo } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage, MessageExtraInfo } from '@modelcontextprotocol/core-internal'; -import { McpServer } from '../../src/server/mcp.js'; -import type { EventId, EventStore, StreamId } from '../../src/server/streamableHttp.js'; -import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { McpServer } from '../../src/server/mcp'; +import type { EventId, EventStore, StreamId } from '../../src/server/streamableHttp'; +import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp'; /** * Gate-closure tests for the two protocol-version checks that guard diff --git a/packages/server/test/server/streamableHttpUnsupportedVersionLiteral.test.ts b/packages/server/test/server/streamableHttpUnsupportedVersionLiteral.test.ts index a797d90eb4..d44cc642dc 100644 --- a/packages/server/test/server/streamableHttpUnsupportedVersionLiteral.test.ts +++ b/packages/server/test/server/streamableHttpUnsupportedVersionLiteral.test.ts @@ -1,10 +1,10 @@ import { randomUUID } from 'node:crypto'; -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; -import { SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; +import { SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core-internal'; -import { McpServer } from '../../src/server/mcp.js'; -import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { McpServer } from '../../src/server/mcp'; +import { WebStandardStreamableHTTPServerTransport } from '../../src/server/streamableHttp'; /** * Wire-level continuity tests for the "Unsupported protocol version" rejection. diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 24da6e426d..2d8ef8ed15 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -5,11 +5,15 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], - "@modelcontextprotocol/core/validators/ajv": ["./node_modules/@modelcontextprotocol/core/src/validators/ajvProvider.ts"], - "@modelcontextprotocol/core/validators/cfWorker": [ - "./node_modules/@modelcontextprotocol/core/src/validators/cfWorkerProvider.ts" + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], + "@modelcontextprotocol/core-internal/validators/ajv": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/ajvProvider.ts" + ], + "@modelcontextprotocol/core-internal/validators/cfWorker": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/cfWorkerProvider.ts" ], "@modelcontextprotocol/test-helpers": ["./node_modules/@modelcontextprotocol/test-helpers/src/index.ts"], "@modelcontextprotocol/server/_shims": ["./src/shimsNode.ts"] diff --git a/packages/server/tsdown.config.ts b/packages/server/tsdown.config.ts index 891ce49641..9908a6e730 100644 --- a/packages/server/tsdown.config.ts +++ b/packages/server/tsdown.config.ts @@ -23,13 +23,13 @@ export default defineConfig({ compilerOptions: { baseUrl: '.', paths: { - '@modelcontextprotocol/core': ['../core/src/index.ts'], - '@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts'], - '@modelcontextprotocol/core/validators/ajv': ['../core/src/validators/ajvProvider.ts'], - '@modelcontextprotocol/core/validators/cfWorker': ['../core/src/validators/cfWorkerProvider.ts'] + '@modelcontextprotocol/core-internal': ['../core-internal/src/index.ts'], + '@modelcontextprotocol/core-internal/public': ['../core-internal/src/exports/public/index.ts'], + '@modelcontextprotocol/core-internal/validators/ajv': ['../core-internal/src/validators/ajvProvider.ts'], + '@modelcontextprotocol/core-internal/validators/cfWorker': ['../core-internal/src/validators/cfWorkerProvider.ts'] } } }, - noExternal: ['@modelcontextprotocol/core', 'ajv', 'ajv-formats', '@cfworker/json-schema'], + noExternal: ['@modelcontextprotocol/core-internal', 'ajv', 'ajv-formats', '@cfworker/json-schema'], external: ['@modelcontextprotocol/server/_shims'] }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a07299bb56..fa3afea05a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -413,6 +413,9 @@ importers: specifier: workspace:^ version: link:../../packages/client devDependencies: + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig '@types/node': specifier: ^24.10.1 version: 24.12.0 @@ -876,6 +879,9 @@ importers: specifier: catalog:runtimeShared version: 4.3.6 devDependencies: + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig '@types/node': specifier: ^24.10.1 version: 24.12.0 @@ -885,9 +891,6 @@ importers: examples/shared: dependencies: - '@modelcontextprotocol/core': - specifier: workspace:^ - version: link:../../packages/core '@modelcontextprotocol/express': specifier: workspace:^ version: link:../../packages/middleware/express @@ -946,9 +949,6 @@ importers: prettier: specifier: catalog:devTools version: 3.6.2 - tsx: - specifier: catalog:devTools - version: 4.21.0 typescript: specifier: catalog:devTools version: 5.9.3 @@ -1152,9 +1152,9 @@ importers: '@eslint/js': specifier: catalog:devTools version: 9.39.4 - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../core + version: link:../core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1200,9 +1200,6 @@ importers: tsdown: specifier: catalog:devTools version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@5.9.3) - tsx: - specifier: catalog:devTools - version: 4.21.0 typescript: specifier: catalog:devTools version: 5.9.3 @@ -1266,6 +1263,55 @@ importers: version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(vite@7.3.0(@types/node@25.5.0)(tsx@4.21.0)(yaml@2.8.3)) packages/core: + dependencies: + zod: + specifier: catalog:runtimeShared + version: 4.3.6 + devDependencies: + '@eslint/js': + specifier: catalog:devTools + version: 9.39.4 + '@modelcontextprotocol/core-internal': + specifier: workspace:^ + version: link:../core-internal + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + '@typescript/native-preview': + specifier: catalog:devTools + version: 7.0.0-dev.20260327.2 + eslint: + specifier: catalog:devTools + version: 9.39.4 + eslint-config-prettier: + specifier: catalog:devTools + version: 10.1.8(eslint@9.39.4) + eslint-plugin-n: + specifier: catalog:devTools + version: 17.24.0(eslint@9.39.4)(typescript@5.9.3) + prettier: + specifier: catalog:devTools + version: 3.6.2 + tsdown: + specifier: catalog:devTools + version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@5.9.3) + typescript: + specifier: catalog:devTools + version: 5.9.3 + typescript-eslint: + specifier: catalog:devTools + version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) + vitest: + specifier: catalog:devTools + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(vite@7.3.0(@types/node@25.5.0)(tsx@4.21.0)(yaml@2.8.3)) + + packages/core-internal: dependencies: json-schema-typed: specifier: catalog:runtimeShared @@ -1328,9 +1374,6 @@ importers: prettier: specifier: catalog:devTools version: 3.6.2 - tsx: - specifier: catalog:devTools - version: 4.21.0 typescript: specifier: catalog:devTools version: 5.9.3 @@ -1518,9 +1561,9 @@ importers: '@eslint/js': specifier: catalog:devTools version: 9.39.4 - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../../core + version: link:../../core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../../common/eslint-config @@ -1554,9 +1597,6 @@ importers: tsdown: specifier: catalog:devTools version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@5.9.3) - tsx: - specifier: catalog:devTools - version: 4.21.0 typescript: specifier: catalog:devTools version: 5.9.3 @@ -1579,9 +1619,9 @@ importers: '@eslint/js': specifier: catalog:devTools version: 9.39.4 - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../core + version: link:../core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1624,9 +1664,6 @@ importers: tsdown: specifier: catalog:devTools version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@5.9.3) - tsx: - specifier: catalog:devTools - version: 4.21.0 typescript: specifier: catalog:devTools version: 5.9.3 @@ -1664,9 +1701,9 @@ importers: '@eslint/js': specifier: catalog:devTools version: 9.39.4 - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../core + version: link:../core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1730,9 +1767,9 @@ importers: '@modelcontextprotocol/conformance': specifier: 0.2.0-alpha.7 version: 0.2.0-alpha.7(@cfworker/json-schema@4.1.1) - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../../packages/core + version: link:../../packages/core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1775,9 +1812,9 @@ importers: '@modelcontextprotocol/client': specifier: workspace:^ version: link:../../packages/client - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../../packages/core + version: link:../../packages/core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1853,9 +1890,9 @@ importers: test/helpers: devDependencies: - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../../packages/core + version: link:../../packages/core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config @@ -1880,9 +1917,9 @@ importers: '@modelcontextprotocol/client': specifier: workspace:^ version: link:../../packages/client - '@modelcontextprotocol/core': + '@modelcontextprotocol/core-internal': specifier: workspace:^ - version: link:../../packages/core + version: link:../../packages/core-internal '@modelcontextprotocol/eslint-config': specifier: workspace:^ version: link:../../common/eslint-config diff --git a/scripts/cli.ts b/scripts/cli.ts deleted file mode 100644 index 809a23efed..0000000000 --- a/scripts/cli.ts +++ /dev/null @@ -1,155 +0,0 @@ -import express from 'express'; -import { Client } from '../src/client/index.js'; -import { SSEClientTransport } from '../src/client/sse.js'; -import { StdioClientTransport } from '../src/client/stdio.js'; -import { Server } from '../src/server/index.js'; -import { SSEServerTransport } from '../src/server/sse.js'; -import { StdioServerTransport } from '../src/server/stdio.js'; -import { ListResourcesResultSchema } from '../src/types.js'; - -async function runClient(url_or_command: string, args: string[]) { - const client = new Client( - { - name: 'mcp-typescript test client', - version: '0.1.0' - }, - { - capabilities: { - sampling: {} - } - } - ); - - let clientTransport; - - let url: URL | undefined = undefined; - try { - url = new URL(url_or_command); - } catch { - // Ignore - } - - if (url?.protocol === 'http:' || url?.protocol === 'https:') { - clientTransport = new SSEClientTransport(new URL(url_or_command)); - } else if (url?.protocol === 'ws:' || url?.protocol === 'wss:') { - throw new Error('WebSocket URLs are no longer supported. Use http(s) or stdio instead.'); - } else { - clientTransport = new StdioClientTransport({ - command: url_or_command, - args - }); - } - - console.log('Connected to server.'); - - await client.connect(clientTransport); - console.log('Initialized.'); - - await client.request({ method: 'resources/list' }, ListResourcesResultSchema); - - await client.close(); - console.log('Closed.'); -} - -async function runServer(port: number | null) { - if (port !== null) { - const app = express(); - - let servers: Server[] = []; - - app.get('/sse', async (req, res) => { - console.log('Got new SSE connection'); - - const transport = new SSEServerTransport('/message', res); - const server = new Server( - { - name: 'mcp-typescript test server', - version: '0.1.0' - }, - { - capabilities: {} - } - ); - - servers.push(server); - - server.onclose = () => { - console.log('SSE connection closed'); - servers = servers.filter(s => s !== server); - }; - - await server.connect(transport); - }); - - app.post('/message', async (req, res) => { - console.log('Received message'); - - const sessionId = req.query.sessionId as string; - const transport = servers.map(s => s.transport as SSEServerTransport).find(t => t.sessionId === sessionId); - if (!transport) { - res.status(404).send('Session not found'); - return; - } - - await transport.handlePostMessage(req, res); - }); - - app.listen(port, error => { - if (error) { - console.error('Failed to start server:', error); - process.exit(1); - } - console.log(`Server running on http://localhost:${port}/sse`); - }); - } else { - const server = new Server( - { - name: 'mcp-typescript test server', - version: '0.1.0' - }, - { - capabilities: { - prompts: {}, - resources: {}, - tools: {}, - logging: {} - } - } - ); - - const transport = new StdioServerTransport(); - await server.connect(transport); - - console.log('Server running on stdio'); - } -} - -const args = process.argv.slice(2); -const command = args[0]; -switch (command) { - case 'client': - if (args.length < 2) { - console.error('Usage: client [args...]'); - process.exit(1); - } - - runClient(args[1], args.slice(2)).catch(error => { - console.error(error); - process.exit(1); - }); - - break; - - case 'server': { - const port = args[1] ? parseInt(args[1]) : null; - runServer(port).catch(error => { - console.error(error); - process.exit(1); - }); - - break; - } - - default: - console.error('Unrecognized command:', command); -} diff --git a/scripts/fetch-schema-twins.ts b/scripts/fetch-schema-twins.ts index c6464e38b6..d693f45905 100644 --- a/scripts/fetch-schema-twins.ts +++ b/scripts/fetch-schema-twins.ts @@ -1,9 +1,9 @@ /** * Vendors the generated `schema.json` twins from the spec repository into - * `packages/core/test/corpus/schema-twins/` as RAW UPSTREAM BYTES. + * `packages/core-internal/test/corpus/schema-twins/` as RAW UPSTREAM BYTES. * * The twins are TEST-ONLY conformance oracles (never bundled, never runtime): - * `packages/core/test/wire/schemaTwinConformance.test.ts` compiles them into + * `packages/core-internal/test/wire/schemaTwinConformance.test.ts` compiles them into * generated validators and locks the hand-written wire layer to them. Their * authority rests on provenance, so they are vendored verbatim — no * formatting of any kind (the directory is .prettierignore'd) — and each file @@ -11,7 +11,7 @@ * (prettier, an editor, a manual touch-up) turns CI red. * * Refresh ATOMICALLY with the matching spec.types anchor (see - * packages/core/src/types/README.md lifecycle rule 4). + * packages/core-internal/src/types/README.md lifecycle rule 4). * * Usage: * pnpm fetch:schema-twins [sha] # default: the manifest's current source commit @@ -30,7 +30,7 @@ const __filename = fileURLToPath(import.meta.url); const PROJECT_ROOT = join(dirname(__filename), '..'); const SPEC_REPO = 'modelcontextprotocol/modelcontextprotocol'; -const TWINS_DIR = join(PROJECT_ROOT, 'packages', 'core', 'test', 'corpus', 'schema-twins'); +const TWINS_DIR = join(PROJECT_ROOT, 'packages', 'core-internal', 'test', 'corpus', 'schema-twins'); const MANIFEST_PATH = join(TWINS_DIR, 'manifest.json'); interface TwinManifest { diff --git a/scripts/fetch-spec-examples.ts b/scripts/fetch-spec-examples.ts index d20b73eb62..bc279551d9 100644 --- a/scripts/fetch-spec-examples.ts +++ b/scripts/fetch-spec-examples.ts @@ -1,10 +1,10 @@ /** * Vendors the draft-revision (2026-07-28) example corpus from the spec - * repository into `packages/core/test/corpus/fixtures/2026-07-28/`. + * repository into `packages/core-internal/test/corpus/fixtures/2026-07-28/`. * * The spec repository ships canonical example instances for the draft schema * (`schema/draft/examples//*.json`). The corpus harness - * (`packages/core/test/corpus/specCorpus.test.ts`) parses every vendored + * (`packages/core-internal/test/corpus/specCorpus.test.ts`) parses every vendored * example through the SDK's wire schemas, so accept-side drift between the * SDK and the specification turns CI red. * @@ -33,7 +33,7 @@ const SPEC_REPO = 'modelcontextprotocol/modelcontextprotocol'; /** The upcoming protocol revision; its examples live in the spec repo's draft directory. */ const DRAFT_REVISION = '2026-07-28'; const EXAMPLES_PATH = 'schema/draft/examples'; -const OUTPUT_DIR = join(PROJECT_ROOT, 'packages', 'core', 'test', 'corpus', 'fixtures', DRAFT_REVISION); +const OUTPUT_DIR = join(PROJECT_ROOT, 'packages', 'core-internal', 'test', 'corpus', 'fixtures', DRAFT_REVISION); interface ExampleFile { /** `/.json` relative to the examples root. */ diff --git a/scripts/fetch-spec-types.ts b/scripts/fetch-spec-types.ts index e1b1ee0eab..c4fc9818ec 100644 --- a/scripts/fetch-spec-types.ts +++ b/scripts/fetch-spec-types.ts @@ -12,7 +12,7 @@ const PROJECT_ROOT = join(__dirname, '..'); * - `2025-11-25`: the frozen, released schema. * - `2026-07-28`: the upcoming protocol revision. * - * Each is written to `packages/core/src/types/spec.types..ts`. + * Each is written to `packages/core-internal/src/types/spec.types..ts`. */ const SUPPORTED_VERSIONS = ['2025-11-25', '2026-07-28'] as const; type SpecVersion = (typeof SUPPORTED_VERSIONS)[number]; @@ -38,7 +38,7 @@ const UPSTREAM_SCHEMA_DIRS: Record = { * Draft-tracking revisions have no entry and float to the latest upstream * commit via the nightly workflow's refresh PRs. * - * See `packages/core/src/types/README.md` for the full lifecycle policy. + * See `packages/core-internal/src/types/README.md` for the full lifecycle policy. */ const RELEASED_REVISION_PINS: Partial> = { '2025-11-25': '0168c57fc74aba6e6dcf8f0b7191db3caaa5ad65' @@ -111,13 +111,13 @@ async function updateSpecTypes(version: SpecVersion, providedSHA?: string): Prom const fullContent = header + specContent; // Format with prettier using the project's config so the output passes lint - const outputPath = join(PROJECT_ROOT, 'packages', 'core', 'src', 'types', `spec.types.${version}.ts`); + const outputPath = join(PROJECT_ROOT, 'packages', 'core-internal', 'src', 'types', `spec.types.${version}.ts`); const prettierConfig = await prettier.resolveConfig(outputPath); const formatted = await prettier.format(fullContent, { ...prettierConfig, filepath: outputPath }); writeFileSync(outputPath, formatted, 'utf-8'); - console.log(`[${version}] Successfully updated packages/core/src/types/spec.types.${version}.ts`); + console.log(`[${version}] Successfully updated packages/core-internal/src/types/spec.types.${version}.ts`); } function isSupportedVersion(value: string): value is SpecVersion { diff --git a/scripts/sync-snippets.ts b/scripts/sync-snippets.ts index 21a2c4e70b..6d5d81410c 100644 --- a/scripts/sync-snippets.ts +++ b/scripts/sync-snippets.ts @@ -516,7 +516,7 @@ function findPackageSrcDirs(packagesDir: string): string[] { const fullPath = join(entry.parentPath, entry.name); // Only include src dirs that are direct children of a package - // (e.g., packages/core/src, packages/middleware/express/src) + // (e.g., packages/core-internal/src, packages/middleware/express/src) // Skip nested src dirs like node_modules/*/src if (fullPath.includes('node_modules')) continue; diff --git a/test/conformance/CHANGELOG.md b/test/conformance/CHANGELOG.md new file mode 100644 index 0000000000..1c9ea88fd3 --- /dev/null +++ b/test/conformance/CHANGELOG.md @@ -0,0 +1,10 @@ +# @modelcontextprotocol/test-conformance + +## 2.0.0-alpha.1 + +### Patch Changes + +- [#2276](https://github.com/modelcontextprotocol/typescript-sdk/pull/2276) [`0657c3b`](https://github.com/modelcontextprotocol/typescript-sdk/commit/0657c3bea9218f67494850562c0c449548c972c1) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Fix the server + conformance script leaking the test server process: the cleanup trap killed the npx wrapper while the actual server kept listening on port 3000, making later runs silently test stale code or hang forever in the readiness loop. The script now spawns the server directly with + `node --import tsx`, refuses to start while the port is taken, and bounds each readiness probe; both test servers report `EADDRINUSE` with an actionable message, and the plain `test:conformance:client` script works again (`--suite core`, required since conformance + 0.2.0-alpha.1). diff --git a/test/conformance/eslint.config.mjs b/test/conformance/eslint.config.mjs index 9f247cf600..3d34b92e4d 100644 --- a/test/conformance/eslint.config.mjs +++ b/test/conformance/eslint.config.mjs @@ -8,14 +8,14 @@ export default [ files: ['**/*.{ts,tsx,js,jsx,mts,cts}'], rules: { // Conformance fixtures MUST use only what a consumer would `npm install` and import: - // public package entry points. Anything reaching into core or package internals is banned. + // public package entry points. Anything reaching into core-internal or package internals is banned. 'no-restricted-imports': [ 'error', { patterns: [ { - group: ['@modelcontextprotocol/core', '@modelcontextprotocol/core/*'], - message: 'Conformance fixtures must import from @modelcontextprotocol/{server,client}, not core.' + group: ['@modelcontextprotocol/core-internal', '@modelcontextprotocol/core-internal/*'], + message: 'Conformance fixtures must import from @modelcontextprotocol/{server,client}, not core-internal.' }, { group: ['@modelcontextprotocol/*/src/*'], diff --git a/test/conformance/package.json b/test/conformance/package.json index fa09cc7d33..6c2c654663 100644 --- a/test/conformance/package.json +++ b/test/conformance/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/test-conformance", "private": true, - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "description": "Model Context Protocol implementation for TypeScript", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -25,9 +25,6 @@ "lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .", "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", - "start": "npm run server", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client", "test:conformance:client": "conformance client --command 'node --import tsx ./src/everythingClient.ts' --suite core --expected-failures ./expected-failures.yaml", "test:conformance:client:all": "conformance client --command 'node --import tsx ./src/everythingClient.ts' --suite all --expected-failures ./expected-failures.yaml", "test:conformance:client:2026": "conformance client --command 'node --import tsx ./src/everythingClient.ts' --suite all --spec-version 2026-07-28 --expected-failures ./expected-failures.2026-07-28.yaml", @@ -44,7 +41,7 @@ "@modelcontextprotocol/conformance": "0.2.0-alpha.7", "@modelcontextprotocol/client": "workspace:^", "@modelcontextprotocol/server": "workspace:^", - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/express": "workspace:^", "@modelcontextprotocol/node": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", diff --git a/test/conformance/src/everythingClient.ts b/test/conformance/src/everythingClient.ts index 78a1bded3b..0c1e010fba 100644 --- a/test/conformance/src/everythingClient.ts +++ b/test/conformance/src/everythingClient.ts @@ -22,9 +22,9 @@ import { } from '@modelcontextprotocol/client'; import * as z from 'zod/v4'; -import { ConformanceOAuthProvider } from './helpers/conformanceOAuthProvider.js'; -import { logger } from './helpers/logger.js'; -import { handle401, withOAuthRetry } from './helpers/withOAuthRetry.js'; +import { ConformanceOAuthProvider } from './helpers/conformanceOAuthProvider'; +import { logger } from './helpers/logger'; +import { handle401, withOAuthRetry } from './helpers/withOAuthRetry'; /** * Fixed client metadata URL for CIMD conformance tests. diff --git a/test/conformance/src/helpers/withOAuthRetry.ts b/test/conformance/src/helpers/withOAuthRetry.ts index a156dbdff9..4f037ea454 100644 --- a/test/conformance/src/helpers/withOAuthRetry.ts +++ b/test/conformance/src/helpers/withOAuthRetry.ts @@ -7,7 +7,7 @@ import { UnauthorizedError } from '@modelcontextprotocol/client'; -import { ConformanceOAuthProvider } from './conformanceOAuthProvider.js'; +import { ConformanceOAuthProvider } from './conformanceOAuthProvider'; export const handle401 = async ( response: Response, diff --git a/test/conformance/tsconfig.json b/test/conformance/tsconfig.json index f529719742..dffb32355b 100644 --- a/test/conformance/tsconfig.json +++ b/test/conformance/tsconfig.json @@ -5,8 +5,10 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], "@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"], "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/express": ["./node_modules/@modelcontextprotocol/express/src/index.ts"], diff --git a/test/e2e/CHANGELOG.md b/test/e2e/CHANGELOG.md new file mode 100644 index 0000000000..1bfd5dc0ba --- /dev/null +++ b/test/e2e/CHANGELOG.md @@ -0,0 +1,11 @@ +# @modelcontextprotocol/test-e2e + +## 2.0.0-alpha.1 + +### Patch Changes + +- [#2203](https://github.com/modelcontextprotocol/typescript-sdk/pull/2203) [`4a5c863`](https://github.com/modelcontextprotocol/typescript-sdk/commit/4a5c863a21f06e3ae43db116f32f2da7df5988b4) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add consumer-sourced + e2e requirements (behaviors real SDK dependents rely on) and run the interaction matrix over the legacy HTTP+SSE transport, with known failures recording where v2 intentionally differs. + +- [#2179](https://github.com/modelcontextprotocol/typescript-sdk/pull/2179) [`1998a18`](https://github.com/modelcontextprotocol/typescript-sdk/commit/1998a186eeb8aa3728c1e82420e381e0f9b80a83) Thanks [@felixweinberger](https://github.com/felixweinberger)! - Add the end-to-end + behavior test suite as a workspace package: a requirements manifest covering protocol-visible SDK behavior across the in-memory, stdio, and Streamable HTTP transports, ported from the v1.x branch and extended with coverage for v2 features. diff --git a/test/e2e/coverage.test.ts b/test/e2e/coverage.test.ts index 4397ae5420..4278429055 100644 --- a/test/e2e/coverage.test.ts +++ b/test/e2e/coverage.test.ts @@ -13,8 +13,8 @@ import { fileURLToPath } from 'node:url'; import { expect, test } from 'vitest'; -import { REQUIREMENTS } from './requirements.js'; -import { ALL_SPEC_VERSIONS, ALL_TRANSPORTS, ENTRY_TRANSPORTS, TRANSPORT_SPEC_VERSIONS } from './types.js'; +import { REQUIREMENTS } from './requirements'; +import { ALL_SPEC_VERSIONS, ALL_TRANSPORTS, ENTRY_TRANSPORTS, TRANSPORT_SPEC_VERSIONS } from './types'; const E2E_DIR = path.dirname(fileURLToPath(import.meta.url)); diff --git a/test/e2e/helpers/index.ts b/test/e2e/helpers/index.ts index 68935b8f2d..0f3b4daa1c 100644 --- a/test/e2e/helpers/index.ts +++ b/test/e2e/helpers/index.ts @@ -15,7 +15,7 @@ import { PassThrough } from 'node:stream'; import type { Client } from '@modelcontextprotocol/client'; import { SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; -import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import type { CreateMcpHandlerOptions, EventStore, @@ -34,10 +34,10 @@ import { } from '@modelcontextprotocol/server'; import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'; -import type { SpecVersion, Transport } from '../types.js'; -import { startLegacySseHost } from './sse-host.js'; -import type { SnifferOptions } from './wire-sniffer.js'; -import { sniffTransport } from './wire-sniffer.js'; +import type { SpecVersion, Transport } from '../types'; +import { startLegacySseHost } from './sse-host'; +import type { SnifferOptions } from './wire-sniffer'; +import { sniffTransport } from './wire-sniffer'; /** Narrows away `null`/`undefined` for values the surrounding test has already proven exist (replaces non-null assertions). */ export function defined(value: T | null | undefined, label: string): NonNullable { diff --git a/test/e2e/helpers/verifies.ts b/test/e2e/helpers/verifies.ts index 0f2d07bdc4..852c920860 100644 --- a/test/e2e/helpers/verifies.ts +++ b/test/e2e/helpers/verifies.ts @@ -17,9 +17,9 @@ import { describe, test } from 'vitest'; -import { REQUIREMENTS } from '../requirements.js'; -import type { Requirement, SpecVersion, TestArgs, Transport } from '../types.js'; -import { ALL_SPEC_VERSIONS, ALL_TRANSPORTS, ENTRY_TRANSPORTS, TRANSPORT_SPEC_VERSIONS } from '../types.js'; +import { REQUIREMENTS } from '../requirements'; +import type { Requirement, SpecVersion, TestArgs, Transport } from '../types'; +import { ALL_SPEC_VERSIONS, ALL_TRANSPORTS, ENTRY_TRANSPORTS, TRANSPORT_SPEC_VERSIONS } from '../types'; type TestBody = (args: TestArgs) => Promise; diff --git a/test/e2e/helpers/wire-sniffer.test.ts b/test/e2e/helpers/wire-sniffer.test.ts index ca072217a9..63d7f8001a 100644 --- a/test/e2e/helpers/wire-sniffer.test.ts +++ b/test/e2e/helpers/wire-sniffer.test.ts @@ -1,7 +1,7 @@ import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/server'; import { describe, expect, it } from 'vitest'; -import { assertWireMessage } from './wire-sniffer.js'; +import { assertWireMessage } from './wire-sniffer'; const req = (method: string, params?: unknown, id = 1) => ({ jsonrpc: '2.0' as const, diff --git a/test/e2e/helpers/wire-sniffer.ts b/test/e2e/helpers/wire-sniffer.ts index 3a5dc2fc3f..4e2c26bea5 100644 --- a/test/e2e/helpers/wire-sniffer.ts +++ b/test/e2e/helpers/wire-sniffer.ts @@ -5,7 +5,7 @@ import { ServerNotificationSchema, ServerRequestSchema, ServerResultSchema -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import type { Transport } from '@modelcontextprotocol/server'; import { isInputRequiredResult, diff --git a/test/e2e/package.json b/test/e2e/package.json index 2b24c771f7..6dfa6a781f 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -1,7 +1,7 @@ { "name": "@modelcontextprotocol/test-e2e", "private": true, - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "description": "Model Context Protocol implementation for TypeScript", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -32,7 +32,7 @@ "devDependencies": { "@hono/node-server": "catalog:runtimeServerOnly", "@modelcontextprotocol/client": "workspace:^", - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/server": "workspace:^", "@modelcontextprotocol/server-legacy": "workspace:^", "@modelcontextprotocol/express": "workspace:^", diff --git a/test/e2e/requirements.ts b/test/e2e/requirements.ts index 1615d93997..99480ae3f7 100644 --- a/test/e2e/requirements.ts +++ b/test/e2e/requirements.ts @@ -7,7 +7,7 @@ * the behavior). */ -import type { Requirement } from './types.js'; +import type { Requirement } from './types'; /** Transports with a persistent server instance / standalone notification stream. */ const STATEFUL_TRANSPORTS = ['inMemory', 'stdio', 'streamableHttp', 'sse'] as const; diff --git a/test/e2e/scenarios/client-auth.test.ts b/test/e2e/scenarios/client-auth.test.ts index b3e94a0789..07d052c3b6 100644 --- a/test/e2e/scenarios/client-auth.test.ts +++ b/test/e2e/scenarios/client-auth.test.ts @@ -56,9 +56,9 @@ import { importSPKI, jwtVerify } from 'jose'; import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { defined, hostPerSession } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { defined, hostPerSession } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const ISSUER = 'https://auth.example.com'; const MCP_URL = 'http://in-process/mcp'; diff --git a/test/e2e/scenarios/completion.test.ts b/test/e2e/scenarios/completion.test.ts index 34f3d888fd..0752fac099 100644 --- a/test/e2e/scenarios/completion.test.ts +++ b/test/e2e/scenarios/completion.test.ts @@ -12,9 +12,9 @@ import { completable, McpServer, ProtocolError, ProtocolErrorCode, ResourceTempl import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const COLORS = ['red', 'green', 'blue', 'rebeccapurple'] as const; const FILE_PATHS = ['README.md', 'src/index.ts', 'src/types.ts'] as const; diff --git a/test/e2e/scenarios/custom-methods.test.ts b/test/e2e/scenarios/custom-methods.test.ts index 6c724cd7b8..5c770eb308 100644 --- a/test/e2e/scenarios/custom-methods.test.ts +++ b/test/e2e/scenarios/custom-methods.test.ts @@ -15,9 +15,9 @@ import { McpServer, ProtocolErrorCode, Server } from '@modelcontextprotocol/serv import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; verifies('custom-methods:server-handler:roundtrip', async ({ transport }: TestArgs) => { const SearchParams = z.object({ query: z.string(), limit: z.number().int().default(5) }); diff --git a/test/e2e/scenarios/dynamic.test.ts b/test/e2e/scenarios/dynamic.test.ts index b806d33c87..4e180d6cc6 100644 --- a/test/e2e/scenarios/dynamic.test.ts +++ b/test/e2e/scenarios/dynamic.test.ts @@ -12,9 +12,9 @@ import { McpServer, ProtocolErrorCode, Server } from '@modelcontextprotocol/serv import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/elicitation.test.ts b/test/e2e/scenarios/elicitation.test.ts index 840a3009e5..30e70a06f5 100644 --- a/test/e2e/scenarios/elicitation.test.ts +++ b/test/e2e/scenarios/elicitation.test.ts @@ -22,9 +22,9 @@ import { import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Client with form-mode elicitation support. */ const formClient = () => new Client({ name: 'c', version: '0' }, { capabilities: { elicitation: { form: {} } } }); diff --git a/test/e2e/scenarios/errors.test.ts b/test/e2e/scenarios/errors.test.ts index 3809c7a172..c8e8562c75 100644 --- a/test/e2e/scenarios/errors.test.ts +++ b/test/e2e/scenarios/errors.test.ts @@ -24,9 +24,9 @@ import { import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { hostPerSession, tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { hostPerSession, tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/flow.test.ts b/test/e2e/scenarios/flow.test.ts index ea3b20e554..2b75c8fe44 100644 --- a/test/e2e/scenarios/flow.test.ts +++ b/test/e2e/scenarios/flow.test.ts @@ -24,10 +24,10 @@ import { McpServer, ProtocolErrorCode, Server, specTypeSchemas, UrlElicitationRe import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { hostPerSession, hostResumable, wire } from '../helpers/index.js'; -import { startLegacySseHost } from '../helpers/sse-host.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { hostPerSession, hostResumable, wire } from '../helpers/index'; +import { startLegacySseHost } from '../helpers/sse-host'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; verifies('flow:compat:dual-transport-server', async (_args: TestArgs) => { // One deployment, one server factory, both transports: the modern Streamable HTTP diff --git a/test/e2e/scenarios/handler-context.test.ts b/test/e2e/scenarios/handler-context.test.ts index f5624faf99..2543a4b745 100644 --- a/test/e2e/scenarios/handler-context.test.ts +++ b/test/e2e/scenarios/handler-context.test.ts @@ -15,9 +15,9 @@ import { McpServer } from '@modelcontextprotocol/server'; import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { hostPerSession, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { hostPerSession, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; verifies('mcpserver:context:log-from-handler', async ({ transport }: TestArgs) => { let releaseHandler!: () => void; diff --git a/test/e2e/scenarios/hosting-auth.test.ts b/test/e2e/scenarios/hosting-auth.test.ts index 235c96f4b4..ce02625872 100644 --- a/test/e2e/scenarios/hosting-auth.test.ts +++ b/test/e2e/scenarios/hosting-auth.test.ts @@ -31,8 +31,8 @@ import { McpServer, WebStandardStreamableHTTPServerTransport } from '@modelconte import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const VALID_TOKEN = 'analytics-dashboard-access-token'; diff --git a/test/e2e/scenarios/hosting-entry-auth.test.ts b/test/e2e/scenarios/hosting-entry-auth.test.ts index a618250207..3242c0ab7d 100644 --- a/test/e2e/scenarios/hosting-entry-auth.test.ts +++ b/test/e2e/scenarios/hosting-entry-auth.test.ts @@ -26,8 +26,8 @@ import { createMcpHandler, McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const MODERN = '2026-07-28'; const VALID_TOKEN = 'e2e-entry-access-token'; diff --git a/test/e2e/scenarios/hosting-entry-http.test.ts b/test/e2e/scenarios/hosting-entry-http.test.ts index 8712da381a..386d843756 100644 --- a/test/e2e/scenarios/hosting-entry-http.test.ts +++ b/test/e2e/scenarios/hosting-entry-http.test.ts @@ -15,9 +15,9 @@ import { McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const LEGACY = '2025-11-25'; diff --git a/test/e2e/scenarios/hosting-entry-session.test.ts b/test/e2e/scenarios/hosting-entry-session.test.ts index 2a09b95d42..0d25ab626b 100644 --- a/test/e2e/scenarios/hosting-entry-session.test.ts +++ b/test/e2e/scenarios/hosting-entry-session.test.ts @@ -31,8 +31,8 @@ import { createMcpHandler, isLegacyRequest, McpServer, WebStandardStreamableHTTP import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { modernEnvelopeMeta } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; +import { modernEnvelopeMeta } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; const LEGACY = '2025-11-25'; diff --git a/test/e2e/scenarios/hosting-entry-stamping.test.ts b/test/e2e/scenarios/hosting-entry-stamping.test.ts index 6cf4c51078..b67fba61d4 100644 --- a/test/e2e/scenarios/hosting-entry-stamping.test.ts +++ b/test/e2e/scenarios/hosting-entry-stamping.test.ts @@ -26,10 +26,10 @@ import { McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import type { Wired } from '../helpers/index.js'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import type { Wired } from '../helpers/index'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const LEGACY = '2025-11-25'; const MODERN = '2026-07-28'; diff --git a/test/e2e/scenarios/hosting-entry-streaming.test.ts b/test/e2e/scenarios/hosting-entry-streaming.test.ts index 0f0360af09..9ae86c062b 100644 --- a/test/e2e/scenarios/hosting-entry-streaming.test.ts +++ b/test/e2e/scenarios/hosting-entry-streaming.test.ts @@ -22,10 +22,10 @@ import { McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import type { Wired } from '../helpers/index.js'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import type { Wired } from '../helpers/index'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const MODERN = '2026-07-28'; diff --git a/test/e2e/scenarios/hosting-entry.test.ts b/test/e2e/scenarios/hosting-entry.test.ts index d979a810dd..4c986e3b75 100644 --- a/test/e2e/scenarios/hosting-entry.test.ts +++ b/test/e2e/scenarios/hosting-entry.test.ts @@ -9,15 +9,15 @@ * still rides the harness-hosted entry. */ import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; -import { PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; +import { PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core-internal'; import type { McpRequestContext } from '@modelcontextprotocol/server'; import { McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { modernEnvelopeMeta, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { modernEnvelopeMeta, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const LEGACY = '2025-11-25'; const MODERN = '2026-07-28'; diff --git a/test/e2e/scenarios/hosting-express.test.ts b/test/e2e/scenarios/hosting-express.test.ts index 85c106f75d..3710414805 100644 --- a/test/e2e/scenarios/hosting-express.test.ts +++ b/test/e2e/scenarios/hosting-express.test.ts @@ -32,10 +32,10 @@ import express from 'express'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { startExpressMinimal, startExpressWithHostValidation } from '../helpers/express.js'; -import { defined } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { startExpressMinimal, startExpressWithHostValidation } from '../helpers/express'; +import { defined } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const RESOURCE_METADATA_URL = 'https://mcp.example.com/.well-known/oauth-protected-resource'; const VALID_TOKEN = 'analytics-dashboard-token'; diff --git a/test/e2e/scenarios/hosting-fastify.test.ts b/test/e2e/scenarios/hosting-fastify.test.ts index d1c1ddb58e..b7d3a6e7ea 100644 --- a/test/e2e/scenarios/hosting-fastify.test.ts +++ b/test/e2e/scenarios/hosting-fastify.test.ts @@ -19,8 +19,8 @@ import type { FastifyInstance, FastifyRequest } from 'fastify'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; function forecastServer(): McpServer { const s = new McpServer({ name: 'forecast-server', version: '0.3.0' }); diff --git a/test/e2e/scenarios/hosting-hono.test.ts b/test/e2e/scenarios/hosting-hono.test.ts index e9df10565a..fb5373c75b 100644 --- a/test/e2e/scenarios/hosting-hono.test.ts +++ b/test/e2e/scenarios/hosting-hono.test.ts @@ -20,8 +20,8 @@ import type { Hono } from 'hono'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; function recipeServer(): McpServer { const s = new McpServer({ name: 'recipe-server', version: '1.2.0' }); diff --git a/test/e2e/scenarios/hosting-http.test.ts b/test/e2e/scenarios/hosting-http.test.ts index e055672e47..68df7ea365 100644 --- a/test/e2e/scenarios/hosting-http.test.ts +++ b/test/e2e/scenarios/hosting-http.test.ts @@ -18,10 +18,10 @@ import { LATEST_PROTOCOL_VERSION, McpServer, WebStandardStreamableHTTPServerTran import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import type { HttpHandler } from '../helpers/index.js'; -import { hostPerSession, hostStateless } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import type { HttpHandler } from '../helpers/index'; +import { hostPerSession, hostStateless } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; function echoServer(): McpServer { const s = new McpServer({ name: 's', version: '0' }); diff --git a/test/e2e/scenarios/hosting-resume.test.ts b/test/e2e/scenarios/hosting-resume.test.ts index 1a0f8b14ad..762c445b7e 100644 --- a/test/e2e/scenarios/hosting-resume.test.ts +++ b/test/e2e/scenarios/hosting-resume.test.ts @@ -12,9 +12,9 @@ import { LATEST_PROTOCOL_VERSION, McpServer, parseJSONRPCMessage } from '@modelc import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { hostResumable } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { hostResumable } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** * These three tests assert the raw frame sequence of the POST SSE stream itself, so they cannot run their traffic through a connected client. diff --git a/test/e2e/scenarios/hosting-session.test.ts b/test/e2e/scenarios/hosting-session.test.ts index 81c5d5ba89..d8af0d34d3 100644 --- a/test/e2e/scenarios/hosting-session.test.ts +++ b/test/e2e/scenarios/hosting-session.test.ts @@ -19,10 +19,10 @@ import express from 'express'; import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { startExpressMinimal } from '../helpers/express.js'; -import { hostPerSession, hostStateless, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { startExpressMinimal } from '../helpers/express'; +import { hostPerSession, hostStateless, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/jsonschema.test.ts b/test/e2e/scenarios/jsonschema.test.ts index 8ac82ae587..4a5e7b20dd 100644 --- a/test/e2e/scenarios/jsonschema.test.ts +++ b/test/e2e/scenarios/jsonschema.test.ts @@ -21,9 +21,9 @@ import { fromJsonSchema, McpServer, ProtocolError, ProtocolErrorCode, Server } f import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Plain client with no extra capabilities declared. */ const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/lifecycle.test.ts b/test/e2e/scenarios/lifecycle.test.ts index 2fba4a84e8..7ccf781aa6 100644 --- a/test/e2e/scenarios/lifecycle.test.ts +++ b/test/e2e/scenarios/lifecycle.test.ts @@ -32,9 +32,9 @@ import { import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; function olderSupportedVersion(): string { const older = SUPPORTED_PROTOCOL_VERSIONS.find(v => v !== LATEST_PROTOCOL_VERSION); diff --git a/test/e2e/scenarios/logging.test.ts b/test/e2e/scenarios/logging.test.ts index 08f3bb40da..277f2a3499 100644 --- a/test/e2e/scenarios/logging.test.ts +++ b/test/e2e/scenarios/logging.test.ts @@ -17,9 +17,9 @@ import { isJSONRPCRequest, McpServer, ProtocolError, ProtocolErrorCode, Server, import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const ALL_LEVELS: LoggingLevel[] = ['debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency']; diff --git a/test/e2e/scenarios/mrtr.test.ts b/test/e2e/scenarios/mrtr.test.ts index 2d8d0a376f..9276401b54 100644 --- a/test/e2e/scenarios/mrtr.test.ts +++ b/test/e2e/scenarios/mrtr.test.ts @@ -16,10 +16,10 @@ import { acceptedContent, inputRequired, McpServer, ProtocolError, UrlElicitatio import { expect } from 'vitest'; import { z } from 'zod/v4'; -import type { Wired } from '../helpers/index.js'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import type { Wired } from '../helpers/index'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Every JSON-RPC request the wired client POSTed for the given method, in order. */ function recordedRequests(wired: Wired, method: string): Array> { diff --git a/test/e2e/scenarios/pagination.test.ts b/test/e2e/scenarios/pagination.test.ts index 93c522431a..0c4285056f 100644 --- a/test/e2e/scenarios/pagination.test.ts +++ b/test/e2e/scenarios/pagination.test.ts @@ -10,9 +10,9 @@ import { isJSONRPCRequest, McpServer, ProtocolError, ProtocolErrorCode, Resource import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/prompts.test.ts b/test/e2e/scenarios/prompts.test.ts index fa941cafe0..a77829975a 100644 --- a/test/e2e/scenarios/prompts.test.ts +++ b/test/e2e/scenarios/prompts.test.ts @@ -14,9 +14,9 @@ import { McpServer, ProtocolError, ProtocolErrorCode, Server } from '@modelconte import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const TINY_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; const TINY_WAV_BASE64 = 'UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA='; diff --git a/test/e2e/scenarios/protocol.test.ts b/test/e2e/scenarios/protocol.test.ts index 9a9b08b9f6..1ba2fb85aa 100644 --- a/test/e2e/scenarios/protocol.test.ts +++ b/test/e2e/scenarios/protocol.test.ts @@ -35,9 +35,9 @@ import { import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/raw-result-type.test.ts b/test/e2e/scenarios/raw-result-type.test.ts index 2307336980..eb42e73f30 100644 --- a/test/e2e/scenarios/raw-result-type.test.ts +++ b/test/e2e/scenarios/raw-result-type.test.ts @@ -26,8 +26,8 @@ import type { JSONRPCRequest } from '@modelcontextprotocol/server'; import { InMemoryTransport, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const INPUT_REQUIRED_BODY = { resultType: 'input_required', diff --git a/test/e2e/scenarios/resources.test.ts b/test/e2e/scenarios/resources.test.ts index 58f7b8b1a6..46ac5b347a 100644 --- a/test/e2e/scenarios/resources.test.ts +++ b/test/e2e/scenarios/resources.test.ts @@ -13,9 +13,9 @@ import type { RegisteredResource } from '@modelcontextprotocol/server'; import { McpServer, ProtocolError, ProtocolErrorCode, ResourceTemplate, Server } from '@modelcontextprotocol/server'; import { expect, vi } from 'vitest'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const TINY_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; const FIXTURE_LAST_MODIFIED = '2024-01-15T10:30:00.000Z'; diff --git a/test/e2e/scenarios/roots.test.ts b/test/e2e/scenarios/roots.test.ts index 8328d088ac..c09f1eb485 100644 --- a/test/e2e/scenarios/roots.test.ts +++ b/test/e2e/scenarios/roots.test.ts @@ -12,9 +12,9 @@ import { McpServer, ProtocolError, ProtocolErrorCode } from '@modelcontextprotoc import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; verifies('roots:list:basic', async ({ transport }: TestArgs) => { const received: Array<{ method: string }> = []; diff --git a/test/e2e/scenarios/sampling.test.ts b/test/e2e/scenarios/sampling.test.ts index 75e4fc52cf..c8048aad3b 100644 --- a/test/e2e/scenarios/sampling.test.ts +++ b/test/e2e/scenarios/sampling.test.ts @@ -10,15 +10,15 @@ import type { ClientCapabilities } from '@modelcontextprotocol/client'; import { Client } from '@modelcontextprotocol/client'; -import { CreateMessageRequestParamsSchema } from '@modelcontextprotocol/core'; +import { CreateMessageRequestParamsSchema } from '@modelcontextprotocol/core-internal'; import type { CreateMessageRequest, CreateMessageResultWithTools, ServerOptions } from '@modelcontextprotocol/server'; import { McpServer, ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { tapWire, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { tapWire, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = (capabilities?: ClientCapabilities) => new Client({ name: 'c', version: '0' }, { capabilities: capabilities ?? { sampling: {} } }); diff --git a/test/e2e/scenarios/sep2243.test.ts b/test/e2e/scenarios/sep2243.test.ts index 23aba54c22..c654a986b6 100644 --- a/test/e2e/scenarios/sep2243.test.ts +++ b/test/e2e/scenarios/sep2243.test.ts @@ -6,13 +6,13 @@ * raw HTTP request headers are observable on the arm-recorded `wired.httpLog`. */ import { Client } from '@modelcontextprotocol/client'; -import { encodeMcpParamValue, MCP_PARAM_HEADER_PREFIX } from '@modelcontextprotocol/core'; +import { encodeMcpParamValue, MCP_PARAM_HEADER_PREFIX } from '@modelcontextprotocol/core-internal'; import { fromJsonSchema, McpServer } from '@modelcontextprotocol/server'; import { expect } from 'vitest'; -import { modernEnvelopeMeta, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { modernEnvelopeMeta, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** * One tool with a single `x-mcp-header`-declared string parameter. Declared as diff --git a/test/e2e/scenarios/standard-schema.test.ts b/test/e2e/scenarios/standard-schema.test.ts index f646b573f3..a8f3406577 100644 --- a/test/e2e/scenarios/standard-schema.test.ts +++ b/test/e2e/scenarios/standard-schema.test.ts @@ -16,9 +16,9 @@ import { type } from 'arktype'; import * as v from 'valibot'; import { expect } from 'vitest'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Plain client with no extra capabilities declared. */ const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/stdio-dual-era.test.ts b/test/e2e/scenarios/stdio-dual-era.test.ts index 503540454c..259cf6ff0b 100644 --- a/test/e2e/scenarios/stdio-dual-era.test.ts +++ b/test/e2e/scenarios/stdio-dual-era.test.ts @@ -19,8 +19,8 @@ import { Client } from '@modelcontextprotocol/client'; import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'; import { expect } from 'vitest'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Absolute path to the runnable dual-era fixture server (executed with tsx). */ const FIXTURE_PATH = fileURLToPath(new URL('../fixtures/dual-era-stdio-server.ts', import.meta.url)); diff --git a/test/e2e/scenarios/stdio.test.ts b/test/e2e/scenarios/stdio.test.ts index a6149945e5..ba4baf69f3 100644 --- a/test/e2e/scenarios/stdio.test.ts +++ b/test/e2e/scenarios/stdio.test.ts @@ -17,11 +17,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url'; import { Client } from '@modelcontextprotocol/client'; import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'; -import { JSONRPCMessageSchema } from '@modelcontextprotocol/core'; +import { JSONRPCMessageSchema } from '@modelcontextprotocol/core-internal'; import { expect, vi } from 'vitest'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Absolute path to the runnable fixture server (executed with tsx). */ const FIXTURE_PATH = fileURLToPath(new URL('../fixtures/stdio-server.ts', import.meta.url)); diff --git a/test/e2e/scenarios/subscriptions.test.ts b/test/e2e/scenarios/subscriptions.test.ts index 0fb481d724..45753afc57 100644 --- a/test/e2e/scenarios/subscriptions.test.ts +++ b/test/e2e/scenarios/subscriptions.test.ts @@ -11,9 +11,9 @@ import { createMcpHandler, McpServer, SUBSCRIPTION_ID_META_KEY } from '@modelcon import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { modernEnvelopeMeta, wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { modernEnvelopeMeta, wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; function makeServer() { const server = new McpServer({ name: 'subs-e2e', version: '1' }); diff --git a/test/e2e/scenarios/tools.test.ts b/test/e2e/scenarios/tools.test.ts index cd840535e2..741665143f 100644 --- a/test/e2e/scenarios/tools.test.ts +++ b/test/e2e/scenarios/tools.test.ts @@ -21,7 +21,7 @@ */ import { Client } from '@modelcontextprotocol/client'; -import type { JsonSchemaType } from '@modelcontextprotocol/core'; +import type { JsonSchemaType } from '@modelcontextprotocol/core-internal'; import type { CreateMessageRequest, CreateMessageResult, @@ -36,9 +36,9 @@ import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const TINY_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; const TINY_WAV_BASE64 = 'UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA='; diff --git a/test/e2e/scenarios/transport-http.test.ts b/test/e2e/scenarios/transport-http.test.ts index 26c7bce868..7cda0f28aa 100644 --- a/test/e2e/scenarios/transport-http.test.ts +++ b/test/e2e/scenarios/transport-http.test.ts @@ -19,7 +19,7 @@ import { randomUUID } from 'node:crypto'; import { Client, SdkHttpError, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; -import { JSONRPCRequestSchema } from '@modelcontextprotocol/core'; +import { JSONRPCRequestSchema } from '@modelcontextprotocol/core-internal'; import { LATEST_PROTOCOL_VERSION, McpServer, @@ -29,10 +29,10 @@ import { import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import type { HttpHandler } from '../helpers/index.js'; -import { defined, hostPerSession, hostStateless } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import type { HttpHandler } from '../helpers/index'; +import { defined, hostPerSession, hostStateless } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; const newClient = () => new Client({ name: 'c', version: '0' }); diff --git a/test/e2e/scenarios/transport-raw.test.ts b/test/e2e/scenarios/transport-raw.test.ts index 6848efafd2..6cda985b4b 100644 --- a/test/e2e/scenarios/transport-raw.test.ts +++ b/test/e2e/scenarios/transport-raw.test.ts @@ -22,15 +22,15 @@ import { InitializeResultSchema, JSONRPCResultResponseSchema, LATEST_PROTOCOL_VERSION -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import type { JSONRPCMessage, JSONRPCNotification, JSONRPCRequest } from '@modelcontextprotocol/server'; import { InMemoryTransport, McpServer } from '@modelcontextprotocol/server'; import { expect, vi } from 'vitest'; import { z } from 'zod/v4'; -import { defined, hostPerSession, hostStateless } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { defined, hostPerSession, hostStateless } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; /** Absolute path to the runnable stdio fixture server (executed with tsx). */ const FIXTURE_PATH = fileURLToPath(new URL('../fixtures/stdio-server.ts', import.meta.url)); diff --git a/test/e2e/scenarios/transport-sse.test.ts b/test/e2e/scenarios/transport-sse.test.ts index b9d5dcefe1..31dbd901e1 100644 --- a/test/e2e/scenarios/transport-sse.test.ts +++ b/test/e2e/scenarios/transport-sse.test.ts @@ -8,8 +8,8 @@ import { expect } from 'vitest'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs } from '../types.js'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs } from '../types'; verifies('transport:sse:server-transport', async (_args: TestArgs) => { // The server half of the legacy SSE transport must be on the public server-side surface for SSE deployments to be hosted on the SDK alone. diff --git a/test/e2e/scenarios/validation.test.ts b/test/e2e/scenarios/validation.test.ts index c1470acd3e..454d9c0f4a 100644 --- a/test/e2e/scenarios/validation.test.ts +++ b/test/e2e/scenarios/validation.test.ts @@ -13,7 +13,7 @@ */ import { Client } from '@modelcontextprotocol/client'; -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core'; +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, StandardSchemaWithJSON } from '@modelcontextprotocol/core-internal'; import type { Tool } from '@modelcontextprotocol/server'; import { fromJsonSchema, @@ -29,9 +29,9 @@ import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/valida import { expect } from 'vitest'; import { z } from 'zod/v4'; -import { wire } from '../helpers/index.js'; -import { verifies } from '../helpers/verifies.js'; -import type { TestArgs, Transport } from '../types.js'; +import { wire } from '../helpers/index'; +import { verifies } from '../helpers/verifies'; +import type { TestArgs, Transport } from '../types'; const FORECAST_OUTPUT_SCHEMA: Tool['outputSchema'] = { type: 'object', diff --git a/test/e2e/tsconfig.json b/test/e2e/tsconfig.json index c9440778bf..a4eaba6bd6 100644 --- a/test/e2e/tsconfig.json +++ b/test/e2e/tsconfig.json @@ -5,10 +5,12 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], - "@modelcontextprotocol/core/validators/cfWorker": [ - "./node_modules/@modelcontextprotocol/core/src/validators/cfWorkerProvider.ts" + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], + "@modelcontextprotocol/core-internal/validators/cfWorker": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/cfWorkerProvider.ts" ], "@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"], "@modelcontextprotocol/client/stdio": ["./node_modules/@modelcontextprotocol/client/src/stdio.ts"], diff --git a/test/helpers/package.json b/test/helpers/package.json index 88f2c3f93e..3b7e49950e 100644 --- a/test/helpers/package.json +++ b/test/helpers/package.json @@ -24,13 +24,10 @@ "scripts": { "lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .", "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", - "check": "npm run typecheck && npm run lint", - "start": "npm run server", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "check": "npm run typecheck && npm run lint" }, "devDependencies": { - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "zod": "catalog:runtimeShared", "vitest": "catalog:devTools", "@modelcontextprotocol/tsconfig": "workspace:^", diff --git a/test/helpers/src/helpers/oauth.ts b/test/helpers/src/helpers/oauth.ts index 61c3d44e40..a689b33909 100644 --- a/test/helpers/src/helpers/oauth.ts +++ b/test/helpers/src/helpers/oauth.ts @@ -1,4 +1,4 @@ -import type { FetchLike } from '@modelcontextprotocol/core'; +import type { FetchLike } from '@modelcontextprotocol/core-internal'; import { vi } from 'vitest'; export interface MockOAuthFetchOptions { diff --git a/test/helpers/src/index.ts b/test/helpers/src/index.ts index 1fd7ce2b9b..99e6ed301b 100644 --- a/test/helpers/src/index.ts +++ b/test/helpers/src/index.ts @@ -1,2 +1,2 @@ -export * from './helpers/http.js'; -export * from './helpers/oauth.js'; +export * from './helpers/http'; +export * from './helpers/oauth'; diff --git a/test/helpers/tsconfig.json b/test/helpers/tsconfig.json index ce44773946..18809d7ac8 100644 --- a/test/helpers/tsconfig.json +++ b/test/helpers/tsconfig.json @@ -5,8 +5,10 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], "@modelcontextprotocol/vitest-config": ["./node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] } } diff --git a/test/integration/package.json b/test/integration/package.json index 8618d0580e..10997c5be3 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -27,16 +27,13 @@ "check": "npm run typecheck && npm run lint", "test": "vitest run", "test:watch": "vitest", - "start": "npm run server", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client", "test:integration:bun": "bun test test/server/bun.test.ts", "test:integration:deno": "deno test --no-check --allow-net --allow-read --allow-env test/server/deno.test.ts" }, "devDependencies": { "@cfworker/json-schema": "catalog:runtimeShared", "@modelcontextprotocol/client": "workspace:^", - "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/core-internal": "workspace:^", "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/express": "workspace:^", "@modelcontextprotocol/node": "workspace:^", diff --git a/test/integration/test/client/client.test.ts b/test/integration/test/client/client.test.ts index 8de980f16a..5cfa15abf2 100644 --- a/test/integration/test/client/client.test.ts +++ b/test/integration/test/client/client.test.ts @@ -1,5 +1,5 @@ import { Client, getSupportedElicitationModes } from '@modelcontextprotocol/client'; -import type { Prompt, Resource, Tool, Transport } from '@modelcontextprotocol/core'; +import type { Prompt, Resource, Tool, Transport } from '@modelcontextprotocol/core-internal'; import { InMemoryTransport, LATEST_PROTOCOL_VERSION, @@ -8,7 +8,7 @@ import { SdkErrorCode, setNegotiatedProtocolVersion, SUPPORTED_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { McpServer, Server } from '@modelcontextprotocol/server'; /*** diff --git a/test/integration/test/client/discoverRoundtrip.test.ts b/test/integration/test/client/discoverRoundtrip.test.ts index c79e148682..13bddc46fb 100644 --- a/test/integration/test/client/discoverRoundtrip.test.ts +++ b/test/integration/test/client/discoverRoundtrip.test.ts @@ -14,7 +14,7 @@ import type { Server as HttpServer } from 'node:http'; import { createServer } from 'node:http'; import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; -import { SdkError, SdkErrorCode, setNegotiatedProtocolVersion, SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core'; +import { SdkError, SdkErrorCode, setNegotiatedProtocolVersion, SUPPORTED_PROTOCOL_VERSIONS } from '@modelcontextprotocol/core-internal'; import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; import { McpServer } from '@modelcontextprotocol/server'; import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers'; diff --git a/test/integration/test/client/versionNegotiation.test.ts b/test/integration/test/client/versionNegotiation.test.ts index a5aaee0148..2bd93eba93 100644 --- a/test/integration/test/client/versionNegotiation.test.ts +++ b/test/integration/test/client/versionNegotiation.test.ts @@ -20,7 +20,7 @@ import { createServer } from 'node:http'; import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'; -import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core'; +import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core-internal'; import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; import { McpServer } from '@modelcontextprotocol/server'; import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers'; diff --git a/test/integration/test/issues/test1277.zod.v4.description.test.ts b/test/integration/test/issues/test1277.zod.v4.description.test.ts index a8a8d0c7be..0d9c6e9cbe 100644 --- a/test/integration/test/issues/test1277.zod.v4.description.test.ts +++ b/test/integration/test/issues/test1277.zod.v4.description.test.ts @@ -7,7 +7,7 @@ */ import { Client } from '@modelcontextprotocol/client'; -import { InMemoryTransport } from '@modelcontextprotocol/core'; +import { InMemoryTransport } from '@modelcontextprotocol/core-internal'; import { McpServer } from '@modelcontextprotocol/server'; import * as z from 'zod/v4'; diff --git a/test/integration/test/issues/test400.optional-tool-params.test.ts b/test/integration/test/issues/test400.optional-tool-params.test.ts index b71d85b819..7671712734 100644 --- a/test/integration/test/issues/test400.optional-tool-params.test.ts +++ b/test/integration/test/issues/test400.optional-tool-params.test.ts @@ -7,7 +7,7 @@ */ import { Client } from '@modelcontextprotocol/client'; -import { InMemoryTransport } from '@modelcontextprotocol/core'; +import { InMemoryTransport } from '@modelcontextprotocol/core-internal'; import { McpServer } from '@modelcontextprotocol/server'; import * as z from 'zod/v4'; diff --git a/test/integration/test/server.test.ts b/test/integration/test/server.test.ts index dcb9cea87f..51cde29161 100644 --- a/test/integration/test/server.test.ts +++ b/test/integration/test/server.test.ts @@ -9,14 +9,14 @@ import type { jsonSchemaValidator, LoggingMessageNotification, Transport -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { InMemoryTransport, LATEST_PROTOCOL_VERSION, SdkError, SdkErrorCode, SUPPORTED_PROTOCOL_VERSIONS -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { createMcpExpressApp } from '@modelcontextprotocol/express'; import { McpServer, Server } from '@modelcontextprotocol/server'; import type { Request, Response } from 'express'; diff --git a/test/integration/test/server/createMcpHandler.test.ts b/test/integration/test/server/createMcpHandler.test.ts index 0cc2f2546c..9c2a6a7a0d 100644 --- a/test/integration/test/server/createMcpHandler.test.ts +++ b/test/integration/test/server/createMcpHandler.test.ts @@ -13,7 +13,7 @@ import { CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY, SUBSCRIPTION_ID_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { toNodeHandler } from '@modelcontextprotocol/node'; import type { CreateMcpHandlerOptions, McpHttpHandler, McpRequestContext } from '@modelcontextprotocol/server'; import { createMcpHandler, McpServer } from '@modelcontextprotocol/server'; diff --git a/test/integration/test/server/declaredCapabilities.test.ts b/test/integration/test/server/declaredCapabilities.test.ts index 60e3f847bb..60e214d129 100644 --- a/test/integration/test/server/declaredCapabilities.test.ts +++ b/test/integration/test/server/declaredCapabilities.test.ts @@ -1,5 +1,5 @@ import { Client } from '@modelcontextprotocol/client'; -import { InMemoryTransport, ProtocolErrorCode } from '@modelcontextprotocol/core'; +import { InMemoryTransport, ProtocolErrorCode } from '@modelcontextprotocol/core-internal'; import { McpServer } from '@modelcontextprotocol/server'; import { describe, expect, test } from 'vitest'; import * as z from 'zod/v4'; diff --git a/test/integration/test/server/dualEraStdio.test.ts b/test/integration/test/server/dualEraStdio.test.ts index 091d7aba26..279ff2b2c6 100644 --- a/test/integration/test/server/dualEraStdio.test.ts +++ b/test/integration/test/server/dualEraStdio.test.ts @@ -21,13 +21,13 @@ import path from 'node:path'; import { Client } from '@modelcontextprotocol/client'; import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'; -import type { JSONRPCMessage } from '@modelcontextprotocol/core'; +import type { JSONRPCMessage } from '@modelcontextprotocol/core-internal'; import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, LATEST_PROTOCOL_VERSION, PROTOCOL_VERSION_META_KEY -} from '@modelcontextprotocol/core'; +} from '@modelcontextprotocol/core-internal'; import { describe, expect, it, vi } from 'vitest'; const FIXTURES_DIR = path.resolve(__dirname, '../__fixtures__'); diff --git a/test/integration/test/server/elicitation.test.ts b/test/integration/test/server/elicitation.test.ts index 84bb071f1b..5963229f0a 100644 --- a/test/integration/test/server/elicitation.test.ts +++ b/test/integration/test/server/elicitation.test.ts @@ -8,10 +8,10 @@ */ import { Client } from '@modelcontextprotocol/client'; -import type { ElicitRequestFormParams } from '@modelcontextprotocol/core'; -import { InMemoryTransport } from '@modelcontextprotocol/core'; -import { AjvJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv'; -import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker'; +import type { ElicitRequestFormParams } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport } from '@modelcontextprotocol/core-internal'; +import { AjvJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/ajv'; +import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core-internal/validators/cfWorker'; import { Server } from '@modelcontextprotocol/server'; const ajvProvider = new AjvJsonSchemaValidator(); diff --git a/test/integration/test/server/mcp.test.ts b/test/integration/test/server/mcp.test.ts index 3d0b3f1b31..2597c14f84 100644 --- a/test/integration/test/server/mcp.test.ts +++ b/test/integration/test/server/mcp.test.ts @@ -1,6 +1,12 @@ import { Client } from '@modelcontextprotocol/client'; -import type { Notification, TextContent } from '@modelcontextprotocol/core'; -import { getDisplayName, InMemoryTransport, ProtocolErrorCode, UriTemplate, UrlElicitationRequiredError } from '@modelcontextprotocol/core'; +import type { Notification, TextContent } from '@modelcontextprotocol/core-internal'; +import { + getDisplayName, + InMemoryTransport, + ProtocolErrorCode, + UriTemplate, + UrlElicitationRequiredError +} from '@modelcontextprotocol/core-internal'; import { completable, McpServer, ResourceTemplate } from '@modelcontextprotocol/server'; import { afterEach, beforeEach, describe, expect, test } from 'vitest'; import * as z from 'zod/v4'; diff --git a/test/integration/test/standardSchema.test.ts b/test/integration/test/standardSchema.test.ts index ffc41ce4d8..92f5a6c78c 100644 --- a/test/integration/test/standardSchema.test.ts +++ b/test/integration/test/standardSchema.test.ts @@ -4,8 +4,8 @@ */ import { Client } from '@modelcontextprotocol/client'; -import type { TextContent } from '@modelcontextprotocol/core'; -import { InMemoryTransport } from '@modelcontextprotocol/core'; +import type { TextContent } from '@modelcontextprotocol/core-internal'; +import { InMemoryTransport } from '@modelcontextprotocol/core-internal'; import { completable, fromJsonSchema as serverFromJsonSchema, McpServer } from '@modelcontextprotocol/server'; import { toStandardJsonSchema } from '@valibot/to-json-schema'; import { type } from 'arktype'; diff --git a/test/integration/test/title.test.ts b/test/integration/test/title.test.ts index 588d300832..50e9460dce 100644 --- a/test/integration/test/title.test.ts +++ b/test/integration/test/title.test.ts @@ -1,5 +1,5 @@ import { Client } from '@modelcontextprotocol/client'; -import { InMemoryTransport } from '@modelcontextprotocol/core'; +import { InMemoryTransport } from '@modelcontextprotocol/core-internal'; import { McpServer, ResourceTemplate, Server } from '@modelcontextprotocol/server'; import * as z from 'zod/v4'; diff --git a/test/integration/tsconfig.json b/test/integration/tsconfig.json index 64391c93e0..4764fcfc84 100644 --- a/test/integration/tsconfig.json +++ b/test/integration/tsconfig.json @@ -5,11 +5,15 @@ "compilerOptions": { "paths": { "*": ["./*"], - "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], - "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], - "@modelcontextprotocol/core/validators/ajv": ["./node_modules/@modelcontextprotocol/core/src/validators/ajvProvider.ts"], - "@modelcontextprotocol/core/validators/cfWorker": [ - "./node_modules/@modelcontextprotocol/core/src/validators/cfWorkerProvider.ts" + "@modelcontextprotocol/core-internal": ["./node_modules/@modelcontextprotocol/core-internal/src/index.ts"], + "@modelcontextprotocol/core-internal/public": [ + "./node_modules/@modelcontextprotocol/core-internal/src/exports/public/index.ts" + ], + "@modelcontextprotocol/core-internal/validators/ajv": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/ajvProvider.ts" + ], + "@modelcontextprotocol/core-internal/validators/cfWorker": [ + "./node_modules/@modelcontextprotocol/core-internal/src/validators/cfWorkerProvider.ts" ], "@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"], "@modelcontextprotocol/client/stdio": ["./node_modules/@modelcontextprotocol/client/src/stdio.ts"], diff --git a/typedoc.config.mjs b/typedoc.config.mjs index 675e3656b3..b7583ed8fc 100644 --- a/typedoc.config.mjs +++ b/typedoc.config.mjs @@ -3,10 +3,12 @@ import fg from 'fast-glob'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; -// Find all package.json files under packages/ and build package list +// Find all package.json files under packages/ and build package list. +// Exclude node_modules and the codemod batch-test's cloned real-world repos, which are not part +// of this SDK's public API surface (and would otherwise fail docs:check locally when present). const packageJsonPaths = await fg('packages/**/package.json', { cwd: process.cwd(), - ignore: ['**/node_modules/**'] + ignore: ['**/node_modules/**', '**/batch-test/**'] }); const packages = packageJsonPaths.map(p => { const rootDir = join(process.cwd(), p.replace('/package.json', '')); @@ -14,7 +16,12 @@ const packages = packageJsonPaths.map(p => { return { rootDir, manifest }; }); -const publicPackages = packages.filter(p => p.manifest.private !== true); +// @modelcontextprotocol/core is published for direct schema imports (CallToolResultSchema.parse(...)), +// but it's a thin re-export of the spec/OAuth Zod schemas whose JSDoc cross-references TYPES that live +// in client/server — unresolvable from core's own per-package doc scope. We skip rendering its API docs +// (the schemas mirror the documented types 1:1) so monorepo-wide invalid-link validation can stay ON. +const DOCS_EXCLUDED_PACKAGES = new Set(['@modelcontextprotocol/core']); +const publicPackages = packages.filter(p => p.manifest.private !== true && !DOCS_EXCLUDED_PACKAGES.has(p.manifest.name)); const entryPoints = publicPackages.map(p => p.rootDir); console.log( @@ -48,7 +55,7 @@ export default { treatWarningsAsErrors: true, out: 'tmp/docs/', externalSymbolLinkMappings: { - '@modelcontextprotocol/core': { + '@modelcontextprotocol/core-internal': { StandardSchemaV1: 'https://standardschema.dev/', StandardJSONSchemaV1: 'https://standardschema.dev/' }