Return '0 B' for negative byte values instead of 'NaN B'.
File sizes cannot be negative, so this is a safe default.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Users hitting the 2.0.0 startup failure land on the README first. Also makes
the three packages qualify for the next release: the release workflow selects
packages by .py/.ts/.md changes, so a dependency-only fix would merge without
publishing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mcp 2.0.0 renamed McpError to MCPError and replaced the low-level Server
decorators with constructor handlers. The three servers had no upper bound,
so a fresh uvx install has resolved 2.0.0 since 2026-07-28 and failed to
start: fetch and time raise ImportError on the McpError import, git raises
AttributeError on server.list_tools().
The floor moves to 1.29.0, the last 1.x release. The previous floors (1.0.0
for git, 1.1.3 for fetch, 1.23.0 for time) resolved versions affected by
GHSA-vj7q-gjh5-988w, GHSA-jpw9-pfvf-9f58, and GHSA-hvrp-rf83-w775.
Porting to the v2 SDK is tracked separately.
Closes#4560Closes#4570Closes#4580
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every filesystem tool operates only on the local filesystem within its allowed
directories — none reaches an open or external world — but none declared the
MCP `openWorldHint` annotation, leaving open-world-hint coverage at 0/14. Set
`openWorldHint: false` on all 14 tools and document it in the README's tool
annotations section.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(filesystem): return valid MCP content type from read_media_file (#4029)
read_media_file returned a content block with type: "blob" for non-image/
non-audio files. "blob" is not a valid MCP content type (the union is
text | image | audio | resource_link | resource), so a strict client rejects
the result on schema validation.
Map the MIME type to a valid block: image/* -> image, audio/* -> audio, and
any other file type -> an embedded resource (the spec-correct carrier for
arbitrary bytes) with a pathToFileURL-encoded uri. Widen the tool's
outputSchema to the matching union and drop the now-unnecessary
`as unknown as CallToolResult` cast so tsc enforces the returned shape.
Tests cover the image, audio, and resource content types, verify the base64
blob round-trips to the original bytes, and assert the resource uri is
percent-encoded (space + non-ASCII) rather than a raw file:// concatenation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(filesystem): assert structuredContent mirrors content in read_media_file tests
The SDK validates content and structuredContent independently against the
outputSchema union, so a refactor that lets the two drift apart (e.g. a
stale image block in structuredContent while content carries the resource)
stays schema-valid and every test stays green. Mirror-equality assertions
on all four callTool cases close that gap (mutation-verified: a schema-valid
drifted structuredContent fails exactly these four assertions).
Also drops a vacuous .not.toBe('blob') assertion that could never add
signal, noting where the real "never blob" guard actually lives (the SDK
client's CallToolResultSchema rejection, upstream of any local assertion).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-ref cancellation is for superseded branch amend-pushes; on main,
every merge keeps its own CI run so failures stay attributable to a
specific commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Previously push-triggered CI ran only on main, so same-repo branches
got no CI until a PR was opened (fork contributions were and remain
covered by pull_request, which fires on open and on every subsequent
push). Run on all pushes, and add a per-ref concurrency group so rapid
amend-pushes cancel superseded runs. Same-repo branches with an open
PR will run under both events; acceptable at this repo's scale.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Releases are now triggered deliberately via workflow_dispatch. The
schedule produced a year of unattended runs stuck awaiting environment
approval, every real release was manually dispatched anyway, and two
runs on the same UTC day collide on the date-based tag. Rename the
workflow to "Release" accordingly and update RELEASING.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Review findings: RELEASING.md claimed publishing happens exclusively
from release.yml with no registry tokens, but typescript.yml and
python.yml still carried release:[published] publish jobs — never
fired (releases are created with GITHUB_TOKEN, which suppresses
workflow triggers) and unable to succeed under OIDC (typescript.yml's
still referenced the deleted NPM_TOKEN). Remove both jobs and their
release triggers; the workflows are now pure CI.
Also:
- add skip-existing to the PyPI publish action so re-runs tolerate
already-uploaded files, and describe the per-registry guard
accurately in RELEASING.md (npm aborts; PyPI skips)
- correct the fresh-dispatch note: same-day dispatches collide on the
date-granular tag rather than minting a new version
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
RELEASING.md documents the pipeline this PR ships (scheduled/dispatch
CalVer releases, OIDC publishing, retry runbook), with a footer noting
the planned Phase 2 changes tracked in #4463. The doc gets updated
when that work merges, not before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Rewrite RELEASING.md as the reference for the target process rather
than a snapshot of the interim state: semver via changesets for
TypeScript / CalVer for Python, versions changed only by PRs on main,
publishing triggered by creating a GitHub Release, per-package
registry-diff guard, OIDC trusted publishing with no registry tokens,
and the failed-publish retry runbook. Implementation tracked in #4463.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Describes how packages publish (release.yml + release environment,
trusted publishing on npm and PyPI, no registry tokens, provenance),
what a release run does, and how to recover from a failed publish leg
(rerun --failed within the window, or ride the next release). Linked
from the root README alongside the other maintainer docs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Review findings from the PR:
- release.py's has_changes() only counted .py/.ts files, so the README
touches meant to enroll the four TS packages in the npm matrix would
have been ignored. Include .md — READMEs ship inside the published
package (npm tarball / PyPI long_description), so doc changes are
release-relevant.
- uv run --frozen pytest for consistency with the job's other uv calls.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
Gate both publish jobs on the package's test suite: npm test
--if-present before the npm build/publish, and pytest (when a tests/
or test/ directory exists, matching python.yml's guard) before the
PyPI build/publish. Previously nothing between tagging and publishing
ran a single test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AViME1R9ES2UXT1uQDx1TG
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
Resolves a fresh batch of Dependabot alerts (disclosed 2026-06-15/16,
after PR #4376 merged) across the fetch, git, and time server lockfiles:
- python-multipart 0.0.27 -> 0.0.32 (CVE-2026-53539 HIGH querystring DoS,
plus CVE-2026-53537/53538/53540 parameter smuggling / buffering)
- cryptography 48.0.0 -> 49.0.0 (GHSA-537c-gmf6-5ccf HIGH, vulnerable
OpenSSL statically linked in wheels < 48.0.1)
- pyjwt 2.12.1 -> 2.13.0 (HIGH + medium JWT advisories)
All three are transitive deps; lockfiles only. Diff scoped to exactly
these 9 version bumps with no other resolution churn. git server tests
unchanged vs base (43 passed; 37 pre-existing Windows tempdir errors).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(memory): expose knowledge graph as MCP Resource
Register the knowledge graph as a readable MCP Resource at
memory://knowledge-graph, enabling clients to discover and read
the graph via the Resources protocol without invoking a tool.
Mutation tools (create_entities, create_relations, add_observations,
delete_entities, delete_observations, delete_relations) now emit
notifications/resources/updated so subscribed clients see live
graph changes.
Resource registration is extracted into the exported
registerKnowledgeGraphResource() function so it can be unit-tested
in isolation, mirroring the everything server's registration
pattern. New tests assert registerResource is called with the
correct kebab-case name, URI, mime type, and that the handler
returns the graph as JSON in the contents array.
Addresses PR #3323 review feedback:
- kebab-case resource name per CLAUDE.md style guide
- single-line comment per CLAUDE.md style guide
- title metadata for client discoverability
- resource update notifications after mutations
- test coverage matching everything/registrations.test.ts pattern
- README documents the new Resource
* feat(memory): support resources/subscribe for the knowledge-graph resource
PR #3323 emitted notifications/resources/updated after every mutation but
the server only advertised resources.listChanged, so resources/subscribe
returned -32601 and a spec-compliant client could never actually subscribe.
Declare resources.subscribe, add subscribe/unsubscribe request handlers that
track subscribed URIs, and only emit notifications/resources/updated when the
client has subscribed to that URI.
Co-authored-by: Lazreg Raed <lazregraed222@gmail.com>
---------
Co-authored-by: olaservo <olahungerford@gmail.com>
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>