You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adopts @SamMorrowDrums's MCP interface-diff workflow from #3260 for the everything server, adapted for v2/main and the factory's gate. His six commits are cherry-picked unchanged, so his authorship is kept; the adaptations are separate commits on top.
On every PR or push that touches everything (or what builds it), CI snapshots the server's public interface (handshake capabilities, tools, prompts, resources, resource templates) in two builds and reports the diff. The report goes in the Actions job summary, in an mcp-diff-report artifact, and in a sticky PR comment for same-repo PRs. A changed interface does not fail the run. A diff that cannot run does (a base that does not build, or a server that cannot be probed).
The check is an npm script, npm run interface-diff (scripts/interface-diff.mjs). It drives the mcp-server-diff3.0.0 CLI, added as an exact-pinned root devDependency, instead of the SHA-pinned v2.3.5 GitHub Action. CI and local:gate run this same script; it is the gate's new last stage. scripts/lib/workflow-gate.test.mjs works out which checks the gate must run from the npm scripts the workflows call, so it now requires this one. It could not see an action.
The base is chosen per event. The tool's own default is the merge-base with origin/main, which is the wrong base for a PR into v2/main. Instead:
a PR compares against its base commit (the checkout is the merge commit);
a push compares against the commit before the push;
a published Release compares against the previous published Release;
a manual dispatch uses compare_ref, or the merge-base with v2/main if none is given. The head is the dispatched branch: ci: add MCP interface diff workflow for Everything server #3260's target_ref input is dropped, because a target older than the script has no npm run interface-diff to run.
Triggers:
pushes to main and v2/main;
PRs on any base, so v2/main, main and stacked PRs are all covered;
release: published, instead of typescript-servers-* tags: no release has used those tags since 2024 (see Decision points).
The sticky comment has its own job. The PR's install, build and server run only in diff, which has a read-only token and persist-credentials: false. comment holds pull-requests: write, runs none of the PR's code, and only runs when the head repo is this repo. It posts with gh api using a hidden marker, so marocchino/sticky-pull-request-comment is no longer needed. Copilot's high-severity finding on ci: add MCP interface diff workflow for Everything server #3260 was that the PR's code could reach the write-scoped token; this split fixes that.
Server: everything. Its code is untouched; this PR adds CI and gate tooling around it.
Changes: .github/workflows/everything-mcp-diff.yml, the new scripts/interface-diff.mjs with its tests, the mcp-server-diff devDependency, and the interface-diff stage in local:gate:stages. Docs: docs/quality-gate.md, AGENTS.md, .claude/skills/pre-push-gate/SKILL.md.
The issue also asks for a decision on #3260, which has been open since January.
How Has This Been Tested?
This change has no client-visible surface, so the evidence is targeted probes:
The workflow on this PR (same-repo, so the comment posts): run 37182376231 passed: the diff job built the base 9c0cf8f and the PR's merge commit and reported "✅ No interface changes detected" (13 tools / 4 prompts / 7 resources / 2 templates on both sides). The comment job posted the sticky comment on this PR.
npm run interface-diff locally against v2/main (the gate stage), about 6 s:
interface-diff: building the base 9c0cf8f92d91 …
interface-diff: probing the base and the head …
## `everything`: MCP interface diff
✅ **No interface changes detected.**
| Base | 13 | 4 | 7 | 2 |
| Head | 13 | 4 | 7 | 2 |
A planted interface change shows up, and it is reported, not failed. I edited the echo tool's description and rebuilt. The script exited 0 and result.json was {"status":"changed","diffCount":1}:
- tools[echo].description: "Echoes back the input string"+ tools[echo].description: "Echoes back the input string, verbatim"
A broken check fails. With --base does-not-exist the script exited 1 with ❌ The interface diff could not run.
The release base.npm run interface-diff -- --base 2026.8.31 (the last published Release) built that tag and showed only serverInfo.version: "2.0.0" → "1.0.0", which is the semver reset. The gh release list query the workflow uses returns 2026.8.18 when the current tag is 2026.8.31.
The parity guard catches a dropped stage. With && npm run interface-diff removed from local:gate:stages, node --test scripts/lib/workflow-gate.test.mjs fails with local:gate must run interface-diff and CI runs these and npm run local:gate does not … everything-mcp-diff.yml: npm run interface-diff. Restored, it passes.
npm run format and npm run local:gate exited 0, including the new interface-diff stage. The unit tests in scripts/interface-diff.test.mjs cover the argument parser, the verdict (a CLI probe failure is an error, not a "difference"; output that is not JSON is never a pass) and the report.
Breaking Changes
None. Nothing published changes, and nobody's client configuration changes.
Types of changes
Bug fix (non-breaking change which fixes an issue)
New feature (non-breaking change which adds functionality): a CI workflow and a gate stage
Breaking change (fix or feature that would cause existing functionality to change)
Documentation update
Checklist
I have read the MCP Protocol Documentation. The snapshot covers the initialize / server/discover results and the */list surfaces.
My changes follow MCP security best practices. Untrusted code runs only with a read-only token; there is no pull_request_target; the write-scoped job runs no PR code.
I have updated the server's README accordingly (not applicable: the server's behavior is unchanged; the gate docs are updated instead)
I have added a changeset (npm run changeset) if this changes what a TypeScript server publishes (not applicable: nothing published changes; the new dependency is a root devDependency)
I have tested this with an LLM client (not applicable: no client-visible change; see the targeted probes above)
My code follows the repository's style guidelines
New and existing tests pass locally
I have added appropriate error handling. Every failure to build or probe becomes an error verdict and exit 1, never a pass.
I have documented all environment variables and configuration options. There are none new; the script's flags are in its header and in docs/quality-gate.md.
The offer to transfer SamMorrowDrums/mcp-server-diff to the org (or to make a maintainer an admin). This PR no longer depends on the outcome: no third-party action runs, and the tool comes in as an npm package held by the lockfile's integrity hash. The options:
Decline politely for now. The pinned package is enough, and the repo can be revisited if we ever need the action or upstream fixes stall.
Accept the transfer. The org then owns the publish rights and the maintenance.
Ask for a maintainer to be added as an admin. This is a middle path.
My recommendation is option 1. Either way, it is a call for the org, not something this PR can settle.
A commit-SHA pin with a # vX.Y.Z comment would satisfy verify:action-pins, but that guard only requires it for credentialed jobs. Here the question went away: the CLI is pinned "mcp-server-diff": "3.0.0", with the lockfile's sha512 integrity hash. That is the repo's convention for npm dependencies, and the Replace Dependabot PRs with issue-filing sweeps; SDK watch; the factory overview #4874 dependency sweep will see it.
The package's runtime dependencies (@actions/*, undici, zod, diff, and SDK ^1.13.2, which dedupes to the root's 1.30) are root dev-only and are not published by any server.
Permissions.
The comment is skipped on fork PRs, which keep the job summary and the artifact.
pull_request_target is not used.
The write token is in a job that runs no PR code.
If fork PRs need the comment later, the way to do it is a separate workflow_run workflow that downloads the artifact and posts it without checking anything out. The workflow header records this.
Branches and tags.
Releases are now tagged vX.Y.Z on main by a maintainer publishing a GitHub Release (RELEASING.md). The newest typescript-servers-* tag is typescript-servers-0.6.2 (2024-12-04).
The date-stamped releases (2026.x) tagged commits that never reached main, so git describe from main would compare against that 2024 tag. The release trigger therefore compares against the previous published Release's tag.
v2/main and main are both push triggers.
2026-07-28 support. It works in both eras, so nothing needs raising upstream. mcp-server-diff 3.x (src/probe.ts) first tries the stateless server/discover request with the SEP-2243 reserved _meta (protocolVersion: "2026-07-28"), over stdio or HTTP. On -32601, an HTTP 400 or a malformed response it falls back to the initialize handshake. The discover result is mapped into the same initialize snapshot, so when Part 5 moves everything to the new era, the change shows up as a content diff of that one snapshot (capabilities, serverInfo, instructions), not as everything removed and re-added. One limit, found in Copilot round 7: the 3.0.0 CLI strips the negotiated protocolVersion from the diff and leaves it out of its JSON output. Only the Action's reporter shows the version banner. So this report never says which era each side negotiated, and a change that only switches era can read as "unchanged". Recommendation (upstream, not filed): ask mcp-server-diff to add the base and target protocolVersion to the CLI's -o json results, then render it here. That is a follow-up to this PR, not part of it. Today's everything answers through the fallback (mcp-server-diff -v):
server/discover not supported (discover request failed: JsonRpcRemoteError: JSON-RPC error -32601: Method not found); falling back to initialize
Negotiated MCP protocol version: 2025-11-25
Probe complete (initialize path)
Scope. Only everything for now. Each Python server would need its own start command and a base uv sync; adding them later means extending SERVER_DIR into a list.
DCO. The six cherry-picked commits from ci: add MCP interface diff workflow for Everything server #3260 carry no Signed-off-by, and I did not add one for the author. The DCO app is not enforced yet (Add pr-flow skill #4867). Once it is, those commits need the author's own signoff, or the app's override, at a maintainer's discretion. The three adaptation commits are signed off.
The base is built from an export of its commit under node_modules/.cache/ and removed afterwards, rather than in the system temp directory. The reason: mcp-server-diff splits a start command on whitespace, and a path relative to the checkout cannot contain any. The script's header has the details.
Adds a GitHub Actions workflow that tracks public interface changes
to the Everything MCP server using mcp-server-diff.
Features:
- Runs on PRs and pushes affecting src/everything/
- Auto-compares against merge-base (PRs) or previous state (pushes)
- Manual workflow_dispatch for comparing any two refs
- Generates diff reports showing tool, resource, prompt, and capability changes
This helps catch unintended interface changes and provides clear
visibility into how the reference server evolves over time.
Related: modelcontextprotocol/inspector#1034
Address review feedback:
- Add concurrency group so superseded runs on the same ref are cancelled
- Repin SamMorrowDrums/mcp-server-diff to the correct v2.3.5 commit SHA
(the previous SHA did not exist in the action's repo)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Surface the Everything server interface diff directly on the PR
instead of requiring reviewers to dig into the Actions tab.
- Add 'pull-requests: write' permission
- Capture mcp-server-diff status output via step id
- Build a comment body that summarises the status and includes the
full report in a collapsed <details> block
- Post via marocchino/sticky-pull-request-comment (SHA-pinned to v3.0.4)
using a stable header so subsequent pushes update the same comment
- Guarded to same-repo PRs only; fork PRs still get the summary and
uploaded artifact
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirrors github/github-mcp-server's pattern of pushing on tags so each
release surfaces its cumulative interface delta. The everything server
ships as part of the typescript-servers monorepo bundle, so we trigger
on typescript-servers-* tags and let mcp-server-diff auto-compare
against the previous matching tag.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…4860)
Adapt #3260's workflow for v2/main:
- Run the check as `npm run interface-diff` (scripts/interface-diff.mjs),
driving the mcp-server-diff 3.0.0 CLI as an exact-pinned root
devDependency instead of the SHA-pinned v2.3.5 action. The same script
is a new last stage of local:gate, which workflow-gate.test.mjs now
requires, so the gate keeps running every check CI runs.
- Choose the base per event (the PR's base, the commit before a push, the
previous release tag, or a dispatch input) instead of the tool's
default merge-base with origin/main, which is wrong for v2/main PRs.
- Trigger pushes on main and v2/main, PRs on any base, and published
Releases instead of the retired typescript-servers-* tags.
- Run the PR's code only in a read-only job with no persisted
credentials; post the sticky comment from a separate job that holds
pull-requests: write, runs no PR code, and only runs for same-repo PRs.
Fork PRs keep the job summary and the report artifact.
- Give every job a timeout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Add `interface-diff` to the stage table in docs/quality-gate.md, to
AGENTS.md's Before pushing and project tree, and a diagnosis section to
the pre-push-gate skill.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
`git describe` finds the nearest ancestor tag, but the date-stamped
releases tagged commits that never reached main, so from main it lands
on typescript-servers-0.6.2 (2024). Take the previous published
Release's tag from the Releases list instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
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
Base: 9c0cf8f92d91 (Merge pull request #4967 from modelcontextprotocol/v2/docs/4966-contribution-model-pr-creation-off)
Head: the build in this checkout, at c6c4d6de9354 (Merge a47bf98 into 9c0cf8f)
✅ No interface changes detected.
Tools
Prompts
Resources
Resource templates
Base
13
4
7
2
Head
13
4
7
2
Updated by this run for a47bf9823351af626dba7d32c52cfd601d8a5d6a.
…rr (#4860)
Copilot round 1 on #4975:
- Check out github.sha rather than github.ref, so a push run diffs the
commit it was triggered for against that event's `before`, not a
branch tip a later push moved.
- When mcp-server-diff prints no JSON report, include its stderr (where
a fatal error goes) in the error, so the reason is not blank.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Selects latest release instead of immediately preceding release
.github/workflows/everything-mcp-diff.yml:135
This selects the latest release other than the current tag, not the release immediately preceding this event. If an older release run is re-run after another release has been published, the newer tag becomes the base and the report compares in the wrong direction. Filter candidates to releases published before the event release before taking the latest one.
Copilot round 2 on #4975: taking the latest Release other than the
current one picks a newer Release when an older one's run is re-run.
Keep only Releases published before this event's Release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 2: no inline findings, and both round-1 threads show as resolved. One "previously missed" finding, which has no thread, so I'm answering it here: the release base took the newest Release other than the current one, so a re-run of an older Release would have compared against a newer one. Fixed in 9180711. It now keeps only Releases published before the event's release.published_at. Checked against the live list: a 2026.8.31 run gets 2026.8.18, and a re-run of 2026.8.18 gets 2026.7.10 (before the fix, it got 2026.8.31). The gate exited 0. Requesting round 3.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
CI trigger omissions and Windows and Dependabot handling leave the new check unreliable in supported scenarios.
Review effort: Balanced Findings: None
Previously missed (4)
In code that hasn't changed since last review
Include root tsconfig.json in both trigger path filters
.github/workflows/everything-mcp-diff.yml:49
Both trigger path lists omit the root tsconfig.json, even though src/everything/tsconfig.json extends it. A PR or push that changes compiler settings can therefore change (or break) the build being probed without running this interface check, contradicting the stated “everything or what builds it” coverage. Add the root config to both filters.
Exclude Dependabot PRs from comment-writing workflow
.github/workflows/everything-mcp-diff.yml:197
This same-repository check also matches Dependabot PRs, but Dependabot-triggered pull_request workflows receive a read-only token. Since the repository still opens weekly Actions update PRs and this workflow file is in the path filter, an update to one of these actions will run this job and fail when gh api tries to write the comment. Exclude Dependabot here; its report remains available through the summary and artifact like a fork PR.
Use winShellArgs to safely invoke Windows shell commands
scripts/interface-diff.mjs:202
On Windows, shell: true causes cmd.exe to re-parse the unquoted argument array. A checkout path containing spaces breaks the absolute checkout-index --prefix=... argument, and metacharacters in a ref can become shell syntax. Use the repository's winShellArgs helper before enabling the Windows shell, as scripts/gate-lease.mjs and scripts/lib/claude-cli.mjs do.
Mock console.error for the expected error-path test
scripts/interface-diff.test.mjs:42
This test intentionally exercises an error path but leaves main's console.error visible in every script-test run. Root test conventions suppress expected diagnostics so genuine failures remain readable; mock console.error for this case.
Copilot round 3 on #4975 ("previously missed"):
- Skip the comment job on Dependabot PRs, which are same-repo but get a
read-only token; they keep the summary and artifact like fork PRs.
- Trigger on the root tsconfig.json, which everything's tsconfig extends.
- Spawn only npm through a shell on Windows, with its arguments quoted by
winShellArgs; git needs no shell.
- Silence the expected usage error in the script test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 3: no inline findings. It flagged four "previously missed" findings with no threads, so I'm answering them here. All four were defects in what this PR added, and all are fixed in 1fe8b98 (the gate exited 0):
Dependabot PRs are same-repo but get a read-only token, so the comment job is now skipped for them, as it is for forks. They keep the summary and the artifact.
The path filters now include the root tsconfig.json, which src/everything/tsconfig.json extends.
On Windows, only npm is spawned through a shell, with its arguments quoted by winShellArgs. git no longer goes through a shell.
The expected usage error in the script test is now mocked rather than printed.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The concurrency configuration can cancel pending push runs, contrary to the promised per-push interface snapshot.
Review effort: Balanced Findings: None
Previously missed (1)
In code that hasn't changed since last review
Concurrency group cancels pending runs and skips interface snapshots
.github/workflows/everything-mcp-diff.yml:77
This group does not actually preserve every push/release run as the comment says. GitHub Actions allows only one running and one pending run per concurrency group; a third push to the same branch cancels the older pending run even when cancel-in-progress is false. That means rapid pushes can skip the promised interface snapshot. Keep the stable group only for PRs and use a run-unique group for other events (or explicitly configure a larger queue).
)
Copilot round 4 on #4975: a concurrency group keeps only one pending
run, so a third rapid push cancelled the queued one even without
cancel-in-progress. Group by ref only for PRs; by run id otherwise.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 4: no inline findings. It flagged one "previously missed" finding, which has no thread, so I'm answering it here. It was a defect in what this PR added: the concurrency group keeps only one pending run, so rapid pushes could drop a push's run. Fixed in 714eea7. PRs still share a per-ref group with cancel-in-progress; every other run now gets a group keyed by run_id. The gate exited 0. Requesting round 5.
Preserve build context in pinned CLI error reports
scripts/interface-diff.mjs:135
The pinned CLI's error field contains only the raw exception; the Base server probe failed / Target probe failed context is stored in the error entry in diffs. Returning only result.error discards which build failed, so the new gate diagnosis documented in the skill will not match its reports. Prefer the contextual error diff here and adjust the fixture so error contains only boom, matching the CLI contract.
Copilot round 5 on #4975:
- A result with no boolean hasDifferences is an error, not "unchanged".
- On a probe failure, report the CLI's contextual message ("Base server
probe failed" / "Target probe failed") rather than the bare exception.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 5: both findings were defects in what this PR added, and both are fixed in 0e151f1 (the gate exited 0).
Inline: a partial report with no hasDifferences no longer passes as "unchanged". It is now an error. I replied in the thread.
"Previously missed" (no thread): on a probe failure, the error now uses the CLI's contextual diffs entry ("Base server probe failed: …" / "Target probe failed: …") instead of the bare exception. The test fixture now matches the CLI's contract.
interface-diff.mjs directly imports scripts/lib/win-shell-args.mjs, but that dependency is absent from the push path filter. A push changing the helper can therefore break the check without running this workflow. Add the helper to this path list.
This issue also appears on line 50 of the same file.
Bound oversized GitHub Actions step summaries
.github/workflows/everything-mcp-diff.yml:166
This appends the report without bounding its size, but GitHub limits each step summary to 1 MiB. renderReport includes complete diffs and can emit far more than that (the subprocess buffer permits up to 64 MiB), so a sufficiently large schema change loses the promised Actions summary. Bound the content and direct reviewers to the artifact when it is oversized.
…4860)
Copilot round 6 on #4975:
- Cap the job summary below GitHub's 1 MiB limit, pointing to the
artifact when the report is longer.
- Add scripts/lib/win-shell-args.mjs, which the script imports, to the
path filters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 6: no inline findings. It flagged two "previously missed" findings with no threads, so I'm answering them here. Both are fixed in 4979c6e (the gate exited 0):
Both path filters now include scripts/lib/win-shell-args.mjs, which the script imports.
The job summary is capped at 900 KB, under GitHub's 1 MiB limit, with a pointer to the mcp-diff-report artifact when the report is longer. The PR comment was already capped at 60 KB.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
Historical target comparisons and protocol-version reporting do not currently work as described, and failure diagnostics can omit the underlying error.
Review effort: Balanced Findings: None
Previously missed (3)
In code that hasn't changed since last review
Historical target_ref values lack the interface-diff tooling
.github/workflows/everything-mcp-diff.yml:98
The advertised arbitrary target_ref fails for historical targets that predate this PR: this checkout replaces the workspace with that target, so the later npm run interface-diff has neither the new script nor its dependency and exits with “Missing script: interface-diff.” Keep the tooling checkout separate and have the script build/probe the selected target (or remove/restrict this input).
Protocol-only changes are reported as unchanged
scripts/interface-diff.mjs:151
This can report a protocol-era-only change as “unchanged.” In mcp-server-diff@3.0.0, the CLI strips initialize.protocolVersion before computing hasDifferences, and unlike the Action reporter its JSON output does not include the base/target protocol versions. Consequently this wrapper cannot produce the protocol-version banner promised for Part 5. Capture and render both negotiated versions, which may require an upstream CLI field or a separate probe.
Build errors discard diagnostics when stderr is nonempty
scripts/interface-diff.mjs:224
This discards stdout whenever the failed command wrote anything to stderr. For example, npm can put a lifecycle footer or warning on stderr while tsc diagnostics are on stdout, leaving the base-build failure without its actual cause. Include the tail of both streams in the thrown error.
)
Copilot round 7 on #4975:
- Remove the dispatch `target_ref` input: a target that predates the
script has no `npm run interface-diff`, so the run failed. The head is
the branch chosen in "Use workflow from".
- A failed base install or build now reports the tail of both stdout and
stderr, so tsc diagnostics are not lost behind an npm footer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 7: no inline findings. It flagged three "previously missed" findings with no threads, so I'm answering them here.
Fixed in a47bf98, failed builds losing their diagnostics: a failed base install or build now reports the tail of both stdout and stderr, so a tsc error is no longer hidden behind an npm footer.
Fixed in a47bf98, by removal, the historical target_ref: the dispatch input is dropped. The head is now the dispatched branch, and compare_ref still picks any base. Diffing an arbitrary target that predates this tooling would be a new capability, so I'm declining that part.
Declined as out of scope, protocol-version reporting: the 3.0.0 CLI strips the negotiated protocolVersion before diffing and leaves it out of its JSON. Adopt MCP interface-diff CI for the everything server (decide on PR #3260) #4860 asks for the snapshot of capabilities, tools, prompts and resources, plus confirmation that 3.x works in both eras, and it does. Surfacing the negotiated era would need a new upstream CLI field. I've corrected the PR body, which had over-claimed a "protocol-version banner", and listed this as a follow-up.
The gate exited 0. I pushed fixes, so I'm requesting round 8.
The reason will be displayed to describe this comment to others. Learn more.
Declined, as outside #4860 and not a new exposure. A same-repo PR can only come from someone with write access, and anyone with write access can already push a branch with any workflow on it, this one included, so this job adds no capability they lack. #4860 asked to skip the comment on forks rather than use pull_request_target, and that is what this does. Moving the posting to a trusted workflow_run workflow is recorded in the workflow header and the PR body as the path if fork PRs ever need the comment. It is listed as a follow-up candidate, not done here.
Copilot round 8: every item was declined as outside #4860, so this is pr-flow's out of scope only exit, and I'm ending the loop here.
Inline: same-repo PRs can edit the comment job. Declined, with the reasons in the thread: write-access authors can already push any workflow, and the fork case the issue cares about is handled. workflow_run stays the documented follow-up.
Overview note: undici 8 declares Node >= 22.19. This comes in through the root devDependency mcp-server-diff. It is not a defect in the acceptance behavior. npm only warns on an engine mismatch (engine-strict is off), CI's setup-node resolves the current Node 22 (above 22.19), and the CLI runs from its own ncc bundle. No change.
The latest workflow runs on this PR are green, and the sticky comment shows "No interface changes detected".
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4860
Description
Adopts @SamMorrowDrums's MCP interface-diff workflow from #3260 for the
everythingserver, adapted forv2/mainand the factory's gate. His six commits are cherry-picked unchanged, so his authorship is kept; the adaptations are separate commits on top.On every PR or push that touches
everything(or what builds it), CI snapshots the server's public interface (handshake capabilities, tools, prompts, resources, resource templates) in two builds and reports the diff. The report goes in the Actions job summary, in anmcp-diff-reportartifact, and in a sticky PR comment for same-repo PRs. A changed interface does not fail the run. A diff that cannot run does (a base that does not build, or a server that cannot be probed).What changed from #3260:
npm run interface-diff(scripts/interface-diff.mjs). It drives themcp-server-diff3.0.0 CLI, added as an exact-pinned root devDependency, instead of the SHA-pinned v2.3.5 GitHub Action. CI andlocal:gaterun this same script; it is the gate's new last stage.scripts/lib/workflow-gate.test.mjsworks out which checks the gate must run from the npm scripts the workflows call, so it now requires this one. It could not see an action.origin/main, which is the wrong base for a PR intov2/main. Instead:compare_ref, or the merge-base withv2/mainif none is given. The head is the dispatched branch: ci: add MCP interface diff workflow for Everything server #3260'starget_refinput is dropped, because a target older than the script has nonpm run interface-diffto run.mainandv2/main;v2/main,mainand stacked PRs are all covered;release: published, instead oftypescript-servers-*tags: no release has used those tags since 2024 (see Decision points).diff, which has a read-only token andpersist-credentials: false.commentholdspull-requests: write, runs none of the PR's code, and only runs when the head repo is this repo. It posts withgh apiusing a hidden marker, somarocchino/sticky-pull-request-commentis no longer needed. Copilot's high-severity finding on ci: add MCP interface diff workflow for Everything server #3260 was that the PR's code could reach the write-scoped token; this split fixes that.timeout-minutes. The docs are updated: the stage table indocs/quality-gate.md(the factory's gate inventory for Tracker: Agentic software factory (AGENTS.md, skills, quality gates, v2/main release flow) #4858),AGENTS.md's Before pushing section and project tree, and a diagnosis section in thepre-push-gateskill.Server Details
everything. Its code is untouched; this PR adds CI and gate tooling around it..github/workflows/everything-mcp-diff.yml, the newscripts/interface-diff.mjswith its tests, themcp-server-diffdevDependency, and theinterface-diffstage inlocal:gate:stages. Docs:docs/quality-gate.md,AGENTS.md,.claude/skills/pre-push-gate/SKILL.md.Motivation and Context
#4860, Wave 1 of the spec-refactor tracker #4857:
The issue also asks for a decision on #3260, which has been open since January.
How Has This Been Tested?
This change has no client-visible surface, so the evidence is targeted probes:
diffjob built the base9c0cf8fand the PR's merge commit and reported "✅ No interface changes detected" (13 tools / 4 prompts / 7 resources / 2 templates on both sides). Thecommentjob posted the sticky comment on this PR.npm run interface-difflocally againstv2/main(the gate stage), about 6 s:echotool's description and rebuilt. The script exited 0 andresult.jsonwas{"status":"changed","diffCount":1}:--base does-not-existthe script exited 1 with❌ The interface diff could not run.npm run interface-diff -- --base 2026.8.31(the last published Release) built that tag and showed onlyserverInfo.version: "2.0.0"→"1.0.0", which is the semver reset. Thegh release listquery the workflow uses returns2026.8.18when the current tag is2026.8.31.&& npm run interface-diffremoved fromlocal:gate:stages,node --test scripts/lib/workflow-gate.test.mjsfails withlocal:gate must run interface-diffandCI runs these and npm run local:gate does not … everything-mcp-diff.yml: npm run interface-diff. Restored, it passes.npm run formatandnpm run local:gateexited 0, including the newinterface-diffstage. The unit tests inscripts/interface-diff.test.mjscover the argument parser, the verdict (a CLI probe failure is an error, not a "difference"; output that is not JSON is never a pass) and the report.Breaking Changes
None. Nothing published changes, and nobody's client configuration changes.
Types of changes
Checklist
initialize/server/discoverresults and the*/listsurfaces.pull_request_target; the write-scoped job runs no PR code.npm run changeset) if this changes what a TypeScript server publishes (not applicable: nothing published changes; the new dependency is a root devDependency)errorverdict and exit 1, never a pass.docs/quality-gate.md.Decision points (#4860)
Needs a maintainer decision:
Whether to merge this and close ci: add MCP interface diff workflow for Everything server #3260. I recommend merging this PR and then closing ci: add MCP interface diff workflow for Everything server #3260 with a thank-you that points here, because this PR carries his commits and credit. A drafted reply is ready. I have not commented on ci: add MCP interface diff workflow for Everything server #3260 or touched it.
The offer to transfer
SamMorrowDrums/mcp-server-diffto the org (or to make a maintainer an admin). This PR no longer depends on the outcome: no third-party action runs, and the tool comes in as an npm package held by the lockfile's integrity hash. The options:My recommendation is option 1. Either way, it is a call for the org, not something this PR can settle.
Recommended, done in this PR:
mcp-server-diffis at 3.0.0 on npm (published 2026-06-29). The tarball'sgitHeadis40d992e, which is exactly thev3.0.0/v3tag of the action repo. ci: add MCP interface diff workflow for Everything server #3260 pinned the action atf7e5e58(v2.3.5).# vX.Y.Zcomment would satisfyverify:action-pins, but that guard only requires it for credentialed jobs. Here the question went away: the CLI is pinned"mcp-server-diff": "3.0.0", with the lockfile'ssha512integrity hash. That is the repo's convention for npm dependencies, and the Replace Dependabot PRs with issue-filing sweeps; SDK watch; the factory overview #4874 dependency sweep will see it.@actions/*,undici,zod,diff, and SDK^1.13.2, which dedupes to the root's 1.30) are root dev-only and are not published by any server.pull_request_targetis not used.workflow_runworkflow that downloads the artifact and posts it without checking anything out. The workflow header records this.vX.Y.Zonmainby a maintainer publishing a GitHub Release (RELEASING.md). The newesttypescript-servers-*tag istypescript-servers-0.6.2(2024-12-04).2026.x) tagged commits that never reachedmain, sogit describefrommainwould compare against that 2024 tag. The release trigger therefore compares against the previous published Release's tag.v2/mainandmainare both push triggers.mcp-server-diff3.x (src/probe.ts) first tries the statelessserver/discoverrequest with the SEP-2243 reserved_meta(protocolVersion: "2026-07-28"), over stdio or HTTP. On-32601, an HTTP 400 or a malformed response it falls back to theinitializehandshake. The discover result is mapped into the sameinitializesnapshot, so when Part 5 moveseverythingto the new era, the change shows up as a content diff of that one snapshot (capabilities,serverInfo,instructions), not as everything removed and re-added. One limit, found in Copilot round 7: the 3.0.0 CLI strips the negotiatedprotocolVersionfrom the diff and leaves it out of its JSON output. Only the Action's reporter shows the version banner. So this report never says which era each side negotiated, and a change that only switches era can read as "unchanged". Recommendation (upstream, not filed): ask mcp-server-diff to add the base and targetprotocolVersionto the CLI's-o jsonresults, then render it here. That is a follow-up to this PR, not part of it. Today'severythinganswers through the fallback (mcp-server-diff -v):everythingfor now. Each Python server would need its own start command and a baseuv sync; adding them later means extendingSERVER_DIRinto a list.local:gatestage, recorded in the gate inventory indocs/quality-gate.md.Additional context
Signed-off-by, and I did not add one for the author. The DCO app is not enforced yet (Add pr-flow skill #4867). Once it is, those commits need the author's own signoff, or the app's override, at a maintainer's discretion. The three adaptation commits are signed off.node_modules/.cache/and removed afterwards, rather than in the system temp directory. The reason:mcp-server-diffsplits a start command on whitespace, and a path relative to the checkout cannot contain any. The script's header has the details.🤖 Generated with Claude Code