Skip to content

Commit 90b6ba0

Browse files
committed
Mirror mcp_types.methods and .jsonrpc under mcp.types too
Main now declares the supported mcp_types import surface as the package plus its jsonrpc, methods, and version submodules, and the "import through the package you depend on" rule only holds if every one of those has an mcp.types spelling. Otherwise an SDK user who needs CACHEABLE_METHODS is straight back to a transitive import. Add mcp.types.jsonrpc and mcp.types.methods mirrors alongside .version, give mcp_types.jsonrpc an explicit __all__ so the mirror is precise, and bind all three submodules on the mcp.types package so `mcp.types.version.X` is attribute-reachable exactly like `mcp_types.version.X` (previously only the from-import form worked). Pin the whole mirror set with one parametrized parity test, and drop the tautological __all__ equality (the mirror shares the source list object by construction) plus a sed artifact in the migration guide.
1 parent b1c9764 commit 90b6ba0

6 files changed

Lines changed: 87 additions & 13 deletions

File tree

docs/migration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1730,7 +1730,7 @@ except MCPError as e:
17301730
raise
17311731
```
17321732

1733-
`e.error.code` also still works; `e.code` is the v2 convenience property. The constant is importable from `mcp.types` or, equivalently, `mcp.types`. The example uses the high-level `Client`; `ClientSession.call_tool()` raises the same `MCPError`.
1733+
`e.error.code` also still works; `e.code` is the v2 convenience property. The constant is importable from `mcp.types` (or from `mcp_types` in a project that uses that package without the SDK). The example uses the high-level `Client`; `ClientSession.call_tool()` raises the same `MCPError`.
17341734

17351735
### `ClientSession` now runs on `JSONRPCDispatcher`; `BaseSession` removed
17361736

src/mcp-types/mcp_types/jsonrpc.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66

77
from pydantic import BaseModel, Field, TypeAdapter
88

9+
__all__ = [
10+
"CONNECTION_CLOSED",
11+
"HEADER_MISMATCH",
12+
"INTERNAL_ERROR",
13+
"INVALID_PARAMS",
14+
"INVALID_REQUEST",
15+
"JSONRPC_VERSION",
16+
"METHOD_NOT_FOUND",
17+
"MISSING_REQUIRED_CLIENT_CAPABILITY",
18+
"PARSE_ERROR",
19+
"REQUEST_TIMEOUT",
20+
"UNSUPPORTED_PROTOCOL_VERSION",
21+
"URL_ELICITATION_REQUIRED",
22+
"ErrorData",
23+
"JSONRPCError",
24+
"JSONRPCMessage",
25+
"JSONRPCNotification",
26+
"JSONRPCRequest",
27+
"JSONRPCResponse",
28+
"RequestId",
29+
"jsonrpc_message_adapter",
30+
]
31+
932
RequestId = Annotated[int, Field(strict=True)] | str
1033
"""The ID of a JSON-RPC request."""
1134

src/mcp/types/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
88
types.TextContent(type="text", text="hi")
99
10-
The protocol-version registry lives in the `mcp.types.version` submodule,
11-
mirroring `mcp_types.version` the same way.
10+
The `mcp.types.jsonrpc`, `mcp.types.methods`, and `mcp.types.version`
11+
submodules mirror `mcp_types.jsonrpc`, `mcp_types.methods`, and
12+
`mcp_types.version` the same way, so every supported `mcp_types` import has
13+
an `mcp.types` spelling.
1214
1315
Depend on and import `mcp_types` directly instead when you only need to
1416
(de)serialize MCP traffic and don't want the SDK's transport stack: its only
@@ -21,6 +23,13 @@
2123
from mcp_types import *
2224
from mcp_types import __all__ as __all__
2325

26+
# Bind the mirror submodules on the package, so `mcp.types.version.X` is as
27+
# reachable by attribute access as `mcp_types.version.X` (whose `__init__`
28+
# binds `.version` by importing from it), not only via `from ... import`.
29+
from . import jsonrpc as jsonrpc
30+
from . import methods as methods
31+
from . import version as version
32+
2433
# Names v1's mcp.types exposed that no longer exist. A bare "cannot import name"
2534
# leaves people grepping; naming the replacement finishes the migration step.
2635
_REMOVED = {

src/mcp/types/jsonrpc.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""The JSON-RPC 2.0 message and error types, as the `mcp.types.jsonrpc` namespace.
2+
3+
A mirror of `mcp_types.jsonrpc` (every name is the same object), so code that
4+
depends on `mcp` can import from `mcp.types.jsonrpc` without importing the
5+
`mcp_types` distribution directly. Depend on and import `mcp_types.jsonrpc`
6+
instead when you use `mcp-types` without the SDK.
7+
"""
8+
9+
# A wildcard mirror of the mcp_types.jsonrpc namespace is the whole point of this module.
10+
# pyright: reportWildcardImportFromLibrary=false
11+
12+
from mcp_types.jsonrpc import *
13+
from mcp_types.jsonrpc import __all__ as __all__

src/mcp/types/methods.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""The MCP method registry, as the `mcp.types.methods` namespace.
2+
3+
A mirror of `mcp_types.methods` (every name is the same object), so code that
4+
depends on `mcp` can import from `mcp.types.methods` without importing the
5+
`mcp_types` distribution directly. Depend on and import `mcp_types.methods`
6+
instead when you use `mcp-types` without the SDK.
7+
"""
8+
9+
# A wildcard mirror of the mcp_types.methods namespace is the whole point of this module.
10+
# pyright: reportWildcardImportFromLibrary=false
11+
12+
from mcp_types.methods import *
13+
from mcp_types.methods import __all__ as __all__

tests/test_types.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import subprocess
22
import sys
3+
from types import ModuleType
34
from typing import Any
45

56
import mcp_types
7+
import mcp_types.jsonrpc
8+
import mcp_types.methods
69
import mcp_types.version
710
import pytest
811
from inline_snapshot import snapshot
@@ -44,6 +47,8 @@
4447

4548
import mcp
4649
import mcp.types
50+
import mcp.types.jsonrpc
51+
import mcp.types.methods
4752
import mcp.types.version
4853

4954

@@ -455,10 +460,29 @@ def test_input_required_result_requires_at_least_one_of_input_requests_or_reques
455460
assert InputRequiredResult(request_state="s").input_requests is None
456461

457462

463+
def _assert_mirrors(mirror: ModuleType, source: ModuleType) -> None:
464+
# The mirror shares the source's `__all__` list object by construction (`from source import
465+
# __all__`), so the meaningful proof is that every exported name is the identical object.
466+
assert all(getattr(mirror, name) is getattr(source, name) for name in source.__all__)
467+
468+
458469
def test_mcp_types_namespace_mirrors_mcp_types_exactly():
459470
"""SDK-defined: `mcp.types` is a permanent alias whose every name is the `mcp_types` object."""
460-
assert mcp.types.__all__ == mcp_types.__all__
461-
assert all(getattr(mcp.types, name) is getattr(mcp_types, name) for name in mcp_types.__all__)
471+
_assert_mirrors(mcp.types, mcp_types)
472+
473+
474+
@pytest.mark.parametrize(
475+
("mirror", "source"),
476+
[
477+
(mcp.types.jsonrpc, mcp_types.jsonrpc),
478+
(mcp.types.methods, mcp_types.methods),
479+
(mcp.types.version, mcp_types.version),
480+
],
481+
ids=["jsonrpc", "methods", "version"],
482+
)
483+
def test_mcp_types_submodules_mirror_mcp_types_submodules_exactly(mirror: ModuleType, source: ModuleType):
484+
"""SDK-defined: every supported `mcp_types` submodule has an `mcp.types` mirror, name for name."""
485+
_assert_mirrors(mirror, source)
462486

463487

464488
def test_mcp_types_attribute_access_names_the_replacement_for_a_removed_name():
@@ -505,11 +529,3 @@ def test_bare_import_mcp_binds_the_types_submodule():
505529
)
506530
assert result.returncode == 0, result.stderr
507531
assert result.stdout == snapshot("Tool\n")
508-
509-
510-
def test_mcp_types_version_mirrors_mcp_types_version_exactly():
511-
"""SDK-defined: `mcp.types.version` is a permanent alias whose every name is the `mcp_types.version` object."""
512-
assert mcp.types.version.__all__ == mcp_types.version.__all__
513-
assert all(
514-
getattr(mcp.types.version, name) is getattr(mcp_types.version, name) for name in mcp_types.version.__all__
515-
)

0 commit comments

Comments
 (0)