Skip to content

fix(server): use null-prototype maps for McpServer registries - #3040

Draft
Hugo-DDT wants to merge 2 commits into
modelcontextprotocol:mainfrom
Hugo-DDT:fix/mcp-registry-null-prototype
Draft

Hugo-DDT wants to merge 2 commits into
modelcontextprotocol:mainfrom
Hugo-DDT:fix/mcp-registry-null-prototype

Conversation

@Hugo-DDT

@Hugo-DDT Hugo-DDT commented Oct 16, 2026 •

Copy link
Copy Markdown

Plain {} registries treat Object.prototype names (constructor, toString, proto, …) as already registered, so proxies that expose such upstream tools fail at registration. Initialize tool/prompt/resource registries with Object.create(null) and cover the names with red-green tests.

Fixes #3019

Supersedes closed drafts #3021.

Plain `{}` registries treat Object.prototype names (constructor, toString,
__proto__, …) as already registered, so proxies that expose such upstream
tools fail at registration. Initialize tool/prompt/resource registries with
Object.create(null) and cover the names with red-green tests.

Fixes modelcontextprotocol#3019
Calling tools/call for an unregistered name like toString used to answer
"disabled" via Object.prototype lookup; cover the fixed "not found" path.
@changeset-bot

changeset-bot Bot commented Oct 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: af73cca

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

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/server Patch
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/core-internal 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

@Hugo-DDT Hugo-DDT changed the title [test limit] null-prototype draft fix(server): use null-prototype maps for McpServer registries Oct 16, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

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

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@3040

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@3040

@modelcontextprotocol/server

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

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@3040

@modelcontextprotocol/express

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

@modelcontextprotocol/fastify

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

@modelcontextprotocol/hono

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

@modelcontextprotocol/node

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

commit: af73cca

@karaaslanz karaaslanz left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Independent exact-source check for PR HEAD af73ccabe2ebe226b34af5e3e262f6cad63cde38 (McpServer registry fix).

I extracted the actual initializer expressions for all five registry/cache members from packages/server/src/server/mcp.ts:
_registeredResources, _registeredResourceTemplates, _registeredTools, _registeredPrompts, and _toolInputSchemaJson.

The GitHub blobs were pinned and validated: base 9bc40e903fde15534ec06ff4c1347d47000dbe16 blob bfb3b798b02a3e8218d46acdd7e5832edc34500e; current PR head blob b5751d9c59c67c091cc2634dac02525bb4f196c4.

I exercised five problematic Object.prototype property names (constructor, toString, __proto__, hasOwnProperty, valueOf) against all five maps:

  • Base: 25/25 fresh registry lookups return inherited values, causing an if (registry[name]) registration guard to falsely reject them.
  • PR: 25/25 fresh lookups are undefined, simulated insertion creates an own enumerable property, and 25/25 second registration attempts correctly reject an actual duplicate.
  • This also covers the tool-input schema cache initializer, separately from the resource/tool/prompt registries. The current head's GitHub CI workflows report success.

The read-only, reproducible probe is stored as mcp-ts-3040-registry-prototype-map-redgreen-probe.cjs (SHA256 e6b9ef42ac5b797b2c74b51c5ce8809577f6314292c11f63f53f3b5d856268c8). Scope: source-extracted JavaScript map initialization and property semantics, not a complete McpServer instance, transport-level integration, or full test suite. I found no issue in these paths; the added end-to-end tests and project CI remain the broader evidence. No upstream files were edited.

@0xamlab 0xamlab left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed. On current main, registering tools named constructor, toString, etc. fails with Tool <name> is already registered because {} inherits those keys. After this change the same repro passes for all five names. I also ran the new registerPrototypeNames.test.ts suite: 18 passed, and the full packages/server suite: 595 passed. The fix is narrowly scoped to the registry initializations at packages/server/src/server/mcp.ts:122 using Object.create(null).

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

McpServer.registerTool rejects tool names inherited from Object.prototype (constructor, toString, __proto__)

3 participants