Skip to content

oxcodexo/mcp-launch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP Launch

A self-hosted, Docker-based stack for running MCP servers on your laptop and exposing them securely to any AI agent over the internet. New MCP servers plug in by adding a service and a single route — no changes to ngrok, Caddy, or any other part of the infrastructure.

How It Works

AI Agent
  └── https://<NGROK_DOMAIN>/<server>/mcp
        └── ngrok  →  caddy :9876
                       ├── /sandbox/*  →  sandbox-mcp:9002
                       ├── /my-tool/*  →  my-tool-mcp:9003
                       └── ...more as needed

Each MCP server runs as an isolated Docker container. Caddy sits in front and routes by path prefix. ngrok gives every MCP a stable public HTTPS URL. A shared bearer token protects all endpoints — validated by supergateway on every incoming request, before any tool is executed.

Prerequisites

Project Structure

mcp-launch/
├── docker/
│   └── sandbox/
│       └── Dockerfile        ← custom image for the sandbox MCP
├── docker-compose.yml        ← all services: caddy, ngrok, MCP servers
├── Caddyfile                 ← routing rules, one route per MCP server
├── .env                      ← secrets (gitignored)
├── .env.example              ← safe template to commit
├── .gitignore
└── README.md

Infrastructure Services

These run once and never change when you add more MCPs:

Service Port Description
caddy 9876 Reverse proxy — routes requests by path prefix to the right MCP container
ngrok 4040 Exposes Caddy to the internet at a stable HTTPS URL

MCP Servers

Currently included:

Service Endpoint Description
sandbox-mcp /sandbox/mcp A self-contained Linux environment the agent can freely operate in — run shell commands, read and write files, execute scripts, and use installed tools. Isolated from the host OS; only the mounted /workspace directory is accessible.

Adding a New MCP Server

The stack is designed to grow. To add any MCP server:

Naming convention: name your service <name>-mcp and use /<name>/* as its Caddy route prefix. The shared root (<name>) ties the service name, the route, and the public URL together. e.g. my-tool-mcp/my-tool/*https://<NGROK_DOMAIN>/my-tool/mcp

Port convention: assign each new MCP server the next available internal port, starting from 9002. sandbox-mcp uses 9002, so the next server gets 9003, then 9004, and so on. Ports are internal only (expose:, not ports:) — they never conflict with anything on your host.

1. Add the service in docker-compose.yml:

my-tool-mcp:
  image: ghcr.io/supercorp-ai/supergateway:latest
  command: >
    --stdio "npx @some-scope/my-tool-mcp"
    --outputTransport streamableHttp
    --streamableHttpPath /mcp
    --port 9003
    --bearerToken "${MCP_BEARER_TOKEN}"
  expose:
    - "9003"
  restart: unless-stopped

2. Add the route in Caddyfile:

route /my-tool/* {
    uri strip_prefix /my-tool
    reverse_proxy my-tool-mcp:9003
}

3. Restart:

docker compose up -d

Your new MCP is now live at https://<NGROK_DOMAIN>/my-tool/mcp. Nothing else changes.

Setup

1. Configure environment

cp .env.example .env
# edit .env with your values
Variable Description
MCP_BEARER_TOKEN Shared secret required by all MCP endpoints
NGROK_AUTHTOKEN From https://dashboard.ngrok.com/get-started/your-authtoken
NGROK_DOMAIN Your static ngrok domain, e.g. worthy-gorgeous-guppy.ngrok-free.app
SANDBOX_MOUNT_PATH Host directory mounted into /workspace inside the sandbox container
UID / GID Linux only. Your host user's IDs — run id -u and id -g to get them. Passed as build args so files the sandbox creates in /workspace are owned by you, not root. Mac and Windows users can leave these unset.

Getting your ngrok static domain:

  1. Log in to the ngrok dashboard
  2. Go to DomainsNew Domain — your free static domain is created instantly
  3. Copy the full domain (e.g. worthy-gorgeous-guppy.ngrok-free.app) into NGROK_DOMAIN

2. Build and start

docker compose up -d --build

3. Inspect ngrok

open http://localhost:4040

Confirm the tunnel shows online and the URL matches your NGROK_DOMAIN.

Endpoints

MCP Server Public URL
Sandbox https://<NGROK_DOMAIN>/sandbox/mcp

All requests require: Authorization: Bearer <MCP_BEARER_TOKEN>

Agent Config

{
  "mcpServers": {
    "sandbox": {
      "url": "https://<NGROK_DOMAIN>/sandbox/mcp",
      "headers": { "Authorization": "Bearer <MCP_BEARER_TOKEN>" }
    }
  }
}

Useful Commands

# Build and start
docker compose up -d --build

# Stop
docker compose down

# Tail all logs
docker compose logs -f

# Restart a single service
docker compose restart sandbox-mcp

# Pull latest images and restart
docker compose pull && docker compose up -d --build

Troubleshooting

ngrok tunnel is offline

  • Check NGROK_AUTHTOKEN is correct and not expired
  • Confirm NGROK_DOMAIN exactly matches the domain in your ngrok dashboard — including the full subdomain
  • Run docker compose logs ngrok for the raw error

Agent gets a 401 Unauthorized

  • The bearer token is enforced by supergateway inside each MCP container, not by Caddy or ngrok
  • Verify the Authorization: Bearer <token> header in your agent config matches MCP_BEARER_TOKEN in .env exactly (no extra spaces or quotes)
  • Run docker compose logs sandbox-mcp to see rejected requests

uvx or supergateway not found inside the container

  • This usually means the image wasn't rebuilt after a Dockerfile change
  • Run docker compose build sandbox-mcp then docker compose up -d

Port 9876 already in use on the host

  • Another process is using port 9876. Either stop it, or change the host port mapping in docker-compose.yml:
    ports:
      - "9877:9876"  # change the left side only

Files created by the sandbox are owned by root on the host (Linux only)

  • Set UID and GID in your .env to match your host user (id -u and id -g)
  • Rebuild: docker compose build sandbox-mcp && docker compose up -d

Security Notes

  • All endpoints are protected by a bearer token — use a strong, unique MCP_BEARER_TOKEN. The token is validated by supergateway on every request before any tool is invoked; neither Caddy nor ngrok perform token checks
  • The sandbox agent can fully read, write, and execute within /workspace only
  • Mount only what the agent needs — do not mount your home directory or sensitive paths
  • Never commit .env to git
  • Keep your ngrok domain private to limit who can reach your endpoints

License

MIT License — see LICENSE for full details.

Copyright (c) 2026 oxcodexo

About

Self-hosted Docker stack to run MCP servers locally and expose them securely to any AI agent over the internet.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors