MCPMCP Python SDK 2.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
24 small wins to finish your pathNext lesson

stdio: a server as a subprocess

On your own computer, apps like Claude Code start an MCP server as a child process and talk over its standard input and output: the stdio transport.

Exampleshop.py, added at the end
if __name__ == "__main__":
    mcp.run()

mcp.run() serves the server, over stdio when given no transport, and blocks until the input closes. It sits under if __name__ == "__main__": so that importing shop.py, as every earlier lesson did, does not start it.

Run python shop.py by itself and nothing seems to happen: it is waiting for a client to write the first message. Press Ctrl+C to stop it.

A client that starts the server

Exampleclient.py
import asyncio
import sys

from mcp import Client, StdioServerParameters

server = StdioServerParameters(command=sys.executable, args=["shop.py"])


async def main():
    async with Client(server) as client:
        result = await client.call_tool("lookup_order", {"order_id": "A17"})
        print(result.structured_content)


asyncio.run(main())

StdioServerParameters describes the command to launch. sys.executable is the Python running the client, so the server starts in the same environment. Entering async with starts the process; leaving it shuts the process down.

Example
python client.py

The same call as lesson 5, now across two processes. This is what a desktop application does with your server.

Two things stdio changes

Standard output is the connection. Anything else your server prints to stdout would corrupt the messages. The SDK redirects stray output while serving, but write logs with Python's logging module, which writes to standard error.

The server does not inherit your environment. The SDK starts it with a short allow-list of variables, such as PATH and HOME, so secrets in your shell do not leak into a process you might not have written. A server that needs an API key gets it through env=: StdioServerParameters(command=..., args=[...], env={"SHOP_API_KEY": "..."}).

Try it yourself
  • Add print("hello") inside lookup_order and run client.py again.
  • Pass env={"SHOP_NAME": "Mugs and Lamps"} and read it with os.environ in a tool.
  • Point args at a file that does not exist and read the error.

Every expert started right here.