MCPcopy
hub / github.com/modelcontextprotocol/python-sdk / ServerRunner

Class ServerRunner

src/mcp/server/runner.py:190–414  ·  view source on GitHub ↗

Per-connection handler kernel. One instance per client connection.

Source from the content-addressed store, hash-verified

188
189@dataclass
190class ServerRunner(Generic[LifespanT]):
191 """Per-connection handler kernel. One instance per client connection."""
192
193 server: Server[LifespanT]
194 connection: Connection
195 lifespan_state: LifespanT
196 _: KW_ONLY
197 init_options: InitializationOptions | None = None
198 """`InitializeResult` payload. Defaults to `server.create_initialization_options()`."""
199 dispatch_middleware: Sequence[DispatchMiddleware] = (otel_middleware,)
200
201 @cached_property
202 def on_request(self) -> OnRequest:
203 """`_on_request` wrapped in `dispatch_middleware`, outermost-first.
204
205 Dispatch-tier middleware sees raw `(dctx, method, params) -> dict` and
206 wraps everything - initialize, METHOD_NOT_FOUND, validation failures
207 included.
208 """
209 return reduce(
210 lambda handler, middleware: middleware(handler), reversed(self.dispatch_middleware), self._on_request
211 )
212
213 @cached_property
214 def on_notify(self) -> OnNotify:
215 return self._on_notify
216
217 async def _on_request(
218 self,
219 dctx: DispatchContext[TransportContext],
220 method: str,
221 params: Mapping[str, Any] | None,
222 ) -> dict[str, Any]:
223 meta = _extract_meta(params)
224 version = self.connection.protocol_version
225 ctx = self._make_context(dctx, method, params, meta, version)
226 is_spec_method = method in _methods.SPEC_CLIENT_METHODS
227
228 async def _inner(ctx: ServerRequestContext[LifespanT, Any]) -> HandlerResult:
229 # Read method/params off `ctx` so a middleware that rewrote them via
230 # `call_next(replace(ctx, ...))` reaches lookup and the handler.
231 method, params = ctx.method, ctx.params
232 # Pinned compat: spec methods are surface-validated before lookup,
233 # so malformed params are INVALID_PARAMS even with no handler
234 # registered. Custom methods miss the monolith map and fall through
235 # to `entry.params_type` exactly as before.
236 if method in _methods.SPEC_CLIENT_METHODS:
237 try:
238 _methods.validate_client_request(method, version, params)
239 except KeyError:
240 raise MCPError(code=METHOD_NOT_FOUND, message="Method not found", data=method) from None
241 # TODO(L29): the 2026-07-28 spec drops the handshake; this branch and
242 # the gate become a per-version legacy path then. Initialize runs inline
243 # (read loop parked), so awaiting the peer anywhere on this path deadlocks.
244 if method == "initialize":
245 return self._handle_initialize(params)
246 # Methods without a handler are METHOD_NOT_FOUND regardless of
247 # initialization state: JSON-RPC 2.0 reserves -32601 for "not

Callers 3

connected_runnerFunction · 0.90
serve_connectionFunction · 0.85
serve_oneFunction · 0.85

Calls

no outgoing calls

Tested by 1

connected_runnerFunction · 0.72