docs: stop presenting the in-memory client as the way to connect (#3443)

This commit is contained in:
Max 2026-09-05 04:15:58 +01:00 • committed by GitHub
commit 7bb486a10f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 803 additions and 598 deletions

View file

@ -137,4 +137,4 @@ A browser-based client needs two permissions from you: to **send** its MCP reque
* Browser clients need CORS: `allow_headers` for the `Mcp-*` request headers, `expose_headers=["Mcp-Session-Id"]` for the response.
* `@mcp.custom_route()` adds plain, unauthenticated HTTP endpoints next to `/mcp`.
Once the server is reachable at a real URL, **[The Client](../client/index.md)** connects to it with that URL instead of a server object.
Once the server is reachable at a real URL, **[The Client](../client/index.md)** connects to it with that URL.

View file

@ -124,6 +124,6 @@ An authorization server can also accept an enterprise identity provider's signed
* `token_verifier=` and `auth=AuthSettings(issuer_url=..., resource_server_url=..., required_scopes=[...])` always travel together.
* The SDK publishes [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) Protected Resource Metadata at `/.well-known/oauth-protected-resource/...` and answers unauthenticated requests with a 401 whose `WWW-Authenticate` header points at it. That is the entire discovery story.
* `get_access_token()` in any handler is who's calling.
* Authorization is an HTTP concern. `stdio` and the in-memory client never see it.
* Authorization is an HTTP concern. `stdio` and the in-memory test client never see it.
The client half (discovering your authorization server and fetching the token for you) is **[OAuth clients](../client/oauth-clients.md)**. And a client that *asserts* an identity instead of asking a user for one is **[Identity assertion](../client/identity-assertion.md)**.

View file

@ -16,15 +16,25 @@ So a legacy client is not something you build *for*. It is something that connec
## One handler, both eras
Here is a tool that has to ask the user something, and both eras of client calling it:
Here is a tool that has to ask the user something:
```python title="server.py" hl_lines="24 37-38"
```python title="server.py" hl_lines="21"
--8<-- "docs_src/legacy_clients/tutorial001.py"
```
`reserve` needs one thing the model didn't supply: how many copies. `Annotated[..., Resolve(ask_quantity)]` is how a tool declares that (**[Dependencies](../handlers/dependencies.md)** is that whole story). Nothing in `reserve` names a version, checks a capability, or branches.
The two clients are open **at the same time**, on the same `mcp` object. `mode="legacy"` runs the `initialize` handshake: the exact connection a pre-2026 client opens. The other one takes the default and lands on `2026-07-28`.
Serve it over HTTP, and here are both eras of client calling it:
```console
uv run mcp run server.py --transport streamable-http
```
```python title="client.py" hl_lines="14-15"
--8<-- "docs_src/legacy_clients/tutorial001_client.py"
```
The two clients are open **at the same time**, against the same running server. `mode="legacy"` runs the `initialize` handshake: the exact connection a pre-2026 client opens. The other one takes the default and lands on `2026-07-28`. Run `python client.py` from a second terminal:
```text
2025-11-25 {'result': "Reserved 2 of 'Dune'."}
@ -115,7 +125,7 @@ Two things about it matter more than what it does.
!!! check
Do the wrong thing. `reserve` is the exact tool that just served both clients. Deploy it with
`stateless_http=True`, connect the same two clients over HTTP, and call it from each.
`stateless_http=True`, connect the same two clients, and call it from each.
The modern client still gets `Reserved 2 of 'Dune'.` The modern leg didn't change.