docs: convert bold cross-references into links, link SEP and RFC mentions (#3017)
This commit is contained in:
parent
f2e63c979a
commit
24fdd909ac
4 changed files with 167 additions and 167 deletions
|
|
@ -15,7 +15,7 @@ Here is a server whose tool can't finish on its own:
|
|||
* `ctx.elicit(...)` sends an `elicitation/create` request **to the client** and waits.
|
||||
* The tool doesn't return until somebody (a person in a form, or your code) supplies a `name`.
|
||||
|
||||
That is the server half, and the **Elicitation** chapter owns it. This chapter is the other end of the wire.
|
||||
That is the server half, and the **[Elicitation](../tutorial/elicitation.md)** chapter owns it. This chapter is the other end of the wire.
|
||||
|
||||
## The elicitation callback
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ That is the server half, and the **Elicitation** chapter owns it. This chapter i
|
|||
!!! tip
|
||||
`params` is a union of the two elicitation modes. Here `params.mode` is `"form"`; a `"url"` request
|
||||
carries `params.url` instead of a schema. One callback handles both; branch on `params.mode`.
|
||||
**Elicitation** shows the full pattern.
|
||||
**[Elicitation](../tutorial/elicitation.md)** shows the full pattern.
|
||||
|
||||
### Try it
|
||||
|
||||
|
|
@ -59,11 +59,11 @@ One `tools/call` from you, one `elicitation/create` back from the server, answer
|
|||
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
|
||||
to answer one; every test behind this page does. **Protocol versions** has the whole story.
|
||||
to answer one; every test behind this page does. **[Protocol versions](protocol-versions.md)** has the whole story.
|
||||
|
||||
On a 2026-07-28 session the callback isn't dead, it's fed differently: when a tool returns an
|
||||
`InputRequiredResult` carrying an `ElicitRequest`, `Client` dispatches that entry to the same
|
||||
`elicitation_callback` and retries the call for you. That flow is **Multi-round-trip requests**.
|
||||
`elicitation_callback` and retries the call for you. That flow is **[Multi-round-trip requests](../advanced/multi-round-trip.md)**.
|
||||
|
||||
## A callback is a capability
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ Pass all three callbacks and you get `['elicitation', 'sampling', 'roots']`. Pas
|
|||
|
||||
`sampling_callback` answers `sampling/createMessage`: the server asking *your* model to complete something. `list_roots_callback` answers `roots/list`: the server asking which directories it may work in.
|
||||
|
||||
Both work. Both follow the rule above. And both serve RPCs the **2026-07-28 spec removes**: a modern server doesn't call back into your client mid-request, it hands the request back to you as part of the tool result (**Multi-round-trip requests**). The callbacks themselves are not dead. When an `InputRequiredResult` carries a `CreateMessageRequest` or a `ListRootsRequest`, `Client`'s auto-loop dispatches it to the same `sampling_callback` or `list_roots_callback` you registered here. The whole list is in **Deprecated features**.
|
||||
Both work. Both follow the rule above. And both serve RPCs the **2026-07-28 spec removes**: a modern server doesn't call back into your client mid-request, it hands the request back to you as part of the tool result (**[Multi-round-trip requests](../advanced/multi-round-trip.md)**). The callbacks themselves are not dead. When an `InputRequiredResult` carries a `CreateMessageRequest` or a `ListRootsRequest`, `Client`'s auto-loop dispatches it to the same `sampling_callback` or `list_roots_callback` you registered here. The whole list is in **[Deprecated features](../advanced/deprecated.md)**.
|
||||
|
||||
You still need the callbacks to talk to servers that haven't moved. The signatures:
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ Pass them to `Client(...)` exactly like `elicitation_callback`.
|
|||
|
||||
Two more. Neither declares anything.
|
||||
|
||||
`logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**Logging** has what to do instead), so this callback exists for the servers that still emit it.
|
||||
`logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**[Logging](../tutorial/logging.md)** has what to do instead), so this callback exists for the servers that still emit it.
|
||||
|
||||
`message_handler` is the catch-all: every server notification reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
|
||||
|
||||
|
|
@ -144,4 +144,4 @@ Two more. Neither declares anything.
|
|||
* `sampling_callback` and `list_roots_callback` work the same way but serve deprecated features; modern servers use multi-round-trip requests instead.
|
||||
* `logging_callback` and `message_handler` receive notifications. They declare nothing.
|
||||
|
||||
Next: the first argument you've been passing to `Client(...)` all along, **Client transports**.
|
||||
Next: the first argument you've been passing to `Client(...)` all along, **[Client transports](transports.md)**.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ The server at the top is only there so you have something to connect to. The cli
|
|||
* A URL string (`Client("http://localhost:8000/mcp")`): Streamable HTTP, the production path.
|
||||
* A **transport**: anything you can `async with ... as (read, write)`, such as `stdio_client(...)` wrapping a subprocess.
|
||||
|
||||
Everything else on this page is identical across all three. Headers, subprocesses, timeouts, and the `Transport` protocol get their own chapter: **Client transports**.
|
||||
Everything else on this page is identical across all three. Headers, subprocesses, timeouts, and the `Transport` protocol get their own chapter: **[Client transports](transports.md)**.
|
||||
|
||||
### What's on a connected client
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ Four read-only properties, populated the moment you enter the block:
|
|||
* `client.protocol_version`: the protocol version the two sides agreed on. Here it is `"2026-07-28"`.
|
||||
* `client.instructions`: the server's `instructions=` string, or `None` if it didn't set one.
|
||||
|
||||
You never picked a protocol version. By default the `Client` probes the server and falls back to the classic handshake on older ones, so one client works against any era of server. When you need to control that, **Protocol versions** has the whole story.
|
||||
You never picked a protocol version. By default the `Client` probes the server and falls back to the classic handshake on older ones, so one client works against any era of server. When you need to control that, **[Protocol versions](protocol-versions.md)** has the whole story.
|
||||
|
||||
!!! tip
|
||||
`client.session` is the underlying `ClientSession`, the low-level escape hatch.
|
||||
|
|
@ -104,7 +104,7 @@ That is why `main` narrows with `isinstance(block, TextContent)` before touching
|
|||
|
||||
`structured_content` is the tool's return value as JSON, matching the tool's declared `output_schema`. No string parsing, no guessing.
|
||||
|
||||
When both are present they say the same thing twice on purpose: `content` is for a model, `structured_content` is for code. Where the structured half comes from, and how to control it, is the **Structured Output** chapter.
|
||||
When both are present they say the same thing twice on purpose: `content` is for a model, `structured_content` is for code. Where the structured half comes from, and how to control it, is the **[Structured Output](../tutorial/structured-output.md)** chapter.
|
||||
|
||||
### `is_error`: whether the tool failed
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ A tool that raises does **not** raise in your client. It comes back as an ordina
|
|||
(`call_tool("does_not_exist", {})`) and nothing raises. You get the same shape back,
|
||||
`is_error=True` with `Unknown tool: does_not_exist` in `content`. A `Client` method raises
|
||||
`MCPError` only when the server answers with a JSON-RPC **error** instead of a result, and
|
||||
**Handling errors** covers when a server produces which.
|
||||
**[Handling errors](../tutorial/handling-errors.md)** covers when a server produces which.
|
||||
|
||||
## Resources
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ The resource verbs come in pairs: two ways to list, one way to read.
|
|||
|
||||
`read_resource` returns `contents`, a list of `TextResourceContents` or `BlobResourceContents`. Same idea as tool content: narrow with `isinstance`, then read `.text` (or `.blob`).
|
||||
|
||||
A client can also **subscribe** to a resource and be told when it changes: `subscribe_resource(uri)` and `unsubscribe_resource(uri)`, same shape as everything else here. `MCPServer` doesn't implement that half. It says so up front (`server_capabilities.resources.subscribe` is `False`) and answers the request with an `MCPError`: `-32601`, *Method not found*. A server that does support subscriptions is built on the low-level `Server` (**The low-level Server**).
|
||||
A client can also **subscribe** to a resource and be told when it changes: `subscribe_resource(uri)` and `unsubscribe_resource(uri)`, same shape as everything else here. `MCPServer` doesn't implement that half. It says so up front (`server_capabilities.resources.subscribe` is `False`) and answers the request with an `MCPError`: `-32601`, *Method not found*. A server that does support subscriptions is built on the low-level `Server` (**[The low-level Server](../advanced/low-level-server.md)**).
|
||||
|
||||
## Prompts
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ A server with a completion handler can autocomplete prompt and resource-template
|
|||
* `ref` says *which* prompt or template you're filling in: a `PromptReference` or a `ResourceTemplateReference`.
|
||||
* `argument` is `{"name": ..., "value": ...}`: the argument and what the user has typed so far.
|
||||
|
||||
The answer is in `result.completion.values`. Type `"p"` and the server comes back with `['poetry']`. The server side, and how a handler uses the *other* already-filled arguments to narrow its suggestions, is the **Completions** chapter.
|
||||
The answer is in `result.completion.values`. Type `"p"` and the server comes back with `['poetry']`. The server side, and how a handler uses the *other* already-filled arguments to narrow its suggestions, is the **[Completions](../tutorial/completions.md)** chapter.
|
||||
|
||||
## Pagination
|
||||
|
||||
|
|
@ -191,13 +191,13 @@ Every `list_*` method takes a `cursor=` keyword and every result carries a `next
|
|||
--8<-- "docs_src/client/tutorial007.py"
|
||||
```
|
||||
|
||||
This loop is correct against every server. `MCPServer` returns everything in one page, so `next_cursor` is `None` and the loop runs once, which is why most code never writes it. Servers that genuinely page, and the rules cursors obey, are in **Pagination**.
|
||||
This loop is correct against every server. `MCPServer` returns everything in one page, so `next_cursor` is `None` and the loop runs once, which is why most code never writes it. Servers that genuinely page, and the rules cursors obey, are in **[Pagination](../advanced/pagination.md)**.
|
||||
|
||||
## In tests
|
||||
|
||||
`Client(mcp)` with no process and no port is already a test harness for your server.
|
||||
|
||||
There is one constructor flag built for that: `Client(mcp, raise_exceptions=True)`. It only has an effect on in-memory connections, and **Testing** is the chapter that explains it and builds the whole pattern around it.
|
||||
There is one constructor flag built for that: `Client(mcp, raise_exceptions=True)`. It only has an effect on in-memory connections, and **[Testing](../tutorial/testing.md)** is the chapter that explains it and builds the whole pattern around it.
|
||||
|
||||
## Recap
|
||||
|
||||
|
|
@ -209,4 +209,4 @@ There is one constructor flag built for that: `Client(mcp, raise_exceptions=True
|
|||
* `list_resources` / `list_resource_templates` / `read_resource`, `list_prompts` / `get_prompt`, and `complete` round out the verbs.
|
||||
* Every `list_*` takes `cursor=`; loop until `next_cursor` is `None`.
|
||||
|
||||
Next: the things a server can ask the *client* for, and how you answer, in **Client callbacks**.
|
||||
Next: the things a server can ask the *client* for, and how you answer, in **[Client callbacks](callbacks.md)**.
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ You want this for the **push-style** features.
|
|||
|
||||
A server-initiated request is the server calling *you*: `ctx.elicit(...)` putting a form in front of your user, sampling asking your model for a completion mid-tool-call. That channel only exists on a handshake-era session.
|
||||
|
||||
At 2026-07-28 it is gone. The server *returns* its questions and you retry the call with the answers (**Multi-round-trip requests**).
|
||||
At 2026-07-28 it is gone. The server *returns* its questions and you retry the call with the answers (**[Multi-round-trip requests](../advanced/multi-round-trip.md)**).
|
||||
|
||||
`mode="auto"` only gives you a handshake when the server is too old for anything else. `mode="legacy"` guarantees one. Reach for it whenever you hand `Client(...)` a `sampling_callback`, an `elicitation_callback` you want driven as a request, or a `message_handler`. **Client callbacks** goes through each.
|
||||
`mode="auto"` only gives you a handshake when the server is too old for anything else. `mode="legacy"` guarantees one. Reach for it whenever you hand `Client(...)` a `sampling_callback`, an `elicitation_callback` you want driven as a request, or a `message_handler`. **[Client callbacks](callbacks.md)** goes through each.
|
||||
|
||||
## Pinning a version
|
||||
|
||||
|
|
@ -124,4 +124,4 @@ The second connection made **zero** negotiation round trips and still knows exac
|
|||
* A version pin (`mode="2026-07-28"`) sends no negotiation traffic at all, at the cost of a blank `server_info`.
|
||||
* `prior_discover=` pays that cost back: save `client.session.discover_result`, reconnect with it, get both.
|
||||
|
||||
A modern connection has no push channel, so how does a 2026 server ask you a question mid-call? It returns it: **Multi-round-trip requests**.
|
||||
A modern connection has no push channel, so how does a 2026 server ask you a question mid-call? It returns it: **[Multi-round-trip requests](../advanced/multi-round-trip.md)**.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Every `Client` talks to its server over a **transport**: the thing that actually
|
|||
|
||||
You never configure one separately. `Client` takes a single positional argument and works the transport out from its type.
|
||||
|
||||
The *server* side of each (what `mcp.run()` does and what you deploy) is **Running your server**.
|
||||
The *server* side of each (what `mcp.run()` does and what you deploy) is **[Running your server](../run/index.md)**.
|
||||
|
||||
## In memory
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ No subprocess, no port, no bytes on a wire. The client and the server are two ob
|
|||
|
||||
That makes it two things at once:
|
||||
|
||||
* **A test harness.** Every example in this documentation is exercised this way, and the **Testing** chapter builds the whole pattern around it.
|
||||
* **A test harness.** Every example in this documentation is exercised this way, and the **[Testing](../tutorial/testing.md)** chapter builds the whole pattern around it.
|
||||
* **An embedding API.** An application that constructs the server doesn't need a network hop to call its tools.
|
||||
|
||||
## Streamable HTTP
|
||||
|
|
@ -68,7 +68,7 @@ Two things to notice:
|
|||
!!! info
|
||||
If you know `httpx`, you already know how to do auth, proxies, event hooks, retries and connection
|
||||
limits here. The SDK adds nothing on top and takes nothing away. It is also where OAuth plugs in:
|
||||
`httpx.AsyncClient(auth=OAuthClientProvider(...))`. That whole flow is **OAuth clients**.
|
||||
`httpx.AsyncClient(auth=OAuthClientProvider(...))`. That whole flow is **[OAuth clients](../advanced/oauth-clients.md)**.
|
||||
|
||||
## stdio
|
||||
|
||||
|
|
@ -112,4 +112,4 @@ A **transport** is any async context manager that yields a `(read, write)` pair
|
|||
* A transport is anything you can `async with x as (read, write)`. `Client` hands anything that isn't a server object or a URL straight to that protocol.
|
||||
* Constructing a `Client` picks the transport. `async with` opens it.
|
||||
|
||||
Once the transport is open the two sides have to agree on a protocol version. You normally never think about it; when you do, **Protocol versions** is the page.
|
||||
Once the transport is open the two sides have to agree on a protocol version. You normally never think about it; when you do, **[Protocol versions](protocol-versions.md)** is the page.
|
||||
|
|
|
|||
Loading…
Reference in a new issue