Skip to content

Release v2.4.0: merge v2/main into main - #5518

Merged
cliffhall merged 87 commits into
mainfrom
v2/chore/5509-release-v2.4.0
Nov 11, 2026
Merged

cliffhall merged 87 commits into
mainfrom
v2/chore/5509-release-v2.4.0

Conversation

@cliffhall

@cliffhall cliffhall commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

Part of #5509

Milestone merge for v2.4.0: v2/main → main. No commits of its own;
the merged tree is origin/v2/main's (25499a98), at 6cfff622.

Release ledger: Servers v2.4.0 Release Ledger

🤖 Generated with Claude Code

cliffhall and others added 30 commits November 4, 2026 22:33
search_files matched each excludePatterns entry with one minimatch against
the path relative to the searched root, while directory_tree also matches a
bare name at any depth (**/<name>) and the subtree below it
(**/<name>/**). The same ["node_modules"] argument pruned a nested
node_modules from one tool's result and not the other's.

The predicate now lives in isExcludedPath in lib.ts, directly above
searchFilesWithValidation, and both tools call it. Wildcard patterns keep
matching the relative path as written, names match whole (node_modules_old
stays), and excludes are still checked before validatePath, so an excluded
directory is never realpath'd or read (#4162).

Based on the prototype by @xubenqiang in the issue (commit 128035e).

Closes #5216

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
In edit_file's whitespace-tolerant fallback, a trailing newline on oldText
became an empty last "line" that had to equal the file's next line, so
whole lines copied with their final newline failed to match whenever only
indentation differed. The newline now ends oldText's last line: the match
keeps the file's indentation and must be followed by a newline in the
file. The newline after the match is kept when newText also ends with one;
otherwise newText's last line joins the next line, as an exact replacement
would leave it. Exact matching is unchanged.

Closes #5431

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…rror

A pinned write (write_file, append_file, move_file, copy_file) into a
directory that does not exist failed with Node's chdir error, which named
chdir and the server's own working directory. Entering the anchor now maps
ENOENT/ENOTDIR to "Parent directory does not exist: <directory>", and any
other failure to "<code>: cannot enter directory: <directory>", keeping the
code on the error.

Closes #5432

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The MAX_ANSWER_BYTES guard compared JSON.stringify(answered).length,
which counts UTF-16 code units, so a non-ASCII answer could exceed the
64 KiB byte budget by up to 3x. Measure with Buffer.byteLength(..., "utf8")
and pin it with a protocol-level test whose answer is under the limit by
string length and over it in bytes.

Closes #5419

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
On Windows, isPathWithinAllowedDirectories now throws "Access denied -
NTFS alternate data stream paths are not supported" for a path holding a
colon anywhere but the drive-letter prefix (optionally behind \\?\ or
\\.\), so file.txt:stream and file.txt::$DATA are refused by every tool
with a clear error instead of reading or writing hidden streams. POSIX
hosts are unaffected. Prototyped by andreiminca in #4523.

Closes #5375

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Add a repeatable --read-only-dir <path> option that makes one allowed
directory read-only while the others stay writable (#5348). validatePath
now takes a required access mode; a "write" validation must be handed the
read-only directories and refuses a resolved path inside any of them, so a
write tool cannot skip the check. Every write tool stays listed. move_file
checks both ends, copy_file its destination. Roots never lift the marking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…th HOST to widen

The Streamable HTTP and HTTP+SSE transports called app.listen(port) with
no host, so they bound every interface and a non-browser client on the
local network (which sends no Origin) could reach the server's tools.
listenOrExit now takes the host to bind; both transports resolve it from
HOST, defaulting to 127.0.0.1, and the listening line and the port-in-use
message name the bound address.

The container image sets HOST=0.0.0.0, since loopback inside a container
is unreachable from a published port. The boot smoke pins HOST to the
loopback address it connects to. The README, the Dockerfile and the
local-dev and client-smoke skills document HOST and the new listening
line.

Based on the prototype in #3303 by TheodorNEngoy.

Closes #5371

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The heartbeat in withFileLock refreshed the lock file's mtime
unconditionally. Once the lock was broken as stale and re-taken by another
process, the previous holder kept refreshing the new owner's lock, so a
crashed new owner's lock could never go stale. The heartbeat now re-reads
the lock token first, as the release path does, and stops the interval on
a mismatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The server read a whole response body into memory before converting or
truncating it, so a URL serving a very large or endless body made it
buffer all of it. Bodies are now streamed and read up to a fixed 5 MiB
cap, counted after content decoding: a page whose Content-Length is over
the cap is refused unread, and one that streams past it is refused once
it does. robots.txt is parsed from its first 5 MiB. Redirects are
followed by hand so a redirect's own body is closed unread, since httpx
reads it whole before following.

Based on the prototype in #4185 by @neuralmanacle.

Closes #5370

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…_path

The --repository option's help text read only "Git repository path", so
--help never said that omitting it leaves every reachable repository in
scope. The help now says the option confines operations to the
repository (any path inside it selects the whole repository) and that
without it every repository the server process can reach is in scope.
validate_repo_path's docstring documents the allowed_repository=None
behavior, and test_main_help asserts the new text. The README warning
already shipped in #5225.

Closes #5230

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
A max_count of 0 or below reached git log unvalidated: -1 returned the
whole history and 0 returned nothing, both as success. The schema now
carries minimum: 1, so SDK argument validation returns a tool error, and
git_log() guards the bound as defense in depth.

Closes #5214

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The interface diff ran on any PR that touched the root lockfile, which is
almost every TypeScript PR, and covered only `everything`.

- scripts/lib/interface-diff-servers.mjs: the server table (how each of
  the seven boots for a probe) and the selection: a server's own files,
  the root tsconfig (TypeScript servers), a package-lock.json edit that
  changes a package the server resolves (its tree walked in both
  lockfiles), and every server when the diff tooling or the pinned
  mcp-server-diff changes.
- scripts/interface-diff.mjs: --server, --all and --list; builds each
  selected base (one npm ci for the TypeScript ones, uv sync for the
  Python ones) and probes Python servers through uv run --no-sync; one
  report per server under <report-dir>/<server>/.
- everything-mcp-diff.yml -> mcp-interface-diff.yml: a `changes` job
  lists the servers, `diff` and `comment` fan out per server with a
  per-server sticky comment and artifact. The security split, the release
  and dispatch triggers and the fork fallback are kept. Both version-PR
  workflows dispatch it, since the CalVer stamps now touch a diffed server.
- The gate's stage diffs only the servers changed since the merge-base,
  through the same selection.
- Docs: quality-gate.md, AGENTS.md, RELEASING.md, the pre-push-gate and
  release skills.

Closes #5428

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Rewrite the descriptions of list_directory and list_directory_with_sizes
(filesystem) and delete_entities and delete_relations (memory) so each says
when to use it and names its sibling. delete_relations also states the
exact-match rule on from, to and relationType, and points to open_nodes for
reading the stored relationType first. Names, schemas and annotations are
unchanged. The READMEs follow, with new tests that read the descriptions
through tools/list, and a patch changeset per server.

Closes #5071

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
context_servers is an object, not an array, and Zed's settings take a
flat string `command` with a separate `args` list. Each snippet is now a
complete JSON object that parses on its own; git's nested
`command.path` shape is replaced with the one Zed documents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
- llm-analysis-assistant: the icon's alt text named Langfuse (copied from
  another entry); it now names the project.
- OpenTools: github.com/opentoolsteam is 404. Point the attribution at
  github.com/opentools, the org opentools.com itself links to.
- AgentR: agentr.dev returns 402 DEPLOYMENT_DISABLED on / and /home, so
  the attribution keeps the name and drops the dead link.
- README Community: github.com/orgs/modelcontextprotocol/discussions is
  404; link the live discussions on modelcontextprotocol/modelcontextprotocol.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…he workspace lockfile

Each image now installs with `npm ci --workspace src/<server>` from the
root package.json and package-lock.json, so the root lockfile and its
`overrides` reach the image instead of a lockfile-less `npm install`.
The release stage uses `--omit=dev` (`--omit-dev` is not an npm flag).
Each Dockerfile gets a `Dockerfile.dockerignore` allow-list for the
repository-root context, the shape src/everything/Dockerfile set (#3309).

sequentialthinking keeps no state and now runs as the `node` user.
filesystem and memory stay root for now: their bind mounts and volumes
are written by the server, so the switch is decided in #4741. memory
keeps /app (a symlink to the workspace directory), so the documented
`claude-memory:/app/dist` volume still holds the graph.

Closes #5345

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
move_file now validates both ends in a "move" mode that also refuses a
path containing a read-only directory, so moving its parent cannot carry
a protected subtree out from under the marking. A read-only directory
that does not exist yet is resolved through its nearest existing
ancestor, so a symlinked ancestor cannot leave it unprotected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The fetch, git and time images created an app user and chowned the
virtualenv to it but never switched to it, and the filesystem, memory and
sequentialthinking images never used the node user their base image ships,
so all six ran their server as root.

Each now ends on USER app or USER node. The Python images install the
uv-managed interpreter under /python instead of /root/.local, which the app
user cannot read, and give app a home directory. The git image trusts every
mounted repository (safe.directory '*'), since a bind mount is rarely owned
by app. The memory image gives /app/dist, where its default graph lives, to
node. The READMEs cover the gitconfig path, --user on Linux hosts, and the
one-time chown of a memory volume an older image created.

Closes #4741

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…elimited

- GitHub dispatches only a workflow whose file is on the default branch,
  and both version workflows dispatch this one by file name from v2/main,
  so the rename to mcp-interface-diff.yml would break their dispatch until
  the next milestone merge. The file stays everything-mcp-diff.yml; its
  display name and status context still change.
- git diff --name-only and ls-files C-quote a path holding a non-ASCII
  character, a tab or a newline, which then matched no server directory
  and passed with nothing to diff. Both now use -z.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The old note told users to delete the volume's index.js, which leaves
/app/dist with no entry point: the claude-memory volume is mounted over
/app/dist and a non-empty named volume is never re-seeded from a newer
image. Replace it with a command that swaps the volume's *.js files for
the new image's while keeping memory.jsonl, and describe the
alternative of a data-only volume with MEMORY_FILE_PATH, including how
to move an existing graph into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…onfig-snippets

docs(git, time): make the Zed configuration snippets valid JSON
A model reads a property's description to decide what to pass; with none
it guesses from the name. 19 filesystem properties, 4 memory properties
and everything's resourceType advertised no description.

Every filesystem path argument now states how it is resolved and that it
must stay inside the allowed directories, and excludePatterns states the
matching rule, which differs between directory_tree (a bare name matches
at any depth) and search_files (it matches like pattern). read_file
advertises ReadTextFileArgsSchema instead of an inline copy of it.

A new input-descriptions test in each TypeScript server walks every
tools/list input schema, nested properties included, and fails on any
property with no description, so a tool added later keeps the rule. The
filesystem one also pins the two excludePatterns rules the descriptions
state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
- everything: express ^5.3.0, jszip ^3.10.2 (with a patch changeset)
- fetch, git, time: uv lock --upgrade within declared ranges, ruff
  held at its locked 0.8.x (0.17 enables new default rules)
- workflows: bump SHA-pinned actions within their majors
  (setup-node v7.1.0, setup-python v7.1.0, upload-artifact v7.0.2,
  download-artifact v8.0.2, claude-code-action v1.0.266,
  gh-action-pypi-publish v1.14.3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…hing-tasks-answer-bytes

fix(everything): count tasks/update answers in UTF-8 bytes
…thing-loopback-bind

everything: bind the HTTP transports to loopback by default, with HOST to widen
…e-additional-link-fixes

docs: fix alt text and dead links in README and ADDITIONAL.md
httpx's gzip and deflate decoders inflate each network chunk whole, so
one small chunk of a compressed body could allocate far past the 5 MiB
cap before the size check saw it: a 199 KiB gzip body made one decode
step allocate 200 MiB. The server now reads raw bytes and inflates them
itself with zlib's max_length set to the room left under the cap, so no
step produces more than one byte past it. It asks for and decodes only
gzip and deflate, and refuses any other content coding (br, zstd, a
chain of codings) rather than decode it without a bound.

The test harness now serves each response unread over its stream, as a
network transport does: a response built with content= is read and
decoded when constructed, which left nothing for a raw read.

Refs #5370

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…ockerfiles-workspace-lockfile

chore(docker): build filesystem, memory and sequentialthinking from the workspace lockfile
cliffhall and others added 14 commits November 10, 2026 00:11
…match-override

chore(deps): override minimatch to ^11.0.1 for the lint tooling
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…on-calver-2026.11.11

chore: stamp Python CalVer versions for 2026.11.11
@cliffhall cliffhall added the v2 label Nov 11, 2026
Copilot AI balanced review requested due to automatic review settings November 11, 2026 06:26
@changeset-bot

changeset-bot Bot commented Nov 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6cfff62

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@github-actions

Copy link
Copy Markdown
Contributor

filesystem: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 4 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 16 0 0 1
Head 16 0 0 1

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"
+ tools[append_file].inputSchema.properties.path.description: "The file to append to; it is created if it does not exist. Absolute, or relative to an allowed direc..."
+ tools[create_directory].inputSchema.properties.path.description: "The directory to create, with any missing parents; an existing directory is left as is. Absolute, or..."
+ tools[directory_tree].inputSchema.properties.excludePatterns.description: "Patterns for entries to leave out, with their contents, matched against each entry's path relative t..."
+ tools[directory_tree].inputSchema.properties.path.description: "The directory at the root of the tree. Absolute, or relative to an allowed directory; it must resolv..."
+ tools[edit_file].inputSchema.properties.edits.description: "The replacements to make, applied in order, each to the result of the ones before it. If any one has..."
+ tools[edit_file].inputSchema.properties.path.description: "The text file to edit. Absolute, or relative to an allowed directory; it must resolve inside the all..."
+ tools[get_file_info].inputSchema.properties.path.description: "The file or directory to describe. Absolute, or relative to an allowed directory; it must resolve in..."
- tools[list_directory].description: "Get a detailed listing of all files and directories in a specified path. Results clearly distinguish..."
+ tools[list_directory].description: "List the files and directories directly inside a path, each marked [FILE] or [DIR]. Use it to see wh..."
+ tools[list_directory].inputSchema.properties.path.description: "The directory to list. Absolute, or relative to an allowed directory; it must resolve inside the all..."
- tools[list_directory_with_sizes].description: "Get a detailed listing of all files and directories in a specified path, including sizes. Results cl..."
+ tools[list_directory_with_sizes].description: "List the files and directories directly inside a path with each file's size, marked [FILE] or [DIR],..."
+ tools[list_directory_with_sizes].inputSchema.properties.path.description: "The directory to list. Absolute, or relative to an allowed directory; it must resolve inside the all..."
+ tools[move_file].inputSchema.properties.destination.description: "Its new path, including the name; nothing may exist there yet. Absolute, or relative to an allowed d..."
+ tools[move_file].inputSchema.properties.source.description: "The file or directory to move or rename. Absolute, or relative to an allowed directory; it must reso..."
+ tools[read_file].inputSchema.properties.path.description: "The file to read as text. Absolute, or relative to an allowed directory; it must resolve inside the ..."
+ tools[read_media_file].inputSchema.properties.path.description: "The image, audio or other file to read as base64. Absolute, or relative to an allowed directory; it ..."
+ tools[read_text_file].inputSchema.properties.path.description: "The file to read as text. Absolute, or relative to an allowed directory; it must resolve inside the ..."
+ tools[search_files].inputSchema.properties.excludePatterns.description: "Patterns for entries to leave out, with their contents, matched against each entry's path relative t..."
+ tools[search_files].inputSchema.properties.path.description: "The directory to search under. Absolute, or relative to an allowed directory; it must resolve inside..."
+ tools[search_files].inputSchema.properties.pattern.description: "Glob matched against each entry's path relative to path, never its content: '*.ts' matches directly ..."
+ tools[write_file].inputSchema.properties.content.description: "The complete text the file will contain, replacing any it had"
+ tools[write_file].inputSchema.properties.path.description: "The file to create, or to overwrite if it exists; its parent directory must exist. Absolute, or rela..."

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

memory: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 4 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 9 0 1 0
Head 9 0 1 0

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.1.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.1.1"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.1.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.1.1"
+ tools[add_observations].inputSchema.properties.observations.description: "The observations to add, grouped by entity. Each entity must already exist; an observation it alread..."
+ tools[create_entities].inputSchema.properties.entities.description: "The entities to create, each with a name unique in the graph"
+ tools[create_relations].inputSchema.properties.relations.description: "The relations to create. Both ends must name existing entities; a relation already in the graph is n..."
- tools[delete_entities].description: "Delete multiple entities and their associated relations from the knowledge graph"
+ tools[delete_entities].description: "Delete whole entities from the knowledge graph, together with every relation that points to or from ..."
+ tools[delete_observations].inputSchema.properties.deletions.description: "The observations to delete, grouped by entity, each matched by its exact text"
- tools[delete_relations].description: "Delete multiple relations from the knowledge graph"
+ tools[delete_relations].description: "Delete specific relations (from, to, relationType) from the knowledge graph and keep the entities th..."

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.1.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.1.1"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.1.0"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.1.1"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

time: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 5 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 3 0 0 0
Head 3 0 0 0

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

prompts

--- base/prompts.json
+++ target/prompts.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

git: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 5 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 14 2 0 0
Head 14 2 0 0

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"
+ tools[git_log].inputSchema.properties.max_count.description: "Maximum number of commits to show. Must be at least 1."
+ tools[git_log].inputSchema.properties.max_count.minimum: 1

prompts

--- base/prompts.json
+++ target/prompts.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

everything: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 5 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 22 4 8 5
Head 22 4 8 5

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.1"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.1"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"
- tools[get-resource-reference].inputSchema.properties.resourceId.description: "ID of the text resource to fetch"
+ tools[get-resource-reference].inputSchema.properties.resourceId.description: "ID of the text or blob resource to fetch, a positive integer"
+ tools[get-resource-reference].inputSchema.properties.resourceType.description: "Whether to reference a text resource or a blob resource"

prompts

--- base/prompts.json
+++ target/prompts.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.1"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.1"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2.2.1"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2.3.0"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

sequentialthinking: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

✅ No interface changes detected.

Tools Prompts Resources Resource templates
Base 1 0 0 0
Head 1 0 0 0

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

@github-actions

Copy link
Copy Markdown
Contributor

fetch: MCP interface diff

Base: 36380287ed3b (Merge pull request #5430 from modelcontextprotocol/v2/chore/5425-release-v2.3.0)
Head: the build in this checkout, at 6999fb7e40d6 (Merge 6cfff62 into 3638028)

Diffed because it was named (--server).

⚠️ Interface changes detected in 5 part(s) of the interface. Review them below to confirm they are intended.

Tools Prompts Resources Resource templates
Base 1 1 0 0
Head 1 1 0 0

initialize

--- base/initialize.json
+++ target/initialize.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

tools

--- base/tools.json
+++ target/tools.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

prompts

--- base/prompts.json
+++ target/prompts.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resources

--- base/resources.json
+++ target/resources.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

resource_templates

--- base/resource_templates.json
+++ target/resource_templates.json

- _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.4"
+ _meta.io.modelcontextprotocol/serverInfo.version: "2026.11.11"

Updated by this run for 6cfff622fb8eb41e2504340d5a6105d34094143c.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The placeholder release ledger and unavailable container build/upgrade validation leave release readiness uncorroborated, requiring maintainer verification before merging.

No open issues 🎉

What changed in this PR

Brings the v2.4.0 milestone changes from v2/main into main, supporting release tracking in #5509. Package publication remains a separate release step.

Changes:

  • Strengthens filesystem access controls, memory lock ownership checks, HTTP binding defaults, and non-root container execution.
  • Expands regression coverage and improves tool descriptions, client configuration examples, and upgrade guidance.
  • Updates package versions, dependencies, and release tooling documentation for interface comparisons across all servers.
File Description
src/​time/​tests/​test_server.py Tightens timezone exception assertions and formats tests.
src/​time/​tests/​test_protocol.py Simplifies startup-error test context managers.
src/​time/​tests/​test_entrypoints.py Adds stderr fixture and clarifies subprocess expectations.
src/​time/​src/​mcp_server_time/​server.py Cleans up imports and exception formatting.
src/​time/​README.md Corrects Zed configuration JSON.
src/​time/​pyproject.toml Updates release version and Ruff requirement.
src/​time/​Dockerfile Makes Python accessible to the non-root runtime.
src/​sequentialthinking/​Dockerfile.dockerignore Restricts the image’s build context.
src/​sequentialthinking/​Dockerfile Uses locked workspace installs and non-root execution.
src/​sequentialthinking/​__tests__/​input-descriptions.test.ts Checks descriptions throughout tool input schemas.
src/​memory/​README.md Clarifies deletion tools and Docker volume upgrades.
src/​memory/​package.json Bumps the package to 2.1.1.
src/​memory/​index.ts Checks heartbeat ownership and improves tool descriptions.
src/​memory/​Dockerfile.dockerignore Restricts the image’s build context.
src/​memory/​Dockerfile Adds locked builds and writable non-root storage.
src/​memory/​CHANGELOG.md Records the 2.1.1 fixes.
src/​memory/​__tests__/​tools.test.ts Updates expected tool descriptions and schemas.
src/​memory/​__tests__/​tool-descriptions.test.ts Verifies deletion guidance and matching behavior.
src/​memory/​__tests__/​input-descriptions.test.ts Checks descriptions throughout tool input schemas.
src/​memory/​__tests__/​file-lock.test.ts Covers heartbeat shutdown after lock replacement.
src/​git/​tests/​test_server.py Tests rejection of non-positive log limits.
src/​git/​tests/​test_remote.py Reorders imports.
src/​git/​tests/​test_prompts.py Reorders imports.
src/​git/​tests/​test_merge.py Tests failed-merge cleanup without repository hooks.
src/​git/​tests/​test_identity.py Cleans up import spacing.
src/​git/​tests/​test_eras.py Reorders test-helper imports.
src/​git/​tests/​test_entrypoints.py Checks repository-scope help and cleans up tests.
src/​git/​tests/​snapshots/​list_tools.json Records the minimum commit-count constraint.
src/​git/​src/​mcp_server_git/​__init__.py Clarifies repository confinement in CLI help.
src/​git/​README.md Documents repository safeguards and updates container/client setup.
src/​git/​pyproject.toml Updates release version and Ruff requirement.
src/​git/​Dockerfile Enables non-root execution with mounted-repository support.
src/​filesystem/​tsconfig.json Formats the source inclusion list.
src/​filesystem/​read-only-directories.ts Adds read-only directory resolution and enforcement helpers.
src/​filesystem/​path-validation.ts Rejects unsafe Windows names and recognizes UNC roots.
src/​filesystem/​package.json Bumps the package to 2.3.0.
src/​filesystem/​index.ts Parses and configures repeatable read-only directories.
src/​filesystem/​file-resources.ts Uses anchored reads for file resources.
src/​filesystem/​Dockerfile.dockerignore Restricts the image’s build context.
src/​filesystem/​Dockerfile Uses locked workspace installs and non-root execution.
src/​filesystem/​CHANGELOG.md Records 2.3.0 features and fixes.
src/​filesystem/​__tests__/​windows-reserved-names-host.test.ts Tests Windows restrictions and POSIX filename compatibility.
src/​filesystem/​__tests__/​stdio.test.ts Updates expected CLI usage text.
src/​filesystem/​__tests__/​server-tools.test.ts Updates schema, anchored-read, and missing-parent assertions.
src/​filesystem/​__tests__/​search-exclude-patterns.test.ts Checks consistent exclusion behavior across search and tree tools.
src/​filesystem/​__tests__/​read-only.test.ts Updates argument parsing and usage expectations.
src/​filesystem/​__tests__/​path-validation.test.ts Covers trailing-name restrictions and UNC roots.
src/​filesystem/​__tests__/​missing-parent-error.test.ts Checks actionable write errors without working-directory disclosure.
src/​filesystem/​__tests__/​list-directory-descriptions.test.ts Verifies directory-listing guidance and non-recursive behavior.
src/​filesystem/​__tests__/​input-descriptions.test.ts Checks input descriptions and documented exclusion rules.
src/​filesystem/​__tests__/​file-resources.test.ts Adapts error mocking to descriptor-based reads.
src/​filesystem/​__tests__/​edit-trailing-newline.test.ts Covers whitespace-tolerant edits with trailing newlines.
src/​filesystem/​__tests__/​confine-roots.test.ts Updates parsed-argument expectations.
src/​filesystem/​__tests__/​append-file.test.ts Checks the clearer missing-parent error.
src/​filesystem/​__tests__/​alternate-data-streams.test.ts Tests Windows stream-path rejection using simulated paths.
src/​filesystem/​__tests__/​alternate-data-streams-host.test.ts Checks stream rejection and POSIX colon-name compatibility.
src/​fetch/​tests/​test_translated_addresses.py Covers IPv4-translated IPv6 address handling.
src/​fetch/​tests/​test_protocol.py Adds robots-path normalization and IPv6 refusal cases.
src/​fetch/​tests/​test_html_charset.py Simplifies default UTF-8 encoding syntax.
src/​fetch/​tests/​test_entrypoints.py Moves stderr setup into a fixture.
src/​fetch/​tests/​test_allowed_hosts.py Uses explicit text-content type assertions.
src/​fetch/​tests/​harness.py Presents mock responses as unread network streams.
src/​fetch/​README.md Documents response limits, robots matching, and address filtering.
src/​fetch/​pyproject.toml Updates release version and Ruff requirement.
src/​fetch/​Dockerfile Makes Python accessible to the non-root runtime.
src/​everything/​transports/​streamableHttp.ts Applies configurable host binding and address logging.
src/​everything/​transports/​sse.ts Applies configurable host binding and address logging.
src/​everything/​transports/​listen.ts Defaults HTTP listeners to loopback.
src/​everything/​tools/​get-resource-reference.ts Clarifies resource input descriptions.
src/​everything/​server/​tasks.ts Measures answer limits in UTF-8 bytes.
src/​everything/​README.md Documents host binding and container networking.
src/​everything/​package.json Bumps version, updates Express, and removes JSZip.
src/​everything/​docs/​features.md Clarifies the task answer byte limit.
src/​everything/​Dockerfile Uses numeric non-root identity and container-wide binding.
src/​everything/​CHANGELOG.md Records 2.3.0 networking and maintenance changes.
src/​everything/​__tests__/​tasks.test.ts Covers non-ASCII answer byte limits.
src/​everything/​__tests__/​surface.test.ts Updates expected resource input descriptions.
src/​everything/​__tests__/​streamable-http.test.ts Checks default and explicit host binding.
src/​everything/​__tests__/​sse.test.ts Checks default and explicit host binding.
src/​everything/​__tests__/​listen.test.ts Tests real bind addresses and host-related errors.
src/​everything/​__tests__/​input-descriptions.test.ts Checks input descriptions across both protocol eras.
scripts/​version-pr-ci.test.mjs Expects interface-diff dispatches for both version workflows.
scripts/​smoke-servers.mjs Pins HTTP smoke servers to loopback.
scripts/​interface-diff.test.mjs Tests server selection, launch commands, and reports.
RELEASING.md Updates dispatched interface-diff status guidance.
README.md Corrects the community discussions link.
package.json Adds a transitive Minimatch override.
docs/​quality-gate.md Documents interface comparisons for each affected server.
AGENTS.md Updates gate guidance for multi-server interface comparisons.
ADDITIONAL.md Corrects community attribution, links, and image alt text.
.github/​workflows/​version-packages.yml Updates comments to reflect broader interface comparisons.
.github/​workflows/​sdk-watch.yml Refreshes pinned action revisions.
.github/​workflows/​release.yml Refreshes pinned build and publishing actions.
.github/​workflows/​prepare-python-release.yml Dispatches interface comparisons for Python version PRs.
.claude/​skills/​release/​SKILL.md Updates guidance for four dispatched release checks.
.claude/​skills/​pre-push-gate/​SKILL.md Documents multi-server interface-diff usage and troubleshooting.
.claude/​skills/​local-dev/​SKILL.md Documents HTTP host defaults and listening output.
.claude/​skills/​client-smoke/​SKILL.md Updates the documented listening-line example.

Review effort: Balanced

@cliffhall

Copy link
Copy Markdown
Member Author

Release verification for v2.4.0, run on this PR's head 6cfff622 (tree 25499a98, identical to origin/v2/main's). Summary of the release ledger linked in the body, for reviewers who cannot open it:

@cliffhall
cliffhall merged commit e1dc4b1 into main Nov 11, 2026
117 of 120 checks passed
@cliffhall
cliffhall deleted the v2/chore/5509-release-v2.4.0 branch November 11, 2026 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants