Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/compat-zod-schemas-subpath.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@modelcontextprotocol/server': patch
---

Add `@modelcontextprotocol/server/zod-schemas` subpath for v1 compatibility

Re-exports the `*Schema` Zod constants (e.g. `CallToolRequestSchema`, `JSONRPCMessageSchema`) and the `getRequestSchema(method)` / `getResultSchema(method)` / `getNotificationSchema(method)` lookup helpers, so v1 code that imported schemas from `@modelcontextprotocol/sdk/types.js` can be pointed at a single subpath. These are Zod schemas; their TS type may change with internal Zod upgrades. Prefer `specTypeSchemas` / `isSpecType` (#1887) for runtime validation.

The `@modelcontextprotocol/sdk` meta-package (#1913 in this series) re-exports this subpath at `sdk/types.js`, so v1 imports work unchanged once both PRs land. The `specTypeSchemas` / `isSpecType` references in the deprecation guidance are added by #1887.
2 changes: 1 addition & 1 deletion docs/migration-SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Notes:
| `StreamableHTTPError` | REMOVED (use `SdkError` with `SdkErrorCode.ClientHttp*`) |
| `WebSocketClientTransport` | REMOVED (use `StreamableHTTPClientTransport` or `StdioClientTransport`) |

All other **type** symbols from `@modelcontextprotocol/sdk/types.js` retain their original names. **Zod schemas** (e.g., `CallToolResultSchema`, `ListToolsResultSchema`) are no longer part of the public API — they are internal to the SDK. For runtime validation, use type guard functions like `isCallToolResult` instead of `CallToolResultSchema.safeParse()`.
All other **type** symbols from `@modelcontextprotocol/sdk/types.js` retain their original names. **Zod schemas** (e.g., `CallToolResultSchema`, `ListToolsResultSchema`) are not exported from the package root; for runtime validation prefer type guard functions like `isCallToolResult`, or the `isSpecType` / `specTypeSchemas` Records. For v1 compatibility the schemas are available from the `@modelcontextprotocol/server/zod-schemas` subpath.

### Error class changes

Expand Down
2 changes: 1 addition & 1 deletion docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@
| `IsomorphicHeaders` | Use Web Standard `Headers` |
| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now re-exported by `@modelcontextprotocol/client` and `@modelcontextprotocol/server`) |

All other types and schemas exported from `@modelcontextprotocol/sdk/types.js` retain their original names — import them from `@modelcontextprotocol/client` or `@modelcontextprotocol/server`.
All other **type** symbols from `@modelcontextprotocol/sdk/types.js` retain their original names — import them from `@modelcontextprotocol/client` or `@modelcontextprotocol/server`. **Zod schemas** (e.g., `CallToolRequestSchema`) are not re-exported from the package roots; for runtime validation prefer the `isSpecType` / `specTypeSchemas` Records, or for v1 source compatibility import them from `@modelcontextprotocol/server/zod-schemas`.

Check warning on line 503 in docs/migration.md

View check run for this annotation

Claude / Claude Code Review

'Unchanged APIs' sections in both migration docs still claim Zod schemas only changed import path

This PR rewrote line 503 (and migration-SKILL.md:101) to clarify that Zod schema constants are **not** at the package roots and live at `@modelcontextprotocol/server/zod-schemas` — but the same two files still say the opposite further down: migration.md:896 ("All Zod schemas and type definitions from `types.ts`" under *Unchanged APIs — only the import paths changed*) and migration-SKILL.md:206-207 ("Unchanged APIs … all Zod schemas"). A reader following those sections will map `sdk/types.js` → p
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 This PR rewrote line 503 (and migration-SKILL.md:101) to clarify that Zod schema constants are not at the package roots and live at @modelcontextprotocol/server/zod-schemas — but the same two files still say the opposite further down: migration.md:896 ("All Zod schemas and type definitions from types.ts" under Unchanged APIs — only the import paths changed) and migration-SKILL.md:206-207 ("Unchanged APIs … all Zod schemas"). A reader following those sections will map sdk/types.js → package root per the §3 table and hit TS2305. Suggest dropping "Zod schemas and" from migration.md:896 (or pointing at the /zod-schemas subpath), and dropping "all Zod schemas," from migration-SKILL.md:207.

Extended reasoning...

What's stale

This PR's purpose is to document where Zod schema constants live in v2. It rewrote two lines to that end:

  • docs/migration.md:503 — now reads: "Zod schemas (e.g., CallToolRequestSchema) are not re-exported from the package roots; … import them from @modelcontextprotocol/server/zod-schemas."
  • docs/migration-SKILL.md:101 — now reads: "Zod schemas … are not exported from the package root; … available from the @modelcontextprotocol/server/zod-schemas subpath."

But each file has a second occurrence of the same claim that the PR didn't touch:

  • docs/migration.md:896 — under ## Unchanged APIs whose lead-in is "The following APIs are unchanged between v1 and v2 (only the import paths changed)", the bullet still reads: "All Zod schemas and type definitions from types.ts (except the aliases listed above)".
  • docs/migration-SKILL.md:206-207"Unchanged APIs (only import paths changed): … StdioServerTransport, all Zod schemas, all callback return types."

Both leftover passages list Zod schemas alongside Client, McpServer, StdioServerTransport, etc. — every other item in those lists moved to a package root. The §3 import-mapping table for @modelcontextprotocol/sdk/types.js also points at the package root. So a reader applying "Zod schemas → unchanged, only import path changed → use the §3 mapping" lands on @modelcontextprotocol/server, which is exactly the misconception line 503 was rewritten to dispel.

Why nothing catches it

Both files are prose markdown; no link-checker or symbol-checker validates API names mentioned in them. CI is green. The author updated one occurrence in each file (responding to earlier bot review of line 503) but missed the second occurrence further down — a classic §Completeness leftover ("grep for surviving instances of the old form").

Step-by-step proof (migration.md)

  1. A v1 consumer reads docs/migration.md top-to-bottom and reaches ## Unchanged APIs (line 889).
  2. The lead-in says "only the import paths changed"; line 896 lists "All Zod schemas and type definitions from types.ts" alongside Client, transports, and StdioServerTransport.
  3. Every sibling bullet in that list resolves via the §Package-split mapping (sdk/types.js@modelcontextprotocol/client or @modelcontextprotocol/server).
  4. Consumer writes import { CallToolRequestSchema } from '@modelcontextprotocol/server'.
  5. packages/server/src/index.ts does not re-export CallToolRequestSchema (only zodSchemas.ts does, behind the ./zod-schemas subpath added in this PR) → TS2305 "Module has no exported member 'CallToolRequestSchema'".
  6. This is precisely the failure mode the 2026-04-16 bot review flagged on line 503 ("A consumer reading migration.md will try import { CallToolRequestSchema } from '@modelcontextprotocol/server' and get a type error") and that the PR fixed at 503 — line 896 is the surviving instance.

The same walk-through applies to migration-SKILL.md, which is designed to be loaded into an LLM for mechanical migration; an automated rewrite that pattern-matches "all Zod schemas → only import path changed → apply §3 table" will produce the broken import.

Addressing the refutation (migration-SKILL.md only)

One verifier argued that for migration-SKILL.md specifically, the PR resolved rather than created a contradiction: pre-PR line 101 said schemas were "no longer part of the public API", which flatly contradicted line 207's "all Zod schemas [unchanged]"; post-PR line 101 says they're at /zod-schemas, so line 207's "(only import paths changed)" is now literally true.

That's fair as far as it goes — line 207 is no longer a hard contradiction in the SKILL file. But it remains misleading in context: every other item in that comma-separated list (Client, McpServer, transports, StdioServerTransport, callback return types) maps to a package root via §3, and line 207 names no path, so the only mapping a mechanical reader can apply is the §3 sdk/types.js → package-root one. Line 101 corrects this if read, but an LLM scanning §5's summary list may not back-reference. Importantly, the refuter explicitly agreed that the migration.md:896 case is a genuine leftover ("both lines were previously consistent (and wrong), and the PR's edit to 503 left 896 stale"). Since the PR should fix migration.md:896 anyway, tidying the parallel migration-SKILL.md:207 in the same sweep is essentially free and keeps the two docs aligned.

Impact

Documentation consistency only — no runtime or build impact. Worst case is a confused migrating user (or LLM-driven migration) trying the package root, getting TS2305, and having to re-read §5. Hence nit.

Fix

  • migration.md:896- All type definitions from types.ts(except the aliases listed above); Zod schema constants moved to@modelcontextprotocol/server/zod-schemas`` — or simply drop "Zod schemas and".
  • migration-SKILL.md:207 → drop "all Zod schemas," (line 101 already covers them), or replace with "all Zod schemas (via the /zod-schemas subpath)".


> **Note on `isJSONRPCResponse`:** v1's `isJSONRPCResponse` was a deprecated alias that only checked for *result* responses (it was equivalent to `isJSONRPCResultResponse`). v2 removes the deprecated alias and introduces a **new** `isJSONRPCResponse` with corrected semantics — it checks for *any* response (either result or error). If you are migrating v1 code that used `isJSONRPCResponse`, rename it to `isJSONRPCResultResponse` to preserve the original behavior. Use the new `isJSONRPCResponse` only when you want to match both result and error responses.

Expand Down
4 changes: 4 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
"./public": {
"types": "./src/exports/public/index.ts",
"import": "./src/exports/public/index.ts"
},
"./schemas": {
"types": "./src/types/schemas.ts",
"import": "./src/types/schemas.ts"
}
},
"scripts": {
Expand Down
4 changes: 4 additions & 0 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
},
"./zod-schemas": {
"types": "./dist/zodSchemas.d.mts",
"import": "./dist/zodSchemas.mjs"
},
"./validators/cf-worker": {
"types": "./dist/validators/cfWorker.d.mts",
"import": "./dist/validators/cfWorker.mjs"
Expand Down
37 changes: 37 additions & 0 deletions packages/server/src/zodSchemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* v1-compat re-export of all protocol Zod schemas.
*
* Prefer `specTypeSchemas` / `isSpecType` (from `@modelcontextprotocol/server`)
* for runtime validation. These are Zod schemas; their TS type may change with
* internal Zod upgrades.
*
* @deprecated Use `specTypeSchemas` / `isSpecType` for runtime validation.
* @packageDocumentation
*/
Comment thread
felixweinberger marked this conversation as resolved.

/** @deprecated Use `specTypeSchemas` / `isSpecType` for runtime validation. */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more from a deeper pass (nit, non-blocking): the /** @deprecated */ on lines 12 and 14 doesn't propagate through export * / block-level export {…} to the individual symbols — TS only honors @deprecated on per-specifier JSDoc or the original declaration. So CallToolRequestSchema etc. won't show IDE strikethrough; only the two aliases at 33-37 do. The @packageDocumentation tag covers the TypeDoc page but not call sites. If per-symbol deprecation matters, each name needs its own /** @deprecated */ specifier (~156 of them); if the module-level signal is enough, fine to leave as-is.

Separately — bughunter independently flagged the JSONRPCResponseSchema claim above; same refutation applies (union since v1.25.2).

export * from '@modelcontextprotocol/core/schemas';

/** @deprecated Use `specTypeSchemas` / `isSpecType` for runtime validation. */
export {
IdJagTokenExchangeResponseSchema,
OAuthClientInformationFullSchema,
OAuthClientInformationSchema,
OAuthClientMetadataSchema,
OAuthClientRegistrationErrorSchema,
OAuthErrorResponseSchema,
OAuthMetadataSchema,
OAuthProtectedResourceMetadataSchema,
OAuthTokenRevocationRequestSchema,
OAuthTokensSchema,
OpenIdProviderDiscoveryMetadataSchema,
OpenIdProviderMetadataSchema,
OptionalSafeUrlSchema,
SafeUrlSchema
} from '@modelcontextprotocol/core';

Check warning on line 31 in packages/server/src/zodSchemas.ts

View check run for this annotation

Claude / Claude Code Review

OAuth/auth schema block's @deprecated points to specTypeSchemas/isSpecType, which won't contain OAuth types

The `@deprecated` message on the OAuth/OIDC export block (line 15) was copy-pasted from the protocol-schema block above and points users at `specTypeSchemas` / `isSpecType` — but those are keyed on MCP **spec** types from `core/src/types/schemas.ts`, while `OAuthTokensSchema`, `OAuthMetadataSchema`, `SafeUrlSchema`, etc. live in `core/src/shared/auth.ts` and won't appear there. Since the PR description explicitly targets "token endpoints, OIDC discovery" consumers, this hint sends them to a dead
Comment on lines +15 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The @deprecated message on the OAuth/OIDC export block (line 15) was copy-pasted from the protocol-schema block above and points users at specTypeSchemas / isSpecType — but those are keyed on MCP spec types from core/src/types/schemas.ts, while OAuthTokensSchema, OAuthMetadataSchema, SafeUrlSchema, etc. live in core/src/shared/auth.ts and won't appear there. Since the PR description explicitly targets "token endpoints, OIDC discovery" consumers, this hint sends them to a dead end; consider dropping the replacement pointer on this block (just @deprecated v1-compat shim) or pointing at whatever the v2-native source for auth schemas is intended to be.

Extended reasoning...

What's wrong

packages/server/src/zodSchemas.ts:15 carries the same @deprecated text as line 12:

/** @deprecated Use `specTypeSchemas` / `isSpecType` for runtime validation. */
export {
    IdJagTokenExchangeResponseSchema,
    OAuthClientInformationFullSchema,
    ...
    OAuthTokensSchema,
    OpenIdProviderDiscoveryMetadataSchema,
    ...
    SafeUrlSchema
} from '@modelcontextprotocol/core';

On line 12 the pointer is correct — the wildcard re-export pulls from @modelcontextprotocol/core/schemas (i.e. core/src/types/schemas.ts), which is exactly the surface that specTypeSchemas / isSpecType (#1887) index by spec-type name. On line 15 it isn't: the OAuth/OIDC schemas come from packages/core/src/shared/auth.ts, which is a separate module that has nothing to do with MCP spec types.

Why specTypeSchemas / isSpecType can't cover these

  • specTypeSchemas / isSpecType (per feat(core): add isSpecType / specTypeSchemas Records for runtime validation of spec types #1887 and the PR description's own example, specTypeSchema('CallToolRequest')) are keyed on MCP protocol type names — the contents of core/src/types/schemas.ts.
  • Grep confirms schemas.ts contains zero OAuth* or OpenId* references — the OAuth/OIDC Zod schemas are defined exclusively in core/src/shared/auth.ts.
  • The core public barrel makes the separation explicit: packages/core/src/exports/public/index.ts:18 is annotated "Auth TypeScript types (NOT Zod schemas like OAuthMetadataSchema)" — the auth Zod schemas are deliberately kept off the spec-type surface.

So there will be no specTypeSchemas.OAuthTokens / isSpecType.OAuthMetadata entry for a consumer to migrate to.

Step-by-step proof

  1. A v1 consumer validates a token-endpoint response: OAuthTokensSchema.parse(await res.json()).
  2. They migrate to v2, import OAuthTokensSchema from @modelcontextprotocol/server/zod-schemas, and their IDE shows the deprecation hover from line 15: "Use specTypeSchemas / isSpecType for runtime validation."
  3. They look up specTypeSchemas (from feat(core): add isSpecType / specTypeSchemas Records for runtime validation of spec types #1887) and find it is a Record<SpecTypeName, ZodType> keyed on names like CallToolRequest, JSONRPCMessage, Tool — the contents of schemas.ts.
  4. There is no OAuthTokens, OAuthMetadata, OpenIdProviderMetadata, or SafeUrl key, because those schemas are defined in shared/auth.ts, not types/schemas.ts.
  5. The deprecation pointer is a dead end — there is no v2-native replacement at the location named.

Why this audience matters

The PR description's own motivation calls out "Consumers using them for runtime validation at HTTP boundaries (token endpoints, OIDC discovery, custom transports)" — i.e., OAuth-schema users are an explicitly targeted audience of this subpath. They are precisely the group that will hover OAuthTokensSchema and follow this hint.

Why nothing catches it

Line 15's text was copy-pasted from line 12 when e8a7dcf updated the wording from specTypeSchema() to specTypeSchemas / isSpecType. zodSchemas.ts is excluded from typedoc (typedoc.json:5), and TypeScript doesn't validate @deprecated prose, so no tooling flags the inapplicable pointer. This falls under the repo's recurring "Documentation & Changesets" catch — prose that promises behavior the code doesn't ship misleads consumers.

Impact & fix

Documentation/DX only, no runtime impact — hence nit. But the whole point of this PR is to give v1 consumers correct migration guidance, so a dead-end pointer on one of its two explicitly-named use cases is worth fixing. Either:

/** @deprecated v1-compat shim; OAuth/OIDC Zod schemas have no v2-native replacement yet. */

or simply drop the replacement clause on this block:

/** @deprecated v1-compat shim. */

(or, if there is an intended v2-native home for auth schemas, point there instead).

export {
/** @deprecated Use {@linkcode JSONRPCErrorResponseSchema}. */
JSONRPCErrorResponseSchema as JSONRPCErrorSchema,
/** @deprecated Use {@linkcode ResourceTemplateReferenceSchema}. */
ResourceTemplateReferenceSchema as ResourceReferenceSchema
} from '@modelcontextprotocol/core/schemas';

Check failure on line 37 in packages/server/src/zodSchemas.ts

View check run for this annotation

Claude / Claude Code Review

JSONRPCResponseSchema re-exported with flipped v2 semantics (silently accepts error responses)

The `export *` carries v2's `JSONRPCResponseSchema` (a union of result **and** error responses) under the same name v1 used for the **result-only** schema, so v1 code doing `JSONRPCResponseSchema.parse(msg)` at a transport boundary will now silently accept `{jsonrpc, id, error}` payloads as valid. This is the schema-constant twin of the `isJSONRPCResponse` flip already called out at migration.md:505 — add `JSONRPCResultResponseSchema as JSONRPCResponseSchema` to this alias block (the explicit na
Comment thread
felixweinberger marked this conversation as resolved.
Comment on lines +32 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 The export * carries v2's JSONRPCResponseSchema (a union of result and error responses) under the same name v1 used for the result-only schema, so v1 code doing JSONRPCResponseSchema.parse(msg) at a transport boundary will now silently accept {jsonrpc, id, error} payloads as valid. This is the schema-constant twin of the isJSONRPCResponse flip already called out at migration.md:505 — add JSONRPCResultResponseSchema as JSONRPCResponseSchema to this alias block (the explicit named export shadows the wildcard) and add the JSONRPCResponseSchema → JSONRPCResultResponseSchema row to the removed-aliases tables in both migration docs.

Extended reasoning...

What changed semantically

In v1 (@modelcontextprotocol/sdk@1.20.2, src/types.ts:99-105), JSONRPCResponseSchema was z.object({jsonrpc, id, result}).strict() with the docstring "A successful (non-error) response to a request." — it required result, and .strict() rejected an error key. v1 had no JSONRPCResultResponseSchema; JSONRPCResponseSchema was the canonical success-response schema.

In v2 (packages/core/src/types/schemas.ts:187), the v1 schema was renamed to JSONRPCResultResponseSchema (line 148, same docstring), and a new JSONRPCResponseSchema was introduced as z.union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema]) — it now matches both result and error responses. The migration guide already documents exactly this flip for the type guard at migration.md:505 (isJSONRPCResponseisJSONRPCResultResponse), and guards.ts:71 shows isJSONRPCResponse is implemented as JSONRPCResponseSchema.safeParse(...) — so the schema flipped the same way the guard did.

How the shim leaks the wider schema

zodSchemas.ts:13 does export * from '@modelcontextprotocol/core/schemas', which carries v2's union JSONRPCResponseSchema under the unchanged v1 name. The alias block at lines 32-37 already shadows the wildcard for two sibling renames (JSONRPCErrorResponseSchema as JSONRPCErrorSchema, ResourceTemplateReferenceSchema as ResourceReferenceSchema) but does not add JSONRPCResultResponseSchema as JSONRPCResponseSchema. Per ESM semantics an explicit named export would shadow the same name from export *, so the omission means consumers get the v2 union.

Why nothing catches it

The compat test (zod-schemas.compat.test.ts) only checks instanceof z.ZodType and a CallToolRequestSchema.parse; it never exercises the JSON-RPC envelope schemas. The migration guide's removed-aliases tables (migration.md:492-501, migration-SKILL.md:84-99) list isJSONRPCResponse → isJSONRPCResultResponse but omit the parallel JSONRPCResponseSchema → JSONRPCResultResponseSchema row, so a migrating user has no warning. Because the v2 schema is a strict superset of the v1 schema, nothing fails at compile time and the happy path (result responses) parses identically — the divergence only surfaces when an error response arrives.

Step-by-step proof

  1. v1 consumer has a custom transport doing const ok = JSONRPCResponseSchema.safeParse(raw); if (ok.success) handleResult(ok.data.result); else handleError(raw); — under v1, ok.successraw.result exists (.strict() + required result).
  2. They follow this PR's migration guidance and point the import at @modelcontextprotocol/server/zod-schemas (or, once feat(sdk): @modelcontextprotocol/sdk meta-package with v1 deep-import subpaths #1913 lands, leave it at sdk/types.js).
  3. export * at line 13 binds JSONRPCResponseSchema to v2's z.union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema]).
  4. Server returns {"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error"}}.
  5. v1 schema: .parse() throws / .safeParse().success === false (no result, extra error key under .strict()).
  6. v2 schema via this shim: .safeParse().success === true (matches the JSONRPCErrorResponseSchema arm of the union).
  7. handleResult(ok.data.result) runs with undefined; the error is swallowed.

Impact

This is the PR's stated target use case ("runtime validation at HTTP boundaries… custom transports"), and the changeset promises "v1 imports work unchanged." Same-name/silently-wider-acceptance is the worst failure mode for that promise: unlike a missing export, nothing fails — error responses pass validation as success and downstream code reads .result on an error payload. The repo already considered this footgun serious enough to give isJSONRPCResponse its own callout box in the migration guide; the schema constant deserves the same treatment.

Fix

Add to the alias block at lines 32-37:

export {
    /** @deprecated Use {@linkcode JSONRPCErrorResponseSchema}. */
    JSONRPCErrorResponseSchema as JSONRPCErrorSchema,
    /** @deprecated Use {@linkcode ResourceTemplateReferenceSchema}. */
    ResourceTemplateReferenceSchema as ResourceReferenceSchema,
    /** @deprecated Use {@linkcode JSONRPCResultResponseSchema}. v2's `JSONRPCResponseSchema` now matches both result and error responses. */
    JSONRPCResultResponseSchema as JSONRPCResponseSchema
} from '@modelcontextprotocol/core/schemas';

And add JSONRPCResponseSchema → JSONRPCResultResponseSchema (and JSONRPCResponse → JSONRPCResultResponse for the type) to the removed-aliases tables in docs/migration.md and docs/migration-SKILL.md, alongside the existing isJSONRPCResponse row.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this against v1.25.2, v1.26.0, and v1.29.0 — JSONRPCResponseSchema is already z.union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema]) at all three (src/types.ts:257-258). The result-only form cited above is from v1.20.2; the schema flipped mid-v1, not at v1→v2. So the shim's export * carrying the union matches latest v1 exactly, and aliasing JSONRPCResultResponseSchema as JSONRPCResponseSchema here would actually diverge from v1.29.0.

The guard isJSONRPCResponse did change semantics v1→v2 (v1.29.0:186 has export const isJSONRPCResponse = isJSONRPCResultResponse as a deprecated result-only alias), which migration.md:503 already documents — but /zod-schemas doesn't re-export guards.

The two 🟡 below (migration.md:896 stale "All Zod schemas" line, and the OAuth-block @deprecated pointing at spec-type-only specTypeSchemas) do look real and worth a quick fixup; my approve stands with those as non-blocking nits.

32 changes: 32 additions & 0 deletions packages/server/test/zod-schemas.compat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as z from 'zod/v4';

// Compat: the deprecated `/zod-schemas` subpath re-exports the internal Zod
// schema constants for v1 source compatibility. This test asserts the import
// resolves and the values are usable Zod schemas at runtime.
import {
CallToolRequestSchema,
getResultSchema,
JSONRPCMessageSchema,
ListToolsResultSchema
} from '@modelcontextprotocol/server/zod-schemas';

describe('@modelcontextprotocol/server/zod-schemas (compat subpath)', () => {
it('re-exports Zod schema constants from core', () => {
expect(CallToolRequestSchema).toBeInstanceOf(z.ZodType);
expect(JSONRPCMessageSchema).toBeInstanceOf(z.ZodType);
expect(ListToolsResultSchema).toBeInstanceOf(z.ZodType);
});

it('re-exports the get*Schema lookup helpers', () => {
expect(getResultSchema('tools/call')).toBeInstanceOf(z.ZodType);
});

it('schemas parse valid spec values', () => {
const parsed = CallToolRequestSchema.parse({
method: 'tools/call',
params: { name: 'echo', arguments: {} }
});
expect(parsed.method).toBe('tools/call');
expect(parsed.params.name).toBe('echo');
});
});
4 changes: 3 additions & 1 deletion packages/server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"*": ["./*"],
"@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"],
"@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"],
"@modelcontextprotocol/core/schemas": ["./node_modules/@modelcontextprotocol/core/src/types/schemas.ts"],
"@modelcontextprotocol/test-helpers": ["./node_modules/@modelcontextprotocol/test-helpers/src/index.ts"],
"@modelcontextprotocol/server/_shims": ["./src/shimsNode.ts"]
"@modelcontextprotocol/server/_shims": ["./src/shimsNode.ts"],
"@modelcontextprotocol/server/zod-schemas": ["./src/zodSchemas.ts"]
}
}
}
5 changes: 3 additions & 2 deletions packages/server/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default defineConfig({
failOnWarn: 'ci-only',
// 1. Entry Points
// Directly matches package.json include/exclude globs
entry: ['src/index.ts', 'src/shimsNode.ts', 'src/shimsWorkerd.ts', 'src/validators/cfWorker.ts'],
entry: ['src/index.ts', 'src/zodSchemas.ts', 'src/shimsNode.ts', 'src/shimsWorkerd.ts', 'src/validators/cfWorker.ts'],

// 2. Output Configuration
format: ['esm'],
Expand All @@ -26,7 +26,8 @@ export default defineConfig({
baseUrl: '.',
paths: {
'@modelcontextprotocol/core': ['../core/src/index.ts'],
'@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts']
'@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts'],
'@modelcontextprotocol/core/schemas': ['../core/src/types/schemas.ts']
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion packages/server/typedoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://typedoc.org/schema.json",
"entryPoints": ["src"],
"entryPointStrategy": "expand",
"exclude": ["**/*.test.ts", "**/__*__/**"],
"exclude": ["**/*.test.ts", "**/__*__/**", "**/zodSchemas.ts"],
"navigation": {
"includeGroups": true,
"includeCategories": true
Expand Down
Loading