The NPM_TOKEN used by publish-npm is dead (npm classic-token sunset) —
both June release attempts failed publishing with a disguised auth error
(E404 on the publish PUT) after PyPI legs succeeded. Each
@modelcontextprotocol/* package's npm trusted publisher is being bound to
this workflow (release.yml) + the release environment, so publish-npm now
authenticates via OIDC instead of a token:
- add id-token: write permission to publish-npm (required to mint the
OIDC token; contents: read added explicitly since setting permissions
drops the defaults)
- upgrade the npm CLI in the publish job (trusted publishing requires
npm >= 11.5.1; Node 22 bundles an older npm)
- drop NODE_AUTH_TOKEN from the publish step
Also touch each TypeScript server's README (add everything's missing
License section; link each package's npm page) so scripts/release.py
includes all four packages in the next npm publish matrix — they've been
stranded on npm at 2026.1.26 while PyPI advanced to 2026.6.16.
See #4463 for the rollout plan.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Real fixes (deps):
- python (git/fetch/time): idna 3.10->3.18 (GHSA-65pc), starlette
0.49.1->1.3.1 (GHSA-86qp)
- npm: vitest ^2.1.8->^4.1.8 (critical GHSA-5xrq UI server RCE). vitest 4
pulls vite 8 (rolldown, no esbuild), clearing the esbuild/vite advisories
natively. Remaining root overrides: qs>=6.15.2 (GHSA-q8mj, via express),
hono>=4.12.21 (via @modelcontextprotocol/sdk).
- npm audit: 0 vulnerabilities; all TS (313) + Python (git/fetch/time) suites
and TS builds pass.
Hardening (git_add):
- The repo already mitigates CVE-2026-27735 by using repo.git.add (the git
CLI rejects out-of-tree paths, PR #3164's fix), not repo.index.add (which
did not). Add an explicit path-boundary check in git_add as defense in
depth plus regression tests asserting the security invariant (out-of-tree
paths are never staged), guarding against a regression to repo.index.add.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* url elicitation
* single tool for normal and error path
* Address review feedback on URL elicitation tool
- Remove src/everything/pnpm-lock.yaml (monorepo uses npm workspaces)
- Drop redundant TriggerUrlElicitationSchema.parse(args) in the handler;
destructure directly from args like the other tools, since the SDK
validates against the registered schema before invoking the handler
- Add explicit accept/decline/cancel messaging in the request path,
mirroring trigger-elicitation-request.ts
- Clarify the registerTool count comment in registrations.test.ts
(task-based tools register via registerToolTask, counted separately)
- Add tests covering the no-url / undefined-capability registration
guards, the randomUUID() elicitationId fallback, and the
decline/cancel response paths (100% coverage of the tool)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add tool annotations to trigger-url-elicitation
Match the annotations block on sibling elicitation tools and the
CLAUDE.md guidance. Uses openWorldHint: true since the tool drives an
external browser flow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(everything): prevent URL elicitation error-path infinite loop
The trigger-url-elicitation tool's error path (errorPath=true) threw
UrlElicitationRequiredError (-32042) carrying the same URL that failed and
re-threw it on every retry, so clients looped (and tripped their own loop
detection).
- Point the prerequisite elicitation at a different URL
(https://modelcontextprotocol.io) than the failing request.
- Track issued prerequisites by the inputs a client resends on retry
(session + url + caller-supplied elicitationId); a plain retry is then
recognized, ignores errorPath, and proceeds via the request path instead
of re-throwing the prerequisite.
- Update tests and docs accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(everything): address review on URL elicitation error path
- Replace raw NUL byte delimiters in errorPathKey with the \u0000 escape
sequence so the source stays plain text and the diff is reviewable
(same collision-proof delimiter at runtime).
- Add a one-shot test reset helper + beforeEach so the suite is robust to
the module-level marker state regardless of order.
- Use a dedicated prerequisite message instead of reusing the caller's.
- Document the unbounded-growth tradeoff as a demo simplification and note
the one-shot marker semantics in docs/features.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: evalstate <1936278+evalstate@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* url elicitation
* single tool for normal and error path
* Address review feedback on URL elicitation tool
- Remove src/everything/pnpm-lock.yaml (monorepo uses npm workspaces)
- Drop redundant TriggerUrlElicitationSchema.parse(args) in the handler;
destructure directly from args like the other tools, since the SDK
validates against the registered schema before invoking the handler
- Add explicit accept/decline/cancel messaging in the request path,
mirroring trigger-elicitation-request.ts
- Clarify the registerTool count comment in registrations.test.ts
(task-based tools register via registerToolTask, counted separately)
- Add tests covering the no-url / undefined-capability registration
guards, the randomUUID() elicitationId fallback, and the
decline/cancel response paths (100% coverage of the tool)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add tool annotations to trigger-url-elicitation
Match the annotations block on sibling elicitation tools and the
CLAUDE.md guidance. Uses openWorldHint: true since the tool drives an
external browser flow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: cliffhall <cliff@futurescale.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Update get-annotated-message description: all tools now have
tool-level annotations, not just this one
- Add missing tool entries: simulate-research-query,
trigger-elicitation-request-async, trigger-sampling-request-async
- Add these tools to the file tree listing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The upstream main added simulate-research-query and async tools that
use server.experimental.tasks.registerToolTask. Update mock servers
to include this API.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed ~29 tests that were adding noise rather than coverage:
- Registration boilerplate tests (16): redundant with registrations.test.ts
- Redundant role/type checks (3): consolidated into behavioral tests
- "Should not throw" tests (6): consolidated into single lifecycle test
- Constant identity tests (2): provided no safety net
- expect(true).toBe(true) test (1): replaced with actual assertion
- Weak capability test (1): removed, handler check already exists
Strengthened remaining tests:
- Resource templates test now verifies specific resource names
- File resources test now asserts registerResource was called
Test count: 124 → 95 (29 removed)
Coverage unchanged at ~71%
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously only get-annotated-message had ToolAnnotations. Now all 18
tools explicitly declare readOnlyHint, destructiveHint, idempotentHint,
and openWorldHint so the server serves as a complete reference for
developers implementing tool annotations per the MCP spec.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a tool like `gzip-file-as-resource` is called multiple times with the
same output name (especially the default `README.md.gz`), the server would
throw "Resource already registered" because the SDK doesn't allow
registering duplicate URIs.
This fix:
- Tracks registered resources by URI in a module-level Map
- Before registering a new resource, checks if the URI already exists
- If it does, removes the old resource using the SDK's `remove()` method
- Then registers the new resource with fresh content
This allows tools to be called repeatedly with the same parameters without
errors, which is important for LLM agents that may retry tool calls.
Found using Bellwether (https://bellwether.sh), an MCP server validation tool.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"Everything Server crashes when multiple clients reconnect"
* In index.ts
- added a variable to hold the initialize timeout
- store the timeout in the oninitialized handler
- clear the timeout in the cleanup callback
* In roots.ts
- In the catch block of syncRoots, log the error to the console via .error rather than attempting to send to the client because the most probable case here is that we don't have a connection.
"Everything Server crashes when multiple clients reconnect"
* In index.ts
- added a variable to hold the initialize timeout
- store the timeout in the oninitialized handler
- clear the timeout in the cleanup callback
* In roots.ts
- In the catch block of syncRoots, log the error to the console via .error rather than attempting to send to the client because the most probable case here is that we don't have a connection.
* In simulate-research-query.ts
- remove redundant local variable in getTask
* Everywhere else, prettier.
- Use params.task instead of params._meta.task for task metadata
- Remove pollInterval from task requests (only available on result)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement graceful degradation for elicitation on HTTP transport:
- STDIO: Full elicitation works via sendRequest
- HTTP: Catches elicitation failure, uses default interpretation
- Task completes successfully on both transports
simulate-research-query now uses try-catch around sendRequest and
includes explanatory message when elicitation is skipped on HTTP.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update documentation to reflect that simulate-research-query now sends
elicitation requests directly from the background task instead of using
the tasks/result side-channel approach.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of waiting for the client to call tasks/result to trigger
elicitation, the server now sends elicitation/create directly from
the background process using sendRequest. This simplifies the flow:
- Server sends elicitation proactively when clarification is needed
- Client receives and handles it via existing elicitation handler
- Task resumes and completes after receiving the response
- Client's polling sees completed status
This approach avoids requiring the client to detect input_required
status and call tasks/result as a side-channel.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add readOnlyHint, destructiveHint, idempotentHint, and openWorldHint
annotations to the tool config. Update docs to reflect that this tool
now demonstrates both tool-level and content annotations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tools that demonstrate bidirectional MCP tasks where the server
sends requests to the client for async execution:
- trigger-sampling-request-async: Send sampling request with task
params, client creates task and executes LLM call in background,
server polls for completion and retrieves result
- trigger-elicitation-request-async: Same pattern for user input,
useful when user may take time to fill out forms
Both tools:
- Check client capabilities (tasks.requests.sampling/elicitation)
- Accept both CreateTaskResult and direct result responses
- Poll tasks/get for status updates
- Fetch final result via tasks/result
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tasks capability with list, cancel, and requests.tools.call
- Add InMemoryTaskStore and InMemoryTaskMessageQueue from SDK experimental
- Add simulate-research-query tool demonstrating task lifecycle
- Task demonstrates working -> input_required -> completed status flow
- Uses elicitation for ambiguous queries when client supports it
Closes#3037🦉 Generated with [Claude Code](https://claude.ai/code)
The syncRoots call should be idempotent, requesting roots if they haven't been yet for the session, but always retuning the cached roots otherwise. That could be deferred but setting the handler for roots_list changed note should not.
* In server/roots.ts
- only set the notification handler and call for initial roots list if the roots aren't already cached for this client.
* In server/index.ts
- in the oninitialized handler
- get the sessionId from the transport
- set a 350ms timeout to call syncRoots with the server and sessionId
- this delay cause it to run after the `notifications/initialized` handler finishes, otherwise, the request gets lost.
* All other changes attributable to prettier
* In server/roots.ts
- in syncRoots, if roots are supported fetch them
* In get-roots-list.ts,
- Don't import and inspect current roots map, just call syncRoots to get the list.
* In how-it-works.md,
- added a section on conditional tool registration
* In server/index.ts
- import registerConditionalTools
- in an oninitialized handler for the server, call registerConditionalTools
- removed clientConnected from ServerFactoryResponse and all mentions in docs
* In tools/index.ts
- export a registerConditionalTools function
- refactor/move calls to registerGetRootsListTool, registerTriggerElicitationRequestTool, and registerTriggerSamplingRequestTool out of registerTools and into registerConditionalTools
* In server/roots.ts
- only act if client supports roots
- remove setInterval from call to requestRoots. It isn't happening during the initialze handshake anymore, so it doesn't interfere with that process if called immediaately
* In get-roots-list.ts, trigger-elicitation-request.ts, and trigger-sampling-request.ts,
- only register tool if client supports capability
* Throughout the rest of the files, removing all references to `clientConnected`