Streamable HTTP: a server other machines can reach
stdio only works on one computer. To offer a server to a team or to hosted agents, run it over Streamable HTTP, the transport a deployed MCP server uses.
if __name__ == "__main__":
mcp.run(transport="streamable-http", port=8200)The same server, served on a port. The SDK builds the web application and runs it with uvicorn, and the MCP endpoint is at /mcp. Transport options like port belong to run(), not to MCPServer(...).
One other change: MCPServer("Shop support", log_level="WARNING"). The default level logs every request, which is useful while debugging and noisy in the output below.
import asyncio
from mcp import Client
async def main():
async with Client("http://127.0.0.1:8200/mcp") as client:
print(client.protocol_version)
result = await client.call_tool("lookup_order", {"order_id": "B42"})
print(result.structured_content)
asyncio.run(main())A URL string is all the client needs. It chooses Streamable HTTP from the http://.
python shop.py &
sleep 3
python client.py
kill %1As in APIs for AI, & starts the server in the background and kill %1 stops it; normally the server runs in its own terminal. 2026-07-28 is the protocol version the two agreed on.
Headers and keys
A deployed server needs to know who is calling. The client's HTTP settings, headers included, go on an httpx2.AsyncClient passed through the transport, and a server can read request headers from ctx.headers. For real sign-in, the SDK implements the OAuth flow the MCP specification describes; it is named in the last lesson and has its own guide in the SDK docs.
- Change the port to 8201 in both files.
- Remove
log_level="WARNING"and read what the server logs. - Run
client.pywith the server stopped and read the error.
Little by little, you're building something great.