On this page
Everything you need to install, operate, and administer Roundhouse — from docker compose up to a fleet of deployed MCP servers.
Screenshots in this guide are shown in dark theme. A light-theme set lives under
docs/screenshots/light/. Seedocs/capture/README.mdfor how to re-capture.
Getting started#
Roundhouse runs entirely on your own hardware. The only requirements are Docker and Docker Compose — there is no cloud dependency, no external service to sign up for, and no telemetry.
Install#
git clone https://github.com/Karmatek-Consulting-LLC/roundhouse.git
cd roundhouse
cp .env.example .env
docker compose up -dWhen the API logs print Application startup complete, the platform is live at http://localhost:3080.
To stop the platform:
docker compose down # preserve database + spec files
docker compose down -v # wipe everythingSign in#
Roundhouse uses email/password sign-in. The first admin is created from the ADMIN_EMAIL and ADMIN_PASSWORD environment variables when the API boots (defaults: [email protected] / admin — change them in .env before first boot, or from the Users page after).

Connecting clients#
Every deployed server gets a stable URL like http://localhost:3080/s/my-server/mcp. Traefik routes MCP clients straight to the spawned container — the platform never proxies MCP traffic on the hot path.
Callers authenticate with a bearer token minted on the server's Auth tab (see Auth below).
Claude Desktop#
Add to claude_desktop_config.json:
{
"mcpServers": {
"my-server": {
"url": "http://localhost:3080/s/my-server/mcp",
"headers": {
"Authorization": "Bearer <token from the server's Auth panel>"
}
}
}
}Claude Code#
claude mcp add my-server \
--url http://localhost:3080/s/my-server/mcp \
--header "Authorization: Bearer <token>"Any other MCP client that speaks streamable HTTP works the same way: point it at the server URL and pass the token in the Authorization header.
Dashboard#
The dashboard is the home view after sign-in. It surfaces fleet-wide health (running/stopped/errored counts), recent call volume, the busiest servers, and a rolling activity timeline.

Servers list#
The full inventory of MCP servers you can see. Each row shows the server's deploy mode (structured or code), live status, recent call count, and quick actions.

Creating a server#
The Create button opens a dialog with a tab for each way a server can be authored.
Structured#
The default: an empty spec-managed server. Primitives, packages, env vars, and middleware are managed through the UI; Roundhouse owns the Dockerfile.

Code-first#
You supply a complete server.py (FastMCP). Roundhouse still owns the Dockerfile and platform middleware, but the primitive surface is hidden in favour of a full source editor.

From Git#
Clone a repo that declares its dependencies in roundhouse.json. The imported server registers as not_deployed — Roundhouse seeds the environment variables declared by the manifest, populates pip and apt packages, and waits for an operator to fill in secrets before the first deploy.

Import#
Paste an exported spec JSON (from another Roundhouse instance, or from POST /api/servers/{name}/export) to clone a server's configuration verbatim.

The server editor#
Selecting a server opens the two-pane editor. The left rail is the server's table of contents — primitives, configuration, and operational tabs. The right pane is whichever section you've selected.
Overview#
The overview is the editor's home base: description, replicas, resource limits, and the lifecycle controls (Start, Stop, Redeploy, Delete, plus Update from Git for repos imported via from-git).

Primitives#
Structured servers expose tools, resources, resource templates, and prompts. Each primitive is edited in-place: parameters, body, and optional middleware overrides (rate limit, max concurrency).
Tool#

Resource#

Prompt#

Adding a new primitive#

Imports and globals#
Any free-form Python imports or module-level globals that should appear in the generated server.py.

PyPI packages#
Pip dependencies. They are pinned into the generated Dockerfile and installed at build time.

APT packages#
OS-level packages installed via apt-get in the build. Use for native toolchains a Python wheel needs.

Environment variables#
Per-server env vars (with optional encrypted-at-rest secrets) and global imports. Changes save instantly; the redeploy banner surfaces because the new value only takes effect on the next container restart.

