diff --git a/docs/advanced/extensions.md b/docs/advanced/extensions.md index 715c5bbdc8..de7937fc75 100644 --- a/docs/advanced/extensions.md +++ b/docs/advanced/extensions.md @@ -128,7 +128,7 @@ The same file's `main()` is the whole client story, both halves of it: The one interceptive hook. Override `intercept_tool_call` to observe, short-circuit, or veto a tool call: -```python title="server.py" hl_lines="18-25" +```python title="server.py" hl_lines="17-24" --8<-- "docs_src/extensions/tutorial005.py" ``` @@ -158,7 +158,7 @@ A **client extension** is the same contract from the consuming side: a bundle of client-side behaviour behind one identifier. Pass instances to `Client(extensions=[...])` and call tools normally: -```python title="client.py" hl_lines="67-69" +```python title="client.py" hl_lines="66-68" --8<-- "docs_src/extensions/tutorial006.py" ``` @@ -188,7 +188,7 @@ client = Client(mcp, extensions=[advertise("com.example/search")]) Subclass `ClientExtension` and override only what you need. Three contribution kinds, each with a default: `settings()`, `claims()`, and `notifications()`. -```python title="client.py" hl_lines="18-19 44-45 47-48" +```python title="client.py" hl_lines="17-18 43-44 46-47" --8<-- "docs_src/extensions/tutorial006.py" ``` @@ -226,12 +226,12 @@ claimed shape reaching a session-tier caller raises `UnexpectedClaimedResult`. ### Extension verbs An extension's own request methods need no client-side registration. A vendor request -type subclasses `mcp_types.Request` and goes through `client.session.send_request`, +type subclasses `mcp.types.Request` and goes through `client.session.send_request`, as in [Serving your own methods](#serving-your-own-methods). One addition: when a params key must ride the `Mcp-Name` header (extension specs such as tasks require this for their verbs), the request type declares `name_param`: -```python title="client.py" hl_lines="23-26 47-48" +```python title="client.py" hl_lines="22-25 46-47" --8<-- "docs_src/extensions/tutorial007.py" ``` diff --git a/docs/advanced/low-level-server.md b/docs/advanced/low-level-server.md index dd5fb427a2..083e03cd61 100644 --- a/docs/advanced/low-level-server.md +++ b/docs/advanced/low-level-server.md @@ -14,7 +14,7 @@ For everything else, stay on `MCPServer`. This is the `search_books` tool that **[Tools](../servers/tools.md)** writes in nine lines of `@mcp.tool()`, with the sugar removed: -```python title="server.py" hl_lines="23 27 33" +```python title="server.py" hl_lines="22 26 32" --8<-- "docs_src/lowlevel/tutorial001.py" ``` @@ -80,7 +80,7 @@ That generalises. An exception raised from a low-level handler is **always** a p `on_call_tool` is the single entry point for every tool on the server. You route on `params.name`: -```python title="server.py" hl_lines="39-44" +```python title="server.py" hl_lines="38-43" --8<-- "docs_src/lowlevel/tutorial002.py" ``` @@ -91,7 +91,7 @@ That generalises. An exception raised from a low-level handler is **always** a p Declare `output_schema` on the `Tool` and put `structured_content` on the result. Both are yours: -```python title="server.py" hl_lines="20-24 37" +```python title="server.py" hl_lines="19-23 36" --8<-- "docs_src/lowlevel/tutorial003.py" ``` @@ -117,7 +117,7 @@ The server never compares the two fields. This SDK's `Client` does: return `stru Use it for record IDs, trace IDs, anything your UI needs and your prompt doesn't: -```python title="server.py" hl_lines="38" +```python title="server.py" hl_lines="37" --8<-- "docs_src/lowlevel/tutorial004.py" ``` @@ -144,7 +144,7 @@ No `resources`, no `prompts`: there is nothing to back them. Pass `on_list_promp `Server` is generic in the type its lifespan yields. Annotate it once and the object is typed everywhere it surfaces: -```python title="server.py" hl_lines="25-27 45-46 51" +```python title="server.py" hl_lines="24-26 44-45 50" --8<-- "docs_src/lowlevel/tutorial005.py" ``` diff --git a/docs/advanced/middleware.md b/docs/advanced/middleware.md index 3d5808550a..3a5fa14264 100644 --- a/docs/advanced/middleware.md +++ b/docs/advanced/middleware.md @@ -16,7 +16,7 @@ If `Server(name, on_call_tool=...)` is new to you, read **[The low-level Server] One server, one tool, one middleware that logs how long each message took: -```python title="server.py" hl_lines="40-46 50" +```python title="server.py" hl_lines="39-45 49" --8<-- "docs_src/middleware/tutorial001.py" ``` diff --git a/docs/advanced/pagination.md b/docs/advanced/pagination.md index 381f7fae04..9f807a8e61 100644 --- a/docs/advanced/pagination.md +++ b/docs/advanced/pagination.md @@ -10,7 +10,7 @@ Pagination is for the server whose resource list is really a database: thousands ## A server that pages -```python title="server.py" hl_lines="13 16-17" +```python title="server.py" hl_lines="12 15-16" --8<-- "docs_src/pagination/tutorial001.py" ``` @@ -38,7 +38,7 @@ The tenth page comes back with `next_cursor` set to `None`. Done. 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`: -```python title="client.py" hl_lines="27-33" +```python title="client.py" hl_lines="26-32" --8<-- "docs_src/pagination/tutorial002.py" ``` diff --git a/docs/client/caching.md b/docs/client/caching.md index 78de2a59f1..5d83cfa92a 100644 --- a/docs/client/caching.md +++ b/docs/client/caching.md @@ -25,7 +25,7 @@ Out of the box every result says `ttlMs: 0, cacheScope: "private"`: immediately 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: -```python title="server.py" hl_lines="11 17" +```python title="server.py" hl_lines="10 16" --8<-- "docs_src/caching/tutorial002.py" ``` @@ -39,7 +39,7 @@ One caveat on paginated lists: the protocol requires the **same `cacheScope` on 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. -```python title="client.py" hl_lines="34 36 39" +```python title="client.py" hl_lines="33 35 38" --8<-- "docs_src/caching/tutorial003.py" ``` diff --git a/docs/client/callbacks.md b/docs/client/callbacks.md index 53f6e563ee..1ac633bea5 100644 --- a/docs/client/callbacks.md +++ b/docs/client/callbacks.md @@ -19,7 +19,7 @@ That is the server half, and the **[Elicitation](../handlers/elicitation.md)** p ## The elicitation callback -```python title="client.py" hl_lines="7-11 17-18" +```python title="client.py" hl_lines="6-10 16-17" --8<-- "docs_src/client_callbacks/tutorial002.py" ``` @@ -55,7 +55,7 @@ result.content # [TextContent(type='text', text='Card issued to Ada Lovelace.') One `tools/call` from you, one `elicitation/create` back from the server, answered by your function, all inside a single tool call. !!! info - `mode="legacy"` on line 17 is doing real work. By default `Client(...)` negotiates the modern + `mode="legacy"` on the `Client(...)` call is doing real work. By default `Client(...)` negotiates the modern protocol path, and that path has no back-channel for server-to-client requests: `ctx.elicit` fails before your callback ever runs. The transport doesn't decide that; the negotiated protocol does, in-memory and over a URL alike. Pin `mode="legacy"` whenever your client has diff --git a/docs/client/index.md b/docs/client/index.md index f70966e1ab..1e1df3c01b 100644 --- a/docs/client/index.md +++ b/docs/client/index.md @@ -135,7 +135,7 @@ A tool that raises does **not** raise in your client. It comes back as an ordina The resource verbs come in pairs: two ways to list, one way to read. -```python title="client.py" hl_lines="23-32" +```python title="client.py" hl_lines="22-31" --8<-- "docs_src/client/tutorial004.py" ``` @@ -174,7 +174,7 @@ A host hands those messages straight to the model. That is the whole feature. A server with a completion handler can autocomplete prompt and resource-template arguments as the user types. -```python title="client.py" hl_lines="28-32" +```python title="client.py" hl_lines="27-31" --8<-- "docs_src/client/tutorial006.py" ``` @@ -187,7 +187,7 @@ The answer is in `result.completion.values`. Type `"p"` and the server comes bac Every `list_*` method takes a `cursor=` keyword and every result carries a `next_cursor`. When `next_cursor` is `None`, you have everything. -```python title="client.py" hl_lines="23-31" +```python title="client.py" hl_lines="22-30" --8<-- "docs_src/client/tutorial007.py" ``` diff --git a/docs/client/session-groups.md b/docs/client/session-groups.md index 70ad86833a..70ac02e859 100644 --- a/docs/client/session-groups.md +++ b/docs/client/session-groups.md @@ -42,7 +42,7 @@ Create a `ClientSessionGroup` and call **`connect_to_server`** once per server: 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: -```python title="client.py" hl_lines="8-9 16" +```python title="client.py" hl_lines="7-8 15" --8<-- "docs_src/session_groups/tutorial004.py" ``` diff --git a/docs/client/subscriptions.md b/docs/client/subscriptions.md index fc7d01308d..fa72634c44 100644 --- a/docs/client/subscriptions.md +++ b/docs/client/subscriptions.md @@ -8,7 +8,7 @@ This page is the client end: opening the stream, watching it beside your main fl 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. -```python title="client.py" hl_lines="16 19 29" +```python title="client.py" hl_lines="15 18 28" --8<-- "docs_src/subscriptions/tutorial003.py" ``` diff --git a/docs/get-started/installation.md b/docs/get-started/installation.md index a0c6100f15..46e0f9b978 100644 --- a/docs/get-started/installation.md +++ b/docs/get-started/installation.md @@ -31,9 +31,9 @@ These docs describe **v2**, currently a release candidate, so the version pin is You don't need to know any of this to use the SDK, but if you're wondering what each dependency is for: -* `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. +* `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. * [`anyio`](https://anyio.readthedocs.io/): the async runtime. The whole SDK is written against anyio, so it runs on either `asyncio` or `trio`. -* [`pydantic`](https://docs.pydantic.dev/): what every `mcp_types` model is built on, plus all schema generation and validation. +* [`pydantic`](https://docs.pydantic.dev/): what every `mcp.types` model is built on, plus all schema generation and validation. * [`httpx2`](https://pypi.org/project/httpx2/): the HTTP client behind the Streamable HTTP and SSE *client* transports, with server-sent events support built in. * [`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. * [`jsonschema`](https://pypi.org/project/jsonschema/): validates a tool's structured output against its declared output schema. diff --git a/docs/get-started/testing.md b/docs/get-started/testing.md index 2c3f9fca74..9abd281ceb 100644 --- a/docs/get-started/testing.md +++ b/docs/get-started/testing.md @@ -40,7 +40,7 @@ Now the test: import pytest from inline_snapshot import snapshot from mcp import Client -from mcp_types import CallToolResult, TextContent +from mcp.types import CallToolResult, TextContent from server import mcp diff --git a/docs/handlers/dependencies.md b/docs/handlers/dependencies.md index 509b2635f0..b347e1b7d6 100644 --- a/docs/handlers/dependencies.md +++ b/docs/handlers/dependencies.md @@ -138,7 +138,7 @@ That's the right default for a precondition: no answer, no order. When declining Elicitation is one of the three questions a resolver can ask, and the multi-round-trip flow allows no others. The other two go to the **client** rather than the user: return `Sample(...)` to run an LLM call through the client (a `sampling/createMessage` request), or `ListRoots()` to fetch the client's current roots. Neither has an accept/decline outcome; the consumer annotates the result type directly, `CreateMessageResult` (`CreateMessageResultWithTools` when the request carries `tools` or `tool_choice`) or `ListRootsResult`: -```python title="server.py" hl_lines="11-16 22" +```python title="server.py" hl_lines="10-15 21" --8<-- "docs_src/dependencies/tutorial004.py" ``` diff --git a/docs/handlers/elicitation.md b/docs/handlers/elicitation.md index 3f3f5a6c07..c9a0a4fabc 100644 --- a/docs/handlers/elicitation.md +++ b/docs/handlers/elicitation.md @@ -128,7 +128,7 @@ Look at the second tool. When your server learns the out-of-band flow finished ( Servers ask. Clients answer by passing an **`elicitation_callback`** to `Client(...)`: -```python title="client.py" hl_lines="7-8 19" +```python title="client.py" hl_lines="6-7 18" --8<-- "docs_src/elicitation/tutorial003.py" ``` diff --git a/docs/handlers/multi-round-trip.md b/docs/handlers/multi-round-trip.md index e08903444b..1d5b9f52c6 100644 --- a/docs/handlers/multi-round-trip.md +++ b/docs/handlers/multi-round-trip.md @@ -21,7 +21,7 @@ That's the whole protocol. Every leg is an ordinary request from the client to t On `@mcp.tool()` you rarely build this by hand: declare a dependency that asks the user (`Elicit`), samples the client's LLM (`Sample`), or lists its roots (`ListRoots`) and the SDK returns the `InputRequiredResult` for you; that form is the **[Dependencies](dependencies.md)** page. The two forms don't mix: a call has one `input_responses`/`request_state` channel, so a tool that uses `Resolve(...)` parameters cannot also return `InputRequiredResult` from its body. A declared `InputRequiredResult` return is rejected at registration (`InvalidSignature`), and an undeclared one fails the call at runtime. The manual form is the **low-level** `Server`, whose `on_call_tool` handler is allowed to return either result type: -```python title="server.py" hl_lines="44-47" +```python title="server.py" hl_lines="43-46" --8<-- "docs_src/mrtr/tutorial001.py" ``` @@ -35,7 +35,7 @@ Everything else in that file (the explicit `input_schema`, the hand-built `CallT `tools/call` is not special: at 2026-07-28 a server may answer `prompts/get` and `resources/read` the same way. On `MCPServer`, an `@mcp.prompt()` function — or an `@mcp.resource()` **template** function — returns the `InputRequiredResult` itself and reads the retry's answers off the context: -```python title="server.py" hl_lines="21 23 25" +```python title="server.py" hl_lines="20 22 24" --8<-- "docs_src/mrtr/tutorial004.py" ``` @@ -51,7 +51,7 @@ Everything else in that file (the explicit `input_schema`, the hand-built `CallT Register the callbacks the server might ask for (`elicitation_callback`, `sampling_callback`, `list_roots_callback`) and call the tool. When an `InputRequiredResult` arrives, `Client` dispatches each entry in `input_requests` to the matching callback, retries with the answers and the echoed `request_state`, and keeps going until a `CallToolResult` comes back: -```python title="client.py" hl_lines="12 13" +```python title="client.py" hl_lines="11 12" --8<-- "docs_src/mrtr/tutorial003.py" ``` @@ -76,7 +76,7 @@ The auto-loop is enough for a single-process client. Own the loop instead when: Drop to the underlying session, where `allow_input_required=True` hands you the union directly: -```python title="client.py" hl_lines="13 14 20" +```python title="client.py" hl_lines="12 13 19" --8<-- "docs_src/mrtr/tutorial002.py" ``` diff --git a/docs/handlers/sampling-and-roots.md b/docs/handlers/sampling-and-roots.md index 6174f42585..f7c192f05b 100644 --- a/docs/handlers/sampling-and-roots.md +++ b/docs/handlers/sampling-and-roots.md @@ -11,7 +11,7 @@ Both still work, on every protocol version the SDK speaks. But read the warning A resolver returns `Sample(...)` and the tool receives the completion, through the same dependency mechanism that runs `Elicit` in **[Dependencies](dependencies.md)**: -```python title="server.py" hl_lines="11-16 20" +```python title="server.py" hl_lines="10-15 19" --8<-- "docs_src/sampling_and_roots/tutorial001.py" ``` @@ -24,7 +24,7 @@ A resolver returns `Sample(...)` and the tool receives the completion, through t Roots are the folders the client says the server may operate on. They are informational guidance, not an access-control mechanism. A resolver returns `ListRoots()`: -```python title="server.py" hl_lines="11-12 16" +```python title="server.py" hl_lines="10-11 15" --8<-- "docs_src/sampling_and_roots/tutorial002.py" ``` diff --git a/docs/handlers/subscriptions.md b/docs/handlers/subscriptions.md index 99b1bc98ad..c0e485114f 100644 --- a/docs/handlers/subscriptions.md +++ b/docs/handlers/subscriptions.md @@ -56,7 +56,7 @@ Two things the stream is *not*: Here is a client on the other side of that stream, following the board: -```python title="client.py" hl_lines="16" +```python title="client.py" hl_lines="15" --8<-- "docs_src/subscriptions/tutorial003.py" ``` @@ -119,7 +119,7 @@ async def tools_reloaded() -> None: Down on the low-level `Server` there is no pre-wired anything, and the same parts assemble in three lines: -```python title="server.py" hl_lines="9-10 48" +```python title="server.py" hl_lines="8-9 47" --8<-- "docs_src/subscriptions/tutorial002.py" ``` diff --git a/docs/migration.md b/docs/migration.md index 7b5950e7cf..11569680e0 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -14,7 +14,7 @@ Every section heading below names the API it affects, so searching this page for |---|---|---| | `FastMCP` renamed to `MCPServer` | `ModuleNotFoundError: No module named 'mcp.server.fastmcp'` | [`FastMCP` renamed](#fastmcp-renamed-to-mcpserver) | | Fields renamed from camelCase to snake_case | `AttributeError: 'Tool' object has no attribute 'inputSchema'` | [snake_case fields](#field-names-changed-from-camelcase-to-snake_case) | -| `mcp.types` moved to the `mcp-types` package | `ModuleNotFoundError: No module named 'mcp.types'` | [`mcp.types` moved](#mcptypes-moved-to-the-mcp-types-package) | +| `mcp.types` names removed | `ImportError: cannot import name 'Content' from 'mcp.types'` | [Removed types](#removed-type-aliases-and-classes) | | `McpError` renamed to `MCPError` | `ImportError: cannot import name 'McpError' from 'mcp'` | [`McpError` renamed](#mcperror-renamed-to-mcperror) | | Resource URIs are `str`, not `AnyUrl` | `AttributeError: 'str' object has no attribute 'host'` | [URI type](#resource-uri-type-changed-from-anyurl-to-str) | | Message unions (`ServerNotification`, `JSONRPCMessage`, ...) are plain unions, not `RootModel` | `AttributeError: 'LoggingMessageNotification' object has no attribute 'root'` | [`RootModel` → unions](#replace-rootmodel-by-union-types-with-typeadapter-validation) | @@ -196,21 +196,38 @@ nothing on PyPI to pin to, keep the unpinned form. ### `mcp.types` moved to the `mcp-types` package -The protocol wire types now live in a standalone distribution, `mcp-types`, imported as -`mcp_types`. Its only runtime dependencies are `pydantic` and `typing-extensions`, so code -that just needs to (de)serialize MCP traffic can install it without the full SDK. The `mcp` package depends on `mcp-types` and -continues to re-export the type names at the top level, so `from mcp import Tool` is -unchanged. Only the `mcp.types` submodule and `mcp.shared.version` were removed. The -package's API reference is at [`mcp_types`](api/mcp_types/index.md). - -The supported import surface is `mcp_types`, `mcp_types.jsonrpc`, `mcp_types.methods`, and -`mcp_types.version`. Underscore-prefixed submodules (`mcp_types._types`, and the generated +The protocol wire types now live in a standalone distribution, `mcp-types` (import package +`mcp_types`). Its only runtime dependencies are `pydantic` and `typing-extensions`, so code +that just needs to (de)serialize MCP traffic can install it without the full SDK. Its API +reference is at [`mcp_types`](api/mcp_types/index.md). + +**If your project depends on `mcp`, nothing changes for you.** `import mcp.types`, +`from mcp.types import ...`, `from mcp import types`, and `import mcp` followed by +`mcp.types.Tool` all keep working: `mcp.types` is a permanent alias that mirrors `mcp_types` +exactly (every name is the same object), and `mcp.types.version` mirrors +`mcp_types.version` the same way. Keep importing through `mcp` — the package you actually +depend on — rather than writing `import mcp_types`, which would reach past your declared +dependency into a transitive one. The old `mcp.shared.version` module was removed; import the +version registry from `mcp.types.version` instead. The top-level `from mcp import Tool` +re-exports are unchanged too. + +**Import `mcp_types` directly only in a project that depends on `mcp-types` without the +SDK.** That is the point of the split: tooling and lightweight clients can depend on the +protocol schema without pulling in `httpx2`, `starlette`, `uvicorn`, and the rest of the +server/transport stack. + +Names that no longer exist (listed under +[Removed type aliases and classes](#removed-type-aliases-and-classes)) fail on import or +attribute access with an ordinary `ImportError` / `AttributeError`; the table below names each +replacement. + +The supported import surface is the package plus its `jsonrpc`, `methods`, and `version` +submodules, and each has both spellings: `mcp.types` / `mcp_types`, `mcp.types.jsonrpc` / +`mcp_types.jsonrpc`, `mcp.types.methods` / `mcp_types.methods`, and `mcp.types.version` / +`mcp_types.version` (each `mcp.types` module mirrors its `mcp_types` counterpart, name for +name, the same objects). Underscore-prefixed submodules (`mcp_types._types`, and the generated per-protocol-version packages `mcp_types._v2025_11_25` / `mcp_types._v2026_07_28`) are internal -validators with unstable class names; don't import from them. - -**Why:** keeping the wire types in their own package lets tooling and lightweight clients -depend on the protocol schema without pulling in `httpx2`, `starlette`, `uvicorn`, and the -rest of the server/transport stack. +validators with unstable class names; don't import from them, under either spelling. **Before (v1):** @@ -219,19 +236,23 @@ from mcp.types import Tool, Resource from mcp.shared.version import LATEST_PROTOCOL_VERSION ``` -**After (v2):** +**After (v2), depending on `mcp`:** + +```python +from mcp.types import Tool, Resource # unchanged +from mcp.types.version import LATEST_PROTOCOL_VERSION +``` + +**After (v2), depending only on `mcp-types` (no SDK):** ```python from mcp_types import Tool, Resource from mcp_types.version import LATEST_PROTOCOL_VERSION - -# Names `mcp` already re-exported at the top level are unchanged: -from mcp import Tool, Resource ``` ### Removed type aliases and classes -The following type aliases and classes have been removed from `mcp_types`: +The following type aliases and classes have been removed from the protocol types (`mcp.types` / `mcp_types`): | Removed | Replacement | |---------|-------------| @@ -254,13 +275,13 @@ from mcp.types import Content, ResourceReference, Cursor **After (v2):** ```python -from mcp_types import ContentBlock, ResourceTemplateReference +from mcp.types import ContentBlock, ResourceTemplateReference # Use `str` instead of `Cursor` for pagination cursors ``` ### Field names changed from camelCase to snake_case -All Pydantic model fields in `mcp_types` now use snake_case names for Python attribute access. The JSON wire format is unchanged — traffic the SDK sends still uses camelCase via Pydantic aliases, but your own `model_dump()` calls now need `by_alias=True` to produce it. +All Pydantic model fields in the protocol types now use snake_case names for Python attribute access. The JSON wire format is unchanged — traffic the SDK sends still uses camelCase via Pydantic aliases, but your own `model_dump()` calls now need `by_alias=True` to produce it. **Before (v1):** @@ -320,7 +341,7 @@ In v1, MCP protocol types were configured with `extra="allow"`: unknown fields p In v2, MCP types silently ignore extra fields. Unknown constructor keyword arguments and unknown keys in wire data are dropped during validation — no error is raised, and the values do not round-trip: ```python -from mcp_types import CallToolRequestParams +from mcp.types import CallToolRequestParams params = CallToolRequestParams( name="my_tool", @@ -356,7 +377,7 @@ resource = Resource(name="test", uri=AnyUrl("users/me")) # Would fail validatio **After (v2):** ```python -from mcp_types import Resource +from mcp.types import Resource # Plain strings accepted resource = Resource(name="test", uri="users/me") # Works @@ -426,7 +447,7 @@ actual_notification = notification.root **After (v2):** ```python -from mcp_types import client_request_adapter, server_notification_adapter +from mcp.types import client_request_adapter, server_notification_adapter # Using TypeAdapter.validate_python() request = client_request_adapter.validate_python(data) @@ -469,7 +490,7 @@ await session.send_notification( | `ServerResult` | `server_result_adapter` | | `JSONRPCMessage` | `jsonrpc_message_adapter` | -All adapters are exported from `mcp_types`. +All adapters are exported from `mcp.types`. These are ordinary `X | Y` unions of the concrete pydantic classes, so `isinstance(msg, ServerNotification)`, `isinstance(msg, LoggingMessageNotification)`, and `match`/`case` on the member classes keep working (unlike `ElicitationResult`, which became a `TypeAliasType` — see [`isinstance()` checks against `ElicitationResult` raise `TypeError`](#isinstance-checks-against-elicitationresult-raise-typeerror)). @@ -525,7 +546,7 @@ attribute access. The JSON wire format is unchanged. ### `SUPPORTED_PROTOCOL_VERSIONS` deprecated; `LATEST_PROTOCOL_VERSION` changed meaning -`SUPPORTED_PROTOCOL_VERSIONS` is deprecated — it's now the union of `HANDSHAKE_PROTOCOL_VERSIONS` (initialize-handshake versions) and `MODERN_PROTOCOL_VERSIONS` (per-request-envelope versions). If you were using it to mean "versions the initialize handshake accepts", switch to `HANDSHAKE_PROTOCOL_VERSIONS`. Named scalars derived from these tuples are now exported alongside them — `LATEST_HANDSHAKE_VERSION`, `LATEST_MODERN_VERSION`, `OLDEST_SUPPORTED_VERSION` — so prefer those over indexing the tuples directly. All of these live in `mcp_types.version` (previously `mcp.shared.version`): `from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS`. +`SUPPORTED_PROTOCOL_VERSIONS` is deprecated — it's now the union of `HANDSHAKE_PROTOCOL_VERSIONS` (initialize-handshake versions) and `MODERN_PROTOCOL_VERSIONS` (per-request-envelope versions). If you were using it to mean "versions the initialize handshake accepts", switch to `HANDSHAKE_PROTOCOL_VERSIONS`. Named scalars derived from these tuples are now exported alongside them — `LATEST_HANDSHAKE_VERSION`, `LATEST_MODERN_VERSION`, `OLDEST_SUPPORTED_VERSION` — so prefer those over indexing the tuples directly. All of these live in `mcp.types.version` (an alias of `mcp_types.version`; previously `mcp.shared.version`): `from mcp.types.version import HANDSHAKE_PROTOCOL_VERSIONS`. `LATEST_PROTOCOL_VERSION` also changed value and meaning. In v1 it was `"2025-11-25"`, the version the client offered during initialization. In v2 it is the newest revision the SDK speaks in any era, currently `"2026-07-28"`, which the initialize handshake cannot negotiate. If you offered it in a hand-built `initialize` request or compared the negotiated version against it, use `LATEST_HANDSHAKE_VERSION` instead. These tuples really are tuples now (`SUPPORTED_PROTOCOL_VERSIONS` was a `list` in v1), so list-only operations such as concatenating with a list raise `TypeError`. @@ -576,7 +597,7 @@ raise McpError(ErrorData(code=INVALID_REQUEST, message="bad input")) ```python from mcp.shared.exceptions import MCPError -from mcp_types import INVALID_REQUEST +from mcp.types import INVALID_REQUEST raise MCPError(INVALID_REQUEST, "bad input") # or, if you already have an ErrorData: @@ -601,7 +622,7 @@ JSONRPCMessage.model_validate( **After (v2):** ```python -from mcp_types import PARSE_ERROR, ErrorData, JSONRPCError, jsonrpc_message_adapter +from mcp.types import PARSE_ERROR, ErrorData, JSONRPCError, jsonrpc_message_adapter message = jsonrpc_message_adapter.validate_python( {"jsonrpc": "2.0", "id": None, "error": {"code": -32700, "message": "Parse error"}} @@ -641,7 +662,7 @@ mcp = MCPServer("Demo") All submodules under `mcp.server.fastmcp.*` are now under `mcp.server.mcpserver.*` with the same structure. Common imports: - `Image`, `Audio` — from `mcp.server.mcpserver` (or `.utilities.types`) -- `Icon` — from `mcp.server.mcpserver` or `mcp_types` (not a top-level `mcp` export); its `mimeType` field is now `mime_type` per the [snake_case renames](#field-names-changed-from-camelcase-to-snake_case), though the `mimeType=` kwarg still constructs +- `Icon` — from `mcp.server.mcpserver` or `mcp.types` (not a top-level `mcp` export); its `mimeType` field is now `mime_type` per the [snake_case renames](#field-names-changed-from-camelcase-to-snake_case), though the `mimeType=` kwarg still constructs - `Message`, `UserMessage`, `AssistantMessage` — from `mcp.server.mcpserver.prompts.base` - `ToolError`, `ResourceError` — from `mcp.server.mcpserver.exceptions` - `MCPServerError` (renamed from `FastMCPError`) — from `mcp.server.mcpserver.exceptions` @@ -844,7 +865,7 @@ Lifespans that set up process-wide state (connection pools, caches, background t Beyond the constructor parameters that moved to `run()`/`streamable_http_app()` and the lifespan change above, the server-side Streamable HTTP machinery is as in v1: -- `mcp.server.streamable_http` still exports the `EventStore` ABC (`store_event()`, `replay_events_after()`), `EventMessage`, `EventCallback`, `EventId`, and `StreamId` with unchanged signatures; a custom `EventStore` only needs `JSONRPCMessage` imported from `mcp_types` instead of `mcp.types`. +- `mcp.server.streamable_http` still exports the `EventStore` ABC (`store_event()`, `replay_events_after()`), `EventMessage`, `EventCallback`, `EventId`, and `StreamId` with unchanged signatures; a custom `EventStore` keeps importing `JSONRPCMessage` from `mcp.types`, unchanged. - `StreamableHTTPSessionManager` keeps its constructor and its `run()` / `handle_request()` methods (see [Lowlevel `Server`: what did not change](#lowlevel-server-what-did-not-change)); its `stateless=` parameter is unrelated to the removed [`Server.run(stateless=)` flag](#serverrun-no-longer-takes-a-stateless-flag). - `mcp.session_manager` still returns the manager once `streamable_http_app()` has been called, with the same `stateless`, `json_response`, `event_store`, and `retry_interval` attributes. - `stateless_http=True` still serves each request with a fresh transport, no `Mcp-Session-Id`, and no state carried between requests; `ctx.close_sse_stream()` and `ctx.close_standalone_sse_stream()` are still available on the handler `Context`. @@ -1205,7 +1226,7 @@ if isinstance(result, AcceptedElicitation): ... # result.data is a Confirm ``` -Narrowing on `result.action` (`"accept"` / `"decline"` / `"cancel"`) is unaffected. The `TypeError` is specific to `TypeAliasType` aliases like `ElicitationResult`; the `mcp_types` message unions (`ClientRequest`, `ServerNotification`, `JSONRPCMessage`, ...) are ordinary unions and stay `isinstance`-compatible (see [Replace `RootModel` by union types with `TypeAdapter` validation](#replace-rootmodel-by-union-types-with-typeadapter-validation)). +Narrowing on `result.action` (`"accept"` / `"decline"` / `"cancel"`) is unaffected. The `TypeError` is specific to `TypeAliasType` aliases like `ElicitationResult`; the `mcp.types` message unions (`ClientRequest`, `ServerNotification`, `JSONRPCMessage`, ...) are ordinary unions and stay `isinstance`-compatible (see [Replace `RootModel` by union types with `TypeAdapter` validation](#replace-rootmodel-by-union-types-with-typeadapter-validation)). ### Registering lowlevel handlers from `MCPServer` @@ -1227,7 +1248,7 @@ In v2, the lowlevel `Server` supports arbitrary request handlers directly via `a ```python from mcp.server import ServerRequestContext -from mcp_types import EmptyResult, SetLevelRequestParams, SubscribeRequestParams +from mcp.types import EmptyResult, SetLevelRequestParams, SubscribeRequestParams async def handle_set_logging_level(ctx: ServerRequestContext, params: SetLevelRequestParams) -> EmptyResult: @@ -1296,7 +1317,7 @@ async def handle_call_tool(name: str, arguments: dict): ```python from mcp.server import Server, ServerRequestContext -from mcp_types import ( +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -1345,13 +1366,13 @@ All handlers receive `ctx: ServerRequestContext` as the first argument. The seco | `@server.progress_notification()` | `on_progress` | `ProgressNotificationParams` | `None` | | — | `on_roots_list_changed` | `NotificationParams \| None` | `None` | -All `params` and return types are importable from `mcp_types`. +All `params` and return types are importable from `mcp.types`. **Notification handlers:** ```python from mcp.server import Server, ServerRequestContext -from mcp_types import ProgressNotificationParams +from mcp.types import ProgressNotificationParams async def handle_progress(ctx: ServerRequestContext, params: ProgressNotificationParams) -> None: @@ -1474,7 +1495,7 @@ async def call_tool(name: str, arguments: dict): ```python from mcp.server import Server -from mcp_types import CallToolResult, TextContent +from mcp.types import CallToolResult, TextContent async def handle_call_tool(ctx, params) -> CallToolResult: @@ -1618,7 +1639,7 @@ async def handle_call_tool(name: str, arguments: dict): ```python from mcp.server import ServerRequestContext -from mcp_types import CallToolRequestParams, CallToolResult, TextContent +from mcp.types import CallToolRequestParams, CallToolResult, TextContent async def handle_call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult: @@ -1813,7 +1834,7 @@ result = await session.list_tools(cursor="next_page_token") **After (v2):** ```python -from mcp_types import PaginatedRequestParams +from mcp.types import PaginatedRequestParams result = await session.list_resources(params=PaginatedRequestParams(cursor="next_page_token")) result = await session.list_tools(params=PaginatedRequestParams(cursor="next_page_token")) @@ -1901,7 +1922,7 @@ To migrate, replace `timedelta(...)` with plain seconds, or mechanically append ### Client request timeouts now raise `-32001` (`REQUEST_TIMEOUT`) instead of `408` -A client request that exceeds `read_timeout_seconds` still raises the SDK's protocol error (`MCPError`, previously `McpError`), but the error code changed from the HTTP status `408` (`httpx.codes.REQUEST_TIMEOUT`) to the JSON-RPC code `-32001` (`REQUEST_TIMEOUT`, importable from `mcp_types`), matching the TypeScript SDK. The message changed too: v1 said `"Timed out while waiting for response to ClientRequest. Waited 5.0 seconds."`, v2 says `"Request 'tools/call' timed out"`. `MCPError.error` still exists, so a migrated `e.error.code == 408` check runs without error and silently never matches; timeouts fall through to whatever generic-error handling follows. Code that matched on the old message text breaks too. Compare against `REQUEST_TIMEOUT` instead. +A client request that exceeds `read_timeout_seconds` still raises the SDK's protocol error (`MCPError`, previously `McpError`), but the error code changed from the HTTP status `408` (`httpx.codes.REQUEST_TIMEOUT`) to the JSON-RPC code `-32001` (`REQUEST_TIMEOUT`, importable from `mcp.types`), matching the TypeScript SDK. The message changed too: v1 said `"Timed out while waiting for response to ClientRequest. Waited 5.0 seconds."`, v2 says `"Request 'tools/call' timed out"`. `MCPError.error` still exists, so a migrated `e.error.code == 408` check runs without error and silently never matches; timeouts fall through to whatever generic-error handling follows. Code that matched on the old message text breaks too. Compare against `REQUEST_TIMEOUT` instead. **Before (v1):** @@ -1922,7 +1943,7 @@ except McpError as e: ```python from mcp.shared.exceptions import MCPError -from mcp_types import REQUEST_TIMEOUT # -32001 +from mcp.types import REQUEST_TIMEOUT # -32001 try: result = await client.call_tool("slow_tool", {}) @@ -1933,7 +1954,7 @@ except MCPError as e: raise ``` -`e.error.code` also still works; `e.code` is the v2 convenience property. `mcp.types` no longer exists, so the constant comes from `mcp_types`. The example uses the high-level `Client`; `ClientSession.call_tool()` raises the same `MCPError`. +`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`. ### `ClientSession` now runs on `JSONRPCDispatcher`; `BaseSession` removed @@ -1951,7 +1972,7 @@ Behavior changes: - **Client callbacks now receive `mcp.client.ClientRequestContext`** (its `request_id` is always populated); the `mcp.shared.context.RequestContext` generic is deleted. Annotations spelled `RequestContext[ClientSession, Any]` become `ClientRequestContext` (details in [`RequestContext` type parameters simplified](#requestcontext-type-parameters-simplified)). Otherwise the callback surface is unchanged: the `sampling_callback=`, `elicitation_callback=`, `list_roots_callback=`, `logging_callback=`, and `message_handler=` keywords; the `SamplingFnT`, `ElicitationFnT`, `ListRootsFnT`, `LoggingFnT`, and `MessageHandlerFnT` protocols (still in `mcp.client.session`); and the params/result types (`CreateMessageRequestParams` → `CreateMessageResult | CreateMessageResultWithTools | ErrorData`, `ElicitRequestParams` → `ElicitResult | ErrorData`, `ListRootsResult | ErrorData` — returning `ErrorData` is not new). The `mcp.client.session`, `mcp.client.stdio`, `mcp.client.sse`, and `mcp.client.streamable_http` module paths are unchanged too, so `unittest.mock.patch` string targets still resolve. - **`message_handler` no longer receives requests.** Server-initiated requests are answered by the typed callbacks (`sampling_callback`, `elicitation_callback`, `list_roots_callback`), so the handler's parameter is now `IncomingMessage = ServerNotification | Exception`, exported from `mcp.client`. Replace the hand-written v1 union `RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception` with `IncomingMessage`; `RequestResponder` is gone (below), so the old annotation no longer imports. Delivered notifications are the concrete member instances rather than the v1 `RootModel` wrapper, so drop `.root` (`message.params`, not `message.root.params`); see [Replace `RootModel` by union types with `TypeAdapter` validation](#replace-rootmodel-by-union-types-with-typeadapter-validation). -The `mcp.shared.session` module is gone. `RequestResponder` is removed — `respond()`, the cancellation-tracking members (`cancel()`, the `cancelled` and `in_flight` properties, the `on_complete` constructor argument) and `BaseSession._in_flight` have no replacement; inbound cancellation is handled by `JSONRPCDispatcher`. `ProgressFnT` now lives only in `mcp.shared.dispatcher`, and `RequestId` in `mcp_types`. The module's generic typing helpers (`SendRequestT`, `SendResultT`, `SendNotificationT`, `ReceiveRequestT`, `ReceiveResultT`, `ReceiveNotificationT`) went with it and have no re-export — the sessions are no longer generic; `ClientSession.send_request` takes a concrete request model plus a result model class (or `pydantic.TypeAdapter`), so an override that needs a type parameter can declare its own `TypeVar` bound to `pydantic.BaseModel`. +The `mcp.shared.session` module is gone. `RequestResponder` is removed — `respond()`, the cancellation-tracking members (`cancel()`, the `cancelled` and `in_flight` properties, the `on_complete` constructor argument) and `BaseSession._in_flight` have no replacement; inbound cancellation is handled by `JSONRPCDispatcher`. `ProgressFnT` now lives only in `mcp.shared.dispatcher`, and `RequestId` in `mcp.types`. The module's generic typing helpers (`SendRequestT`, `SendResultT`, `SendNotificationT`, `ReceiveRequestT`, `ReceiveResultT`, `ReceiveNotificationT`) went with it and have no re-export — the sessions are no longer generic; `ClientSession.send_request` takes a concrete request model plus a result model class (or `pydantic.TypeAdapter`), so an override that needs a type parameter can declare its own `TypeVar` bound to `pydantic.BaseModel`. Subclassing `ClientSession` remains a valid interception point: every typed helper routes through `send_request`, and the notification helpers through `send_notification`, so overriding those two still sees that traffic (the 2026-era `discover()`/`send_discover()` are the exception — they call the dispatcher directly). For wire-level interception, use the `dispatcher=` argument instead (with the caveat above on hand-written dispatchers). @@ -1969,7 +1990,7 @@ async def elicitation_callback( ```python from mcp.client import ClientRequestContext -from mcp_types import ElicitRequestParams, ElicitResult, ErrorData +from mcp.types import ElicitRequestParams, ElicitResult, ErrorData async def elicitation_callback( @@ -1979,7 +2000,7 @@ async def elicitation_callback( ### Experimental Tasks support removed -Tasks ([SEP-1686](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1686)) have been removed from the MCP specification and are no longer part of this SDK. The `mcp.client.experimental`, `mcp.server.experimental`, `mcp.shared.experimental`, and `mcp.server.lowlevel.experimental` modules have been removed, along with the `experimental` properties on `ClientSession`, `ServerSession`, `Server`, and `ServerRequestContext`. The corresponding `Task*` types remain in `mcp_types` as types-only definitions, except the `TaskExecutionMode` alias, whose literal is now inlined on `ToolExecution.task_support`. +Tasks ([SEP-1686](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1686)) have been removed from the MCP specification and are no longer part of this SDK. The `mcp.client.experimental`, `mcp.server.experimental`, `mcp.shared.experimental`, and `mcp.server.lowlevel.experimental` modules have been removed, along with the `experimental` properties on `ClientSession`, `ServerSession`, `Server`, and `ServerRequestContext`. The corresponding `Task*` types remain in `mcp.types` as types-only definitions, except the `TaskExecutionMode` alias, whose literal is now inlined on `ToolExecution.task_support`. The 2026-07-28 revision reintroduces Tasks as an official extension: [SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663), `io.modelcontextprotocol/tasks`, redesigned around polling (`tasks/get`) instead of a blocking `tasks/result`. This SDK does not implement the extension yet. @@ -2025,7 +2046,7 @@ result = await client.call_tool("long_running_task", {}, progress_callback=on_pr **Detached work** (create the task now, fetch its result on a later connection or after a client restart) has no v2 equivalent until the SEP-2663 extension is implemented. -Also drop `execution=ToolExecution(taskSupport=types.TASK_REQUIRED)` from tool definitions: the `TASK_REQUIRED` / `TASK_OPTIONAL` / `TASK_FORBIDDEN` constants are gone from `mcp_types` (`ToolExecution.task_support` takes the plain `"required"` / `"optional"` / `"forbidden"` literal), and no v2 client or server reads the field. +Also drop `execution=ToolExecution(taskSupport=types.TASK_REQUIRED)` from tool definitions: the `TASK_REQUIRED` / `TASK_OPTIONAL` / `TASK_FORBIDDEN` constants are gone from `mcp.types` (`ToolExecution.task_support` takes the plain `"required"` / `"optional"` / `"forbidden"` literal), and no v2 client or server reads the field. ## Transports @@ -2187,7 +2208,7 @@ while True: ```python from mcp import ClientSession, MCPError from mcp.client.streamable_http import streamable_http_client -from mcp_types import INVALID_REQUEST # -32600 +from mcp.types import INVALID_REQUEST # -32600 async with streamable_http_client(url) as (read, write): async with ClientSession(read, write) as session: @@ -2626,7 +2647,7 @@ Validation runs when the result is serialized onto the wire, not when the model ### Client validates inbound traffic against the protocol schema -`ClientSession` now validates server requests, notifications, and results against the negotiated protocol version's schema before parsing them into `mcp_types` models. Spec-invalid server output that the previous monolith parse tolerated may now raise `pydantic.ValidationError` from `list_tools()`, `call_tool()`, and similar calls. `_meta` remains the sanctioned place for result extras (and `experimental` for capability extras). +`ClientSession` now validates server requests, notifications, and results against the negotiated protocol version's schema before parsing them into `mcp.types` models. Spec-invalid server output that the previous monolith parse tolerated may now raise `pydantic.ValidationError` from `list_tools()`, `call_tool()`, and similar calls. `_meta` remains the sanctioned place for result extras (and `experimental` for capability extras). ### Unknown request methods now return `-32601` (Method not found) diff --git a/docs/run/deploy.md b/docs/run/deploy.md index 7cec58163b..24f25c2019 100644 --- a/docs/run/deploy.md +++ b/docs/run/deploy.md @@ -76,7 +76,7 @@ A **[multi-round-trip](../handlers/multi-round-trip.md)** tool needs something t Here is a tool that asks before it acts, on a server that configures nothing: -```python title="server.py" hl_lines="15 21" +```python title="server.py" hl_lines="14 20" --8<-- "docs_src/deploy/tutorial002.py" ``` @@ -111,7 +111,7 @@ The two rounds are two independent HTTP requests, and several ordinary things se The fix is one argument. It has **two** halves. -```python title="server.py" hl_lines="3 13 15" +```python title="server.py" hl_lines="1 12 14" --8<-- "docs_src/deploy/tutorial003.py" ``` diff --git a/docs/servers/completions.md b/docs/servers/completions.md index b7b8750fcd..1d7eca8e2c 100644 --- a/docs/servers/completions.md +++ b/docs/servers/completions.md @@ -21,7 +21,7 @@ Nothing here is about completions yet. Add **one** function decorated with `@mcp.completion()`: -```python title="server.py" hl_lines="22-30" +```python title="server.py" hl_lines="21-29" --8<-- "docs_src/completions/tutorial002.py" ``` @@ -91,7 +91,7 @@ You didn't list `completions` anywhere. The SDK saw the handler and declared the That's what `context` is for. It carries the arguments the user has **already resolved**: -```python title="server.py" hl_lines="9-12 35-39" +```python title="server.py" hl_lines="8-11 34-38" --8<-- "docs_src/completions/tutorial003.py" ``` diff --git a/docs/servers/handling-errors.md b/docs/servers/handling-errors.md index 0cb0a7df32..4262f586a7 100644 --- a/docs/servers/handling-errors.md +++ b/docs/servers/handling-errors.md @@ -41,7 +41,7 @@ The model is the one calling your tool. It picked the arguments. So a tool error Now swap `ValueError` for `MCPError`. -```python title="server.py" hl_lines="1 3 15" +```python title="server.py" hl_lines="1 3 14" --8<-- "docs_src/handling_errors/tutorial002.py" ``` @@ -56,7 +56,7 @@ Now swap `ValueError` for `MCPError`. * There is **no result**. No `content`, no `is_error`: nothing for the model to read. * The **host** application gets the error instead, the same way it would if the tool didn't exist at all. -* `code`, `message`, and `data` arrive intact. `INVALID_PARAMS` is `-32602`; `mcp_types` exports it and the other JSON-RPC error codes (`INVALID_REQUEST`, `INTERNAL_ERROR`, ...) as constants so you never type a magic number. +* `code`, `message`, and `data` arrive intact. `INVALID_PARAMS` is `-32602`; `mcp.types` exports it and the other JSON-RPC error codes (`INVALID_REQUEST`, `INTERNAL_ERROR`, ...) as constants so you never type a magic number. !!! check Same lookup, same miss, but now the call *raises* on the client side instead of returning: @@ -127,7 +127,7 @@ It means a whole class of `raise` statements you don't write: don't re-validate * The deciding question: *could a smarter model have avoided this?* Yes -> exception. No -> `MCPError`. * `ResourceNotFoundError` from a resource handler -> the protocol's `-32602`, with the URI in `data`. * Bad arguments are rejected against the schema before your function runs; you don't `raise` for those. -* `from mcp import MCPError`; the error-code constants come from `mcp_types`. +* `from mcp import MCPError`; the error-code constants come from `mcp.types`. Errors handled. That is everything a server *exposes*. What every handler can read, and do back to the client while it runs, is the next section: **[Inside your handler](../handlers/index.md)**. diff --git a/docs/servers/media.md b/docs/servers/media.md index e8042b83ab..8655b77f12 100644 --- a/docs/servers/media.md +++ b/docs/servers/media.md @@ -29,7 +29,7 @@ Two things to notice: * `structured_content` is `None`. An `Image` is content for the model to look at, not data for the application to parse: there is no output schema. (Contrast **[Structured Output](structured-output.md)**, where the return annotation *is* the schema.) !!! info - `ImageContent` and `AudioContent` live in `mcp_types`, right next to the `TextContent` + `ImageContent` and `AudioContent` live in `mcp.types`, right next to the `TextContent` that a plain `str` result becomes (**[Tools](tools.md)**). A tool result is a list of content blocks; `Image` and `Audio` are the shortest way to produce the two binary kinds. @@ -85,7 +85,7 @@ A suffix it doesn't recognise falls back to `application/octet-stream`. An `Icon` is metadata, not content. It doesn't carry the image; it points at one with a URI, and a client may fetch it and show it next to your server's name, a tool, a resource, or a prompt. -```python title="server.py" hl_lines="5-6 8 11 17" +```python title="server.py" hl_lines="4-5 7 10 16" --8<-- "docs_src/media/tutorial004.py" ``` diff --git a/docs/servers/tools.md b/docs/servers/tools.md index 8b7ee05721..5b728cb782 100644 --- a/docs/servers/tools.md +++ b/docs/servers/tools.md @@ -142,7 +142,7 @@ There is nothing else to configure. Everything the SDK infers, you can override in the decorator: -```python title="server.py" hl_lines="8-11" +```python title="server.py" hl_lines="7-10" --8<-- "docs_src/tools/tutorial005.py" ``` diff --git a/docs/servers/uri-templates.md b/docs/servers/uri-templates.md index 6cda30eb30..406a8fda6a 100644 --- a/docs/servers/uri-templates.md +++ b/docs/servers/uri-templates.md @@ -215,7 +215,7 @@ return the protocol types yourself. For fixed URIs, keep a registry and dispatch on exact match: -```python title="server.py" hl_lines="18 22 28" +```python title="server.py" hl_lines="17 21 27" --8<-- "docs_src/uri_templates/tutorial004.py" ``` @@ -229,7 +229,7 @@ The template engine `MCPServer` uses lives in `mcp.shared.uri_template` and works on its own. You get the same parsing and matching; you wire up the routing and security policy yourself. -```python title="server.py" hl_lines="14-17 23-26 30 34 46" +```python title="server.py" hl_lines="13-16 22-25 29 33 45" --8<-- "docs_src/uri_templates/tutorial005.py" ``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 58c863f41d..fda7e4bc30 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -291,7 +291,7 @@ async def main() -> None: !!! info `-32021` is `MISSING_REQUIRED_CLIENT_CAPABILITY`, one of three error codes the 2026-07-28 spec adds. None of them is an exception class: they all arrive as `MCPError`, and - `e.error.code` is where to look. `mcp_types` exports the constants. The other two are + `e.error.code` is where to look. `mcp.types` exports the constants. The other two are `-32020` `HEADER_MISMATCH` (an HTTP header disagrees with the request body it accompanies) and `-32022` `UNSUPPORTED_PROTOCOL_VERSION` (the request named a version this server does not speak). A conforming SDK client cannot produce either, so if you see one, look at whatever is diff --git a/docs/whats-new.md b/docs/whats-new.md index 9826fa5909..3107d2e8aa 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -117,7 +117,7 @@ Underneath, the v1 `BaseSession` receive loop was replaced by a dispatcher engin ### The wire types moved to `mcp-types`, and every field is snake_case -The protocol types now live in their own distribution, `mcp-types`, imported as `mcp_types`. It depends on nothing but pydantic and typing-extensions, so a gateway, a proxy, or a code generator can consume MCP's wire shapes without installing an HTTP stack. `mcp` depends on it at an exact version and re-exports the common names, so `from mcp import Tool` still works; `import mcp.types` does not. +The protocol types now live in their own distribution, `mcp-types`. It depends on nothing but pydantic and typing-extensions, so a gateway, a proxy, or a code generator can consume MCP's wire shapes without installing an HTTP stack: such a project installs `mcp-types` and imports `mcp_types`. `mcp` itself depends on that package at an exact version and re-exposes it, so code that depends on the SDK keeps writing `import mcp.types as types` and `from mcp.types import Tool` (a permanent alias, every name the same object) and declares only its one real dependency, `mcp`. The rule of thumb: import through whichever package you actually depend on. On those types, every Python attribute is now snake_case: `result.is_error`, `tool.input_schema`, `listing.next_cursor`. The JSON on the wire is camelCase, exactly as before; only the attribute spelling changed. Two stricter defaults ride along: unknown fields are ignored instead of round-tripped (put extras in `_meta`), and both sides validate traffic against the protocol version they negotiated. See the **[Migration Guide](migration.md#field-names-changed-from-camelcase-to-snake_case)** for the rename table. @@ -146,7 +146,7 @@ Each of these is a section in the **[Migration Guide](migration.md)**: * The **WebSocket transport**, both sides, and the `mcp[ws]` extra. It was never part of the MCP specification. * The **experimental Tasks** API (`mcp.*.experimental`). 2026-07-28 moves tasks out of the core protocol and into an official extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)), which this SDK does not implement yet. -* `mcp.types`, `mcp.shared.version`, `mcp.shared.progress`, and `mcp.shared.session` (with the `RequestResponder` stub v1 `message_handler` annotations imported) as import paths. +* `mcp.shared.version`, `mcp.shared.progress`, and `mcp.shared.session` (with the `RequestResponder` stub v1 `message_handler` annotations imported) as import paths. (`mcp.types` is *not* removed: it remains as a permanent alias for the standalone `mcp_types` package.) * The deprecated `streamablehttp_client` spelling, and the `get_session_id` callback from `streamable_http_client` (which now yields exactly two streams). * `McpError`, renamed **`MCPError`** with a direct `(code, message, data)` constructor. * `MCPServer.get_context()`, `mount_path=`, and the lowlevel `Server`'s decorator methods, ContextVar, and handler dicts. diff --git a/docs_src/caching/tutorial002.py b/docs_src/caching/tutorial002.py index 6bbfec9e27..e1722e81f7 100644 --- a/docs_src/caching/tutorial002.py +++ b/docs_src/caching/tutorial002.py @@ -1,8 +1,7 @@ from typing import Any -from mcp_types import ListToolsResult, PaginatedRequestParams, Tool - from mcp.server import CacheHint, Server, ServerRequestContext +from mcp.types import ListToolsResult, PaginatedRequestParams, Tool TOOLS = [Tool(name="forecast", input_schema={"type": "object"})] diff --git a/docs_src/caching/tutorial003.py b/docs_src/caching/tutorial003.py index 29c168c9f6..9ff3c36101 100644 --- a/docs_src/caching/tutorial003.py +++ b/docs_src/caching/tutorial003.py @@ -1,11 +1,10 @@ from dataclasses import dataclass from typing import Any -from mcp_types import ListToolsResult, PaginatedRequestParams, Tool - from mcp import Client from mcp.client import CacheConfig from mcp.server import CacheHint, Server, ServerRequestContext +from mcp.types import ListToolsResult, PaginatedRequestParams, Tool @dataclass diff --git a/docs_src/client/tutorial003.py b/docs_src/client/tutorial003.py index 1aeab63a49..bf74c46748 100644 --- a/docs_src/client/tutorial003.py +++ b/docs_src/client/tutorial003.py @@ -1,8 +1,8 @@ -from mcp_types import TextContent from pydantic import BaseModel from mcp import Client from mcp.server import MCPServer +from mcp.types import TextContent mcp = MCPServer("Bookshop") diff --git a/docs_src/client/tutorial004.py b/docs_src/client/tutorial004.py index fddcde90a5..b0d62a7714 100644 --- a/docs_src/client/tutorial004.py +++ b/docs_src/client/tutorial004.py @@ -1,7 +1,6 @@ -from mcp_types import TextResourceContents - from mcp import Client from mcp.server import MCPServer +from mcp.types import TextResourceContents mcp = MCPServer("Bookshop") diff --git a/docs_src/client/tutorial006.py b/docs_src/client/tutorial006.py index b76b6a0f11..370e0b79ef 100644 --- a/docs_src/client/tutorial006.py +++ b/docs_src/client/tutorial006.py @@ -1,7 +1,6 @@ -from mcp_types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference - from mcp import Client from mcp.server import MCPServer +from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference mcp = MCPServer("Bookshop") diff --git a/docs_src/client/tutorial007.py b/docs_src/client/tutorial007.py index 594b052020..c5c918bc63 100644 --- a/docs_src/client/tutorial007.py +++ b/docs_src/client/tutorial007.py @@ -1,7 +1,6 @@ -from mcp_types import Tool - from mcp import Client from mcp.server import MCPServer +from mcp.types import Tool mcp = MCPServer("Bookshop") diff --git a/docs_src/client_callbacks/tutorial002.py b/docs_src/client_callbacks/tutorial002.py index 2bae985d60..a37fbd635b 100644 --- a/docs_src/client_callbacks/tutorial002.py +++ b/docs_src/client_callbacks/tutorial002.py @@ -1,7 +1,6 @@ -from mcp_types import ElicitRequestParams, ElicitResult - from mcp import Client from mcp.client import ClientRequestContext +from mcp.types import ElicitRequestParams, ElicitResult async def handle_elicitation( diff --git a/docs_src/client_callbacks/tutorial003.py b/docs_src/client_callbacks/tutorial003.py index c7a269a36d..0ce615a6ff 100644 --- a/docs_src/client_callbacks/tutorial003.py +++ b/docs_src/client_callbacks/tutorial003.py @@ -1,8 +1,8 @@ -from mcp_types import ClientCapabilities, ElicitationCapability, RootsCapability, SamplingCapability from pydantic import BaseModel from mcp.server import MCPServer from mcp.server.mcpserver import Context +from mcp.types import ClientCapabilities, ElicitationCapability, RootsCapability, SamplingCapability mcp = MCPServer("Library") diff --git a/docs_src/client_callbacks/tutorial004.py b/docs_src/client_callbacks/tutorial004.py index 20c9b81870..1c5fc2a601 100644 --- a/docs_src/client_callbacks/tutorial004.py +++ b/docs_src/client_callbacks/tutorial004.py @@ -1,7 +1,7 @@ -from mcp_types import CreateMessageRequestParams, CreateMessageResult, ListRootsResult, Root, TextContent from pydantic import FileUrl from mcp.client import ClientRequestContext +from mcp.types import CreateMessageRequestParams, CreateMessageResult, ListRootsResult, Root, TextContent async def handle_sampling( diff --git a/docs_src/completions/tutorial002.py b/docs_src/completions/tutorial002.py index 471527792b..01ec02c5cb 100644 --- a/docs_src/completions/tutorial002.py +++ b/docs_src/completions/tutorial002.py @@ -1,6 +1,5 @@ -from mcp_types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference - from mcp.server import MCPServer +from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference mcp = MCPServer("GitHub Explorer") diff --git a/docs_src/completions/tutorial003.py b/docs_src/completions/tutorial003.py index 3cbe21bcd6..13897a5e3a 100644 --- a/docs_src/completions/tutorial003.py +++ b/docs_src/completions/tutorial003.py @@ -1,6 +1,5 @@ -from mcp_types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference - from mcp.server import MCPServer +from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference mcp = MCPServer("GitHub Explorer") diff --git a/docs_src/dependencies/tutorial004.py b/docs_src/dependencies/tutorial004.py index ff55e5ce15..d08cc53b40 100644 --- a/docs_src/dependencies/tutorial004.py +++ b/docs_src/dependencies/tutorial004.py @@ -1,9 +1,8 @@ from typing import Annotated -from mcp_types import CreateMessageResult, SamplingMessage, TextContent - from mcp.server import MCPServer from mcp.server.mcpserver import Resolve, Sample +from mcp.types import CreateMessageResult, SamplingMessage, TextContent mcp = MCPServer("Bookshop") diff --git a/docs_src/deploy/tutorial002.py b/docs_src/deploy/tutorial002.py index 8b61aacac1..bb92fd9099 100644 --- a/docs_src/deploy/tutorial002.py +++ b/docs_src/deploy/tutorial002.py @@ -1,6 +1,5 @@ -from mcp_types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult - from mcp.server.mcpserver import Context, MCPServer +from mcp.types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult CONFIRM = ElicitRequest( params=ElicitRequestFormParams( diff --git a/docs_src/deploy/tutorial003.py b/docs_src/deploy/tutorial003.py index 8d9d126c0c..f7ffc2e2a1 100644 --- a/docs_src/deploy/tutorial003.py +++ b/docs_src/deploy/tutorial003.py @@ -1,6 +1,5 @@ -from mcp_types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult - from mcp.server.mcpserver import Context, MCPServer, RequestStateSecurity +from mcp.types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult CONFIRM = ElicitRequest( params=ElicitRequestFormParams( diff --git a/docs_src/elicitation/tutorial003.py b/docs_src/elicitation/tutorial003.py index f6bb4020b6..c63c3e00b7 100644 --- a/docs_src/elicitation/tutorial003.py +++ b/docs_src/elicitation/tutorial003.py @@ -1,7 +1,6 @@ -from mcp_types import ElicitRequestParams, ElicitRequestURLParams, ElicitResult - from mcp import Client from mcp.client import ClientRequestContext +from mcp.types import ElicitRequestParams, ElicitRequestURLParams, ElicitResult async def handle_elicitation(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult: diff --git a/docs_src/extensions/tutorial004.py b/docs_src/extensions/tutorial004.py index 7ad32052d2..d3e2ef3bf8 100644 --- a/docs_src/extensions/tutorial004.py +++ b/docs_src/extensions/tutorial004.py @@ -1,9 +1,9 @@ from collections.abc import Sequence from typing import Any, Literal -import mcp_types as types from pydantic import Field +import mcp.types as types from mcp import Client from mcp.client import advertise from mcp.server.context import ServerRequestContext diff --git a/docs_src/extensions/tutorial005.py b/docs_src/extensions/tutorial005.py index 61ec6c76bc..05b5210c79 100644 --- a/docs_src/extensions/tutorial005.py +++ b/docs_src/extensions/tutorial005.py @@ -1,11 +1,10 @@ import logging from typing import Any -from mcp_types import CallToolRequestParams - from mcp.server.context import CallNext, HandlerResult, ServerRequestContext from mcp.server.extension import Extension from mcp.server.mcpserver import MCPServer +from mcp.types import CallToolRequestParams logger = logging.getLogger(__name__) diff --git a/docs_src/extensions/tutorial006.py b/docs_src/extensions/tutorial006.py index 05ffbcb9d6..88592af99e 100644 --- a/docs_src/extensions/tutorial006.py +++ b/docs_src/extensions/tutorial006.py @@ -1,8 +1,7 @@ from collections.abc import Sequence from typing import Any, Literal -import mcp_types as types - +import mcp.types as types from mcp import Client from mcp.client import ClaimContext, ClientExtension, ResultClaim from mcp.server.context import CallNext, HandlerResult, ServerRequestContext diff --git a/docs_src/extensions/tutorial007.py b/docs_src/extensions/tutorial007.py index 37706ca219..182fc8f61b 100644 --- a/docs_src/extensions/tutorial007.py +++ b/docs_src/extensions/tutorial007.py @@ -1,8 +1,7 @@ from collections.abc import Sequence from typing import Any, Literal -import mcp_types as types - +import mcp.types as types from mcp import Client from mcp.client import advertise from mcp.server.context import ServerRequestContext diff --git a/docs_src/handling_errors/tutorial002.py b/docs_src/handling_errors/tutorial002.py index b45c67e967..52c3a261de 100644 --- a/docs_src/handling_errors/tutorial002.py +++ b/docs_src/handling_errors/tutorial002.py @@ -1,7 +1,6 @@ -from mcp_types import INVALID_PARAMS - from mcp import MCPError from mcp.server import MCPServer +from mcp.types import INVALID_PARAMS mcp = MCPServer("Bookshop") diff --git a/docs_src/legacy_clients/tutorial001.py b/docs_src/legacy_clients/tutorial001.py index 2f8b1191e4..2090201f91 100644 --- a/docs_src/legacy_clients/tutorial001.py +++ b/docs_src/legacy_clients/tutorial001.py @@ -1,12 +1,12 @@ from typing import Annotated -from mcp_types import ElicitRequestParams, ElicitResult from pydantic import BaseModel from mcp import Client from mcp.client import ClientRequestContext from mcp.server import MCPServer from mcp.server.mcpserver import AcceptedElicitation, Elicit, ElicitationResult, Resolve +from mcp.types import ElicitRequestParams, ElicitResult mcp = MCPServer("Bookshop") diff --git a/docs_src/lowlevel/tutorial001.py b/docs_src/lowlevel/tutorial001.py index 999c707f25..3b96aa2af4 100644 --- a/docs_src/lowlevel/tutorial001.py +++ b/docs_src/lowlevel/tutorial001.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -7,8 +8,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - SEARCH_BOOKS = Tool( name="search_books", description="Search the catalog by title or author.", diff --git a/docs_src/lowlevel/tutorial002.py b/docs_src/lowlevel/tutorial002.py index d3033f6013..97eb4c4a6a 100644 --- a/docs_src/lowlevel/tutorial002.py +++ b/docs_src/lowlevel/tutorial002.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -7,8 +8,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - SEARCH_BOOKS = Tool( name="search_books", description="Search the catalog by title or author.", diff --git a/docs_src/lowlevel/tutorial003.py b/docs_src/lowlevel/tutorial003.py index 65d89f198c..682848588f 100644 --- a/docs_src/lowlevel/tutorial003.py +++ b/docs_src/lowlevel/tutorial003.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -7,8 +8,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - SEARCH_BOOKS = Tool( name="search_books", description="Search the catalog by title or author.", diff --git a/docs_src/lowlevel/tutorial004.py b/docs_src/lowlevel/tutorial004.py index 18b0bef8f6..cb8dfe4e26 100644 --- a/docs_src/lowlevel/tutorial004.py +++ b/docs_src/lowlevel/tutorial004.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -7,8 +8,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - SEARCH_BOOKS = Tool( name="search_books", description="Search the catalog by title or author.", diff --git a/docs_src/lowlevel/tutorial005.py b/docs_src/lowlevel/tutorial005.py index e33077ecec..69e58024b6 100644 --- a/docs_src/lowlevel/tutorial005.py +++ b/docs_src/lowlevel/tutorial005.py @@ -2,7 +2,8 @@ from contextlib import asynccontextmanager from dataclasses import dataclass -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -11,8 +12,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - @dataclass class Catalog: diff --git a/docs_src/lowlevel/tutorial006.py b/docs_src/lowlevel/tutorial006.py index 601fe5c576..158dca506d 100644 --- a/docs_src/lowlevel/tutorial006.py +++ b/docs_src/lowlevel/tutorial006.py @@ -1,4 +1,7 @@ -from mcp_types import ( +from pydantic import BaseModel + +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -7,9 +10,6 @@ TextContent, Tool, ) -from pydantic import BaseModel - -from mcp.server import Server, ServerRequestContext SEARCH_BOOKS = Tool( name="search_books", diff --git a/docs_src/media/tutorial004.py b/docs_src/media/tutorial004.py index a06e6dfcd1..d0b717c866 100644 --- a/docs_src/media/tutorial004.py +++ b/docs_src/media/tutorial004.py @@ -1,6 +1,5 @@ -from mcp_types import Icon - from mcp.server import MCPServer +from mcp.types import Icon LOGO = Icon(src="https://example.com/brand-kit.png", mime_type="image/png", sizes=["48x48"]) PALETTE = Icon(src="https://example.com/palette.svg", mime_type="image/svg+xml", sizes=["any"]) diff --git a/docs_src/middleware/tutorial001.py b/docs_src/middleware/tutorial001.py index 71be62db8f..0c26c48201 100644 --- a/docs_src/middleware/tutorial001.py +++ b/docs_src/middleware/tutorial001.py @@ -1,7 +1,9 @@ import logging import time -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.server.context import CallNext, HandlerResult +from mcp.types import ( CallToolRequestParams, CallToolResult, ListToolsResult, @@ -10,9 +12,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext -from mcp.server.context import CallNext, HandlerResult - logger = logging.getLogger(__name__) diff --git a/docs_src/mrtr/tutorial001.py b/docs_src/mrtr/tutorial001.py index c0f4153cab..9175ca4e28 100644 --- a/docs_src/mrtr/tutorial001.py +++ b/docs_src/mrtr/tutorial001.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( CallToolRequestParams, CallToolResult, ElicitRequest, @@ -11,8 +12,6 @@ Tool, ) -from mcp.server import Server, ServerRequestContext - ASK_REGION = ElicitRequest( params=ElicitRequestFormParams( message="Which region should the database live in?", diff --git a/docs_src/mrtr/tutorial002.py b/docs_src/mrtr/tutorial002.py index 0a14021833..23cc1b19f4 100644 --- a/docs_src/mrtr/tutorial002.py +++ b/docs_src/mrtr/tutorial002.py @@ -1,6 +1,5 @@ -from mcp_types import CallToolResult, ElicitRequest, ElicitResult, InputRequest, InputRequiredResult, InputResponse - from mcp import Client +from mcp.types import CallToolResult, ElicitRequest, ElicitResult, InputRequest, InputRequiredResult, InputResponse def fulfil(request: InputRequest) -> InputResponse: diff --git a/docs_src/mrtr/tutorial003.py b/docs_src/mrtr/tutorial003.py index 03eb6bf74f..6d7af85d9c 100644 --- a/docs_src/mrtr/tutorial003.py +++ b/docs_src/mrtr/tutorial003.py @@ -1,7 +1,6 @@ -from mcp_types import ElicitRequestParams, ElicitResult - from mcp import Client from mcp.client import ClientRequestContext +from mcp.types import ElicitRequestParams, ElicitResult async def handle_elicitation(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult: diff --git a/docs_src/mrtr/tutorial004.py b/docs_src/mrtr/tutorial004.py index 05b945935f..8cf90bee5a 100644 --- a/docs_src/mrtr/tutorial004.py +++ b/docs_src/mrtr/tutorial004.py @@ -1,7 +1,6 @@ -from mcp_types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult - from mcp.server.mcpserver import Context, MCPServer from mcp.server.mcpserver.prompts.base import UserMessage +from mcp.types import ElicitRequest, ElicitRequestFormParams, ElicitResult, InputRequiredResult mcp = MCPServer("Briefing") diff --git a/docs_src/pagination/tutorial001.py b/docs_src/pagination/tutorial001.py index 2ad4b9453f..3bc97540f9 100644 --- a/docs_src/pagination/tutorial001.py +++ b/docs_src/pagination/tutorial001.py @@ -1,8 +1,7 @@ from typing import Any -from mcp_types import ListResourcesResult, PaginatedRequestParams, Resource - from mcp.server import Server, ServerRequestContext +from mcp.types import ListResourcesResult, PaginatedRequestParams, Resource BOOKS = [f"book-{n}" for n in range(1, 101)] diff --git a/docs_src/pagination/tutorial002.py b/docs_src/pagination/tutorial002.py index cacb796e8b..f72847772a 100644 --- a/docs_src/pagination/tutorial002.py +++ b/docs_src/pagination/tutorial002.py @@ -1,9 +1,8 @@ from typing import Any -from mcp_types import ListResourcesResult, PaginatedRequestParams, Resource - from mcp import Client from mcp.server import Server, ServerRequestContext +from mcp.types import ListResourcesResult, PaginatedRequestParams, Resource BOOKS = [f"book-{n}" for n in range(1, 101)] diff --git a/docs_src/sampling_and_roots/tutorial001.py b/docs_src/sampling_and_roots/tutorial001.py index c1e041c328..406d48d3ad 100644 --- a/docs_src/sampling_and_roots/tutorial001.py +++ b/docs_src/sampling_and_roots/tutorial001.py @@ -1,9 +1,8 @@ from typing import Annotated -from mcp_types import CreateMessageResult, SamplingMessage, TextContent - from mcp.server import MCPServer from mcp.server.mcpserver import Resolve, Sample +from mcp.types import CreateMessageResult, SamplingMessage, TextContent mcp = MCPServer("Bookshop") diff --git a/docs_src/sampling_and_roots/tutorial002.py b/docs_src/sampling_and_roots/tutorial002.py index 44a1d10578..1646d432b0 100644 --- a/docs_src/sampling_and_roots/tutorial002.py +++ b/docs_src/sampling_and_roots/tutorial002.py @@ -1,9 +1,8 @@ from typing import Annotated -from mcp_types import ListRootsResult - from mcp.server import MCPServer from mcp.server.mcpserver import ListRoots, Resolve +from mcp.types import ListRootsResult mcp = MCPServer("Bookshop") diff --git a/docs_src/session_groups/tutorial004.py b/docs_src/session_groups/tutorial004.py index 7d107669f7..88fcec9cd1 100644 --- a/docs_src/session_groups/tutorial004.py +++ b/docs_src/session_groups/tutorial004.py @@ -1,8 +1,7 @@ import asyncio -from mcp_types import Implementation - from mcp import ClientSessionGroup, StdioServerParameters +from mcp.types import Implementation def by_server(name: str, server_info: Implementation) -> str: diff --git a/docs_src/subscriptions/tutorial002.py b/docs_src/subscriptions/tutorial002.py index 39e42dcc04..b5e99d1ed2 100644 --- a/docs_src/subscriptions/tutorial002.py +++ b/docs_src/subscriptions/tutorial002.py @@ -1,7 +1,6 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.server.subscriptions import InMemorySubscriptionBus, ListenHandler, ResourceUpdated diff --git a/docs_src/subscriptions/tutorial003.py b/docs_src/subscriptions/tutorial003.py index 811f6944bd..00abeacb8e 100644 --- a/docs_src/subscriptions/tutorial003.py +++ b/docs_src/subscriptions/tutorial003.py @@ -1,7 +1,6 @@ -from mcp_types import TextResourceContents - from mcp import Client from mcp.client.subscriptions import ResourceUpdated, ToolsListChanged +from mcp.types import TextResourceContents BOARD = "board://sprint" diff --git a/docs_src/tools/tutorial005.py b/docs_src/tools/tutorial005.py index f9fcbce966..9ba551293a 100644 --- a/docs_src/tools/tutorial005.py +++ b/docs_src/tools/tutorial005.py @@ -1,6 +1,5 @@ -from mcp_types import ToolAnnotations - from mcp.server import MCPServer +from mcp.types import ToolAnnotations mcp = MCPServer("Bookshop") diff --git a/docs_src/uri_templates/tutorial004.py b/docs_src/uri_templates/tutorial004.py index c1920b3cc5..5abeb94d85 100644 --- a/docs_src/uri_templates/tutorial004.py +++ b/docs_src/uri_templates/tutorial004.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.types import ( ListResourcesResult, PaginatedRequestParams, ReadResourceRequestParams, @@ -7,8 +8,6 @@ TextResourceContents, ) -from mcp.server import Server, ServerRequestContext - RESOURCES = { "config://shop": '{"currency": "USD", "tax_rate": 0.08}', "status://health": "ok", diff --git a/docs_src/uri_templates/tutorial005.py b/docs_src/uri_templates/tutorial005.py index 716ff08dc1..94ac2facca 100644 --- a/docs_src/uri_templates/tutorial005.py +++ b/docs_src/uri_templates/tutorial005.py @@ -1,4 +1,7 @@ -from mcp_types import ( +from mcp.server import Server, ServerRequestContext +from mcp.shared.path_security import contains_path_traversal, is_absolute_path +from mcp.shared.uri_template import UriTemplate +from mcp.types import ( ListResourceTemplatesResult, PaginatedRequestParams, ReadResourceRequestParams, @@ -7,10 +10,6 @@ TextResourceContents, ) -from mcp.server import Server, ServerRequestContext -from mcp.shared.path_security import contains_path_traversal, is_absolute_path -from mcp.shared.uri_template import UriTemplate - TEMPLATES = { "manuals": UriTemplate.parse("manuals://{+path}"), "books": UriTemplate.parse("books://{isbn}"), diff --git a/docs_src/whats_new/tutorial001.py b/docs_src/whats_new/tutorial001.py index 5e41ae1c04..0a2426cab8 100644 --- a/docs_src/whats_new/tutorial001.py +++ b/docs_src/whats_new/tutorial001.py @@ -1,4 +1,6 @@ -from mcp_types import ( +from mcp import MCPError +from mcp.server import Server, ServerRequestContext +from mcp.types import ( INVALID_PARAMS, CallToolRequestParams, CallToolResult, @@ -8,9 +10,6 @@ Tool, ) -from mcp import MCPError -from mcp.server import Server, ServerRequestContext - SEARCH_BOOKS = Tool( name="search_books", description="Search the catalog by title or author.", diff --git a/examples/mcpserver/direct_call_tool_result_return.py b/examples/mcpserver/direct_call_tool_result_return.py index c73e6164f5..44a316bc6b 100644 --- a/examples/mcpserver/direct_call_tool_result_return.py +++ b/examples/mcpserver/direct_call_tool_result_return.py @@ -2,10 +2,10 @@ from typing import Annotated -from mcp_types import CallToolResult, TextContent from pydantic import BaseModel from mcp.server.mcpserver import MCPServer +from mcp.types import CallToolResult, TextContent mcp = MCPServer("Echo Server") diff --git a/examples/servers/everything-server/mcp_everything_server/server.py b/examples/servers/everything-server/mcp_everything_server/server.py index 4b03421f44..b22e76aeab 100644 --- a/examples/servers/everything-server/mcp_everything_server/server.py +++ b/examples/servers/everything-server/mcp_everything_server/server.py @@ -16,7 +16,8 @@ from mcp.server.mcpserver.prompts.base import Prompt, UserMessage from mcp.server.streamable_http import EventCallback, EventMessage, EventStore from mcp.shared.exceptions import MCPError -from mcp_types import ( +from mcp.types import ( + MISSING_REQUIRED_CLIENT_CAPABILITY, AudioContent, Completion, CompletionArgument, @@ -44,7 +45,6 @@ TextResourceContents, UnsubscribeRequestParams, ) -from mcp_types.jsonrpc import MISSING_REQUIRED_CLIENT_CAPABILITY from pydantic import BaseModel, Field logger = logging.getLogger(__name__) diff --git a/examples/servers/simple-pagination/mcp_simple_pagination/server.py b/examples/servers/simple-pagination/mcp_simple_pagination/server.py index 9aca87f730..b2bf0cc611 100644 --- a/examples/servers/simple-pagination/mcp_simple_pagination/server.py +++ b/examples/servers/simple-pagination/mcp_simple_pagination/server.py @@ -8,7 +8,7 @@ import anyio import click -import mcp_types as types +import mcp.types as types from mcp.server import Server, ServerRequestContext T = TypeVar("T") diff --git a/examples/servers/simple-prompt/mcp_simple_prompt/server.py b/examples/servers/simple-prompt/mcp_simple_prompt/server.py index 31e3eb7d76..6ddec6536c 100644 --- a/examples/servers/simple-prompt/mcp_simple_prompt/server.py +++ b/examples/servers/simple-prompt/mcp_simple_prompt/server.py @@ -1,6 +1,6 @@ import anyio import click -import mcp_types as types +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/servers/simple-resource/mcp_simple_resource/server.py b/examples/servers/simple-resource/mcp_simple_resource/server.py index fe9dcfb709..24534cf35d 100644 --- a/examples/servers/simple-resource/mcp_simple_resource/server.py +++ b/examples/servers/simple-resource/mcp_simple_resource/server.py @@ -2,7 +2,7 @@ import anyio import click -import mcp_types as types +import mcp.types as types from mcp.server import Server, ServerRequestContext SAMPLE_RESOURCES = { diff --git a/examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py b/examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py index 9df18cc6a2..575f8ab808 100644 --- a/examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py +++ b/examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py @@ -2,7 +2,7 @@ import anyio import click -import mcp_types as types +import mcp.types as types import uvicorn from mcp.server import Server, ServerRequestContext from starlette.middleware.cors import CORSMiddleware diff --git a/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py b/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py index c9369cfc2c..3501fa47ce 100644 --- a/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py +++ b/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py @@ -10,7 +10,7 @@ from uuid import uuid4 from mcp.server.streamable_http import EventCallback, EventId, EventMessage, EventStore, StreamId -from mcp_types import JSONRPCMessage +from mcp.types import JSONRPCMessage logger = logging.getLogger(__name__) diff --git a/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py b/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py index e650b35732..70ddaf10d3 100644 --- a/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py +++ b/examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py @@ -2,7 +2,7 @@ import anyio import click -import mcp_types as types +import mcp.types as types import uvicorn from mcp.server import Server, ServerRequestContext from starlette.middleware.cors import CORSMiddleware diff --git a/examples/servers/simple-tool/mcp_simple_tool/server.py b/examples/servers/simple-tool/mcp_simple_tool/server.py index b16249e068..a43dd0f7b4 100644 --- a/examples/servers/simple-tool/mcp_simple_tool/server.py +++ b/examples/servers/simple-tool/mcp_simple_tool/server.py @@ -1,6 +1,6 @@ import anyio import click -import mcp_types as types +import mcp.types as types from mcp.server import Server, ServerRequestContext from mcp.shared._httpx_utils import create_mcp_http_client diff --git a/examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py b/examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py index e2cca4a2eb..c77bddef36 100644 --- a/examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py +++ b/examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py @@ -10,7 +10,7 @@ from uuid import uuid4 from mcp.server.streamable_http import EventCallback, EventId, EventMessage, EventStore, StreamId -from mcp_types import JSONRPCMessage +from mcp.types import JSONRPCMessage logger = logging.getLogger(__name__) diff --git a/examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py b/examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py index 7d2c60fa32..452a3816da 100644 --- a/examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py +++ b/examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py @@ -16,7 +16,7 @@ import anyio import click -import mcp_types as types +import mcp.types as types import uvicorn from mcp.server import Server, ServerRequestContext diff --git a/examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py b/examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py index 393ff7a5a0..2fb62a947a 100644 --- a/examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py +++ b/examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py @@ -10,9 +10,8 @@ import random from datetime import datetime -import mcp_types as types - import mcp.server.stdio +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/snippets/clients/completion_client.py b/examples/snippets/clients/completion_client.py index 52957d97d8..dc0c1b4f72 100644 --- a/examples/snippets/clients/completion_client.py +++ b/examples/snippets/clients/completion_client.py @@ -5,10 +5,9 @@ import asyncio import os -from mcp_types import PromptReference, ResourceTemplateReference - from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client +from mcp.types import PromptReference, ResourceTemplateReference # Create server parameters for stdio connection server_params = StdioServerParameters( diff --git a/examples/snippets/clients/pagination_client.py b/examples/snippets/clients/pagination_client.py index 00663ef038..b9b8c23ae7 100644 --- a/examples/snippets/clients/pagination_client.py +++ b/examples/snippets/clients/pagination_client.py @@ -2,10 +2,9 @@ import asyncio -from mcp_types import PaginatedRequestParams, Resource - from mcp.client.session import ClientSession from mcp.client.stdio import StdioServerParameters, stdio_client +from mcp.types import PaginatedRequestParams, Resource async def list_all_resources() -> None: diff --git a/examples/snippets/clients/parsing_tool_results.py b/examples/snippets/clients/parsing_tool_results.py index f9aade41e3..6f2a985efb 100644 --- a/examples/snippets/clients/parsing_tool_results.py +++ b/examples/snippets/clients/parsing_tool_results.py @@ -2,8 +2,7 @@ import asyncio -import mcp_types as types - +import mcp.types as types from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client diff --git a/examples/snippets/clients/stdio_client.py b/examples/snippets/clients/stdio_client.py index 6fff083853..577189eb8d 100644 --- a/examples/snippets/clients/stdio_client.py +++ b/examples/snippets/clients/stdio_client.py @@ -5,8 +5,7 @@ import asyncio import os -import mcp_types as types - +import mcp.types as types from mcp import ClientSession, StdioServerParameters from mcp.client.context import ClientRequestContext from mcp.client.stdio import stdio_client diff --git a/examples/snippets/clients/url_elicitation_client.py b/examples/snippets/clients/url_elicitation_client.py index de962eb718..14fc08d9f9 100644 --- a/examples/snippets/clients/url_elicitation_client.py +++ b/examples/snippets/clients/url_elicitation_client.py @@ -28,13 +28,12 @@ from typing import Any from urllib.parse import urlparse -import mcp_types as types -from mcp_types import URL_ELICITATION_REQUIRED - +import mcp.types as types from mcp import ClientSession from mcp.client.context import ClientRequestContext from mcp.client.sse import sse_client from mcp.shared.exceptions import MCPError, UrlElicitationRequiredError +from mcp.types import URL_ELICITATION_REQUIRED async def handle_elicitation( diff --git a/examples/snippets/servers/completion.py b/examples/snippets/servers/completion.py index 7fc2f20454..47accffa3b 100644 --- a/examples/snippets/servers/completion.py +++ b/examples/snippets/servers/completion.py @@ -1,4 +1,5 @@ -from mcp_types import ( +from mcp.server.mcpserver import MCPServer +from mcp.types import ( Completion, CompletionArgument, CompletionContext, @@ -6,8 +7,6 @@ ResourceTemplateReference, ) -from mcp.server.mcpserver import MCPServer - mcp = MCPServer(name="Example") diff --git a/examples/snippets/servers/direct_call_tool_result.py b/examples/snippets/servers/direct_call_tool_result.py index f3035338b3..4c98c358ee 100644 --- a/examples/snippets/servers/direct_call_tool_result.py +++ b/examples/snippets/servers/direct_call_tool_result.py @@ -2,10 +2,10 @@ from typing import Annotated -from mcp_types import CallToolResult, TextContent from pydantic import BaseModel from mcp.server.mcpserver import MCPServer +from mcp.types import CallToolResult, TextContent mcp = MCPServer("CallToolResult Example") diff --git a/examples/snippets/servers/elicitation.py b/examples/snippets/servers/elicitation.py index 97e847b510..79453f543e 100644 --- a/examples/snippets/servers/elicitation.py +++ b/examples/snippets/servers/elicitation.py @@ -7,11 +7,11 @@ import uuid -from mcp_types import ElicitRequestURLParams from pydantic import BaseModel, Field from mcp.server.mcpserver import Context, MCPServer from mcp.shared.exceptions import UrlElicitationRequiredError +from mcp.types import ElicitRequestURLParams mcp = MCPServer(name="Elicitation Example") diff --git a/examples/snippets/servers/lowlevel/basic.py b/examples/snippets/servers/lowlevel/basic.py index ff9b0a2c49..6292a2d153 100644 --- a/examples/snippets/servers/lowlevel/basic.py +++ b/examples/snippets/servers/lowlevel/basic.py @@ -4,9 +4,8 @@ import asyncio -import mcp_types as types - import mcp.server.stdio +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/snippets/servers/lowlevel/direct_call_tool_result.py b/examples/snippets/servers/lowlevel/direct_call_tool_result.py index 4d6607d2ff..5545887f63 100644 --- a/examples/snippets/servers/lowlevel/direct_call_tool_result.py +++ b/examples/snippets/servers/lowlevel/direct_call_tool_result.py @@ -4,9 +4,8 @@ import asyncio -import mcp_types as types - import mcp.server.stdio +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/snippets/servers/lowlevel/lifespan.py b/examples/snippets/servers/lowlevel/lifespan.py index 46db9ecc07..747dfb3894 100644 --- a/examples/snippets/servers/lowlevel/lifespan.py +++ b/examples/snippets/servers/lowlevel/lifespan.py @@ -6,9 +6,8 @@ from contextlib import asynccontextmanager from typing import TypedDict -import mcp_types as types - import mcp.server.stdio +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/snippets/servers/lowlevel/structured_output.py b/examples/snippets/servers/lowlevel/structured_output.py index 84e411ff55..70c6ebfb9d 100644 --- a/examples/snippets/servers/lowlevel/structured_output.py +++ b/examples/snippets/servers/lowlevel/structured_output.py @@ -5,9 +5,8 @@ import asyncio import json -import mcp_types as types - import mcp.server.stdio +import mcp.types as types from mcp.server import Server, ServerRequestContext diff --git a/examples/snippets/servers/pagination_example.py b/examples/snippets/servers/pagination_example.py index 4f7435acf6..6ee17e8102 100644 --- a/examples/snippets/servers/pagination_example.py +++ b/examples/snippets/servers/pagination_example.py @@ -1,7 +1,6 @@ """Example of implementing pagination with the low-level MCP server.""" -import mcp_types as types - +import mcp.types as types from mcp.server import Server, ServerRequestContext # Sample data to paginate diff --git a/examples/snippets/servers/sampling.py b/examples/snippets/servers/sampling.py index 83ec5066dd..a3f6d5c7bd 100644 --- a/examples/snippets/servers/sampling.py +++ b/examples/snippets/servers/sampling.py @@ -1,6 +1,5 @@ -from mcp_types import SamplingMessage, TextContent - from mcp.server.mcpserver import Context, MCPServer +from mcp.types import SamplingMessage, TextContent mcp = MCPServer(name="Sampling Example") diff --git a/examples/stories/_harness.py b/examples/stories/_harness.py index 62e02e70ab..9501fc065a 100644 --- a/examples/stories/_harness.py +++ b/examples/stories/_harness.py @@ -19,13 +19,13 @@ import anyio import httpx2 -from mcp_types.version import LATEST_MODERN_VERSION from mcp import StdioServerParameters, stdio_client from mcp.client import Transport from mcp.client.streamable_http import streamable_http_client from mcp.server import Server from mcp.server.mcpserver import MCPServer +from mcp.types.version import LATEST_MODERN_VERSION if sys.version_info >= (3, 11): import tomllib diff --git a/examples/stories/apps/client.py b/examples/stories/apps/client.py index dd79071b1d..661cfbf457 100644 --- a/examples/stories/apps/client.py +++ b/examples/stories/apps/client.py @@ -1,9 +1,8 @@ """Negotiate MCP Apps, discover a tool's `ui://` UI, fetch it, and call the tool.""" -from mcp_types import TextContent, TextResourceContents - from mcp.client import Client, advertise from mcp.server.apps import APP_MIME_TYPE, EXTENSION_ID +from mcp.types import TextContent, TextResourceContents from stories._harness import Target, run_client diff --git a/examples/stories/bearer_auth/server_lowlevel.py b/examples/stories/bearer_auth/server_lowlevel.py index f5abfc08c4..e03cb26d03 100644 --- a/examples/stories/bearer_auth/server_lowlevel.py +++ b/examples/stories/bearer_auth/server_lowlevel.py @@ -2,10 +2,10 @@ from typing import Any -import mcp_types as types from pydantic import AnyHttpUrl from starlette.applications import Starlette +import mcp.types as types from mcp.server.auth.middleware.auth_context import get_access_token from mcp.server.auth.settings import AuthSettings from mcp.server.context import ServerRequestContext diff --git a/examples/stories/custom_methods/client.py b/examples/stories/custom_methods/client.py index 7bf27dd76c..5e64068fe5 100644 --- a/examples/stories/custom_methods/client.py +++ b/examples/stories/custom_methods/client.py @@ -2,8 +2,7 @@ from typing import Literal -import mcp_types as types - +import mcp.types as types from mcp.client import Client from stories._harness import Target, run_client diff --git a/examples/stories/custom_methods/server.py b/examples/stories/custom_methods/server.py index 260aff787c..88013db2ae 100644 --- a/examples/stories/custom_methods/server.py +++ b/examples/stories/custom_methods/server.py @@ -6,8 +6,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/dual_era/client.py b/examples/stories/dual_era/client.py index b884c70609..30eb262bac 100644 --- a/examples/stories/dual_era/client.py +++ b/examples/stories/dual_era/client.py @@ -1,9 +1,8 @@ """Connect to the same server factory twice — once per era, so `main` takes `targets` — and assert both are served.""" -import mcp_types as types -from mcp_types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION - +import mcp.types as types from mcp.client import Client +from mcp.types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION from stories._harness import TargetFactory, run_client diff --git a/examples/stories/dual_era/server.py b/examples/stories/dual_era/server.py index 3f70ee63c9..59b6571ff8 100644 --- a/examples/stories/dual_era/server.py +++ b/examples/stories/dual_era/server.py @@ -1,8 +1,7 @@ """One MCPServer factory that serves both the 2025 handshake era and the 2026 stateless era.""" -from mcp_types.version import MODERN_PROTOCOL_VERSIONS - from mcp.server.mcpserver import Context, MCPServer +from mcp.types.version import MODERN_PROTOCOL_VERSIONS from stories._hosting import run_server_from_args diff --git a/examples/stories/dual_era/server_lowlevel.py b/examples/stories/dual_era/server_lowlevel.py index b209135e6d..6402420172 100644 --- a/examples/stories/dual_era/server_lowlevel.py +++ b/examples/stories/dual_era/server_lowlevel.py @@ -2,11 +2,10 @@ from typing import Any -import mcp_types as types -from mcp_types.version import MODERN_PROTOCOL_VERSIONS - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server +from mcp.types.version import MODERN_PROTOCOL_VERSIONS from stories._hosting import run_server_from_args GREET_INPUT_SCHEMA: dict[str, Any] = { diff --git a/examples/stories/error_handling/client.py b/examples/stories/error_handling/client.py index 872ec7fe31..4a7cffb0c0 100644 --- a/examples/stories/error_handling/client.py +++ b/examples/stories/error_handling/client.py @@ -1,9 +1,8 @@ """Prove the two error channels: is_error results return; MCPError raises.""" -from mcp_types import INVALID_PARAMS, TextContent - from mcp import MCPError from mcp.client import Client +from mcp.types import INVALID_PARAMS, TextContent from stories._harness import Target, run_client diff --git a/examples/stories/error_handling/server.py b/examples/stories/error_handling/server.py index e4f3554433..96667a5d0c 100644 --- a/examples/stories/error_handling/server.py +++ b/examples/stories/error_handling/server.py @@ -1,10 +1,9 @@ """Two error channels: ToolError -> is_error result; MCPError -> JSON-RPC protocol error.""" -from mcp_types import INVALID_PARAMS - from mcp.server.mcpserver import MCPServer from mcp.server.mcpserver.exceptions import ToolError from mcp.shared.exceptions import MCPError +from mcp.types import INVALID_PARAMS from stories._hosting import run_server_from_args diff --git a/examples/stories/error_handling/server_lowlevel.py b/examples/stories/error_handling/server_lowlevel.py index 9bb9aef86a..81462abe3a 100644 --- a/examples/stories/error_handling/server_lowlevel.py +++ b/examples/stories/error_handling/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.shared.exceptions import MCPError diff --git a/examples/stories/extensions/client.py b/examples/stories/extensions/client.py index 0bb033d7a3..eceb4a1a58 100644 --- a/examples/stories/extensions/client.py +++ b/examples/stories/extensions/client.py @@ -2,10 +2,9 @@ from typing import Literal -import mcp_types as types -from mcp_types import TextContent - +import mcp.types as types from mcp.client import Client, advertise +from mcp.types import TextContent from stories._harness import Target, run_client EXTENSION_ID = "com.example/catalog" diff --git a/examples/stories/extensions/server.py b/examples/stories/extensions/server.py index 837c668dc5..7c34e8fa22 100644 --- a/examples/stories/extensions/server.py +++ b/examples/stories/extensions/server.py @@ -9,9 +9,9 @@ from collections.abc import Sequence from typing import Any -import mcp_types as types from pydantic import Field +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.extension import Extension, MethodBinding, ToolBinding from mcp.server.mcpserver import MCPServer, require_client_extension diff --git a/examples/stories/identity_assertion/server_lowlevel.py b/examples/stories/identity_assertion/server_lowlevel.py index 1fcf8def79..8085276289 100644 --- a/examples/stories/identity_assertion/server_lowlevel.py +++ b/examples/stories/identity_assertion/server_lowlevel.py @@ -3,9 +3,9 @@ import json from typing import Any -import mcp_types as types from starlette.applications import Starlette +import mcp.types as types from mcp.server.auth.middleware.auth_context import get_access_token from mcp.server.auth.provider import ProviderTokenVerifier from mcp.server.context import ServerRequestContext diff --git a/examples/stories/json_response/client.py b/examples/stories/json_response/client.py index 8cbfed3fce..c5a00a6760 100644 --- a/examples/stories/json_response/client.py +++ b/examples/stories/json_response/client.py @@ -6,15 +6,15 @@ """ import httpx2 -from mcp_types import TextContent -from mcp_types.version import LATEST_MODERN_VERSION from mcp.client import Client +from mcp.types import TextContent +from mcp.types.version import LATEST_MODERN_VERSION from stories._harness import Target, run_client # The raw 2026-07-28 POST envelope: per-request `_meta` replaces the initialize handshake. # The key/header strings are spelled out on purpose — this is the raw-wire story. In code -# use the named constants instead: `mcp_types.PROTOCOL_VERSION_META_KEY` / +# use the named constants instead: `mcp.types.PROTOCOL_VERSION_META_KEY` / # `CLIENT_INFO_META_KEY` / `CLIENT_CAPABILITIES_META_KEY` and # `mcp.shared.inbound.MCP_PROTOCOL_VERSION_HEADER` (`legacy_routing/` shows that form). RAW_ENVELOPE_BODY: dict[str, object] = { diff --git a/examples/stories/json_response/server_lowlevel.py b/examples/stories/json_response/server_lowlevel.py index bcb14eb9ab..33c2ebdc3a 100644 --- a/examples/stories/json_response/server_lowlevel.py +++ b/examples/stories/json_response/server_lowlevel.py @@ -2,9 +2,9 @@ from typing import Any -import mcp_types as types from starlette.applications import Starlette +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import NO_DNS_REBIND, run_app_from_args diff --git a/examples/stories/legacy_elicitation/client.py b/examples/stories/legacy_elicitation/client.py index 52bb95e516..96ce0ec4e0 100644 --- a/examples/stories/legacy_elicitation/client.py +++ b/examples/stories/legacy_elicitation/client.py @@ -1,7 +1,6 @@ """Auto-answer form and URL elicitations and assert the tool result reflects them.""" -import mcp_types as types - +import mcp.types as types from mcp.client import Client, ClientRequestContext from stories._harness import Target, run_client diff --git a/examples/stories/legacy_elicitation/server_lowlevel.py b/examples/stories/legacy_elicitation/server_lowlevel.py index 08c7c3a766..6c93a9ed54 100644 --- a/examples/stories/legacy_elicitation/server_lowlevel.py +++ b/examples/stories/legacy_elicitation/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/legacy_routing/client.py b/examples/stories/legacy_routing/client.py index b9b401a2d3..a32094727c 100644 --- a/examples/stories/legacy_routing/client.py +++ b/examples/stories/legacy_routing/client.py @@ -2,12 +2,11 @@ from typing import Any -import mcp_types as types -from mcp_types import CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY -from mcp_types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION - +import mcp.types as types from mcp.client import Client from mcp.shared.inbound import MCP_METHOD_HEADER, MCP_PROTOCOL_VERSION_HEADER, InboundLadderRejection +from mcp.types import CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, PROTOCOL_VERSION_META_KEY +from mcp.types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION from stories._harness import TargetFactory, run_client from .server import classify_era diff --git a/examples/stories/legacy_routing/server.py b/examples/stories/legacy_routing/server.py index 79cc2afa67..29712d09bb 100644 --- a/examples/stories/legacy_routing/server.py +++ b/examples/stories/legacy_routing/server.py @@ -3,13 +3,13 @@ from collections.abc import Mapping from typing import Any, Literal -from mcp_types import INVALID_PARAMS -from mcp_types.version import MODERN_PROTOCOL_VERSIONS from starlette.applications import Starlette from starlette.middleware.cors import CORSMiddleware from mcp.server.mcpserver import Context, MCPServer from mcp.shared.inbound import InboundLadderRejection, InboundModernRoute, classify_inbound_request +from mcp.types import INVALID_PARAMS +from mcp.types.version import MODERN_PROTOCOL_VERSIONS from stories._hosting import NO_DNS_REBIND, run_app_from_args #: Response headers a browser-based MCP client must be able to read. diff --git a/examples/stories/legacy_routing/server_lowlevel.py b/examples/stories/legacy_routing/server_lowlevel.py index d2f763c8ec..034f9e1894 100644 --- a/examples/stories/legacy_routing/server_lowlevel.py +++ b/examples/stories/legacy_routing/server_lowlevel.py @@ -2,13 +2,13 @@ from typing import Any -import mcp_types as types -from mcp_types.version import MODERN_PROTOCOL_VERSIONS from starlette.applications import Starlette from starlette.middleware.cors import CORSMiddleware +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server +from mcp.types.version import MODERN_PROTOCOL_VERSIONS from stories._hosting import NO_DNS_REBIND, run_app_from_args from .server import MCP_ALLOWED_HEADERS, MCP_ALLOWED_METHODS, MCP_EXPOSED_HEADERS diff --git a/examples/stories/lifespan/client.py b/examples/stories/lifespan/client.py index 51633177fa..f84895cd9d 100644 --- a/examples/stories/lifespan/client.py +++ b/examples/stories/lifespan/client.py @@ -1,8 +1,7 @@ """Prove the lifespan-yielded state is reachable from a tool call.""" -from mcp_types import TextContent - from mcp.client import Client +from mcp.types import TextContent from stories._harness import Target, run_client diff --git a/examples/stories/lifespan/server_lowlevel.py b/examples/stories/lifespan/server_lowlevel.py index 09945c12c3..c5301dc149 100644 --- a/examples/stories/lifespan/server_lowlevel.py +++ b/examples/stories/lifespan/server_lowlevel.py @@ -5,8 +5,7 @@ from dataclasses import dataclass from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/middleware/server.py b/examples/stories/middleware/server.py index 076120dccd..e2164eb668 100644 --- a/examples/stories/middleware/server.py +++ b/examples/stories/middleware/server.py @@ -7,8 +7,7 @@ import json from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import CallNext, HandlerResult, ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/mrtr/client.py b/examples/stories/mrtr/client.py index 7280fd0aed..eb770c712e 100644 --- a/examples/stories/mrtr/client.py +++ b/examples/stories/mrtr/client.py @@ -1,7 +1,6 @@ """Drive the deploy tool both ways: the Client auto-loop, and a manual session-level loop.""" -import mcp_types as types - +import mcp.types as types from mcp import MCPError from mcp.client import Client, ClientRequestContext from stories._harness import Target, run_client diff --git a/examples/stories/mrtr/server.py b/examples/stories/mrtr/server.py index 8155b90f4d..cb308b9bc4 100644 --- a/examples/stories/mrtr/server.py +++ b/examples/stories/mrtr/server.py @@ -1,8 +1,7 @@ """Multi-round tool result (2026 era): a tool returns input_required and resumes from echoed state.""" -from mcp_types import ElicitRequest, ElicitRequestedSchema, ElicitRequestFormParams, ElicitResult, InputRequiredResult - from mcp.server.mcpserver import Context, MCPServer +from mcp.types import ElicitRequest, ElicitRequestedSchema, ElicitRequestFormParams, ElicitResult, InputRequiredResult from stories._hosting import run_server_from_args CONFIRM_SCHEMA: ElicitRequestedSchema = { diff --git a/examples/stories/mrtr/server_lowlevel.py b/examples/stories/mrtr/server_lowlevel.py index 6f3f489d8b..4382acbf0a 100644 --- a/examples/stories/mrtr/server_lowlevel.py +++ b/examples/stories/mrtr/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.server.request_state import RequestStateBoundary, RequestStateSecurity diff --git a/examples/stories/oauth/server_lowlevel.py b/examples/stories/oauth/server_lowlevel.py index 0bc7799c1e..df2b0a4d29 100644 --- a/examples/stories/oauth/server_lowlevel.py +++ b/examples/stories/oauth/server_lowlevel.py @@ -2,9 +2,9 @@ from typing import Any -import mcp_types as types from starlette.applications import Starlette +import mcp.types as types from mcp.server.auth.middleware.auth_context import get_access_token from mcp.server.auth.provider import ProviderTokenVerifier from mcp.server.context import ServerRequestContext diff --git a/examples/stories/oauth_client_credentials/server_lowlevel.py b/examples/stories/oauth_client_credentials/server_lowlevel.py index ba2003dedf..cde947e9ed 100644 --- a/examples/stories/oauth_client_credentials/server_lowlevel.py +++ b/examples/stories/oauth_client_credentials/server_lowlevel.py @@ -5,13 +5,13 @@ import secrets from typing import Any -import mcp_types as types from pydantic import AnyHttpUrl from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import JSONResponse from starlette.routing import Route +import mcp.types as types from mcp.server.auth.middleware.auth_context import get_access_token from mcp.server.auth.provider import AccessToken from mcp.server.context import ServerRequestContext diff --git a/examples/stories/pagination/server_lowlevel.py b/examples/stories/pagination/server_lowlevel.py index 55958a9624..cf024abf21 100644 --- a/examples/stories/pagination/server_lowlevel.py +++ b/examples/stories/pagination/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.shared.exceptions import MCPError diff --git a/examples/stories/parallel_calls/client.py b/examples/stories/parallel_calls/client.py index 945e5410a6..c940053dc8 100644 --- a/examples/stories/parallel_calls/client.py +++ b/examples/stories/parallel_calls/client.py @@ -1,9 +1,9 @@ """Two concurrent `Client`s, so `main` takes `targets`; their rendezvous in one tool proves concurrent dispatch.""" import anyio -from mcp_types import TextContent from mcp.client import Client +from mcp.types import TextContent from stories._harness import TargetFactory, run_client diff --git a/examples/stories/parallel_calls/server_lowlevel.py b/examples/stories/parallel_calls/server_lowlevel.py index 32807e1706..2874e85dd1 100644 --- a/examples/stories/parallel_calls/server_lowlevel.py +++ b/examples/stories/parallel_calls/server_lowlevel.py @@ -4,8 +4,8 @@ from typing import Any import anyio -import mcp_types as types +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/prompts/client.py b/examples/stories/prompts/client.py index 22aae4af43..d683713204 100644 --- a/examples/stories/prompts/client.py +++ b/examples/stories/prompts/client.py @@ -1,8 +1,7 @@ """List prompts, autocomplete an argument, then render both prompts.""" -from mcp_types import PromptReference, TextContent - from mcp.client import Client +from mcp.types import PromptReference, TextContent from stories._harness import Target, run_client diff --git a/examples/stories/prompts/server.py b/examples/stories/prompts/server.py index 2ef3fc3d83..9fe9788d22 100644 --- a/examples/stories/prompts/server.py +++ b/examples/stories/prompts/server.py @@ -1,9 +1,8 @@ """Prompts primitive: register templates, list, render, complete an argument.""" -from mcp_types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference - from mcp.server.mcpserver import MCPServer from mcp.server.mcpserver.prompts.base import AssistantMessage, Message, UserMessage +from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference from stories._hosting import run_server_from_args LANGUAGES = ["python", "pytorch", "rust", "go", "typescript"] diff --git a/examples/stories/prompts/server_lowlevel.py b/examples/stories/prompts/server_lowlevel.py index 2fb41de8bc..2524f79dd9 100644 --- a/examples/stories/prompts/server_lowlevel.py +++ b/examples/stories/prompts/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/reconnect/client.py b/examples/stories/reconnect/client.py index 0bf3c7af95..c9c8a548f8 100644 --- a/examples/stories/reconnect/client.py +++ b/examples/stories/reconnect/client.py @@ -1,9 +1,8 @@ """Probe server/discover once, persist the result, reconnect with zero round-trips — a fresh `Client` via `targets`.""" -from mcp_types import DiscoverResult -from mcp_types.version import LATEST_MODERN_VERSION - from mcp.client import Client +from mcp.types import DiscoverResult +from mcp.types.version import LATEST_MODERN_VERSION from stories._harness import TargetFactory, run_client diff --git a/examples/stories/reconnect/server_lowlevel.py b/examples/stories/reconnect/server_lowlevel.py index 5c6a057d6e..ce6e2cb350 100644 --- a/examples/stories/reconnect/server_lowlevel.py +++ b/examples/stories/reconnect/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/refund_desk/client.py b/examples/stories/refund_desk/client.py index 0ff8d28fca..293947d5e5 100644 --- a/examples/stories/refund_desk/client.py +++ b/examples/stories/refund_desk/client.py @@ -1,7 +1,6 @@ """Prove the refund amount is schema-hidden, resolvers memoize per call, and decline semantics differ per consumer.""" -import mcp_types as types - +import mcp.types as types from mcp.client import Client, ClientRequestContext from stories._harness import Target, run_client diff --git a/examples/stories/resources/client.py b/examples/stories/resources/client.py index 29f88d529a..9e12e51e7f 100644 --- a/examples/stories/resources/client.py +++ b/examples/stories/resources/client.py @@ -1,8 +1,7 @@ """List resources and templates, then read both the static and templated URIs.""" -from mcp_types import TextResourceContents - from mcp.client import Client +from mcp.types import TextResourceContents from stories._harness import Target, run_client diff --git a/examples/stories/resources/server_lowlevel.py b/examples/stories/resources/server_lowlevel.py index 2161fecc9e..2431ffdba6 100644 --- a/examples/stories/resources/server_lowlevel.py +++ b/examples/stories/resources/server_lowlevel.py @@ -2,12 +2,11 @@ from typing import Any -import mcp_types as types -from mcp_types.jsonrpc import INVALID_PARAMS - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.shared.exceptions import MCPError +from mcp.types import INVALID_PARAMS from stories._hosting import run_server_from_args diff --git a/examples/stories/roots/client.py b/examples/stories/roots/client.py index 9d8252991d..ce18cd10dc 100644 --- a/examples/stories/roots/client.py +++ b/examples/stories/roots/client.py @@ -1,9 +1,9 @@ """Expose two filesystem roots and verify the server's tool can read them back.""" -from mcp_types import ListRootsResult, Root, TextContent from pydantic import FileUrl from mcp.client import Client, ClientRequestContext +from mcp.types import ListRootsResult, Root, TextContent from stories._harness import Target, run_client diff --git a/examples/stories/roots/server_lowlevel.py b/examples/stories/roots/server_lowlevel.py index 2696c946c5..af48d427a8 100644 --- a/examples/stories/roots/server_lowlevel.py +++ b/examples/stories/roots/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/sampling/client.py b/examples/stories/sampling/client.py index 0ca88db996..93d3dddf1c 100644 --- a/examples/stories/sampling/client.py +++ b/examples/stories/sampling/client.py @@ -1,8 +1,7 @@ """Supply a canned sampling_callback and assert its text round-trips through the tool.""" -from mcp_types import CreateMessageRequestParams, CreateMessageResult, TextContent - from mcp.client import Client, ClientRequestContext +from mcp.types import CreateMessageRequestParams, CreateMessageResult, TextContent from stories._harness import Target, run_client diff --git a/examples/stories/sampling/server.py b/examples/stories/sampling/server.py index c97d8ab24f..7481f2e36b 100644 --- a/examples/stories/sampling/server.py +++ b/examples/stories/sampling/server.py @@ -1,8 +1,7 @@ """Sampling primitive: a tool asks the client's LLM for a completion mid-call.""" -from mcp_types import SamplingMessage, TextContent - from mcp.server.mcpserver import Context, MCPServer +from mcp.types import SamplingMessage, TextContent from stories._hosting import run_server_from_args diff --git a/examples/stories/sampling/server_lowlevel.py b/examples/stories/sampling/server_lowlevel.py index 5bc2a19436..82f87332af 100644 --- a/examples/stories/sampling/server_lowlevel.py +++ b/examples/stories/sampling/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/schema_validators/client.py b/examples/stories/schema_validators/client.py index 8f6794eddc..66e990bc61 100644 --- a/examples/stories/schema_validators/client.py +++ b/examples/stories/schema_validators/client.py @@ -1,8 +1,7 @@ """Asserts each variant publishes a `who` object schema and the call round-trips.""" -from mcp_types import TextContent - from mcp.client import Client +from mcp.types import TextContent from stories._harness import Target, run_client diff --git a/examples/stories/schema_validators/server_lowlevel.py b/examples/stories/schema_validators/server_lowlevel.py index 02dca8d162..657c03202f 100644 --- a/examples/stories/schema_validators/server_lowlevel.py +++ b/examples/stories/schema_validators/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/serve_one/client.py b/examples/stories/serve_one/client.py index 73bd457e10..b75510e9a6 100644 --- a/examples/stories/serve_one/client.py +++ b/examples/stories/serve_one/client.py @@ -1,9 +1,8 @@ """Drive `handle_one` directly to assert the raw result-dict shape, then over the wire.""" -import mcp_types as types -from mcp_types.version import LATEST_MODERN_VERSION - +import mcp.types as types from mcp.client import Client +from mcp.types.version import LATEST_MODERN_VERSION from stories._harness import Target, run_client from stories.serve_one.server import build_server, handle_one diff --git a/examples/stories/serve_one/server.py b/examples/stories/serve_one/server.py index 447e4a82b8..774a08fc39 100644 --- a/examples/stories/serve_one/server.py +++ b/examples/stories/serve_one/server.py @@ -13,9 +13,8 @@ from typing import Any import anyio -import mcp_types as types -from mcp_types.version import LATEST_MODERN_VERSION +import mcp.types as types from mcp.server.connection import Connection # deep-path import; shorter re-export planned from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server @@ -24,6 +23,7 @@ from mcp.shared.exceptions import NoBackChannelError from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher from mcp.shared.transport_context import TransportContext +from mcp.types.version import LATEST_MODERN_VERSION __all__ = ["SingleExchangeContext", "build_server", "handle_one"] diff --git a/examples/stories/sse_polling/client.py b/examples/stories/sse_polling/client.py index d2f3918952..39cec5dc93 100644 --- a/examples/stories/sse_polling/client.py +++ b/examples/stories/sse_polling/client.py @@ -1,9 +1,9 @@ """Call a tool whose SSE stream the server closes mid-flight; the call still completes. HTTP-only — no SSE on stdio.""" import anyio -from mcp_types import TextContent from mcp.client import Client +from mcp.types import TextContent from stories._harness import Target, run_client diff --git a/examples/stories/sse_polling/event_store.py b/examples/stories/sse_polling/event_store.py index 95d2b8accf..1cd24827a7 100644 --- a/examples/stories/sse_polling/event_store.py +++ b/examples/stories/sse_polling/event_store.py @@ -4,9 +4,8 @@ this interface with persistent storage so replay survives a process restart. """ -from mcp_types import JSONRPCMessage - from mcp.server.streamable_http import EventCallback, EventId, EventMessage, EventStore, StreamId +from mcp.types import JSONRPCMessage class InMemoryEventStore(EventStore): diff --git a/examples/stories/sse_polling/server_lowlevel.py b/examples/stories/sse_polling/server_lowlevel.py index fcf3199861..72cb79d61f 100644 --- a/examples/stories/sse_polling/server_lowlevel.py +++ b/examples/stories/sse_polling/server_lowlevel.py @@ -2,9 +2,9 @@ from typing import Any -import mcp_types as types from starlette.applications import Starlette +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import NO_DNS_REBIND, run_app_from_args diff --git a/examples/stories/standalone_get/client.py b/examples/stories/standalone_get/client.py index d2054ca8df..7e9801db22 100644 --- a/examples/stories/standalone_get/client.py +++ b/examples/stories/standalone_get/client.py @@ -1,8 +1,8 @@ """Receive `notifications/resources/list_changed` over the standalone GET stream, then re-list.""" import anyio -import mcp_types as types +import mcp.types as types from mcp.client import Client, IncomingMessage from stories._harness import Target, run_client diff --git a/examples/stories/standalone_get/server_lowlevel.py b/examples/stories/standalone_get/server_lowlevel.py index 21ee8c1f1b..d8c054f10a 100644 --- a/examples/stories/standalone_get/server_lowlevel.py +++ b/examples/stories/standalone_get/server_lowlevel.py @@ -3,8 +3,7 @@ import itertools from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/starlette_mount/client.py b/examples/stories/starlette_mount/client.py index dcfc3495b3..c286577354 100644 --- a/examples/stories/starlette_mount/client.py +++ b/examples/stories/starlette_mount/client.py @@ -1,8 +1,7 @@ """Connect to the sub-mounted MCP endpoint at /api/, list tools and call greet. HTTP-only: the mount is the story.""" -from mcp_types import TextContent - from mcp.client import Client +from mcp.types import TextContent from stories._harness import Target, run_client diff --git a/examples/stories/stateless_legacy/client.py b/examples/stories/stateless_legacy/client.py index d21ff850cf..1f9ea47fde 100644 --- a/examples/stories/stateless_legacy/client.py +++ b/examples/stories/stateless_legacy/client.py @@ -1,9 +1,8 @@ """Connect at each era — two connections, so `main` takes `targets`; the same stateless app answers both.""" -from mcp_types import TextContent -from mcp_types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION - from mcp.client import Client +from mcp.types import TextContent +from mcp.types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION from stories._harness import TargetFactory, run_client diff --git a/examples/stories/stateless_legacy/server_lowlevel.py b/examples/stories/stateless_legacy/server_lowlevel.py index 44943abd3d..1bcf358106 100644 --- a/examples/stories/stateless_legacy/server_lowlevel.py +++ b/examples/stories/stateless_legacy/server_lowlevel.py @@ -2,9 +2,9 @@ from typing import Any -import mcp_types as types from starlette.applications import Starlette +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import NO_DNS_REBIND, run_app_from_args diff --git a/examples/stories/stickynotes/client.py b/examples/stories/stickynotes/client.py index a5b0e41dad..b6b89151b3 100644 --- a/examples/stories/stickynotes/client.py +++ b/examples/stories/stickynotes/client.py @@ -1,10 +1,10 @@ """Drive the sticky-notes board end to end and prove `remove_all` clears only on a confirmed elicitation.""" import anyio -import mcp_types as types -from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS +import mcp.types as types from mcp.client import Client, ClientRequestContext, IncomingMessage +from mcp.types.version import HANDSHAKE_PROTOCOL_VERSIONS from stories._harness import Target, run_client diff --git a/examples/stories/stickynotes/server_lowlevel.py b/examples/stories/stickynotes/server_lowlevel.py index 15a20a797d..92266f144a 100644 --- a/examples/stories/stickynotes/server_lowlevel.py +++ b/examples/stories/stickynotes/server_lowlevel.py @@ -5,8 +5,7 @@ from dataclasses import dataclass, field from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/streaming/client.py b/examples/stories/streaming/client.py index e584b4c1ef..99398265ce 100644 --- a/examples/stories/streaming/client.py +++ b/examples/stories/streaming/client.py @@ -1,9 +1,9 @@ """Asserts progress + log notifications arrive in order, then cancels a call mid-flight.""" import anyio -from mcp_types import LoggingMessageNotificationParams from mcp.client import Client +from mcp.types import LoggingMessageNotificationParams from stories._harness import Target, run_client diff --git a/examples/stories/streaming/server.py b/examples/stories/streaming/server.py index ced59878d7..1c3dda9a85 100644 --- a/examples/stories/streaming/server.py +++ b/examples/stories/streaming/server.py @@ -1,8 +1,8 @@ """Progress, in-flight logging, and cancellation from a single long-running tool.""" import anyio -import mcp_types as types +import mcp.types as types from mcp.server.mcpserver import Context, MCPServer from stories._hosting import run_server_from_args diff --git a/examples/stories/streaming/server_lowlevel.py b/examples/stories/streaming/server_lowlevel.py index 6d9add0b6c..13393d49b1 100644 --- a/examples/stories/streaming/server_lowlevel.py +++ b/examples/stories/streaming/server_lowlevel.py @@ -3,8 +3,8 @@ from typing import Any import anyio -import mcp_types as types +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/examples/stories/subscriptions/client.py b/examples/stories/subscriptions/client.py index d2053aaf7c..a034f0a83e 100644 --- a/examples/stories/subscriptions/client.py +++ b/examples/stories/subscriptions/client.py @@ -1,8 +1,8 @@ """Open a `subscriptions/listen` stream, watch one URI and the tool list, then close it.""" import anyio -import mcp_types as types +import mcp.types as types from mcp.client import Client from mcp.client.subscriptions import ResourceUpdated, ToolsListChanged from stories._harness import Target, run_client diff --git a/examples/stories/subscriptions/server_lowlevel.py b/examples/stories/subscriptions/server_lowlevel.py index 6d9da182d5..d982c1ff13 100644 --- a/examples/stories/subscriptions/server_lowlevel.py +++ b/examples/stories/subscriptions/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from mcp.server.subscriptions import ( diff --git a/examples/stories/tools/client.py b/examples/stories/tools/client.py index 74e1ab4c0f..55c22e3b64 100644 --- a/examples/stories/tools/client.py +++ b/examples/stories/tools/client.py @@ -1,8 +1,7 @@ """List tools, inspect schemas + annotations, call both tools, assert structured output.""" -from mcp_types import TextContent - from mcp.client import Client +from mcp.types import TextContent from stories._harness import Target, run_client diff --git a/examples/stories/tools/server.py b/examples/stories/tools/server.py index a1f035c26a..93e4398092 100644 --- a/examples/stories/tools/server.py +++ b/examples/stories/tools/server.py @@ -2,10 +2,10 @@ from typing import Literal -from mcp_types import ToolAnnotations from pydantic import BaseModel from mcp.server.mcpserver import MCPServer +from mcp.types import ToolAnnotations from stories._hosting import run_server_from_args diff --git a/examples/stories/tools/server_lowlevel.py b/examples/stories/tools/server_lowlevel.py index e6c4c05ef7..15cc7db364 100644 --- a/examples/stories/tools/server_lowlevel.py +++ b/examples/stories/tools/server_lowlevel.py @@ -2,8 +2,7 @@ from typing import Any -import mcp_types as types - +import mcp.types as types from mcp.server.context import ServerRequestContext from mcp.server.lowlevel import Server from stories._hosting import run_server_from_args diff --git a/pyproject.toml b/pyproject.toml index aa79ed39ed..a18d6e98ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -217,6 +217,8 @@ max-complexity = 24 # Default is 10 [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] +# The mcp.types package is an alias that mirrors mcp_types namespaces by design. +"src/mcp/types/*.py" = ["F403"] # Generated by scripts/gen_surface_types.py: raw datamodel-codegen output (TID251 lifts the repo-wide RootModel ban for these generated validators). "src/mcp-types/mcp_types/_v*/__init__.py" = ["D212", "E501", "I001", "TID251", "UP007", "UP037"] "tests/server/mcpserver/test_func_metadata.py" = ["E501"] diff --git a/scripts/docs/gen_ref_pages.py b/scripts/docs/gen_ref_pages.py index 2340e18466..26916e8c39 100644 --- a/scripts/docs/gen_ref_pages.py +++ b/scripts/docs/gen_ref_pages.py @@ -30,6 +30,12 @@ # it from `src/` would emit the unimportable `mcp-types.mcp_types.*`. PACKAGES = (ROOT / "src" / "mcp", ROOT / "src" / "mcp-types" / "mcp_types") +# Alias packages that mirror another package's namespaces (`mcp.types` mirrors +# `mcp_types`, `mcp.types.version` mirrors `mcp_types.version`): the mirrored +# package's pages are the canonical rendering, so an alias, and every module +# under it, earns no page of its own. +EXCLUDED = frozenset({"mcp.types"}) + _KIND_SECTIONS = { griffe.Kind.MODULE: "Modules", griffe.Kind.CLASS: "Classes", @@ -185,6 +191,8 @@ def generate() -> list[NavItem]: continue ident = ".".join(parts) + if any(ident == e or ident.startswith(f"{e}.") for e in EXCLUDED): + continue documented.add(ident) stubs[API_DIR / doc_path] = _stub(parts[-1], f"::: {ident}") pages[ident] = API_DIR / doc_path diff --git a/src/mcp-types/mcp_types/jsonrpc.py b/src/mcp-types/mcp_types/jsonrpc.py index fcc3317d86..e9c6db96b4 100644 --- a/src/mcp-types/mcp_types/jsonrpc.py +++ b/src/mcp-types/mcp_types/jsonrpc.py @@ -6,6 +6,29 @@ from pydantic import BaseModel, Field, TypeAdapter +__all__ = [ + "CONNECTION_CLOSED", + "HEADER_MISMATCH", + "INTERNAL_ERROR", + "INVALID_PARAMS", + "INVALID_REQUEST", + "JSONRPC_VERSION", + "METHOD_NOT_FOUND", + "MISSING_REQUIRED_CLIENT_CAPABILITY", + "PARSE_ERROR", + "REQUEST_TIMEOUT", + "UNSUPPORTED_PROTOCOL_VERSION", + "URL_ELICITATION_REQUIRED", + "ErrorData", + "JSONRPCError", + "JSONRPCMessage", + "JSONRPCNotification", + "JSONRPCRequest", + "JSONRPCResponse", + "RequestId", + "jsonrpc_message_adapter", +] + RequestId = Annotated[int, Field(strict=True)] | str """The ID of a JSON-RPC request.""" diff --git a/src/mcp-types/mcp_types/version.py b/src/mcp-types/mcp_types/version.py index c5c2233274..e2f7e1ac86 100644 --- a/src/mcp-types/mcp_types/version.py +++ b/src/mcp-types/mcp_types/version.py @@ -9,6 +9,18 @@ from typing import Final +__all__ = [ + "KNOWN_PROTOCOL_VERSIONS", + "HANDSHAKE_PROTOCOL_VERSIONS", + "MODERN_PROTOCOL_VERSIONS", + "SUPPORTED_PROTOCOL_VERSIONS", + "LATEST_PROTOCOL_VERSION", + "LATEST_HANDSHAKE_VERSION", + "LATEST_MODERN_VERSION", + "OLDEST_SUPPORTED_VERSION", + "is_version_at_least", +] + KNOWN_PROTOCOL_VERSIONS: Final[tuple[str, ...]] = ( "2024-11-05", "2025-03-26", diff --git a/src/mcp/__init__.py b/src/mcp/__init__.py index 085e445d4a..28bc4703ed 100644 --- a/src/mcp/__init__.py +++ b/src/mcp/__init__.py @@ -58,6 +58,9 @@ ) from mcp_types import Role as SamplingRole +# Bind the `mcp.types` submodule on the package, as v1's `from .types import +# ...` did, so `import mcp` followed by `mcp.types.Tool` keeps working. +from . import types as types from .client._input_required import InputRequiredRoundsExceededError from .client.client import Client from .client.session import ClientSession diff --git a/src/mcp/types/__init__.py b/src/mcp/types/__init__.py new file mode 100644 index 0000000000..9bdfa06a56 --- /dev/null +++ b/src/mcp/types/__init__.py @@ -0,0 +1,31 @@ +"""The MCP protocol wire types, as the `mcp.types` namespace. + +This module mirrors the standalone `mcp_types` package exactly (every name is the +same object), so SDK users can keep the familiar v1 spelling: + + import mcp.types as types + + types.TextContent(type="text", text="hi") + +The `mcp.types.jsonrpc`, `mcp.types.methods`, and `mcp.types.version` +submodules mirror `mcp_types.jsonrpc`, `mcp_types.methods`, and +`mcp_types.version` the same way, so every supported `mcp_types` import has +an `mcp.types` spelling. + +Depend on and import `mcp_types` directly instead when you only need to +(de)serialize MCP traffic and don't want the SDK's transport stack: its only +runtime dependencies are `pydantic` and `typing-extensions`. +""" + +# A wildcard mirror of the mcp_types namespace is the whole point of this module. +# pyright: reportWildcardImportFromLibrary=false + +from mcp_types import * +from mcp_types import __all__ as __all__ + +# Bind the mirror submodules on the package, so `mcp.types.version.X` is as +# reachable by attribute access as `mcp_types.version.X` (whose `__init__` +# binds `.version` by importing from it), not only via `from ... import`. +from . import jsonrpc as jsonrpc +from . import methods as methods +from . import version as version diff --git a/src/mcp/types/jsonrpc.py b/src/mcp/types/jsonrpc.py new file mode 100644 index 0000000000..a76b74ee26 --- /dev/null +++ b/src/mcp/types/jsonrpc.py @@ -0,0 +1,13 @@ +"""The JSON-RPC 2.0 message and error types, as the `mcp.types.jsonrpc` namespace. + +A mirror of `mcp_types.jsonrpc` (every name is the same object), so code that +depends on `mcp` can import from `mcp.types.jsonrpc` without importing the +`mcp_types` distribution directly. Depend on and import `mcp_types.jsonrpc` +instead when you use `mcp-types` without the SDK. +""" + +# A wildcard mirror of the mcp_types.jsonrpc namespace is the whole point of this module. +# pyright: reportWildcardImportFromLibrary=false + +from mcp_types.jsonrpc import * +from mcp_types.jsonrpc import __all__ as __all__ diff --git a/src/mcp/types/methods.py b/src/mcp/types/methods.py new file mode 100644 index 0000000000..4b01fcc6cf --- /dev/null +++ b/src/mcp/types/methods.py @@ -0,0 +1,13 @@ +"""The MCP method registry, as the `mcp.types.methods` namespace. + +A mirror of `mcp_types.methods` (every name is the same object), so code that +depends on `mcp` can import from `mcp.types.methods` without importing the +`mcp_types` distribution directly. Depend on and import `mcp_types.methods` +instead when you use `mcp-types` without the SDK. +""" + +# A wildcard mirror of the mcp_types.methods namespace is the whole point of this module. +# pyright: reportWildcardImportFromLibrary=false + +from mcp_types.methods import * +from mcp_types.methods import __all__ as __all__ diff --git a/src/mcp/types/version.py b/src/mcp/types/version.py new file mode 100644 index 0000000000..857c53f0f8 --- /dev/null +++ b/src/mcp/types/version.py @@ -0,0 +1,13 @@ +"""The protocol-version registry, as the `mcp.types.version` namespace. + +A mirror of `mcp_types.version` (every name is the same object), so code that +depends on `mcp` can write `from mcp.types.version import LATEST_MODERN_VERSION` +without importing the `mcp_types` distribution directly. Depend on and import +`mcp_types.version` instead when you use `mcp-types` without the SDK. +""" + +# A wildcard mirror of the mcp_types.version namespace is the whole point of this module. +# pyright: reportWildcardImportFromLibrary=false + +from mcp_types.version import * +from mcp_types.version import __all__ as __all__ diff --git a/tests/test_types.py b/tests/test_types.py index ad481d2c0a..e338280507 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,5 +1,12 @@ +import subprocess +import sys +from types import ModuleType from typing import Any +import mcp_types +import mcp_types.jsonrpc +import mcp_types.methods +import mcp_types.version import pytest from inline_snapshot import snapshot from mcp_types import ( @@ -38,6 +45,12 @@ ) from pydantic import ValidationError +import mcp +import mcp.types +import mcp.types.jsonrpc +import mcp.types.methods +import mcp.types.version + @pytest.mark.anyio async def test_jsonrpc_request(): @@ -445,3 +458,48 @@ def test_input_required_result_requires_at_least_one_of_input_requests_or_reques with pytest.raises(ValidationError): InputRequiredResult(input_requests={}) assert InputRequiredResult(request_state="s").input_requests is None + + +def _assert_mirrors(mirror: ModuleType, source: ModuleType) -> None: + # The mirror shares the source's `__all__` list object by construction (`from source import + # __all__`), so the meaningful proof is that every exported name is the identical object. + assert all(getattr(mirror, name) is getattr(source, name) for name in source.__all__) + + +def test_mcp_types_namespace_mirrors_mcp_types_exactly(): + """SDK-defined: `mcp.types` is a permanent alias whose every name is the `mcp_types` object.""" + _assert_mirrors(mcp.types, mcp_types) + + +@pytest.mark.parametrize( + ("mirror", "source"), + [ + (mcp.types.jsonrpc, mcp_types.jsonrpc), + (mcp.types.methods, mcp_types.methods), + (mcp.types.version, mcp_types.version), + ], + ids=["jsonrpc", "methods", "version"], +) +def test_mcp_types_submodules_mirror_mcp_types_submodules_exactly(mirror: ModuleType, source: ModuleType): + """SDK-defined: every supported `mcp_types` submodule has an `mcp.types` mirror, name for name.""" + _assert_mirrors(mirror, source) + + +def test_bare_import_mcp_binds_the_types_submodule(): + """SDK-defined: `import mcp` alone binds `mcp.types`, so v1's `mcp.types.Tool` idiom works. + + A fresh interpreter is required to observe `import mcp` in isolation: this test process + has already imported `mcp.types`, and reloading `mcp` here would rebind classes that other + tests hold references to. + """ + # A regression hangs forever, so the bound only has to beat never (matches the suite's + # other subprocess.run calls). + result = subprocess.run( + [sys.executable, "-c", "import mcp; print(mcp.types.Tool.__name__)"], + capture_output=True, + text=True, + check=False, + timeout=20, + ) + assert result.returncode == 0, result.stderr + assert result.stdout == snapshot("Tool\n")