Skip to content

Commit b1c9764

Browse files
committed
Import protocol types through mcp.types in all user-facing code
Every distribution whose modules a project imports should be a declared dependency, and `mcp` exact-pins `mcp-types` such that declaring `mcp-types` independently is pointless-to-harmful. So code that depends on `mcp` should import through `mcp.types` (one declared dependency, one import root), and `mcp_types` is the spelling only for projects that install `mcp-types` without the SDK. Previously the examples and docs imported `mcp_types` directly, modeling exactly the transitive-import leak this rule forbids. To let the sweep drop every direct `mcp_types` import, `mcp.types` is now a package: `types/__init__.py` (the existing mirror) plus a `types/version.py` mirror of `mcp_types.version` (star re-export, so every name is the same object), and `mcp_types.version` gains an explicit `__all__` so its typing import does not leak through the mirror. A parity test pins the version mirror. Rewrite the type imports in every example, snippet, and docs tutorial, remap the `hl_lines` highlights that the import reordering shifted, and restate the migration guide / What's New / installation docs around the "import through the package you depend on" rule.
1 parent 2cb00e6 commit b1c9764

168 files changed

Lines changed: 323 additions & 368 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/advanced/extensions.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ The same file's `main()` is the whole client story, both halves of it:
128128
The one interceptive hook. Override `intercept_tool_call` to observe, short-circuit,
129129
or veto a tool call:
130130

131-
```python title="server.py" hl_lines="18-25"
131+
```python title="server.py" hl_lines="17-24"
132132
--8<-- "docs_src/extensions/tutorial005.py"
133133
```
134134

@@ -158,7 +158,7 @@ A **client extension** is the same contract from the consuming side: a bundle of
158158
client-side behaviour behind one identifier. Pass instances to
159159
`Client(extensions=[...])` and call tools normally:
160160

161-
```python title="client.py" hl_lines="67-69"
161+
```python title="client.py" hl_lines="66-68"
162162
--8<-- "docs_src/extensions/tutorial006.py"
163163
```
164164

@@ -188,7 +188,7 @@ client = Client(mcp, extensions=[advertise("com.example/search")])
188188
Subclass `ClientExtension` and override only what you need. Three contribution
189189
kinds, each with a default: `settings()`, `claims()`, and `notifications()`.
190190

191-
```python title="client.py" hl_lines="18-19 44-45 47-48"
191+
```python title="client.py" hl_lines="17-18 43-44 46-47"
192192
--8<-- "docs_src/extensions/tutorial006.py"
193193
```
194194

@@ -226,12 +226,12 @@ claimed shape reaching a session-tier caller raises `UnexpectedClaimedResult`.
226226
### Extension verbs
227227

228228
An extension's own request methods need no client-side registration. A vendor request
229-
type subclasses `mcp_types.Request` and goes through `client.session.send_request`,
229+
type subclasses `mcp.types.Request` and goes through `client.session.send_request`,
230230
as in [Serving your own methods](#serving-your-own-methods). One addition: when a
231231
params key must ride the `Mcp-Name` header (extension specs such as tasks require
232232
this for their verbs), the request type declares `name_param`:
233233

234-
```python title="client.py" hl_lines="23-26 47-48"
234+
```python title="client.py" hl_lines="22-25 46-47"
235235
--8<-- "docs_src/extensions/tutorial007.py"
236236
```
237237

docs/advanced/low-level-server.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ For everything else, stay on `MCPServer`.
1414

1515
This is the `search_books` tool that **[Tools](../servers/tools.md)** writes in nine lines of `@mcp.tool()`, with the sugar removed:
1616

17-
```python title="server.py" hl_lines="23 27 33"
17+
```python title="server.py" hl_lines="22 26 32"
1818
--8<-- "docs_src/lowlevel/tutorial001.py"
1919
```
2020

@@ -80,7 +80,7 @@ That generalises. An exception raised from a low-level handler is **always** a p
8080

8181
`on_call_tool` is the single entry point for every tool on the server. You route on `params.name`:
8282

83-
```python title="server.py" hl_lines="39-44"
83+
```python title="server.py" hl_lines="38-43"
8484
--8<-- "docs_src/lowlevel/tutorial002.py"
8585
```
8686

