Nine examples, from two simple tools to transactional applications. Docker
Compose is the default way to run them; no host Python installation is needed.
Every server exposes remote Streamable HTTP at /mcp and a liveness probe at
/health.
Install Docker Desktop (or Docker Engine with the Compose plugin), start Docker, and run these commands from the repository root.
-
Copy
.env.exampleto.envif you do not already have one:# PowerShell Copy-Item .env.example .env
# Bash cp .env.example .env -
Generate a token with Docker, then paste the output into
MCP_AUTH_TOKENin.env. Keep your existing token if it already has at least 32 random characters.docker run --rm python:3.12-slim python -c "import secrets; print(secrets.token_hex(24))" -
Build and start all nine services:
docker compose up -d --build docker compose ps
-
Call the hello-world server using a client inside its container:
docker compose exec hello-world python clients/01-hello-client.py
The client connects over HTTP and inherits the container's bearer token. All
Compose services run in production mode with authentication, including the first
example. Ports are published only on 127.0.0.1.
To start just one example:
docker compose up -d --build workflow-engine
docker compose exec workflow-engine python clients/07-workflow-client.pyThe workflow demo deliberately fails one step, retries it, and prints the saved results. All commands in the example guides run from the repository root.
| # | Example | Default port | What it teaches |
|---|---|---|---|
| 01 | Hello world | 8101 | Tools, typed inputs, remote initialization |
| 02 | Remote basic | 8102 | Tools, resources and prompts |
| 03 | Remote auth | 8103 | Required bearer authentication |
| 04 | Tool features | 8104 | Async upstream calls, structured results, progress and logging |
| 05 | Task manager | 8105 | Persistent SQLite CRUD and pagination |
| 06 | Secure gateway | 8106 | Bounded TTL caching, rate limiting, upstream failures |
| 07 | Knowledge base | 8107 | FTS5 search, immutable revisions, optimistic concurrency |
| 08 | Workflow engine | 8108 | DAG validation, durable checkpoints, retries, cancellation |
| 09 | Inventory reservations | 8109 | Atomic multi-item reservations, idempotency, audit trails |
A compatible MCP client on your computer can connect to
http://localhost:<port>/mcp using Authorization: Bearer <your .env token>.
For example, hello-world uses http://localhost:8101/mcp.
The bundled clients can run inside the containers without installing anything on your host. To inspect the knowledge-base tools interactively:
docker compose up -d --build knowledge-base
docker compose exec knowledge-base python clients/05-interactive-cli.py http://localhost:8107/mcpEnter list to discover tools, <tool-name> {JSON-object} to call one, or quit
to exit. See the client guide for all client commands.
docker compose logs --tail=100 workflow-engine
docker compose restart workflow-engine
docker compose downAll services share one image and run as UID 10001 with read-only application
files. Task manager, knowledge base, workflow engine and inventory reservations
each have a writable named volume mounted at /app/data. Data survives container
recreation and docker compose down; adding -v deletes the volumes.
After changing .env, run docker compose up -d to recreate affected containers
with the new configuration. restart alone does not apply environment changes.
After changing source files, use docker compose up -d --build.
Compose reads these settings from .env:
| Variable | Default | Meaning |
|---|---|---|
MCP_AUTH_TOKEN |
Required | Random bearer token of at least 32 characters |
MCP_ALLOWED_HOSTS |
Localhost addresses only | Additional exact public hostnames, optionally with ports; comma-separated |
RATE_LIMIT_PER_MINUTE |
120 | Request limit per socket peer IP, per process |
MAX_REQUEST_BYTES |
1048576 | Request body ceiling; reading also has a 15-second deadline |
Compose sets each service's port, HOST=0.0.0.0, ENVIRONMENT=production, and
DATA_DIR=/app/data inside the container. Task manager also uses
TASKS_DB=/app/data/tasks.db. These are service settings in
docker-compose.yml, not additional .env substitutions.
The gateway cache defaults to 300 seconds and at most 256 entries; change
CACHE_TTL_SECONDS through a service environment override if needed.
Terminate HTTPS at a reverse proxy and set MCP_ALLOWED_HOSTS to the public
hostname, e.g. knowledge.example.com. Preserve the original Host header. A
proxy on the same host can reach the loopback-published ports; a containerized
proxy can join the Compose network. Public DNS, TLS and hosting are not
provisioned here. Connect remote clients to https://<public-host>/mcp.
Host and Origin validation remain enabled on /mcp. /health is public and
reports liveness only. Rate limits use the socket peer rather than forwarded
headers: behind a proxy, clients share its quota. Caches and rate limits are
process-local, not distributed.
Static bearer tokens demonstrate service authentication. They do not implement OAuth discovery, consent, scopes, user identity or tenant isolation. Use a client that supports custom bearer headers; clients requiring OAuth need an OAuth implementation before they can connect.
- Knowledge base: create, search and version documents, then try a stale edit.
- Workflow engine: checkpoint a branching pipeline, retry a failed step, and inspect saved outputs.
- Inventory: reserve multiple SKUs atomically, retry safely, then confirm or release the reservation.
Each walkthrough includes Compose startup and a container-based client command.
Run isolated tests without starting the Compose services or mounting their data:
docker build -t mcp-server-examples:local .
docker run --rm --read-only --tmpfs /tmp:mode=1777 mcp-server-examples:local python -m unittest discover -s tests -v
docker run --rm --read-only --tmpfs /tmp:mode=1777 mcp-server-examples:local python scripts/smoke_remote.pyThe regression suite covers rollback, concurrency, retries, bounds and ingress failures. HTTP smoke tests launch all nine servers inside the test container, using temporary databases and ports, and exercise tools, clients, resources and progress. Weather calls are mocked; paid model calls are not required.
GitHub Actions also tests Windows, Linux and database persistence across container restarts. The manual validation guide covers running those host-side checks and the Docker orchestration test script.
For running servers or clients directly on your host, virtualenv setup, optional Claude agent setup and host environment variables, use MANUAL.md.
Example 01 now uses port 8101 and clients/01-hello-client.py. Replace old
command/args client entries with its Streamable HTTP URL. There are no stdio
server entry points. Existing task databases remain compatible; manual and
Compose execution use different data locations, described in the manual guide.
The shared runtime uses FastMCP.streamable_http_app() served by Uvicorn.
See the MCP Python SDK
for the underlying APIs. Progress notifications are explicitly routed to the
active POST stream for compatibility with stateless HTTP in SDK 1.28.1.