Example MCP Server (Streamable HTTP)
A minimal MCP server built on the official Python SDK (mcp==2.0.0), runningover Streamable HTTP so it can live in a container and be reached over thenetwork.
It ships with two demo tools (echo, add) and one resource (time://now)so you have something to test against immediately — replace them with yourown.
Run it
docker compose up -d --build
docker compose logs -f mcp-server
The server listens on http://localhost:8000/mcp.
Test it without a client
curl -i -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}}}'
The response headers include mcp-session-id — reuse it in anMcp-Session-Id header on subsequent calls (tools/list, tools/call,resources/read, etc.) once you've sent a notifications/initializedmessage.
Point a client at it
Any MCP client that supports Streamable HTTP just needs the URL:http://localhost:8000/mcp (or your host's address/port if not runninglocally).
Add your own tools
@mcp.tool()
def my_tool(arg: str) -> str:
"""This docstring becomes the tool description the model sees."""
return do_something(arg)
Resources (@mcp.resource("scheme://path")) and prompts (@mcp.prompt())follow the same pattern. Restart the container after changes:
docker compose up -d --build
Notes
MCP_HOST/MCP_PORTenv vars control what the server binds to insidethe container — leaveMCP_HOST=0.0.0.0or it won't be reachable fromoutside the container.- This has no authentication. Fine for local/dev use behind
localhost:8000; if you expose it beyond your machine, put it behind areverse proxy or gateway that handles auth (or use the SDK's built-inOAuth support viatoken_verifier/auth_server_provider). - The old
from mcp.server.fastmcp import FastMCPimport path sometutorials still show is gone as ofmcp==2.0.0— it's nowfrom mcp.server import MCPServer.