Skip to content

fix(server): honour enabled on resource templates - #2694

Open
sainikhiljuluri wants to merge 2 commits into
modelcontextprotocol:mainfrom
sainikhiljuluri:fix/resource-template-enabled
Open

fix(server): honour enabled on resource templates#2694
sainikhiljuluri wants to merge 2 commits into
modelcontextprotocol:mainfrom
sainikhiljuluri:fix/resource-template-enabled

Conversation

@sainikhiljuluri

Copy link
Copy Markdown

Fixes #2693

Problem

enabled is written for resource templates but never read, so disable() is a no-op. A static resource registered through the same registerResource call is guarded correctly:

tpl.enabled                → false            // the flag is set
resources/list             → ["secret://alpha"]     // still listed
resources/templates/list   → ["secret://{id}"]      // still listed
read secret://alpha        → "SECRET alpha"         // still served
read res://public          → REJECTED: Resource res://public disabled   // static is correct
completion/complete        → ["alpha","beta"]       // still completing

disable() also fires notifications/resources/list_changed, so the SDK reports a list change that did not happen.

Fix

Four enabled checks in packages/server/src/server/mcp.ts, each matching the guard its sibling primitive already has:

site mirrors
resources/list template loop the static filter three lines above
resources/templates/list same filter
resources/read template match the static guard eight lines above, same message
handleResourceCompletion if (!prompt.enabled) in the prompt path

Kept as inline checks rather than a shared helper, since the eight existing enabled checks are all inline and a helper used only by templates would be the odd one out.

One judgement call worth flagging: in resources/read the guard throws inside if (variables), so a disabled template shadows a later enabled template matching the same URI rather than falling through. That matches what static resources already do today — a disabled static resource errors instead of falling through to a template that would match — and fail-closed seems right for an API whose purpose is withdrawing access. Happy to switch to skip-and-continue if you prefer. A test pins the current choice.

Tests

Six unit tests in packages/server/test/server/resourceTemplateEnabled.test.ts, one per guard plus the shadowing case and an enable() restore.

Reverting only mcp.ts fails five of the six, each on the bug itself:

expected [ { name: 'alpha', … } ] to deeply equal []
expected [ { name: 'secret', … } ] to deeply equal []
expected { contents: [ … ] } to be undefined
expected { completion: { … } } to be undefined
expected { contents: [ … ] } to be undefined

The sixth (enable() restores) passes either way by design — it guards against over-correcting.

I also added a resource-template body to mcpserver:handle:enable-disable in test/e2e/scenarios/dynamic.test.ts. The requirement is written generically but was only exercised with a RegisteredTool, which is why this gap survived. All eight cells fail without the fix.

packages/server 43 files / 481 tests, pnpm -r --no-bail test green across every package, typecheck and lint clean. test/e2e's protocol:timeout:max-total fails ~2 runs in 3 on unpatched main — pre-existing flake, unrelated.

Notes

  • Patch bump: this corrects behaviour to match documented intent rather than changing an API. enabled defaults to true and only update() can clear it, so only code that explicitly called disable() is affected.
  • v1.x has the same omission. Happy to open a backport if useful — not included here.
  • packages/server-legacy has no template registry, so nothing to do there.

Per CONTRIBUTING this is a straightforward bug fix with tests, so I filed the report and the fix together rather than waiting. Glad to close either if you would rather discuss first.


AI assistance was used to investigate and write this change.

sainikhiljuluri and others added 2 commits August 21, 2026 00:26
registerResource returns a handle with enable(), disable() and enabled for
every primitive, but nothing ever read the flag for resource templates. A
disabled template stayed in resources/list and resources/templates/list, was
still served by resources/read, and still answered completion/complete, while
disable() fired resources/list_changed as if the list had changed.

Static resources registered through the same call were already guarded, so the
two behaved differently three lines apart in the same handler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The mcpserver:handle:enable-disable requirement is written generically but
was only exercised with a RegisteredTool, which is why the resource-template
gap went unnoticed. Adds a second body for a template, and corrects the
changeset to say every registration handle rather than registerResource.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sainikhiljuluri
sainikhiljuluri requested a review from a team as a code owner August 21, 2026 07:31
@changeset-bot

changeset-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 543361c

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/core Patch
@modelcontextprotocol/client Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/codemod 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

@pkg-pr-new

pkg-pr-new Bot commented Aug 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

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

@modelcontextprotocol/codemod

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

@modelcontextprotocol/core

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

@modelcontextprotocol/server

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

@modelcontextprotocol/server-legacy

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

@modelcontextprotocol/express

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

@modelcontextprotocol/fastify

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

@modelcontextprotocol/hono

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

@modelcontextprotocol/node

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

commit: 543361c

@claude claude Bot added the v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes label Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resource templates ignore enabled: disable() leaves them listed, readable and completable

1 participant