@@ -91,7 +91,7 @@ That generalises. An exception raised from a low-level handler is **always** a p
9191

9292
Declare `output_schema` on the `Tool` and put `structured_content` on the result. Both are yours:
9393

94-
```python title="server.py" hl_lines="20-24 37"
94+
```python title="server.py" hl_lines="19-23 36"
9595
--8<-- "docs_src/lowlevel/tutorial003.py"
9696
```
9797

@@ -117,7 +117,7 @@ The server never compares the two fields. This SDK's `Client` does: return `stru
117117

118118
Use it for record IDs, trace IDs, anything your UI needs and your prompt doesn't:
119119

120-
```python title="server.py" hl_lines="38"
120+
```python title="server.py" hl_lines="37"
121121
--8<-- "docs_src/lowlevel/tutorial004.py"
122122
```
123123

@@ -144,7 +144,7 @@ No `resources`, no `prompts`: there is nothing to back them. Pass `on_list_promp
144144

145145
`Server` is generic in the type its lifespan yields. Annotate it once and the object is typed everywhere it surfaces:
146146

147-
```python title="server.py" hl_lines="25-27 45-46 51"
147+
```python title="server.py" hl_lines="24-26 44-45 50"
148148
--8<-- "docs_src/lowlevel/tutorial005.py"
149149
```
150150

docs/advanced/middleware.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ If `Server(name, on_call_tool=...)` is new to you, read **[The low-level Server]
1616

1717
One server, one tool, one middleware that logs how long each message took:
1818

19-
```python title="server.py" hl_lines="40-46 50"
19+
```python title="server.py" hl_lines="39-45 49"
2020
--8<-- "docs_src/middleware/tutorial001.py"
2121
```
2222

docs/advanced/pagination.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Pagination is for the server whose resource list is really a database: thousands
1010

1111
## A server that pages
1212

13-
```python title="server.py" hl_lines="13 16-17"
13+
```python title="server.py" hl_lines="12 15-16"
1414
--8<-- "docs_src/pagination/tutorial001.py"
1515
```
1616

@@ -38,7 +38,7 @@ The tenth page comes back with `next_cursor` set to `None`. Done.
3838

3939
Every `list_*` method on `Client` (`list_tools`, `list_resources`, `list_resource_templates`, `list_prompts`) takes a `cursor=` keyword. Draining a paged list is one `while True`:
4040

41-
```python title="client.py" hl_lines="27-33"
41+
```python title="client.py" hl_lines="26-32"
4242
--8<-- "docs_src/pagination/tutorial002.py"
4343
```
4444

docs/client/caching.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Out of the box every result says `ttlMs: 0, cacheScope: "private"`: immediately
2525

2626
On the low-level `Server`, handlers build their results by hand, and `ttl_ms` / `cache_scope` are just fields on the result models. A handler that sets them explicitly always wins over the constructor map, field by field:
2727

28-
```python title="server.py" hl_lines="11 17"
28+
```python title="server.py" hl_lines="10 16"
2929
--8<-- "docs_src/caching/tutorial002.py"
3030
```
3131

@@ -39,7 +39,7 @@ One caveat on paginated lists: the protocol requires the **same `cacheScope` on
3939

4040
On a 2026-07-28 session, `Client` honors the hints for you: it has a built-in response cache, on by default. A result that arrives carrying a `ttlMs` is stored, and an identical call within that TTL is served from the cache with no round trip. A result that carries *no* hint is not cached: hint-less results get `CacheConfig.default_ttl_ms`, which defaults to `0` (immediately stale), so a server that declares nothing sees exactly the call-for-call traffic it always did.
4141

42-
```python title="client.py" hl_lines="34 36 39"
42+
```python title="client.py" hl_lines="33 35 38"
4343
--8<-- "docs_src/caching/tutorial003.py"
4444
```
4545

docs/client/callbacks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ That is the server half, and the **[Elicitation](../handlers/elicitation.md)** p
1919

