You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0bc072e
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/run/deploy.md
+25Lines changed: 25 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -170,6 +170,30 @@ Nothing about the fan-out cares which server object a stream is attached to. Two
170
170
* Streams are **not** resumable and events are **not** replayed. Losing a replica drops its streams; the clients re-listen and re-fetch. There is no event store to share and nothing else to configure. This is the one place where scaling out is genuinely just more of the same.
171
171
* A server that needs no change notifications skips the bus: **[turn them off](../handlers/subscriptions.md#turning-it-off)**.
172
172
173
+
## Runtimes that reuse a process
174
+
175
+
Some serverless adapters, including AWS Lambda adapters, start and stop the ASGI lifespan for each invocation while keeping the Python process warm. Keep your registered `MCPServer`, but call `streamable_http_app()` inside each invocation before passing the returned app to the adapter:
176
+
177
+
```python title="server.py"
178
+
from starlette.applications import Starlette
179
+
180
+
from mcp.server import MCPServer
181
+
from mcp.server.transport_security import TransportSecuritySettings
Call `app_for_invocation()` from your adapter's handler on every invocation. If you mount the MCP app in a host Starlette or FastAPI app, build the host app, its lifespan, and the mount inside that handler too. Each new HTTP app has a new `StreamableHTTPSessionManager`; re-entering the old app's lifespan fails because its manager can run only once.
192
+
193
+
Replace `mcp.example.com` with your public Host header. If browsers call the endpoint, also configure `allowed_origins`; see [the Host allowlist](#before-anything-else-the-host-allowlist).
194
+
195
+
The example uses `stateless_http=True` so legacy clients do not try to resume a session that ended with the previous invocation. It gives up the legacy server-to-client back-channel; see [Serving legacy clients](legacy-clients.md). Your server's own `lifespan=` also runs on every invocation, so keep resources that must outlive an invocation outside it. Modern requests are sessionless, but they still need a fresh app when the adapter restarts its lifespan. If your adapter keeps one lifespan open across invocations, keep the app for that lifespan instead.
196
+
173
197
## What the SDK does not give you
174
198
175
199
An `MCPServer` is a protocol implementation, not an application server. The deployment knobs you go looking for next are missing on purpose:
@@ -187,6 +211,7 @@ An `MCPServer` is a protocol implementation, not an application server. The depl
187
211
* The default `requestState` key is `os.urandom(32)`, minted per process. A multi-round-trip retry that reaches a different worker fails with `-32602`*"Invalid or expired requestState"*.
188
212
* The fix is `RequestStateSecurity(keys=[...])`**and** the same server name on every instance. The name is the token's default audience claim. Same keys, same name.
189
213
* Change notifications cross replicas through one shared `SubscriptionBus`. The SDK's only implementation is in-process; the two-method `Protocol` over your own pub/sub is yours to write.
214
+
* If an adapter restarts ASGI lifespan on each warm-process invocation, call `streamable_http_app()` for each invocation. A manager cannot enter `run()` twice.
190
215
* There is no `workers=`, no health route, no production settings object. Bring your own ASGI server.
191
216
192
217
The other thing a real hostname needs in front of it is a token: **[Authorization](authorization.md)**.
**[Add to an existing app](run/asgi.md)** is the page for this, including several servers in one app and FastAPI. Two neighbouring strings from the same class:
257
257
258
258
*`StreamableHTTPSessionManager .run() can only be called once per instance. Create a new instance if you need to run again.` The manager is single-use; entering the same app's lifespan twice hits it.
259
+
In a warm AWS Lambda process, an adapter that starts and stops the lifespan for each invocation hits this on the second invocation. Build a fresh HTTP app inside each invocation; see [Runtimes that reuse a process](run/deploy.md#runtimes-that-reuse-a-process).
259
260
*`mcp.session_manager` only exists **after**`streamable_http_app()` has been called, so build the routes first and touch the manager only inside the lifespan.
0 commit comments