Rename mcp-gateway -> mcp-proxy throughout

Aligns the compose service name, local config filename, and all
log/restart commands with the image and binary name. Adds an explicit
-config arg since the image CMD still defaults to the legacy
/etc/mcp-gateway path.

🏠 Remote-Dev: homespace
This commit is contained in:
Den Delimarsky 2026-05-21 06:06:15 +00:00
parent 12482fd9e2
commit 529d105a78
No known key found for this signature in database
2 changed files with 14 additions and 13 deletions

View File

@ -31,7 +31,7 @@ and runs everything else for you:
4. **Register the CA** (Console) — you upload `ca.crt`; the tunnel goes Active. 4. **Register the CA** (Console) — you upload `ca.crt`; the tunnel goes Active.
5. **Upstream** — scaffolds a verifiable FastMCP sample server, or wires up an 5. **Upstream** — scaffolds a verifiable FastMCP sample server, or wires up an
MCP server you already have. MCP server you already have.
6. **Proxy config + Compose** — writes `mcp-gateway.yaml` and a 6. **Proxy config + Compose** — writes `mcp-proxy.yaml` and a
`docker-compose.yaml` with digest-pinned images and the cloudflared agent. `docker-compose.yaml` with digest-pinned images and the cloudflared agent.
7. **Start and verify** — brings the stack up and checks the proxy and tunnel 7. **Start and verify** — brings the stack up and checks the proxy and tunnel
logs. logs.
@ -87,7 +87,7 @@ A small container stack on your host:
| Container | Role | | Container | Role |
|---|---| |---|---|
| **mcp-gateway** | Anthropic's proxy. Terminates inner TLS with a cert you control, validates upstream IPs, routes by hostname. | | **mcp-proxy** | Anthropic's proxy. Terminates inner TLS with a cert you control, validates upstream IPs, routes by hostname. |
| **cloudflared** | The tunnel agent. Outbound-only to the Anthropic tunnel edge; shares the proxy's network namespace. | | **cloudflared** | The tunnel agent. Outbound-only to the Anthropic tunnel edge; shares the proxy's network namespace. |
| **hello-mcp** *(optional)* | A FastMCP sample server, only if you don't have an MCP server to expose yet. | | **hello-mcp** *(optional)* | A FastMCP sample server, only if you don't have an MCP server to expose yet. |

View File

@ -29,7 +29,7 @@ default to `./mcp-tunnel`. Refer to it below as `$DIR`.
A container stack on the user's machine: A container stack on the user's machine:
- **mcp-gateway** — Anthropic's proxy. Terminates the inner TLS handshake using - **mcp-proxy** — Anthropic's proxy. Terminates the inner TLS handshake using
a certificate the user controls, validates upstream IPs, routes by hostname. a certificate the user controls, validates upstream IPs, routes by hostname.
- **cloudflared** — the tunnel agent. Outbound-only connection to the Anthropic - **cloudflared** — the tunnel agent. Outbound-only connection to the Anthropic
tunnel edge; shares the proxy's network namespace. tunnel edge; shares the proxy's network namespace.
@ -209,7 +209,7 @@ if __name__ == "__main__":
## Step 7 — Proxy config ## Step 7 — Proxy config
Write `$DIR/config/mcp-gateway.yaml`. `tunnel_domain` is **required** (the Write `$DIR/config/mcp-proxy.yaml`. `tunnel_domain` is **required** (the
proxy strips it from the incoming hostname to find the subdomain in `routes`). proxy strips it from the incoming hostname to find the subdomain in `routes`).
`routes` is a **flat map** subdomain → upstream URL, *not* a list: `routes` is a **flat map** subdomain → upstream URL, *not* a list:
@ -234,10 +234,11 @@ Write `$DIR/docker-compose.yaml`. Images are pinned by digest:
```yaml ```yaml
services: services:
mcp-gateway: mcp-proxy:
image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:6b9adedbf2763143ec72f106ecaf0ce7fd3294e89b208f54a1db97a33d14c5ba image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:6b9adedbf2763143ec72f106ecaf0ce7fd3294e89b208f54a1db97a33d14c5ba
command: ["-config", "/etc/mcp-proxy/config.yaml"]
volumes: volumes:
- ./config/mcp-gateway.yaml:/etc/mcp-gateway/config.yaml:ro - ./config/mcp-proxy.yaml:/etc/mcp-proxy/config.yaml:ro
- ./data:/data:ro - ./data:/data:ro
restart: unless-stopped restart: unless-stopped
@ -246,13 +247,13 @@ services:
command: tunnel --no-autoupdate run --url http://localhost:8080 command: tunnel --no-autoupdate run --url http://localhost:8080
environment: environment:
- TUNNEL_TOKEN - TUNNEL_TOKEN
network_mode: "service:mcp-gateway" network_mode: "service:mcp-proxy"
restart: unless-stopped restart: unless-stopped
``` ```
`--url http://localhost:8080` is **required** in the manual flow: no ingress `--url http://localhost:8080` is **required** in the manual flow: no ingress
rules are pushed server-side, so without it cloudflared 503s every request. rules are pushed server-side, so without it cloudflared 503s every request.
`network_mode: "service:mcp-gateway"` shares the proxy's netns so `network_mode: "service:mcp-proxy"` shares the proxy's netns so
`localhost:8080` reaches it. `environment: - TUNNEL_TOKEN` (no value) passes `localhost:8080` reaches it. `environment: - TUNNEL_TOKEN` (no value) passes
the variable through from `.env`. the variable through from `.env`.
@ -281,7 +282,7 @@ this quickstart keeps it minimal for fast local testing.)
```bash ```bash
cd "$DIR" && docker compose up -d cd "$DIR" && docker compose up -d
sleep 5 sleep 5
docker compose logs mcp-gateway | grep -i "route configured" docker compose logs mcp-proxy | grep -i "route configured"
docker compose logs cloudflared | grep -i "Registered tunnel connection" docker compose logs cloudflared | grep -i "Registered tunnel connection"
``` ```
@ -327,11 +328,11 @@ it the same as for any other MCP server.
| Symptom | Cause | Fix | | Symptom | Cause | Fix |
|---|---|---| |---|---|---|
| Caller sees HTTP 500; cloudflared logs `No ingress rules were defined` | cloudflared has no local target | Ensure `--url http://localhost:8080` and `network_mode: "service:mcp-gateway"` are both present, then `docker compose up -d` | | Caller sees HTTP 500; cloudflared logs `No ingress rules were defined` | cloudflared has no local target | Ensure `--url http://localhost:8080` and `network_mode: "service:mcp-proxy"` are both present, then `docker compose up -d` |
| Proxy exits `cannot unmarshal !!seq into map[string]string` | `routes` written as a YAML list | Use `routes: { name: http://host:port }`, not a list of objects | | Proxy exits `cannot unmarshal !!seq into map[string]string` | `routes` written as a YAML list | Use `routes: { name: http://host:port }`, not a list of objects |
| Proxy exits `open /data/tls.key: permission denied` | key is `0600`, proxy runs non-root | `chmod 644 data/tls.key` | | Proxy exits `open /data/tls.key: permission denied` | key is `0600`, proxy runs non-root | `chmod 644 data/tls.key` |
| Proxy logs `no route for host` (caller gets `502 No route configured for host`) | `tunnel_domain` missing or wrong | Set it to the exact domain on the tunnel detail page; then **restart the proxy** (next row) | | Proxy logs `no route for host` (caller gets `502 No route configured for host`) | `tunnel_domain` missing or wrong | Set it to the exact domain on the tunnel detail page; then **restart the proxy** (next row) |
| Edited config but nothing changed | proxy does **not** hot-reload `config.yaml` (only `tls.cert_file`) | `docker compose restart mcp-gateway` — `up -d` alone won't recreate it on a file-content change | | Edited config but nothing changed | proxy does **not** hot-reload `config.yaml` (only `tls.cert_file`) | `docker compose restart mcp-proxy` — `up -d` alone won't recreate it on a file-content change |
| `tls handshake failed ... unknown certificate authority` | CA not registered/revoked on this tunnel | Re-upload `data/ca.crt` in the Console (Step 5) | | `tls handshake failed ... unknown certificate authority` | CA not registered/revoked on this tunnel | Re-upload `data/ca.crt` in the Console (Step 5) |
| `tls handshake failed ... bad certificate` | server cert SAN ≠ `*.<tunnel-domain>`, or expired | Regenerate the server cert (Step 4) with the correct `TUNNEL_DOMAIN` | | `tls handshake failed ... bad certificate` | server cert SAN ≠ `*.<tunnel-domain>`, or expired | Regenerate the server cert (Step 4) with the correct `TUNNEL_DOMAIN` |
| `IP validation failed: <ip> is not a private address` | upstream resolves outside RFC1918 (e.g. `127.0.0.1`, public IP) | Run the upstream as a Compose service on the proxy's network; or narrow `upstream.allowed_ips` deliberately (avoid `0.0.0.0/0` outside local testing) | | `IP validation failed: <ip> is not a private address` | upstream resolves outside RFC1918 (e.g. `127.0.0.1`, public IP) | Run the upstream as a Compose service on the proxy's network; or narrow `upstream.allowed_ips` deliberately (avoid `0.0.0.0/0` outside local testing) |
@ -341,7 +342,7 @@ it the same as for any other MCP server.
| `curl https://<proxy>:8080` fails `wrong version number` | expected — listener is plaintext WS, TLS is inside the WS stream | Don't curl the proxy directly; verify via Managed Agent or Messages API | | `curl https://<proxy>:8080` fails `wrong version number` | expected — listener is plaintext WS, TLS is inside the WS stream | Don't curl the proxy directly; verify via Managed Agent or Messages API |
`docker compose logs cloudflared` (token/edge reachability) and `docker compose logs cloudflared` (token/edge reachability) and
`docker compose logs mcp-gateway` (config/cert/routing) are the two primary `docker compose logs mcp-proxy` (config/cert/routing) are the two primary
diagnostics. Check the outbound connection first, then the inner TLS handshake, diagnostics. Check the outbound connection first, then the inner TLS handshake,
then upstream routing. See then upstream routing. See
[Troubleshooting](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/troubleshooting) [Troubleshooting](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/troubleshooting)
@ -355,7 +356,7 @@ for additional cases.
- **Cert renewal:** the server cert is valid 90 days. Re-sign with the same CA - **Cert renewal:** the server cert is valid 90 days. Re-sign with the same CA
(the registered CA doesn't change) and replace `data/tls.crt`; the proxy (the registered CA doesn't change) and replace `data/tls.crt`; the proxy
polls and reloads it, no restart needed. polls and reloads it, no restart needed.
- **Config changes always need** `docker compose restart mcp-gateway`. - **Config changes always need** `docker compose restart mcp-proxy`.
## Wrap up ## Wrap up