What you already know

This is less new material than it looks like. Lesson 7 connected a client to a server to watch error handling; Lesson 9 did it again to compare against the Inspector; Lesson 10's checkpoint did it a third time against your own Notes Server. This lesson just slows that same shape down and explains every piece.

The three layers of a connection

params = StdioServerParameters(command=sys.executable, args=[str(server_script)])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
  • StdioServerParameters: configuration only, not a connection. Just describes which command to run and with what arguments.
  • stdio_client(params): an async context manager that launches the server as a subprocess and gives you back a (read, write) stream pair. Entering it starts the process; leaving it terminates it.
  • ClientSession(read, write): wraps those raw streams with the actual protocol logic, building JSON-RPC requests, matching responses by id, tracking capabilities.

session.initialize() is not optional

Before any other request, the client and server perform a handshake: the client declares its protocol version and capabilities, the server responds with its own. session.server_capabilities and session.server_info are populated by this call, and other requests will fail if you skip it. This is the client-side mirror of Lesson 1's JSON-RPC sketch.

Listing tools

tools = await session.list_tools()
for tool in tools.tools:
print(tool.name, tool.description)

tools.tools is a plain list of the same Tool objects you inspected server-side with mcp.list_tools() back in Lesson 3, name, description, inputSchema, just arriving from across the connection this time instead of from the same process.

Checkpoint

  • StdioServerParameters: describes the subprocess to launch, not a live connection.
  • stdio_client: launches the subprocess, gives you raw streams.
  • ClientSession: the actual protocol logic, built on top of those streams.
  • session.initialize(): the required handshake, must happen before any other request.

If anything here still feels unclear, ask before moving to Lesson 12, actually calling one of these tools.