Make the per-version wire packages private (mcp_types._v*) - #3191
Conversation
`mcp_types.v2025_11_25` and `mcp_types.v2026_07_28` are generated per-schema-era validators with unstable, codegen-derived class names (`Params1`, `Error1`, ...); their own docstrings and `methods.py` already describe them as internal, but the public-looking module names meant the API reference generator would publish ~350 of these classes as documented API. Rename them to `_v2025_11_25` / `_v2026_07_28` so the naming, the docs generator's underscore rule, and the stated intent agree. The supported surface (`mcp_types`, `.jsonrpc`, `.methods`, `.version`) is unchanged, and `methods.py`'s public maps still route through the same models. Update the codegen output path, the ruff per-file ignore, the standalone smoke import, and note the supported import surface in the migration guide.
📚 Documentation preview
|
There was a problem hiding this comment.
LGTM — a mechanical rename of the two generated wire packages to underscore-private names, with every consumer (imports, ruff glob, CI import check, generator target, tests) updated consistently; the one inline nit is a stale doc path in schema/README.md, which is not blocking.
Extended reasoning...
Overview
This PR renames mcp_types.v2025_11_25 / mcp_types.v2026_07_28 to mcp_types._v2025_11_25 / mcp_types._v2026_07_28. The two generated __init__.py files are 100% git renames (byte-identical content), and the remaining changes are path/reference updates: the generator's output target in scripts/gen_surface_types.py, imports in mcp_types/methods.py and mcp/server/elicitation.py, the ruff per-file-ignores glob in pyproject.toml, the CI standalone-import check in .github/workflows/shared.yml, docstrings, and the two test files' import/mapping strings.
Security risks
None. No logic changes, no validation behavior changes, no auth/crypto/permission code touched. The wire validators themselves are byte-identical after the move.
Level of scrutiny
This is nominally a breaking change (the old module paths stop resolving), which warrants a check that it is deliberate and documented. It is: the modules were documented as internal from the start, the rename lands in the pre-2.0 window, and docs/migration.md is updated in this PR to document the supported import surface — satisfying the repo's breaking-change policy. Beyond that, the change is mechanical rename-plus-reference-update, the lowest-scrutiny category, and multiple automated gates verify consistency: the gen_surface_types.py --check drift gate now targets the new path, the CI standalone-import step imports both _v* packages from the built package (so a packaging regression would fail CI — I confirmed the wheel packages the whole mcp_types tree, so underscored subpackages still ship), and the test suite pins module identity per version via PACKAGE_BY_VERSION and the parity test's qualname maps.
Other factors
I verified there are no remaining references to the old mcp_types.v20* paths anywhere in the repo except the one flagged inline in schema/README.md (it uses the v<version> placeholder form, which is why it escaped the sweep). I also confirmed scripts/docs/gen_ref_pages.py skips underscore-prefixed path components, so the stated motivation (keeping ~350 unstable generated class names out of the API reference) holds. The elicitation.py import of PrimitiveSchemaDefinition from the now-private package is lockstep-safe because mcp exact-pins mcp-types to the same version. The single finding is a documentation-only nit with no runtime or CI impact.
No-Verification-Needed: doc-only fix
There was a problem hiding this comment.
LGTM — a mechanical privatization rename (mcp_types.v* → mcp_types._v*) with all references updated consistently, and the stale schema/README.md path from my earlier comment is now fixed.
What was reviewed:
- Both generated packages are 100%-similarity git renames (byte-identical content), so no wire-shape behavior changes; the only runtime edits are the import statements in
methods.pyandelicitation.py, which CI's standalone-import check and the full suite cover. - Grepped the whole tree for stale
mcp_types.v20*/mcp_types/v20*references — none remain after the README fix. - Verified the docs motivation:
scripts/docs/gen_ref_pages.pyskips any_-prefixed path component, so the rename removes the unstable generated classes from the API reference as described. - The breaking rename is noted in
docs/migration.mdalongside the supported import surface, per repo policy.
Extended reasoning...
Overview
This PR renames the two datamodel-code-generator output packages from mcp_types.v2025_11_25 / mcp_types.v2026_07_28 to underscore-private mcp_types._v2025_11_25 / mcp_types._v2026_07_28. Both __init__.py files are 100%-similarity git renames, so the generated content is unchanged. The remaining diff is reference updates: imports in mcp_types/methods.py and mcp/server/elicitation.py, the ruff per-file-ignores glob in pyproject.toml, the CI standalone-import check in .github/workflows/shared.yml, the generator target path and docstring in scripts/gen_surface_types.py, docstrings in _types.py/_wire_base.py, a migration-guide paragraph documenting the supported import surface, the schema README, and mechanical string updates in tests/types/test_methods.py / test_parity.py.
Security risks
None. No auth, crypto, permission, or input-handling code changes; the validators themselves are byte-identical after the move, and the parse/serialize paths through mcp_types.methods are untouched apart from the import spelling.
Level of scrutiny
Moderate-low. It is nominally a breaking change (the old module paths stop resolving), but it lands on the pre-release v2 line, the packages were documented as internal from the start, and the migration guide now records the supported import surface. I verified the two claims that make the change safe rather than taking them on faith: a repo-wide grep confirms no stale references to the old paths remain (the one straggler, schema/README.md, was flagged in my previous review and is fixed in the head commit), and scripts/docs/gen_ref_pages.py line 184 confirms that a _-prefixed path component excludes a module from the generated API reference, which is the PR's stated motivation.
Other factors
CI provides direct coverage of the risky spots: the pre-commit job runs gen_surface_types.py --check against the new target path, and the standalone-import step imports both _v* packages from a clean environment. The test suite pins the new module names in PACKAGE_BY_VERSION and the parity maps, so any missed rename would fail loudly. A finder agent this run questioned whether docs/migration.md adequately states the rename; the added paragraph names the _v* packages as internal and defines the supported import surface, which covers the migration story for a pre-stable internal module. No unresolved reviewer comments remain.
Renames the two generated per-protocol-version wire packages,
mcp_types.v2025_11_25andmcp_types.v2026_07_28, to underscore-privatemcp_types._v2025_11_25/mcp_types._v2026_07_28.Motivation and Context
These packages are
datamodel-code-generatoroutput: strict per-schema-era validators (~175 classes each) whose names are derived by the generator, including unstable ones for anonymous inline schema objects (Params1,Params2,Error1,Elicitation1, ...) that renumber whenever the upstream schema gains an anonymous object. The types users actually hold are the version-free models inmcp_types._types, re-exported at themcp_typestop level; everymcp_types.methodsparse function returns those.Their own module docstrings and the
methods.pydocstring already say "internal validators, not for direct import" — but with public-looking names,scripts/docs/gen_ref_pages.py(which documents every module without a_-prefixed path component) would publish all ~350 unstable-named classes as API reference. Rather than special-casing the docs generator, this makes the name match the intent: the existing underscore convention (_types,_wire_base) now covers these too, and the docs, IDE autocomplete, and prose all agree.Nothing on the supported surface changes:
mcp_types,mcp_types.jsonrpc,mcp_types.methods,mcp_types.versionare untouched, and the public surface maps (CLIENT_REQUESTSet al.) still hold the same models — extending them per the docs never required importing these packages.How Has This Been Tested?
./scripts/test, 100% coverage),gen_surface_types.py --checkreports no drift under the new output path (the generated files are byte-identical after the move).parse_client_request/serialize_server_resultroute through the renamed internals correctly,mcp.server.elicitation's schema gate still validates, andmcp_types.v2025_11_25now raisesModuleNotFoundErroras intended.scripts/docs/gen_ref_pages.pynow emits onlyindex/jsonrpc/methods/versionformcp_types— the versioned pages are gone.Breaking Changes
Yes, nominally:
import mcp_types.v2025_11_25/mcp_types.v2026_07_28stop resolving. These modules only exist on the v2 pre-release line (added in #2849) and were documented as internal from the start. A GitHub-wide search finds no supported usage — FastMCP'sfastmcp-slimand mcpscore (both on 2.0.0b2) import only the top-level surface — so this lands in the pre-stable window where the rename is cheap rather than after 2.0.0. Noted indocs/migration.mdalongside the supported import surface.Types of changes
Checklist
Additional context
src/mcp/server/elicitation.pykeeps importingPrimitiveSchemaDefinitionfrom the (now underscored)_v2025_11_25package rather than promoting it to the public monolith:mcpexact-pinsmcp-typesto the same version, so this is a lockstep-safe internal import, and the monolith deliberately keepsElicitRequestedSchemaas a rawdict[str, Any].AI Disclaimer