Skip to content

feat(compat): restore McpServer.tool()/.prompt()/.resource() variadic overloads#1900

Closed
felixweinberger wants to merge 4 commits intomainfrom
fweinberger/v2-bc-mcpserver-variadic
Closed

feat(compat): restore McpServer.tool()/.prompt()/.resource() variadic overloads#1900
felixweinberger wants to merge 4 commits intomainfrom
fweinberger/v2-bc-mcpserver-variadic

Conversation

@felixweinberger
Copy link
Copy Markdown
Contributor

@felixweinberger felixweinberger commented Apr 15, 2026

Part of the v2 backwards-compatibility series — see reviewer guide.

v2 removed the variadic .tool()/.prompt()/.resource() methods in favor of register* with config objects. This restores them as @deprecated forwarders.

Motivation and Context

v2 removed the variadic .tool()/.prompt()/.resource() methods in favor of register* with config objects. This restores them as @deprecated forwarders.

v1 vs v2 pattern & evidence

v1 pattern:

`server.tool('echo', {msg: z.string()}, async ({msg}) => ({content: [{type:'text', text: msg}]}))`

v2-native:

`server.registerTool('echo', {inputSchema: z.object({msg: z.string()})}, async ({msg}) => ...)`

Evidence: GitHub code search: ~8,300 files use server.tool(. The single highest-volume break.

How Has This Been Tested?

  • packages/server/test/server/mcp.compat.test.ts — 5 cases (all 3 methods, raw shape, warn-once)
  • Integration: validated bump-only against 5 OSS repos via the v2-bc-integration validation branch
  • pnpm typecheck:all && pnpm lint:all && pnpm test:all green

Breaking Changes

None — additive @deprecated shim.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added or updated documentation as needed

Additional context

Stacks on: C1

@felixweinberger felixweinberger added the v2-bc v2 backwards-compatibility series label Apr 15, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 15, 2026

🦋 Changeset detected

Latest commit: 47dc6b5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@modelcontextprotocol/server Patch
@modelcontextprotocol/express Patch
@modelcontextprotocol/fastify Patch
@modelcontextprotocol/hono Patch
@modelcontextprotocol/node Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinberger felixweinberger added this to the v2.0.0-bc milestone Apr 15, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 15, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1900

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1900

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1900

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1900

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1900

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1900

commit: 47dc6b5

@felixweinberger felixweinberger force-pushed the fweinberger/v2-bc-mcpserver-variadic branch from 4e0c457 to 4ab915b Compare April 16, 2026 09:36
@felixweinberger felixweinberger force-pushed the fweinberger/v2-bc-mcpserver-variadic branch 2 times, most recently from 4a6b4de to 910a861 Compare April 16, 2026 16:11
@felixweinberger felixweinberger force-pushed the fweinberger/v2-bc-mcpserver-variadic branch from 910a861 to b44029f Compare April 16, 2026 17:42
@felixweinberger
Copy link
Copy Markdown
Contributor Author

@claude review

Comment thread packages/server/src/server/mcp.ts
Comment thread packages/server/src/server/mcp.ts
Comment thread .changeset/mcpserver-variadic-compat.md Outdated
@felixweinberger
Copy link
Copy Markdown
Contributor Author

@claude review

Comment thread packages/server/src/index.ts
Comment thread packages/server/src/server/mcp.ts Outdated
@felixweinberger
Copy link
Copy Markdown
Contributor Author

@claude review

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

All prior feedback is addressed (empty-object raw shape, changeset wording, InferRawShape export, zod/v4 imports) and I found nothing new — deferring only because this adds ~180 LOC of variadic-disambiguation logic plus four new public type exports, which is enough new API surface to warrant a human sign-off.

Extended reasoning...

Overview

Restores McpServer.tool()/.prompt()/.resource() as @deprecated v1-compat shims that forward to the register* methods. Touches packages/server/src/server/mcp.ts (~180 added lines: 6+4+4 overload signatures, variadic argument disambiguation, isZodRawShape/wrapRawShape helpers, 4 new exported types), packages/server/src/index.ts (re-exports), a new mcp.compat.test.ts, and a changeset.

Feedback status

All four of my earlier comments are resolved in 0dafed3 and 1e2946b: empty {} is now treated as a raw shape (with a regression test), the changeset no longer claims a runtime warning, InferRawShape is re-exported, and both files use import * as z from 'zod/v4'. The migration-docs contradiction is intentionally deferred to #1910 per the author; that's reasonable for a coordinated v2-bc series, though it does mean the docs will briefly disagree with the implementation if this lands first.

Security risks

None. No I/O, auth, or untrusted-input handling — purely internal argument-shape disambiguation that delegates to existing registration paths.

Level of scrutiny

Medium. The implementation is straightforward forwarding, but it (a) adds public API surface (4 exported types + 3 deprecated methods) which per REVIEW.md should be intentional, (b) re-introduces the notoriously fiddly v1 variadic overload resolution where ordering/shape sniffing matters, and (c) introduces a direct zod import into mcp.ts. None of this is wrong, but it's the kind of API-shape decision a maintainer should rubber-stamp rather than a bot.

Other factors

Test coverage exists for the main overloads (raw shape, full 5-arg, zero-arg, empty-object, prompt, resource string+template). The disambiguation logic mirrors v1 semantics including the empty-object edge case. I did not find any new correctness issues on this pass.

@felixweinberger felixweinberger marked this pull request as ready for review April 17, 2026 10:11
@felixweinberger felixweinberger requested a review from a team as a code owner April 17, 2026 10:11
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

All prior feedback is addressed (empty-object raw shape, changeset wording, InferRawShape export, zod/v4 imports) and I have no further findings — deferring final sign-off to a human since this adds ~180 lines of public (deprecated) API surface with non-trivial variadic disambiguation as part of the coordinated v2-bc series.

Extended reasoning...

Overview

Adds @deprecated v1-compat shims McpServer.tool()/.prompt()/.resource() that forward to the v2 register* methods, plus four supporting type exports (ZodRawShape, InferRawShape, LegacyToolCallback, LegacyPromptCallback) and two @internal helpers (isZodRawShape, wrapRawShape). Touches packages/server/src/server/mcp.ts (+~180 lines), the package barrel index.ts, a new mcp.compat.test.ts, and a changeset. All five of my prior inline comments are resolved and verified in the current diff: empty {} is now treated as a raw shape (with a regression test), the changeset no longer claims a runtime warning, InferRawShape is re-exported, and both new zod imports use import * as z from 'zod/v4'.

Security risks

None identified. The shims are pure argument-shape dispatch over user-provided registration data and delegate to the existing _createRegisteredTool/_createRegisteredPrompt/registerResource paths — no new I/O, auth, or untrusted-input parsing.

Level of scrutiny

Medium-high. This is additive and deprecated-from-birth, but it expands the curated public API surface of @modelcontextprotocol/server and encodes variadic disambiguation logic that ~8.3k downstream call sites will exercise. Per REVIEW.md ("every new export is intentional", "burden of proof is on addition"), public-surface additions warrant a maintainer's eye even when the implementation looks correct.

Other factors

  • The migration-docs drift I flagged is intentionally deferred to #1910 per the author; reasonable for a stacked series.
  • Tests cover the main overload permutations including the empty-object edge case; the author also reports OSS integration validation.
  • Two prior review rounds were promptly addressed; no outstanding threads remain.
  • I'm deferring rather than approving because this is a deliberate API-design decision in a coordinated series (see linked reviewer guide), not a mechanical change — a human should ratify the surface shape, not just the implementation correctness.

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

All prior feedback is addressed and I found nothing new — deferring only because this adds three public methods (14 overloads) and four exported types to McpServer, which is enough new public API surface that a maintainer should give the final sign-off.

Extended reasoning...

Overview

Restores the v1 variadic McpServer.tool()/.prompt()/.resource() methods as @deprecated forwarders to registerTool/registerPrompt/registerResource. Touches packages/server/src/server/mcp.ts (+~180 lines: 3 methods with 14 overload signatures, 2 internal helpers, 4 exported types), packages/server/src/index.ts (re-exports), a new mcp.compat.test.ts, and a changeset. Part of the labeled v2-bc series.

Prior feedback — all resolved

  • Empty {} now treated as a raw shape (isZodRawShape uses .every() which is vacuously true) with a regression test.
  • Changeset no longer claims a runtime deprecation warning.
  • InferRawShape re-exported from the package barrel.
  • Both new files use import * as z from 'zod/v4'.
  • Migration-doc updates deferred to #1910 (reasonable scoping).

Security risks

None identified. Pure additive registration-API forwarders; no transport, auth, or untrusted-input handling beyond what register* already does.

Level of scrutiny

Medium-high. The implementation is straightforward and well-tested, but per REVIEW.md ("burden of proof is on addition", "every new export is intentional") this is a deliberate expansion of the package's public surface on its primary class. The design decision (restore-as-deprecated vs. hard break) appears settled at the series level, but signing off on 4 new exports + 3 new methods is a maintainer call, not a bot call.

Other factors

Bug-hunting pass found nothing. Integration-tested against 5 OSS repos per the PR description. CI green.

@felixweinberger
Copy link
Copy Markdown
Contributor Author

Closing — .tool()/.prompt()/.resource() were already @deprecated in v1 (with "Use registerTool instead"), so v2 removing them is the expected deprecation→removal step rather than a surprise break. The codemod (#1950) handles the static-call migration; only dynamic patterns (e.g. registering tools in a forEach) need manual attention. Keeping the shim would be carrying a v1 deprecation forward indefinitely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2-bc v2 backwards-compatibility series

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant