Loading
0x30Lesson 4 of 16

Follow the stateless request lifecycle

See how every request carries its own version and capabilities, and how clients discover servers.

20 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • Explain what the stateless core of the 2026-07-28 revision means
  • Fill in the required _meta fields of a request
  • Negotiate a protocol version and use server/discover

MCP revisions are named by date. In the current revision, 2026-07-28, MCP became a stateless request/response protocol. Earlier revisions (2025-11-25 and before) opened a connection with an initialize handshake and kept a session; now there is no handshake and no protocol-level session.

Instead, every request carries what the server needs in its params._meta:

  • io.modelcontextprotocol/protocolVersion - required, e.g. "2026-07-28",
  • io.modelcontextprotocol/clientCapabilities - required, what this client supports,
  • io.modelcontextprotocol/clientInfo - recommended, the client’s name and version.

A request missing a required field is rejected with -32602. Because each request is self-contained, any server instance behind a plain load balancer can answer it - no sticky sessions or shared session store needed.

Try it

Up to 15 XP

A stateless conversation

Step through a host listing a server’s tools and calling one. Before each message appears, predict it. Notice that every request repeats the _meta fields.

Message 1 of 6Predicted 0/0
Host + client
MCP server

Predict: What does a client send first if it wants to learn a server’s versions and capabilities in one go?

Choosing a version

Clients and servers may support several revisions. If a server does not support the version a request declares, it replies with an UnsupportedProtocolVersionError (-32022) listing the versions it does support, and the client retries with a common one. Version strings are dates in YYYY-MM-DD form, so the newest common version is simply the largest shared string.

negotiate.py
1client = ["2025-11-25", "2026-07-28"]
2server = ["2025-06-18", "2025-11-25"]
3common = set(client) & set(server)
4print(max(common) if common else "no common version")
Output
2025-11-25

Key takeaways

  • The current revision (2026-07-28) is stateless: no handshake, no session.

  • Every request carries protocolVersion and clientCapabilities (required) and clientInfo in _meta.

  • server/discover returns versions, capabilities and identity; unsupported versions get -32022 with the supported list.

Lesson quiz

7 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: build an MCP server

Write Python in the editor and run it against sample inputs. Python runs locally in your browser using a WebAssembly runtime.

Exercise 1

Negotiate a protocol version

+25 XP

The first line lists the client’s supported versions and the second the server’s, separated by spaces. Print the newest version both support, or no common version.

  • Older shared version
  • Both current
  • Nothing shared
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Validate request metadata

+25 XP

Read one JSON-RPC request. Print ok if its params._meta contains both required keys - io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities. Otherwise print -32602 missing: followed by the missing key names, comma-separated, in that order.

  • Complete
  • No capabilities
  • No params at all
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…