Install
$ agentstack add mcp-yawlabs-caddy-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
@yawlabs/caddy-mcp
[](https://www.npmjs.com/package/@yawlabs/caddy-mcp) [](https://opensource.org/licenses/MIT) [](https://github.com/YawLabs/caddy-mcp/stargazers)
Manage Caddy web servers from Claude Code, Cursor, and any MCP client. 18 tools + 4 resources covering every endpoint of Caddy's admin API — config, routes, reverse proxies, TLS, PKI, metrics, snapshots.
Built and maintained by Yaw Labs.
[](https://yaw.sh/mcp/install?name=Caddy&command=npx&args=-y%2C%40yawlabs%2Fcaddy-mcp&description=Manage%20Caddy%20web%20servers%20-%20config%2C%20routes%2C%20TLS%2C%20PKI&source=https%3A%2F%2Fgithub.com%2FYawLabs%2Fcaddy-mcp)
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
Why this one?
Other Caddy MCP servers wrap half the admin API and silently swallow errors. This one doesn't.
- Complete admin API coverage — every documented endpoint:
/load,/config/*,/id/*,/stop,/adapt,/pki/ca/*,/reverse_proxy/upstreams,/metrics. No placeholder tools that 404. - Safe concurrent writes — uses ETags (
If-Match) so your changes never silently overwrite someone else's. SurfacesHTTP 412 Precondition Failedas a clear message, not a cryptic error. - Safe-by-default mutations —
caddy_config_setdefaults to idempotentoverwrite(PATCH), notappend(POST). Calling twice doesn't duplicate your route. - Defensive parsing —
caddy_list_routesnever crashes on malformed config, even if routes are null, handlers are strings, or matchers are non-arrays. Regression-tested. - No leaked credentials in errors — if
CADDY_ADMIN_URLcontains a token in the path/query, the connect-failed message shows only the origin. - Fallback error surfacing — when a TLS write PATCH fails and the POST fallback also fails, both error bodies are returned so you know what actually went wrong.
- Tool annotations — every tool declares
readOnlyHint,destructiveHint, andidempotentHint, so MCP clients can skip confirmations for safe ops. - Instant startup — ships as a single bundle with two runtime deps (the MCP SDK + Zod). No 5-minute
node_modulesinstall. - Input hardening — adapter names,
@idvalues, server names, and CA ids are all regex-validated with length caps. Blocks CRLF header injection and ReDoS.
Quick start
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:
{
"mcpServers": {
"caddy": {
"command": "npx",
"args": ["-y", "@yawlabs/caddy-mcp@latest"]
}
}
}
Windows:
{
"mcpServers": {
"caddy": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@yawlabs/caddy-mcp@latest"]
}
}
}
> Why the extra step on Windows? Since Node 20, child_process.spawn cannot directly execute .cmd files (that's what npx is on Windows). Wrapping with cmd /c is 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"
Configuration
| 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 remote admin. | | CADDY_API_TOKEN | (none) | Optional Bearer token for authenticated admin endpoints. Only needed if you've configured Caddy with auth. | | CADDY_MAX_RETRIES | 2 | Number of retries on transient failures (5xx, network errors). 4xx and 412 never retry. POSTs to /config/* and /id/* also skip retry (non-idempotent appends/creates -- retrying could duplicate routes or 409 a half-applied create). 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 all admin API requests except /load (which uses CADDY_LOAD_TIMEOUT). Non-numeric, ` "Proxy api.example.com to my app on port 3000" → caddyreverseproxy({ from: "api.example.com", to: ["localhost:3000"] })
### Idempotent reverse proxy (safe to re-run from automation)
> "Make sure api.example.com points at localhost:3000, with a stable id" → caddyreverseproxy({ from: "api.example.com", to: ["localhost:3000"], id: "api-prod" }) # First call creates the route under @id="api-prod". # Subsequent calls with the same id REPLACE in place — no duplicate routes. # Refuses with a clear error if "api-prod" is already in use by a non-route # config object (TLS issuer, server, etc.) — @ids are config-global in Caddy.
### Filter Prometheus metrics
> "Just the HTTP request metrics, please" → caddymetrics({ filter: "httprequests" }) # Keeps sample lines whose metric name contains "http_requests", # plus their # HELP / # TYPE lines. Drops the rest.
### Preview a Caddyfile before applying it
> "Convert this Caddyfile to JSON so I can review it: example.com { reverseproxy localhost:8080 }" → caddyadapt({ config: "..." })
### Diagnose slow routes
> "Fetch Prometheus metrics and tell me which route is slowest" → caddy_metrics()
### Safely update a route by @id
> "Update the route with @id 'api-v2' to point to the new backend" → caddyconfigby_id({ id: "api-v2", action: "set", value: {...} }) # Uses ETags — you'll get HTTP 412 if someone else changed it first
### Atomic deploy
> "Replace the whole config with this Caddyfile" → caddyadapt({ config: "..." }) # validate first → caddyload({ config: adaptedJson }) # apply atomically
## Troubleshooting
**"Cannot connect to Caddy admin API"**
- Make sure Caddy is running. `caddy run` or `systemctl status caddy`.
- Check the admin endpoint. Default is `http://localhost:2019`. If Caddy is in Docker, use the container hostname.
- Set `CADDY_ADMIN_URL` in your MCP config `env` to match.
**"HTTP 412 Precondition Failed"**
- Someone (or something) changed the config between your read and your write.
- The cached ETag has been invalidated. Re-read the config and retry.
**"HTTP 403" on /load or /config writes**
- You have `admin.listen` or `admin.origins` restrictions set in your Caddy config, or you're missing an `Authorization` header.
- Set `CADDY_API_TOKEN` in your MCP config env if Caddy expects a Bearer token.
**Windows: MCP server doesn't start**
- Use the `cmd /c npx ...` pattern from the Quick start section. Node 20+ can't spawn `.cmd` files directly.
## Requirements
- Node.js 20+
- Caddy 2.x with admin API enabled (default: `localhost:2019`)
## Contributing
```bash
git clone https://github.com/YawLabs/caddy-mcp.git
cd caddy-mcp
npm install
npm run lint # Biome check
npm run lint:fix # Auto-fix
npm run build # tsup bundle
npm test # Vitest (230 unit tests; +8 live-Caddy integration tests gated by CADDY_MCP_INTEGRATION=1)
npm run typecheck # tsc --noEmit
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow, including release process.
License
MIT
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: YawLabs
- Source: YawLabs/caddy-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.