Files
Max Isbey ec5b2258c9 Cut import and startup cost with deferred model builds and lazy imports
Every import path now pays only for what it uses, with no public API
added or removed:

- The protocol models (mcp.types / mcp_types, incl. the JSON-RPC
  envelopes and the generated per-version wire packages) build their
  pydantic validators on first use instead of at import (defer_build),
  through one shared private base class. First-use builds are
  serialised behind a single process-wide lock, since released pydantic
  does not make concurrent first use of a deferred model thread-safe;
  this also fixes a pre-existing concurrent-first-use failure that
  reproduces on main.
- `import mcp` binds the client/server names lazily on first attribute
  access (PEP 562) instead of importing both stacks eagerly, and the
  client no longer imports the server, so client entry points stop
  loading the server, the web stack, httpx2 and cryptography.
- The web application stack (starlette's app machinery, sse_starlette,
  uvicorn) loads with the app builders that use it, and each protocol
  version's wire package loads on the first message parsed for that
  version rather than both loading at import.

On the fresh-interpreter harness `import mcp` is ~0.4x of v1 (main is
~1.6x), the client entry points ~0.6x of v1, `import mcp.server.mcpserver`
~0.7x, and time-to-ready / stdio cold start land at parity with v1. RSS
after `import mcp` is 19 MiB (v1 43.5, main 57). Steady-state per-call
latency is unchanged.

Observable-but-incidental differences (removed incidental namespace
bindings, deeper submodules no longer imported as a side effect of a
bare `import mcp`, get_type_hints needing localns= for a documented set
of callables, pre-first-use introspection) are catalogued in
docs/migration.md; ratchet tests pin the import footprints and the
concurrent-first-use safety.
2026-08-03 15:06:11 +00:00

1.6 KiB

Advanced

Everything an ordinary server or client needs has a topical home in the sections above. This section is the escape hatches you reach for when MCPServer's convenience layer is in the way:

  • The low-level Server: the class MCPServer is built on. Hand-written schemas, on_* handlers, nothing checked for you, and custom JSON-RPC methods of your own.
  • Pagination and Middleware: two things you can only do on the low-level Server.
  • Extensions and MCP Apps: the protocol's extension surface. Compose extension packages into a server, or write your own.
  • Startup cost: what an import loads, and the one-time bills paid on first use instead — for when you are measuring cold start.

A few things you might reasonably look for here live where you'd actually use them instead:

  • Authorization is under Running your server because you protect a server where you deploy it.
  • OAuth, identity assertion, connecting to multiple servers, and the response cache are all under Clients.
  • Multi-round-trip requests and Subscriptions are under Inside your handler because both are things a handler does.
  • URI templates is under Servers, next to Resources.
  • Protocol versions and Deprecated features each have their own top-level page.

If you're not sure whether you need this section, you don't.