context
ServerRequestContext
dataclass
Bases: Generic[LifespanContextT, RequestT]
Per-request context handed to lowlevel request and notification handlers.
Built by ServerRunner._make_context for each inbound message. Carries the
connection-scoped ServerSession (server-to-client requests and
notifications), per-request metadata, and any per-message data the
transport attached (the HTTP request, SSE stream-close callbacks).
Source code in src/mcp/server/context.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
Context
Bases: BaseContext[TransportContext], Generic[LifespanT_co]
Server-side per-request context.
Extends BaseContext (transport metadata, the raw back-channel, progress
reporting) with lifespan, connection, and request-scoped log.
Not currently constructed by ServerRunner, which hands handlers a
ServerRequestContext instead.
Source code in src/mcp/server/context.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
lifespan
property
lifespan: LifespanT_co
The server-wide lifespan output (what Server(..., lifespan=...) yielded).
session_id
property
session_id: str | None
The transport's session id for this connection, when one exists.
Convenience for ctx.connection.session_id. None on stdio and
stateless HTTP.
headers
property
Request headers carried by this message, when the transport has them.
Convenience for ctx.transport.headers. None on stdio.
log
async
log(
level: LoggingLevel,
data: Any,
logger: str | None = None,
*,
meta: Meta | None = None
) -> None
Send a request-scoped notifications/message log entry.
Uses this request's back-channel (so the entry rides the request's SSE
stream in streamable HTTP), not the standalone stream - use
ctx.connection.log(...) for that.
Source code in src/mcp/server/context.py
94 95 96 97 98 99 100 101 102 103 104 105 106 | |
HandlerResult
module-attribute
What a request handler (or middleware) may return. ServerRunner serializes
all three to a result dict.
ServerMiddleware
Bases: Protocol[_MwLifespanT]
Context-tier middleware: (ctx, method, params, call_next) -> result.
Runs at the top of ServerRunner._on_request / _on_notify after ctx
is built but before any validation, lookup, or handshake. Wraps every
inbound request and notification: initialize, the pre-init gate,
METHOD_NOT_FOUND, params validation, the handler call, and
notifications/initialized all run inside call_next().
notifications/cancelled is observed too; the dispatcher applies the
cancellation itself, then forwards the notification. A request-side
failure reaches the middleware as a raised MCPError (or
ValidationError for malformed params) so observation/logging middleware
can record it. Listed outermost-first on Server.middleware.
ctx.request_id is None distinguishes a notification from a request. For
notifications call_next() returns None (a dropped or unhandled
notification also returns None) and the middleware's own return value is
discarded.
params is the raw inbound mapping (no model validation has happened
yet). For typed inspection, validate against the model the middleware
expects.
Warning: initialize is handled inline - the dispatcher does not read
further inbound messages until the middleware chain returns. Awaiting a
server-to-client request (ctx.session.send_request, send_ping, ...)
while handling initialize therefore deadlocks the connection: the
response can never be dequeued. Send-and-forget notifications are safe.
Server[L].middleware holds ServerMiddleware[L], so an app-specific
middleware sees ctx.lifespan_context: L. While the context is the
mutable ServerRequestContext dataclass it is invariant in L, so a
reusable middleware should be typed ServerMiddleware[Any] to register on
any Server[L].
Source code in src/mcp/server/context.py
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |