Skip to content

Container deployment reference

The Docker Compose example builds a generated Streamable HTTP server and runs it alongside a synthetic API. It tests the full path: CLI generation, TypeScript compilation, tool discovery, API-key injection, and an MCP tool call across the Compose network.

Run the example

Clone the repository, install Python 3.14+, uv, and Docker Compose v2, then follow the example's README. Generated files go into the directory named by MCP_CONTAINER_DIR; the generator's normal output remains unchanged.

The MCP endpoint is http://127.0.0.1:8080/mcp. The mock API is reachable only inside Compose at http://mock-api:8081. Host loopback and container service names are different network addresses: a generated server running in a container cannot reach another container through its own localhost.

Local health and readiness

HTTP servers reserve the fixed /healthz and /readyz paths, including their case and trailing-slash equivalents. GET /healthz returns 200 with {"status":"ok"} and GET /readyz returns 200 with {"status":"ready"} once the local listener is ready. A listener marked not ready returns 503 with {"status":"not_ready"}; before the listener binds, probes are unreachable. Both responses set Cache-Control: no-store.

These probes require no MCP session, tool identity, upstream credentials, or dependency availability. They use the same MCP_ALLOWED_HOSTS and MCP_ALLOWED_ORIGINS checks as the MCP endpoint. HEAD follows the GET status semantics; other methods return 405. The probes stop succeeding when the server shuts down. Readiness does not add a draining grace period or promise upstream availability.

If an existing MCP_HTTP_ENDPOINT equals or matches either reserved route, change it to a separate path such as /mcp and update clients before deploying the regenerated server. Conflicting endpoint patterns fail at startup.

Adapt the Dockerfile

Copy Dockerfile and .dockerignore into a generated project. The build stage installs dependencies and compiles TypeScript. The runtime stage contains the compiled application and production dependencies, and runs as the non-root node user. An existing package-lock.json is honored with npm ci.

Provide TARGET_API_BASE_URL and the generated AUTH_* variables as runtime environment values. The image does not copy .env, source configuration, or build logs. The example's API key is synthetic and only protects its mock API.

For HTTP servers, set MCP_HTTP_HOST=0.0.0.0 inside the container and configure MCP_ALLOWED_HOSTS and MCP_ALLOWED_ORIGINS for the client-facing address. The example publishes only to host loopback. Remote deployments also need their own TLS and MCP-client authorization setup; upstream API credentials do not authenticate incoming MCP clients.

For stdio servers, use docker run --rm -i with runtime environment variables and no HTTP port. Avoid -t, which allocates a terminal to the protocol stream.

Verification

Run bash scripts/e2e_container.sh from the repository root. It uses a unique Compose project and temporary generated directory, verifies non-root execution and .env exclusion, calls getWidget, and removes its containers and build output. The container GitHub Actions workflow runs the same check on Linux.