Auth (server tokens)#
Bearer tokens that callers present in the Authorization header. Per-token scopes can lock individual primitives down to specific token holders.

Assets#
Arbitrary files that get baked into the image under /app/assets/. Useful for prompt templates, large JSON fixtures, or any read-only data your tools reference at runtime.

Usage#
Per-primitive call counts, p50/p95/p99 latency, error rate, and the busiest client tokens. Sampled in-process by the platform middleware and surfaced without an extra metrics backend — no Prometheus, no Grafana, no add-on agent. Drilling into a server's usage tab is how you find latency regressions or the one tool that's getting hammered.

A busier server (crew-scheduling, which carries the heaviest call volume in the demo fleet) makes the chart variety obvious:

Logs#
Streams stdout/stderr from the server container via Server-Sent Events.
For spec-based servers, the Level dropdown writes the LOG_LEVEL environment variable on the spec; the platform middleware reads it and configures stdlib logging accordingly. At DEBUG, the middleware also emits a start record (with arguments) for every tool/resource/prompt call. Failed calls promote the end-of-call record to WARNING. The dropdown is hidden for code-mode servers, since they own their own logging surface.

Source (code mode)#
For servers in code mode, the editor replaces the primitive surface with a full server.py editor (CodeMirror, Python syntax highlighting). The platform still controls the Dockerfile.

Code-mode servers still expose every operational tab — env vars, logs, usage — so the operator surface is unchanged.

Stopped server#
A stopped server keeps its spec on disk; restarting it reuses the cached image without a rebuild.

Platform administration#
Roundhouse ships with a small set of platform admin views.
Platform settings#
Host configuration: external hostname, Docker registry credentials, custom CA bundle for outbound TLS, and platform-wide env defaults that get imported into spec-based servers.

Users#
User accounts with role assignment. The seeded demo includes a handful of operators alongside the platform admin; superadmins can reset passwords and revoke access from this page.

Teams#
Teams group users into shared-access bundles. A team can own one or more servers, and any team member inherits access to those servers without needing per-server token grants. The seeded demo creates three railroad departments — Operations, Maintenance of Way, and Revenue Service — each with its own member roster.

Audit log#
Every state-mutating action — server create/delete, env-var change, token rotation — is recorded with the acting user, target, and a structured detail payload.

Configuration reference#
Everything reads from environment variables — see .env.example for the full list. The knobs you'll actually touch:
| Variable | Purpose |
|---|---|
APP_KEY | base64:<32 random bytes> — encrypts runtime tokens at rest. Generate with printf 'base64:%s' "$(openssl rand -base64 32)". |
MCP_BASE_URL | The URL clients see for spawned servers. Set this when deploying past localhost. |
MCP_DOCKER_HOST | /var/run/docker.sock (default) or tcp://socket-proxy:2375 for hardened Swarm setups. |
MAX_MCP_SERVER_REPLICAS | Per-server replica cap (Swarm only). |
ADMIN_EMAIL / ADMIN_PASSWORD | First-boot seed user. Ignored once a user exists. |
Behind a corporate TLS-inspecting proxy#
If your network MITMs outbound TLS during image builds, drop the proxy's CA bundle at api/docker/corp-ca.crt before running docker compose build. The Dockerfiles pick it up automatically; the file is gitignored so it can't be committed by accident. In any other environment, leave it absent and the build skips that step.
Deployment modes#
| Mode | File | Best for |
|---|---|---|
| Local / single-host | docker-compose.yml | Trying it out, small teams, hosting on one box. Single Docker daemon, Traefik on the same socket. |
| Docker Swarm | docker-stack.yml | Multi-node, scoped socket proxies. Designed to sit behind a cluster ingress that terminates TLS. |
Both modes are fully self-contained — well suited to air-gapped and restricted networks where outbound connectivity and cloud integrations aren't an option.