Split protocol types into a standalone mcp-types package (#2973)

This commit is contained in:
Marcelo Trylesinski 2026-06-25 19:18:38 +02:00 • committed by GitHub
commit 0ee7f1b293
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 1040 additions and 867 deletions

View file

@ -1,20 +1,19 @@
"""Tests for the wire-method maps and two-step parse functions in `mcp.types.methods`."""
"""Tests for the wire-method maps and two-step parse functions in `mcp_types.methods`."""
import importlib.util
from collections.abc import Mapping
from types import MappingProxyType, UnionType
from typing import Any, get_args
import mcp_types as types
import mcp_types.v2025_11_25 as v2025
import mcp_types.v2026_07_28 as v2026
import pydantic
import pytest
from mcp_types import methods
from mcp_types.version import KNOWN_PROTOCOL_VERSIONS
from pydantic import BaseModel
import mcp.types as types
import mcp.types.v2025_11_25 as v2025
import mcp.types.v2026_07_28 as v2026
from mcp.shared.version import KNOWN_PROTOCOL_VERSIONS
from mcp.types import methods
# Transcribed from each schema's ClientRequest/ServerRequest/ClientNotification/
# ServerNotification unions, minus the tasks/* family (extensions register those).
EXPECTED_METHODS: dict[str, dict[str, frozenset[str]]] = {
@ -298,11 +297,11 @@ EMPTY_CLIENT_RESPONSE_METHODS = frozenset({"ping"})
# Pre-2026 versions share the 2025-11-25 surface package.
PACKAGE_BY_VERSION = {
"2024-11-05": "mcp.types.v2025_11_25",
"2025-03-26": "mcp.types.v2025_11_25",
"2025-06-18": "mcp.types.v2025_11_25",
"2025-11-25": "mcp.types.v2025_11_25",
"2026-07-28": "mcp.types.v2026_07_28",
"2024-11-05": "mcp_types.v2025_11_25",
"2025-03-26": "mcp_types.v2025_11_25",
"2025-06-18": "mcp_types.v2025_11_25",
"2025-11-25": "mcp_types.v2025_11_25",
"2026-07-28": "mcp_types.v2026_07_28",
}
# The three reserved `params._meta` entries the 2026 surface requires on every request.
@ -920,7 +919,7 @@ def test_serialize_server_result_raises_key_error_for_an_absent_row_and_value_er
def test_importing_the_module_builds_no_adapters_and_identical_rows_share_one():
# Execute a fresh copy so the cache assertion is order-independent.
spec = importlib.util.find_spec("mcp.types.methods")
spec = importlib.util.find_spec("mcp_types.methods")
assert spec is not None and spec.loader is not None
fresh = importlib.util.module_from_spec(spec)
spec.loader.exec_module(fresh)

View file

@ -1,21 +1,20 @@
"""Assert every per-version surface model's wire fields are a subset of its `mcp.types` superset counterpart."""
"""Assert every per-version surface model's wire fields are a subset of its `mcp_types` superset counterpart."""
from __future__ import annotations
import inspect
from types import ModuleType
import mcp_types as monolith
import mcp_types._types as _types
import mcp_types.v2025_11_25 as v2025_11_25
import mcp_types.v2026_07_28 as v2026_07_28
import pytest
from pydantic import BaseModel
import mcp.types as monolith
import mcp.types._types as _types
import mcp.types.v2025_11_25 as v2025_11_25
import mcp.types.v2026_07_28 as v2026_07_28
SURFACES: tuple[ModuleType, ...] = (v2025_11_25, v2026_07_28)
# Envelope fields the monolith models on `mcp.types.jsonrpc` instead of on each request/notification.
# Envelope fields the monolith models on `mcp_types.jsonrpc` instead of on each request/notification.
ENVELOPE_FIELDS: frozenset[str] = frozenset({"jsonrpc", "id"})
# Surface classes whose monolith counterpart has a different name (key: "<surface_tail>.<ClassName>").
@ -186,7 +185,7 @@ def test_monolith_is_superset_of_surface_fields(
assert not missing, f"{qualname}: monolith {mono_cls.__name__} missing wire fields {sorted(missing)}"
# Monolith model classes intentionally kept out of `mcp.types.__all__`.
# Monolith model classes intentionally kept out of `mcp_types.__all__`.
PRIVATE_MONOLITH_MODELS: frozenset[str] = frozenset(
{
"MCPModel", # internal base; users subclass the concrete spec types instead
@ -205,7 +204,7 @@ def test_every_public_monolith_model_is_exported_from_mcp_types() -> None:
and obj.__module__ == _types.__name__
}
missing = defined - set(monolith.__all__) - PRIVATE_MONOLITH_MODELS
assert not missing, f"_types models not in mcp.types.__all__: {sorted(missing)}"
assert not missing, f"_types models not in mcp_types.__all__: {sorted(missing)}"
def test_every_surface_class_is_accounted_for() -> None:

View file

@ -3,9 +3,7 @@
from typing import Any
from inline_snapshot import snapshot
from pydantic import BaseModel
from mcp.types import (
from mcp_types import (
METHOD_NOT_FOUND,
CallToolRequest,
CallToolRequestParams,
@ -24,6 +22,7 @@ from mcp.types import (
TextContent,
Tool,
)
from pydantic import BaseModel
def _body(model: BaseModel) -> dict[str, Any]: