Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
15c8b0c
Port fetch, git and time to the MCP Python SDK v2
cliffhall Oct 7, 2026
b5af226
chore: migrate the TypeScript servers to TS SDK v2 (#4856)
cliffhall Oct 7, 2026
ccab68c
docs(skills): the TypeScript servers are on SDK v2 but still legacy-e…
cliffhall Oct 7, 2026
d13408d
Serve only the legacy era from the Python servers
cliffhall Oct 7, 2026
b614ecc
fix: address Copilot round 1 on #5063
cliffhall Oct 7, 2026
019d40c
Add purpose headers and rename two tests after the SDK v2 port
cliffhall Oct 7, 2026
2ca5de7
chore(changeset): drop pending notes for the task tools #4856 removes
cliffhall Oct 7, 2026
92eca9c
chore(changeset): match the conditional-tools note to its one remaini…
cliffhall Oct 7, 2026
623a8df
Call out the unknown-method error code change from SDK v2
cliffhall Oct 7, 2026
4f39a54
fix: address Copilot round 3 on #5063
cliffhall Oct 7, 2026
701c2aa
chore(changeset): record SDK v2's 10 MiB stdio message cap (#4856)
cliffhall Oct 7, 2026
ff6d4e1
docs(everything): name the v2 transports in structure.md (#4856)
cliffhall Oct 7, 2026
6246e0f
Merge branch 'v2/main' into v2/chore/4856-ts-sdk-v2
cliffhall Oct 7, 2026
0d61612
Merge pull request #5063 from modelcontextprotocol/v2/chore/4856-ts-s…
cliffhall Oct 7, 2026
41a154d
Merge branch 'v2/main' into v2/chore/4851-python-sdk-v2
cliffhall Oct 7, 2026
0763da6
Merge pull request #5062 from modelcontextprotocol/v2/chore/4851-pyth…
cliffhall Oct 7, 2026
d0d81b1
ci: add MCP interface diff workflow for Everything server
SamMorrowDrums Jan 28, 2026
4948cdc
fix: update mcp-server-diff to v2.3.5
SamMorrowDrums Jan 28, 2026
e245576
fix: use full paths instead of working-directory
SamMorrowDrums Jan 28, 2026
9f05f49
ci: add concurrency group and fix mcp-server-diff SHA pin
inexistenzz Jun 10, 2026
124b28f
ci: post sticky PR comment with MCP diff report
inexistenzz Jun 10, 2026
afc0711
ci: also run MCP diff on TypeScript release tags
inexistenzz Jun 10, 2026
e5ca90c
ci(everything): run the interface diff as an npm script on v2/main (#…
cliffhall Oct 4, 2026
dde6224
docs: record the interface diff as a gate stage (#4860)
cliffhall Oct 4, 2026
b35e29d
ci(everything): diff a Release against the previous Release (#4860)
cliffhall Oct 4, 2026
f242458
fix(interface-diff): check out the event's SHA; report the CLI's stde…
cliffhall Oct 4, 2026
0c2a61d
fix(interface-diff): diff a Release against its own predecessor (#4860)
cliffhall Oct 4, 2026
a793ed4
fix(interface-diff): Dependabot, root tsconfig, Windows quoting (#4860)
cliffhall Oct 4, 2026
b15cf21
fix(interface-diff): give each push and release run its own group (#4…
cliffhall Oct 4, 2026
fe4cef3
fix(interface-diff): never pass a report without a verdict (#4860)
cliffhall Oct 4, 2026
ff19179
fix(interface-diff): bound the job summary; watch the Windows helper …
cliffhall Oct 4, 2026
9d7128c
fix(interface-diff): drop target_ref; keep both streams in errors (#4…
cliffhall Oct 4, 2026
6eebb0c
chore(interface-diff): refresh the lockfile after rebasing onto v2/ma…
cliffhall Oct 10, 2026
d52c223
time: accept only exact IANA timezone keys on every platform
cliffhall Oct 10, 2026
d7388c6
test(memory): expect Node 26's path-suffixed EISDIR message
cliffhall Oct 10, 2026
8efea13
Merge pull request #5077 from modelcontextprotocol/v2/fix/5060-time-c…
cliffhall Oct 10, 2026
4423f2c
Merge pull request #5078 from modelcontextprotocol/v2/fix/5076-memory…
cliffhall Oct 10, 2026
4d0fcbe
Merge branch 'v2/main' into v2/chore/4860-everything-interface-diff
cliffhall Oct 10, 2026
1a9554d
Merge pull request #4975 from modelcontextprotocol/v2/chore/4860-ever…
cliffhall Oct 10, 2026
cd34c3b
chore(deps): pin proxy-addr to ^2.0.8 (GHSA-jqcg-44mw-7w3h)
cliffhall Oct 10, 2026
916ccca
chore(deps): pin ip-address to ^10.7.1 (GHSA-mwp4-54f8-5fhr and six m…
cliffhall Oct 10, 2026
5f0b9b9
chore(deps): pin brace-expansion to ^5.0.12 (GHSA-rgw5-rvv9-x895 and …
cliffhall Oct 10, 2026
ed640a1
chore(deps): raise the hono override to >=4.13.7 (GHSA-8j4g-w8fx-2239…
cliffhall Oct 10, 2026
c88aa6d
chore(deps): raise the qs override to >=6.16.0 (GHSA-x5fp-wj9c-mxmx, …
cliffhall Oct 10, 2026
d261885
chore(deps): pin nanoid to ^3.3.18 (GHSA-2v37-7h3g-55p8)
cliffhall Oct 10, 2026
fb942ea
chore(deps): pin source-map-js to ^1.2.2 (GHSA-68fv-2mgg-jv7q)
cliffhall Oct 10, 2026
12efa9b
chore(deps): bump vitest and @vitest/coverage-v8 to ^4.1.11 (GHSA-82f…
cliffhall Oct 10, 2026
73fe328
chore(fetch): require protego>=0.6.2 (PYSEC-2026-3906)
cliffhall Oct 10, 2026
c8cee71
chore(git): require gitpython>=3.1.60 (PYSEC-2026-3783 and fourteen m…
cliffhall Oct 10, 2026
ce54c89
chore(python): lock cryptography 50 (PYSEC-2026-3552)
cliffhall Oct 10, 2026
ac259b6
chore(python): lock pyjwt 2.15 (PYSEC-2026-4140 and twelve more)
cliffhall Oct 10, 2026
ef6bffb
chore(fetch): lock urllib3 2.8 (PYSEC-2026-4175, -4176, -4177)
cliffhall Oct 10, 2026
478a08e
chore(fetch): lock soupsieve 2.10 (PYSEC-2026-4170, -4171)
cliffhall Oct 10, 2026
0c505a6
chore: fold the pending changesets into a 1.0.0 CHANGELOG entry per T…
cliffhall Oct 10, 2026
34d715a
Merge pull request #5082 from modelcontextprotocol/v2/chore/5080-rele…
cliffhall Oct 10, 2026
eb991bd
chore: credit @cliffhall without the Thanks prefix in the 1.0.0 chang…
cliffhall Oct 10, 2026
7327e89
Merge pull request #5083 from modelcontextprotocol/v2/chore/5080-type…
cliffhall Oct 10, 2026
3423e57
chore: stamp Python CalVer versions for 2026.10.10
cliffhall Oct 10, 2026
207fa99
Merge pull request #5084 from modelcontextprotocol/v2/chore/5080-pyth…
cliffhall Oct 10, 2026
211aa1e
docs(release): warn against Update branch on the milestone merge PR
cliffhall Oct 10, 2026
aa7fa78
docs(release): reset to the update merge's first parent, not origin/v…
cliffhall Oct 10, 2026
5ea217b
fix(filesystem): revoke access when a roots update leaves no valid root
cliffhall Oct 10, 2026
de49bdd
fix(filesystem): say the client exposes no valid roots, not none
cliffhall Oct 10, 2026
423fe6b
fix(filesystem): apply only the newest roots refresh's answer
cliffhall Oct 10, 2026
3e005bb
Merge pull request #5095 from modelcontextprotocol/v2/fix/5094-filesy…
cliffhall Oct 10, 2026
564e84d
fix(filesystem): keep tool calls waiting for the update that overtook…
cliffhall Oct 10, 2026
11394a4
test(filesystem): assert waiting calls are released before the initia…
cliffhall Oct 10, 2026
fc5e9c9
test(filesystem): wait for the stale initial answer before teardown
cliffhall Oct 10, 2026
c9fdf34
Merge pull request #5098 from modelcontextprotocol/v2/fix/5097-filesy…
cliffhall Oct 10, 2026
92f9558
fix(filesystem): hold tool calls while any roots refresh is pending
cliffhall Oct 10, 2026
dcaa6fe
fix(filesystem): install each roots refresh barrier before its roots/…
cliffhall Oct 10, 2026
43980dc
fix(filesystem): claim the initial roots load's generation before def…
cliffhall Oct 10, 2026
3e41913
fix(filesystem): wake calls waiting on a replaced roots refresh
cliffhall Oct 10, 2026
5429925
Merge pull request #5102 from modelcontextprotocol/v2/fix/5101-filesy…
cliffhall Oct 10, 2026
b4d3a6f
ci(release): publish with Node 24's bundled npm instead of installing…
cliffhall Oct 10, 2026
4d13264
test(release): pin the publish job's npm floor check and its no-insta…
cliffhall Oct 10, 2026
28b468e
test(release): pin the ./ tarball path npm publish needs
cliffhall Oct 10, 2026
c6f0cf7
Merge pull request #5093 from modelcontextprotocol/v2/docs/5092-relea…
cliffhall Oct 10, 2026
e718eca
Merge pull request #5105 from modelcontextprotocol/v2/chore/5104-rele…
cliffhall Oct 10, 2026
eda4646
fix(fetch): annotate the fetch tool
cliffhall Oct 10, 2026
0cfc5c7
Merge pull request #5112 from modelcontextprotocol/v2/fix/3572-fetch-…
cliffhall Oct 11, 2026
5ecca0c
Merge v2/release/1.0.0 into v2/main
cliffhall Oct 11, 2026
5b400a6
chore(changeset): restore the SDK v2 majors, drop fixes shipped in 1.0.0
cliffhall Oct 11, 2026
9245b93
Merge pull request #5118 from modelcontextprotocol/v2/chore/5117-reco…
cliffhall Oct 11, 2026
a8a13d3
ci: guard main so a PR into it brings nothing not already on v2/main
cliffhall Oct 11, 2026
9422c3f
test: pin main-source.yml's safety properties; name the guard as a ga…
cliffhall Oct 11, 2026
c9c6e0e
docs(release): the admin escape hatch for a release that cannot be a …
cliffhall Oct 11, 2026
8002268
docs(release): run the escape hatch's disable, merge and re-enable un…
cliffhall Oct 11, 2026
2f8dc42
Merge pull request #5120 from modelcontextprotocol/v2/chore/5119-guar…
cliffhall Oct 11, 2026
38fa696
feat(fetch,git,time): serve the 2026-07-28 era beside 2025-11-25
cliffhall Oct 11, 2026
c32f931
Merge pull request #5126 from modelcontextprotocol/v2/feat/4853-pytho…
cliffhall Oct 12, 2026
89d6642
feat: serve both protocol eras on stdio in filesystem, memory and seq…
cliffhall Oct 11, 2026
27b2d24
feat(everything): serve both protocol eras and demonstrate the 2026-0…
cliffhall Oct 11, 2026
9ef661c
test(everything): cover both protocol eras and the 2026-07-28 features
cliffhall Oct 12, 2026
419200b
docs: show which feature belongs to which protocol era; changesets fo…
cliffhall Oct 12, 2026
4735ab3
docs(client-smoke): the TypeScript servers now serve 2026-07-28
cliffhall Oct 12, 2026
7f3b522
fix: task timestamps, task capability gates, async form validation, s…
cliffhall Oct 12, 2026
d19037a
fix(everything): refuse task tools and tasks/* without the extension …
cliffhall Oct 12, 2026
c059fb6
chore(release-notes): put the release-ledger line under the Packages …
cliffhall Oct 12, 2026
4416643
fix(everything): tasks/update ignores non-outstanding answers; bound …
cliffhall Oct 12, 2026
8d40eb2
Merge pull request #5132 from modelcontextprotocol/v2/chore/5115-rele…
cliffhall Oct 12, 2026
d9ce091
fix(everything): bound the task store; document the async task tools'…
cliffhall Oct 12, 2026
ddbd190
fix(everything): catch failed list-change sends; require inputRespons…
cliffhall Oct 12, 2026
8eea6d9
fix(everything): refuse a minted resource over the byte budget; simul…
cliffhall Oct 12, 2026
88410f8
fix(everything): keep live tasks until their TTL; acknowledge any can…
cliffhall Oct 12, 2026
0d01ee5
fix(everything): answer a JSON primitive POST body as an invalid requ…
cliffhall Oct 12, 2026
2b830d4
fix(everything): bound the answers a task keeps; correct the task-lim…
cliffhall Oct 12, 2026
7bb70f6
fix(everything): declare get-header-params' nullable regionHeader wit…
cliffhall Oct 12, 2026
6d613ec
Merge pull request #5131 from modelcontextprotocol/v2/feat/4852-moder…
cliffhall Oct 12, 2026
e923f51
docs: always start PR work in a new git worktree
cliffhall Oct 13, 2026
dedd411
docs: record the v2/main ruleset in AGENTS.md
cliffhall Oct 13, 2026
3875197
docs(pr-flow): use the generic branch pattern in the worktree cleanup
cliffhall Oct 13, 2026
d01c3df
docs(release): cut the release branches into worktrees too
cliffhall Oct 13, 2026
0a861a9
Merge pull request #5140 from modelcontextprotocol/v2/chore/5121-prot…
cliffhall Oct 13, 2026
c41c367
Merge pull request #5139 from modelcontextprotocol/v2/docs/5138-pr-wo…
cliffhall Oct 13, 2026
ce15905
ci: declare read-only GITHUB_TOKEN permissions in python.yml and type…
cliffhall Oct 13, 2026
d7f76a6
Merge pull request #5141 from modelcontextprotocol/v2/chore/5091-work…
cliffhall Oct 13, 2026
0d40c33
docs: add an AGENTS.md rule for pacing bulk GitHub writes
cliffhall Oct 13, 2026
fd55745
fix(scripts): double backslashes before a quote in win-shell-args
cliffhall Oct 13, 2026
d6fd666
fix(sequentialthinking): pad the thought box's header row to the border
cliffhall Oct 13, 2026
c2df185
fix(git): prefix git_show diff headers with a/ and b/
cliffhall Oct 13, 2026
6e44a2c
docs: pace the triage and recovery loops under the hourly cap
cliffhall Oct 13, 2026
dba6d5f
docs(issue-triage): pace step 0's comment and close as separate writes
cliffhall Oct 13, 2026
59abda2
Merge pull request #5143 from modelcontextprotocol/v2/fix/5111-win-sh…
cliffhall Oct 13, 2026
7f4922b
Merge pull request #5144 from modelcontextprotocol/v2/fix/5108-sequen…
cliffhall Oct 13, 2026
5902152
Merge branch 'v2/main' into v2/fix/5107-git-show-diff-prefixes
cliffhall Oct 13, 2026
810ec72
docs(skills): drop the restated pacing limits and pace step 0 at 8 s
cliffhall Oct 13, 2026
0584bee
Merge pull request #5142 from modelcontextprotocol/v2/docs/5133-pace-…
cliffhall Oct 13, 2026
2ffe79f
ci: dispatch CI on the version PRs that automation opens
cliffhall Oct 13, 2026
3de22b0
Merge pull request #5145 from modelcontextprotocol/v2/fix/5107-git-sh…
cliffhall Oct 13, 2026
7071ed7
ci: validate the TypeScript servers on Node 22, 24 and 26 in parallel
cliffhall Oct 13, 2026
0b58b33
ci: report dispatched CI runs on the PR as commit statuses
cliffhall Oct 13, 2026
0f1ac4f
docs(quality-gate): list the Validate legs per Node in the stage table
cliffhall Oct 13, 2026
521ddb2
ci: finalize a cancelled dispatched run's status, and pin the path
cliffhall Oct 13, 2026
e92e82f
Merge pull request #5147 from modelcontextprotocol/v2/chore/5068-node…
cliffhall Oct 13, 2026
38569bd
Merge pull request #5146 from modelcontextprotocol/v2/chore/5110-vers…
cliffhall Oct 13, 2026
29746ba
chore: drop "Thanks" from the changesets attribution, keep the author
cliffhall Oct 18, 2026
16548d0
Merge pull request #5163 from modelcontextprotocol/v2/chore/5161-chan…
cliffhall Oct 18, 2026
41752e3
chore: version packages
github-actions[bot] Oct 18, 2026
4be9e98
Merge pull request #5100 from modelcontextprotocol/changeset-release/…
cliffhall Oct 18, 2026
38fdee2
chore: stamp Python CalVer versions for 2026.10.18
cliffhall Oct 18, 2026
bbcc15b
Merge pull request #5165 from modelcontextprotocol/v2/chore/5159-pyth…
cliffhall Oct 18, 2026
1ad67f5
fix: raise the TypeScript servers' Node floor to 24
cliffhall Oct 19, 2026
8061773
Merge pull request #5169 from modelcontextprotocol/v2/fix/5168-node-f…
cliffhall Oct 19, 2026
99b11a4
Merge main into v2/main so main-source.yml shares history (#5171)
cliffhall Oct 19, 2026
306f5a4
ci: run the main-source guard on Node 24 again (#5168)
cliffhall Oct 19, 2026
4c7fcdf
Merge pull request #5172 from modelcontextprotocol/v2/chore/5171-merg…
cliffhall Oct 19, 2026
400777f
feat(time): build on MCPServer; an unknown tool is JSON-RPC -32602
cliffhall Oct 19, 2026
50c6823
feat(fetch): build on MCPServer; an unknown tool is a -32602 error (#…
cliffhall Oct 19, 2026
916cdc9
feat(git): build the git server on MCPServer; unknown tool is -32602
cliffhall Oct 19, 2026
2b2e2a2
fix(git): report a detached HEAD in git_create_branch instead of catc…
cliffhall Oct 19, 2026
a5587f2
test(git): expect the platform's form of / in the outside-repository …
cliffhall Oct 19, 2026
005e7e6
fix(python): serialize git tool calls, delegate malformed names, requ…
cliffhall Oct 19, 2026
f1783c3
Merge pull request #5175 from modelcontextprotocol/v2/feat/5174-pytho…
cliffhall Oct 19, 2026
eaaa712
chore: stamp Python CalVer versions for 2026.10.19
cliffhall Oct 19, 2026
d533150
fix(ci): a superseded dispatched run posts no status, whatever its jo…
cliffhall Oct 19, 2026
803df28
Merge pull request #5177 from modelcontextprotocol/v2/chore/5159-pyth…
cliffhall Oct 19, 2026
163a5e9
test: skip the dispatch-status script tests without bash or jq
cliffhall Oct 19, 2026
f18beb7
Merge pull request #5179 from modelcontextprotocol/v2/fix/5178-dispat…
cliffhall Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"$schema": "https://unpkg.com/@changesets/config@4.0.1/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "modelcontextprotocol/servers" }
{
"repo": "modelcontextprotocol/servers",
"template": "\n\n- {pull} {commit} {authors} - {summary}"
}
],
"commit": false,
"fixed": [],
Expand Down
6 changes: 5 additions & 1 deletion .claude/skills/board-ops/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,17 @@ if [ -s "$BOARD_TMP/lost-ids.json" ]; then
gh project item-edit --project-id PVT_kwDOCt2Azc4BcZgq --id "$id" \
--field-id PVTSSF_lADOCt2Azc4BcZgqzhXCpm0 --single-select-option-id <NEW_OPTION_ID> \
|| { echo "item-edit failed on $id — stopping; re-run step 1 to see what is left" >&2; break; }
sleep 0.4
sleep 8 # a sustained loop: see AGENTS.md "Pacing GitHub writes"
done
else
echo "no lost-ids.json — step 1 did not complete; nothing re-applied" >&2
fi
```

Step 3 is a sustained loop, so it sleeps 8 s between edits, long enough to stay
inside every limit in `AGENTS.md` **Pacing GitHub writes** for as long as it
runs: a restore of 250 cards takes about 35 minutes.

Step 1's join is the safety check: only a card that held the deleted option in
the snapshot is re-applied, so you don't overwrite a card that was already blank
or that someone legitimately cleared in the meantime. Read its "NOT restored"
Expand Down
48 changes: 25 additions & 23 deletions .claude/skills/client-smoke/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,27 +172,27 @@ CLI) or **Server Settings → Protocol Era** (the web UI):
| `modern` | Pins 2026-07-28 through `server/discover`, with no fallback |
| `auto` | Probes `server/discover`, and falls back to `initialize` |

⚠️ **Only the legacy era can be exercised against these servers today.** All
seven are on a v1 SDK (`@modelcontextprotocol/sdk` 1.x, `mcp` 1.x), whose
newest protocol version is 2025-11-25. None implements `server/discover`. So:

- `--protocol-era modern` fails, by design, with `Version negotiation failed:
the server did not offer pinned protocol version 2026-07-28 via
server/discover (no fallback in pin mode)` and exit 1. That is the expected
result for an unmigrated server, not a regression in your change.
- `--protocol-era auto` succeeds, but through the fallback, so it is a legacy
connection and proves nothing about 2026-07-28.

The both-eras check that `/pr-flow` asks for (#4857) therefore has one half
that can pass today. For a server that does not yet serve the modern era,
record the legacy run, and say in the PR that the server does not yet speak
2026-07-28 rather than leaving the modern era unmentioned. Moving a server to
a v2 SDK (#4856 for TypeScript, #4851 for Python) does not change that by
itself: those keep the legacy wire behavior. Modern-era support arrives with
#4852 (TypeScript) and #4853 (Python). Once a server has it, run every command
twice, with `--protocol-era legacy` and `--protocol-era modern`, and expect
both to succeed. Do not use `auto` for evidence in either case: it
does not say which era answered.
**Every server serves both eras**: the Python servers since #4853, the
TypeScript servers since #4852 (stdio through the SDK's `serveStdio`, and
`everything`'s Streamable HTTP endpoint through `createMcpHandler` for
2026-07-28 requests). Run every command twice, with `--protocol-era legacy`
and `--protocol-era modern`, and expect both to succeed. A 2026-07-28 result
carries `io.modelcontextprotocol/serverInfo` in its `_meta`, which is the
quick way to see which era answered. Do not use `auto` for evidence: it does
not say which era answered.

`everything` lists some tools on one era only (the task tools on 2026-07-28,
the two `toggle-*` tools on the 2025 era), so a `tools/list` that differs
between the two runs is expected.

The CLI declares no client capabilities, so a tool that asks the client for
input (elicitation, sampling, roots) cannot run from it: on the 2025 era
`everything` does not list it (`tool_not_found`, exit 5), and on 2026-07-28
the SDK refuses the call because the request did not declare the capability
(`Cannot request input 'form' (elicitation/create): the request's client
capabilities do not declare the required capability`, exit 1). Drive those
from the web UI. On 2026-07-28 the CLI does follow a task handle: a call to
`simulate-research-query` polls the task and prints its final result.

## The Inspector web UI

Expand Down Expand Up @@ -259,8 +259,10 @@ Claude Code, run this way, has no era switch and does not print the protocol
version it negotiated. `/pr-flow` asks for the LLM client in both eras as well;
where the client gives no way to choose, record the client and its version and
say that the era could not be selected, rather than labelling the run with an
era it was not shown to use. Against a v1-SDK server the connection is legacy
whatever the client prefers, for the reason given under Protocol eras.
era it was not shown to use. `everything` shows which era a client
negotiated through its tool list: a 2026-07-28 client sees
`simulate-research-query` and no `toggle-*` tools, a 2025-era client the
reverse. Claude Code 2.1.296 negotiates 2026-07-28 against these servers.

## What to write down

Expand Down
41 changes: 29 additions & 12 deletions .claude/skills/issue-triage/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ reporter is notified of each one. So:
manifest** that lists each item, its class, and the issue it will point at.
A wrong class is cheap to fix in a file and expensive to fix after a
notification went out. Closing a single item the maintainer named is fine.
- **Pace every write loop**: a few seconds between calls, and **stop on the
first failed call** rather than carrying on blind. GitHub's secondary rate
limit on content creation trips well before its primary one, and a loop that
- **Pace every write loop** by `AGENTS.md` **Pacing GitHub writes**, and
**stop on the first failed call** rather than carrying on blind. GitHub's
secondary rate limit trips well before its primary one, and a loop that
keeps going after a 403 leaves a half-applied batch nobody can see.
- **Never restate a vulnerability in public**, not even to summarize a report
that was already filed publicly. See [Security reports](#security-reports).
Expand Down Expand Up @@ -86,14 +86,22 @@ D=${D:-$(mktemp -d)}
# Copy the class's response from Canned responses into "$D/response.md" (the
# text inside the quote, with #ORIGINAL or the SDK link filled in) first.
# Close as not planned, with that response (body in a file, so quoting is
# safe). NOT for a duplicate: post the Duplicate response with `gh issue
# comment`, close it with the `board-ops` state_reason=duplicate call, and
# delete its card if it has one (`board-ops`, Delete a card). An empty or missing response stops here instead of closing silently.
# safe). The comment and the close are two writes (`gh issue close --comment`
# sends them back to back), and a run closes several issues, so every write
# here is followed by the PR-close loop's `sleep 8`, including the last one
# before the next issue. NOT for a duplicate: post the Duplicate response with
# `gh issue comment`, close it with the `board-ops` state_reason=duplicate
# call, and delete its card if it has one (`board-ops`, Delete a card), with
# the same `sleep 8` after each of those three writes. An empty or missing
# response stops here instead of closing silently.
BODY=$(cat "$D/response.md") && [ -n "$BODY" ] \
&& gh issue close <N> --repo modelcontextprotocol/servers --reason "not planned" --comment "$BODY" \
|| { echo "no response or close failed for #<N> — stop and check it" >&2; false; }
&& gh issue comment <N> --repo modelcontextprotocol/servers --body "$BODY" \
&& sleep 8 \
&& gh issue close <N> --repo modelcontextprotocol/servers --reason "not planned" \
&& sleep 8 \
|| { echo "no response, or the comment or close failed for #<N> — look before retrying" >&2; false; }
# Spam or empty, the one class with no response:
gh issue close <N> --repo modelcontextprotocol/servers --reason "not planned"
gh issue close <N> --repo modelcontextprotocol/servers --reason "not planned" && sleep 8
```

## Pass 1 — sweep onto the board (no approval implied)
Expand Down Expand Up @@ -447,13 +455,22 @@ while IFS=$'\t' read -r PR CLASS ISSUE _; do
if [ -n "$SWEEP_LABEL" ]; then
gh pr edit "$PR" --repo modelcontextprotocol/servers --add-label "$SWEEP_LABEL" </dev/null \
|| { echo "label FAILED on #$PR — stopping" >&2; break; }
sleep 8
fi
gh pr close "$PR" --repo modelcontextprotocol/servers --comment "$BODY" </dev/null \
|| { echo "close FAILED on #$PR — stopping; re-snapshot to see what is left" >&2; break; }
sleep 5
# Comment and close as two writes, so each is paced: `gh pr close --comment`
# sends both back to back.
gh pr comment "$PR" --repo modelcontextprotocol/servers --body "$BODY" </dev/null \
|| { echo "comment FAILED on #$PR — stopping; look before retrying, it may have landed" >&2; break; }
sleep 8
gh pr close "$PR" --repo modelcontextprotocol/servers </dev/null \
|| { echo "close FAILED on #$PR (its comment is posted; close it, do not re-comment) — stopping" >&2; break; }
sleep 8
done < "$D/manifest.tsv"
```

Each `sleep 8` paces a sustained loop, long enough to stay inside every limit
in `AGENTS.md` **Pacing GitHub writes** for as long as the batch runs.

The step 0 issue closes take the same two sweep additions during the backlog
sweep: the close label (`gh issue edit <N> --add-label`) and the `#4875`
sentence at the end of the response, in the original comment rather than a
Expand Down
3 changes: 2 additions & 1 deletion .claude/skills/local-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Driving a running server with a client is `/client-smoke`; tests are

## Install and build

Node 22 for the TypeScript servers, and `uv` for the Python ones.
Node 24 (the development version, and the oldest supported) for the
TypeScript servers, and `uv` for the Python ones.

```sh
npm install # at the repo root: all four TypeScript workspaces
Expand Down
56 changes: 50 additions & 6 deletions .claude/skills/pr-flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,40 @@ gh issue edit <N> --repo modelcontextprotocol/servers --add-assignee @me

## 2. Branch

`v2/<type>/<N>-<slug>`, cut from **`origin/v2/main`**:
`v2/<type>/<N>-<slug>`, cut from **`origin/v2/main`** into a **new git
worktree**, never by switching branches in the primary checkout. Several agent
sessions work this repo on one machine at once and share the primary checkout:
a `git switch` there moves the branch out from under every other session using
it, and carries one task's uncommitted edits, `dist/` output and
`node_modules` into another's. A worktree per issue gives each task its own
tree and leaves the primary checkout alone.

Run it from the primary checkout. The worktree is a **sibling** directory named
for the checkout plus the issue number (`servers` → `../servers-4810`), never a
directory inside the repo, where every format, lint and typecheck scope would
see a second copy of the source:

```sh
git fetch origin v2/main
git switch -c v2/fix/4810-filesystem-symlink-escape origin/v2/main
git worktree add --no-track "../$(basename "$PWD")-4810" \
-b v2/fix/4810-filesystem-symlink-escape origin/v2/main
cd "../$(basename "$PWD")-4810"
npm install
```

- `--no-track` keeps the new branch from tracking `origin/v2/main`, so
`git status` does not report your work as "ahead of v2/main", and the first
push is an explicit `git push -u origin <branch>` to a branch of its own name.
- ⚠️ **The `npm install` is part of the step.** A worktree starts with no
`node_modules`, no `dist/` and no `.venv` (`/local-dev`). The root install
builds every TypeScript server; a Python server builds its `.venv` on its
first `uv run`. Background the install if you have edits to make first; the
gate needs it finished.
- Every later step (edits, the gate, commits, the push) runs **inside the
worktree**.
- The harness's `EnterWorktree` tool, where available, does the same; name the
branch by the rule above.

`<type>` follows the issue's type label: `bug` → `fix`, `enhancement` → `feat`,
`documentation` → `docs`, `chore` → `chore`. A `question` has no branch type,
because answering one ships nothing: if it turns out to need a change, relabel
Expand All @@ -56,10 +83,11 @@ branch and keeps the work legible in `git branch -a` next to `main`.
history, so the PR diff would show unrelated changes.

**Stacking.** When one issue's work depends on another PR that has not merged
yet, branch from that PR's branch and open the PR with `--base` set to it. Say
in the body that it is stacked and on which PR. When the lower PR merges,
retarget the stacked one to `v2/main` (`gh pr edit <PR> --base v2/main`) and
rebase it if GitHub reports conflicts.
yet, branch from that PR's branch (its worktree is cut from it:
`git worktree add … -b <child> <parent-branch>`) and open the PR with `--base`
set to it. Say in the body that it is stacked and on which PR. When the lower
PR merges, retarget the stacked one to `v2/main`
(`gh pr edit <PR> --base v2/main`) and rebase it if GitHub reports conflicts.

## 3. Sign off every commit (DCO)

Expand Down Expand Up @@ -310,6 +338,9 @@ worth doing on its own. Implementing a suggestion differently is fine.
-f body='Fixed in <sha>: …'
```

A round with many comments is a bulk write: send the replies one at a time,
paced by `AGENTS.md` **Pacing GitHub writes**.

- ⚠️ **Then post a PR-level summary of the round, in addition, never instead.**
Inline replies go hidden once the fix is pushed, because the threads become
outdated, so the summary is what keeps the round readable afterwards. It does
Expand Down Expand Up @@ -391,3 +422,16 @@ issue will not be done, the issue shipped nothing: close it as not planned and
**delete its card** (`/board-ops`) rather than moving it to Done.
If PRs were stacked on this one, retarget each to `v2/main` (step 2).
**Then remove the worktree and its local branch**, from the primary checkout,
once the PR shows as merged (or closed, for abandoned work). A stale worktree
keeps its branch checked out, so git refuses to check that branch out anywhere
else, and it holds a full `node_modules` on disk per issue:
```sh
git worktree remove "../$(basename "$PWD")-<N>"
git branch -D v2/<type>/<N>-<slug>
```
`git worktree remove` refuses a worktree with uncommitted or untracked changes;
read what is there before reaching for `--force`.
25 changes: 25 additions & 0 deletions .claude/skills/pre-push-gate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,31 @@ of the server's stderr. Re-run a subset with
- **A new server fails `test:scripts`** with "every server directory in the
repo has a smoke entry": add it to `SERVERS` in `scripts/smoke-servers.mjs`.

### `interface-diff`

The last stage diffs the `everything` server's MCP interface (capabilities,
tools, prompts, resources, resource templates) in this checkout's build
against the same server built from the merge-base with `origin/v2/main`, and
prints the report. **A changed interface does not fail it**: the report is
what the PR's sticky comment will show, so read it, and if a change is not
one you meant, that is the finding. It fails only when the diff cannot run,
with `❌ The interface diff could not run` and the reason:

- **"origin/v2/main is not available"**: `git fetch origin v2/main`.
- **"src/everything/dist/index.js does not exist"**: you ran it on its own
before building: `npm run build -w src/everything`.
- **An `npm ci` or `npm run build` failure**: the _base_ did not install or
build. Offline with a cold npm cache is the usual cause; otherwise name a
base that builds with `npm run interface-diff -- --base <ref>`.
- **"Base server probe failed" / "Target probe failed"**: a server did not
answer the probe. A target failure is this checkout's server and is the
real defect; the smoke stage before it usually fails first.

Re-run it on its own with `npm run interface-diff` (about ten seconds). What
it compares against in CI, and why it is a script rather than an action, is
in [`docs/quality-gate.md`](../../../docs/quality-gate.md) and the header of
`scripts/interface-diff.mjs`.

## Waiting on the lease

A gate that starts with
Expand Down
Loading
Loading