2020
## The elicitation callback
2121

22-
```python title="client.py" hl_lines="7-11 17-18"
22+
```python title="client.py" hl_lines="6-10 16-17"
2323
--8<-- "docs_src/client_callbacks/tutorial002.py"
2424
```
2525

docs/client/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ A tool that raises does **not** raise in your client. It comes back as an ordina
135135

136136
The resource verbs come in pairs: two ways to list, one way to read.
137137

138-
```python title="client.py" hl_lines="23-32"
138+
```python title="client.py" hl_lines="22-31"
139139
--8<-- "docs_src/client/tutorial004.py"
140140
```
141141

@@ -174,7 +174,7 @@ A host hands those messages straight to the model. That is the whole feature.
174174

175175
A server with a completion handler can autocomplete prompt and resource-template arguments as the user types.
176176

177-
```python title="client.py" hl_lines="28-32"
177+
```python title="client.py" hl_lines="27-31"
178178
--8<-- "docs_src/client/tutorial006.py"
179179
```
180180

@@ -187,7 +187,7 @@ The answer is in `result.completion.values`. Type `"p"` and the server comes bac
187187

188188
Every `list_*` method takes a `cursor=` keyword and every result carries a `next_cursor`. When `next_cursor` is `None`, you have everything.
189189

190-
```python title="client.py" hl_lines="23-31"
190+
```python title="client.py" hl_lines="22-30"
191191
--8<-- "docs_src/client/tutorial007.py"
192192
```
193193

docs/client/session-groups.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Create a `ClientSessionGroup` and call **`connect_to_server`** once per server:
4242

4343
You fix this at the group, not at the servers. Pass a function of `(name, server_info)` and the group runs it on every name it registers:
4444

45-
```python title="client.py" hl_lines="8-9 16"
45+
```python title="client.py" hl_lines="7-8 15"
4646
--8<-- "docs_src/session_groups/tutorial004.py"
4747
```
4848

docs/client/subscriptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This page is the client end: opening the stream, watching it beside your main fl
88

99
A subscription is one context manager. Entering it sends the request, with your keyword arguments as the subscription filter, and waits for the server's acknowledgment, so the stream is live by the time the block starts.
1010

11-
```python title="client.py" hl_lines="16 19 29"
11+
```python title="client.py" hl_lines="15 18 28"
1212
--8<-- "docs_src/subscriptions/tutorial003.py"
1313
```
1414

docs/get-started/installation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ These docs describe **v2**, currently a release candidate, so the version pin is
3131

3232
You don't need to know any of this to use the SDK, but if you're wondering what each dependency is for:
3333

34-
* `mcp-types`: every protocol type (requests, results, content blocks) as its own package, versioned in lockstep with the SDK. Every `from mcp_types import ...` in these docs is this package.
34+
* `mcp-types`: every protocol type (requests, results, content blocks) as its own package, versioned in lockstep with the SDK. Code that depends on `mcp` imports it through the `mcp.types` alias (every `from mcp.types import ...` in these docs); import `mcp_types` directly only in a project that installs `mcp-types` without the SDK.
3535
* [`anyio`](https://anyio.readthedocs.io/): the async runtime. The whole SDK is written against anyio, so it runs on either `asyncio` or `trio`.
36-
* [`pydantic`](https://docs.pydantic.dev/): what every `mcp_types` model is built on, plus all schema generation and validation.
36+
* [`pydantic`](https://docs.pydantic.dev/): what every `mcp.types` model is built on, plus all schema generation and validation.
3737
* [`httpx2`](https://pypi.org/project/httpx2/): the HTTP client behind the Streamable HTTP and SSE *client* transports, with server-sent events support built in.
3838
* [`starlette`](https://www.starlette.io/), [`uvicorn`](https://www.uvicorn.org/), [`sse-starlette`](https://pypi.org/project/sse-starlette/), and [`python-multipart`](https://pypi.org/project/python-multipart/): the HTTP *server* transports.
3939
* [`jsonschema`](https://pypi.org/project/jsonschema/): validates a tool's structured output against its declared output schema.

0 commit comments

Comments
 (0)