Skip to content

Tool definition drift: 124 of 131 definitions changed in v2.0.0 (data + a pinning fix) #3466

Closed

Description

@AAtomless

I track how MCP server tool definitions change across releases for an agent security project.

In v2.0.0, 124 of 131 tool definitions changed, with no new capabilities advertised. The count still holds at v2.0.2, since PR #3454 only touches HTTP header validation.

Why it matters to your users:

Teams that pin definition hashes for injection review were forced into a full re-review by this release. Teams that don't pin absorbed 124 changed descriptions into running agents without noticing. Most teams don't know which of those two groups they're in.

I have per-release tables back through v1.14.0, reproduced independently twice, and a two-tier pinning scheme that separates meaningful changes from cosmetic ones so a release like this doesn't force a full re-review.

If useful, I can post both here.

Thanks,
Mike

Activity

  1. Paraphern commented on Oct 10, 2026

    @Paraphern

    Independent confirmation and decomposition. We pin tool contracts (name + description + inputSchema + annotations) via sha-256, diff on update, and grade changes by direction. Running the same comparison on the __toolsnaps__ files at v1.14.0 vs v2.0.0:

    Numbers match: 123 of 131 tools changed (you said 124 - the one-tool difference is likely a formatting boundary in one snap file). 8 unchanged, 10 added, 0 removed.

    But the decomposition matters more than the count. Every single one of the 123 changes is the same thing: an outputSchema was added. The inputSchema, description, and annotations are byte-identical between versions for all 123 tools. This is a Go SDK upgrade artifact (output schema support landed in the SDK), not a semantic change to any tool.

    The 8 unchanged tools are the list/search family (list_branches, list_issues, search_code, etc.) - they didn't get outputSchemas in-place. Instead, 10 new *_output variants were added alongside them (list_branches_output, search_code_output, etc.) with outputSchemas and the same operation. So the list/search tools have both an original (no outputSchema) and an _output variant (with outputSchema) in v2.0.0.

    Why this matters for the pinning scheme you're proposing: a naive hash-pin flags all 123 tools and forces exactly the re-review storm you described. But if the pin grades changes by what actually moved, this entire release is:

    • 0 BREAKING (no inputSchema change, no description rewrite, no annotation flip)
    • 0 LOOSENED (no constraint dropped)
    • 123 NOTATION (outputSchema added, input/description unchanged)
    • 10 NEW (output-variant tools)

    A reviewer seeing "123 NOTATION, 0 BREAKING" clicks through in seconds. A reviewer seeing "123 tools changed" without decomposition spends an afternoon. The grading is what makes pinning survive contact with SDK upgrades.

    For calibration on how common SDK-upgrade waves are: we saw the identical pattern in chrome-devtools-mcp (MCP SDK v2 migration re-serialized all 28 tool schemas - dialect declaration, key order, additionalProperties form - with zero parameter-level edits). Graded, that wave scores 0 BREAKING + 30 NOTATION. Without grading, both releases look like emergencies.

    Happy to share the full per-tool comparison table if useful. We also keep a public corpus of benign/weaponized contract pairs for testing pinning schemes against real attack shapes (description rewrites, schema mutations, sleeper tools): https://github.com/Paraphern/rugsnare

    (Disclosure: I maintain the pinning/diff tool referenced above - open source, zero deps. The 218-finding drift audit across the npm MCP top is its output: https://github.com/Paraphern/rugsnare/blob/main/audits/npm-top-mcp-drift-2026-10.md)

  2. AAtomless commented on Oct 12, 2026

    @AAtomless
    Author
  3. Paraphern commented on Oct 12, 2026

    @Paraphern

    All three corrections verified against both tags - and our comment above was wrong where you said it was. The "inputSchema byte-identical for all 123" claim fails on 48 tools: 46 add the x-mcp-header keyword (46 snap files carry it at v2.0.0, zero at v1.14.0 - notation), and two are real:

    • find_duplicate_ff_duplicate_detection: page and perPage minimum 1 -> 0 (confirmed in both snaps) - a genuine LOOSENED, on a feature-flagged tool as you note.
    • search_repositories.minimal_output: v2.0.0 documents "modern clients receive additional curated repository details, not the complete GitHub API object. Legacy clients retain full GitHub API repository objects" - a behavior change carried in a parameter description, which also quietly introduces a legacy/modern client split.

    We also misread the 7 *_output snaps as new served tools rather than output-schema snapshots. Thank you for the field-by-field recheck - our decomposition used the same snap files and inherited the same blind spots.

    The corrected shared result is stronger than either original: 0 breaking at schema level, 1 loosened, 1 documented behavior change, the rest notation. And this thread is now itself the best argument for the method: two independent analyses publicly correcting each other down to graded truth, in front of the repo that needs it. For pinned users the actionable line is exactly yours - nothing breaks callers, but find_duplicate accepting page 0 and search_repositories changing shape for modern clients are the two things a changelog should have named.

  4. SamMorrowDrums commented on Oct 12, 2026

    @SamMorrowDrums
    Collaborator

    Sometimes our tool surface changes, in this case adding output schemas and structured outputs.

    It's broadly a noop beyond output schemas, but we reserve the right to change our offered tool schemas from time to time and so I'll close this as it's expected that we may decide to do this as models and agents evolve, to ensure we stay fit for purpose.

    In this case it is an effort to support code mode clients.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions