MCP server for managing Caddy web servers via the admin API
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
One-click editor setup isnβt available for this listing yet β we donβt have a confirmed install command, and weβd rather show nothing than point your editor at the wrong package or host. Follow the projectβs own setup instructions, linked above.
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
Manage Caddy web servers from Claude Code, Cursor, and any MCP client. 18 tools + 4 resources covering every endpoint in Caddy's admin API reference β config, routes, reverse proxies, TLS, PKI, metrics, snapshots.
Built and maintained by Yaw Labs.
Other Caddy MCP servers wrap half the admin API and silently swallow errors. This one doesn't.
/load, /config/*, /id/*, /stop, /adapt, /pki/ca/*, /reverse_proxy/upstreams, /metrics. No placeholder tools that 404. Caddy's Go runtime debug endpoints (/debug/pprof/*, /debug/vars) are deliberately not wrapped β for leak trends use caddy_metrics with filter: "go_goroutines" or "go_memstats", which come from the same admin registry; for stack dumps, CPU profiles and traces, curl the admin endpoint directly (Caddy profiling docs).If-Match) so your changes never silently overwrite someone else's. Surfaces HTTP 412 Precondition Failed as a clear message, not a cryptic error.caddy_config_set defaults to idempotent overwrite (PATCH), not append (POST). Calling twice doesn't duplicate your route. A write to the config root β which replaces the entire config, admin endpoint included β is refused without confirm=true and snapshotted first, like caddy_load.caddy_list_routes never crashes on malformed config, even if routes are null, handlers are strings, or matchers are non-arrays. Regression-tested.CADDY_ADMIN_URL contains a token in the path/query, the connect-failed message shows only the origin.readOnlyHint, destructiveHint, and idempotentHint, so MCP clients can skip confirmations for safe ops.node_modules install.@id values, server names, and CA ids are all regex-validated with length caps. Blocks CRLF header injection and ReDoS.1. Enable the Caddy admin API
Caddy ships with the admin API enabled on localhost:2019 by default. If you're running Caddy in Docker or on a remote host, expose it via CADDY_ADMIN_URL.
2. Create .mcp.json in your project root
macOS / Linux / WSL:
Windows:
Why the extra step on Windows? Since Node 20,
child_process.spawncannot directly execute.cmdfiles (that's whatnpxis on Windows). Wrapping withcmd /cis the standard workaround. This file is safe to commit β it contains no secrets.
3. Restart and approve
Restart Claude Code (or your MCP client) and approve the Caddy MCP server when prompted.
That's it. Now ask your AI assistant:
"Proxy api.local to localhost:3000"
"What routes are configured on srv0?"
"Show me the Prometheus metrics"
| Environment variable | Default | Description |
|---|---|---|
CADDY_ADMIN_URL | http://localhost:2019 | Caddy admin API URL. Set to http://caddy:2019 inside Docker, or an https URL for an admin endpoint behind a TLS-terminating reverse proxy β see Troubleshooting for the Host / Origin rules Caddy applies to anything that is not its own loopback address. Caddy's native remote admin listener (admin.remote, default :2021) is not supported: it requires a TLS client certificate, which caddy-mcp does not present. Also accepts a unix socket, in either unix:///var/run/caddy-admin.sock or Caddy's own unix//var/run/caddy-admin.sock spelling β see below. |
CADDY_API_TOKEN | (none) | Optional Bearer token, sent as Authorization: Bearer <token> on every request. Caddy's admin API has no token auth of its own and ignores this header β it matters only to an authenticating proxy in front of the admin endpoint, so leave it unset when caddy-mcp reaches Caddy directly. If the header does arrive at the admin listener, Caddy 2.0 through 2.11.2 writes it in clear into the admin.api "received request" log line, at INFO β on every path except /metrics, which has logged at DEBUG since 2.2.1. Run Caddy 2.11.3 or later, which logs it as REDACTED, or have the proxy strip the header once it has authenticated (Caddy: header_up -Authorization; nginx: proxy_set_header Authorization "";). |
CADDY_MCP_SNAPSHOT_DIR | (none) | Directory for persisting caddy_revert snapshots. Unset, snapshots live in memory only and are lost when this server restarts. Snapshots are full Caddy configs and can contain secrets, so the location is opt-in rather than defaulted. |
CADDY_MAX_RETRIES | 2 | Number of retries on transient failures: network errors, and 502/503/504 (which only a proxy in front of Caddy sends). Caddy's own 500s are deterministic rejections and never retry, nor do 4xx and 412. Requests a replay could change the outcome of also skip retry: POSTs to /config/* and /id/* (they append, or replace an existing key -- retrying could duplicate routes), and a PUT or DELETE at an array index such as .../routes/0 (a replay would insert a second route, or remove the one that slid into that index), including a PUT to a bare /id/<id>, which Caddy resolves to the identified element's array index. Those match however the path is spelled β with trailing slashes, or with the trailing /... segment Caddy strips before it picks a method, so .../routes/0/... and PUT /id/<id>/... are covered too. A config change whose timeout fired is never retried (see CADDY_LOAD_TIMEOUT). A refused connection retries for every method, since nothing was sent. POSTs to /load, /adapt, /stop still retry. Hard-capped at 5; values above the cap log a one-time stderr notice so the clamp is visible. Set to 0 to disable. |
CADDY_TIMEOUT | 10000 | Timeout in ms for admin API requests that do not change the config: GETs, /adapt, /stop, PKI, upstreams and metrics. Config changes use CADDY_LOAD_TIMEOUT. Non-numeric, <= 0, or fractional values below 1ms fall back to the default. |
CADDY_LOAD_TIMEOUT | 55000 | Timeout in ms for every request that changes the config: POST /load, and every POST/PUT/PATCH/DELETE under /config/* and /id/*. Each is a full synchronous reload inside Caddy, which can legitimately run long -- Caddy sleeps through apps.http.shutdown_delay inside the reload whenever a change closes a listener, and a change can wait behind another reload. A timeout here is never retried: Caddy keeps applying a change after the client gives up, so the error says the outcome is unknown and to re-read the config before retrying (caddy_load and caddy_revert keep their snapshot in that case). Keep it below your MCP client's request timeout (60 s by default in the MCP SDK), or that error arrives after the client has given up and is never shown; the default sits 5 s under it. Non-numeric, <= 0, or fractional values below 1ms fall back to the default. |
Unix socket admin endpoints:
Caddy's recommended hardening is to move the admin API off a loopback port and onto a unix socket, where access is governed by filesystem permissions:
Point CADDY_ADMIN_URL at the same path (unix:///var/run/caddy-admin.sock)
and requests are sent over the socket instead of TCP. The process running
caddy-mcp needs read/write permission on the socket file. Leave
CADDY_API_TOKEN unset here unless an authenticating proxy actually listens on
that socket: over a unix path caddy-mcp is usually talking to Caddy's own
socket, where the token does nothing β and, before Caddy 2.11.3, is logged in
clear.
Alternate MCP clients:
| Client | Config file |
|---|---|
| Claude Code | .mcp.json (project root) or ~/.claude.json (global) |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code | .vscode/mcp.json |
Use the same JSON block shown above in any of these.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/caddy-mcp-server)<a href="https://allmcps.com/mcp/caddy-mcp-server"><img src="https://allmcps.com/api/badge/caddy-mcp-server?style=directory" alt="Caddy MCP Server on AllMCPs" /></a>