docs: add a middleware tutorial that refuses tool calls
Merged
MA
1mo ago+266+266+012345678901234567890123456789-6-6-0123456789
Fixes #3272.
The Middleware page lists "Refuse" among the things a middleware can do, but the only code for it was on the Subscriptions page. This adds a worked example to the Middleware page itself: a middleware that caps how many tool calls run at once and refuses the rest.
It covers the gap #3272 pointed out with a small deterministic example in the middleware docs, rather than the separate model-backed example server the issue proposed.
What it adds
docs_src/middleware/tutorial002.pymax_concurrent_tool_calls(limit), a factory that returns the middleware, on the low-levelServerlike the page's first example.- Only
tools/callis counted, so discovery and listing keep answering while tool calls are refused. - Over the limit it raises
MCPErrorwith the server's ownSERVER_BUSYcode. MCP has no standard code for "busy", and the spec leaves codes outside the JSON-RPC reserved range to applications.
docs/advanced/middleware.md- A new "A concurrency cap" section after the timing example.
- The "Refuse" bullet now points at it, and still points at the subscriptions example.
tests/docs_src/test_middleware.py- The call over the limit is refused while the earlier ones are still running, including when it comes from a second client.
tools/listis answered with the cap reached.- A call that finishes, raises or is cancelled gives its slot back.
- Answering with an
is_error=Trueresult instead of raising reaches the client as a tool result.
Notes
- Nothing changes under
src/and there is no new API. - The translated pages aren't regenerated here. They show the "behind the English page" notice until the next translation refresh, the same as after any other change to an English page.