@yawlabs/caddy-mcp 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +276 -246
- package/bin/caddy-mcp.mjs +334 -175
- package/dist/index.js +196 -54
- package/dist/server.js +196 -54
- package/dist/snapshots.d.ts +10 -0
- package/package.json +82 -82
package/README.md
CHANGED
|
@@ -1,246 +1,276 @@
|
|
|
1
|
-
# @yawlabs/caddy-mcp
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@yawlabs/caddy-mcp)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/YawLabs/caddy-mcp/stargazers)
|
|
6
|
-
|
|
7
|
-
**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.
|
|
8
|
-
|
|
9
|
-
Built and maintained by [Yaw Labs](https://yaw.sh).
|
|
10
|
-
|
|
11
|
-
[](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)
|
|
12
|
-
|
|
13
|
-
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
|
|
14
|
-
|
|
15
|
-
## Why this one?
|
|
16
|
-
|
|
17
|
-
Other Caddy MCP servers wrap half the admin API and silently swallow errors. This one doesn't.
|
|
18
|
-
|
|
19
|
-
- **Complete admin API coverage** — every documented endpoint: `/load`, `/config/*`, `/id/*`, `/stop`, `/adapt`, `/pki/ca/*`, `/reverse_proxy/upstreams`, `/metrics`. No placeholder tools that 404.
|
|
20
|
-
- **Safe concurrent writes** — uses ETags (`If-Match`) so your changes never silently overwrite someone else's. Surfaces `HTTP 412 Precondition Failed` as a clear message, not a cryptic error.
|
|
21
|
-
- **Safe-by-default mutations** — `caddy_config_set` defaults to idempotent `overwrite` (PATCH), not `append` (POST). Calling twice doesn't duplicate your route.
|
|
22
|
-
- **Defensive parsing** — `caddy_list_routes` never crashes on malformed config, even if routes are null, handlers are strings, or matchers are non-arrays. Regression-tested.
|
|
23
|
-
- **No leaked credentials in errors** — if `CADDY_ADMIN_URL` contains a token in the path/query, the connect-failed message shows only the origin.
|
|
24
|
-
- **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.
|
|
25
|
-
- **Tool annotations** — every tool declares `readOnlyHint`, `destructiveHint`, and `idempotentHint`, so MCP clients can skip confirmations for safe ops.
|
|
26
|
-
- **Instant startup** — ships as a single bundle with two runtime deps (the MCP SDK + Zod). No 5-minute `node_modules` install.
|
|
27
|
-
- **Input hardening** — adapter names, `@id` values, server names, and CA ids are all regex-validated with length caps. Blocks CRLF header injection and ReDoS.
|
|
28
|
-
|
|
29
|
-
## Quick start
|
|
30
|
-
|
|
31
|
-
**1. Enable the Caddy admin API**
|
|
32
|
-
|
|
33
|
-
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`.
|
|
34
|
-
|
|
35
|
-
**2. Create `.mcp.json` in your project root**
|
|
36
|
-
|
|
37
|
-
macOS / Linux / WSL:
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
{
|
|
41
|
-
"mcpServers": {
|
|
42
|
-
"caddy": {
|
|
43
|
-
"command": "npx",
|
|
44
|
-
"args": ["-y", "@yawlabs/caddy-mcp@latest"]
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Windows:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"mcpServers": {
|
|
55
|
-
"caddy": {
|
|
56
|
-
"command": "cmd",
|
|
57
|
-
"args": ["/c", "npx", "-y", "@yawlabs/caddy-mcp@latest"]
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
> **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.
|
|
64
|
-
|
|
65
|
-
**3. Restart and approve**
|
|
66
|
-
|
|
67
|
-
Restart Claude Code (or your MCP client) and approve the Caddy MCP server when prompted.
|
|
68
|
-
|
|
69
|
-
That's it. Now ask your AI assistant:
|
|
70
|
-
|
|
71
|
-
> "Proxy api.local to localhost:3000"
|
|
72
|
-
>
|
|
73
|
-
> "What routes are configured on srv0?"
|
|
74
|
-
>
|
|
75
|
-
> "Show me the Prometheus metrics"
|
|
76
|
-
|
|
77
|
-
## Configuration
|
|
78
|
-
|
|
79
|
-
| Environment variable | Default | Description |
|
|
80
|
-
|---|---|---|
|
|
81
|
-
| `CADDY_ADMIN_URL` | `http://localhost:2019` | Caddy admin API URL. Set to `http://caddy:2019` inside Docker, or an https URL for remote admin. |
|
|
82
|
-
| `CADDY_API_TOKEN` | (none) | Optional Bearer token for authenticated admin endpoints. Only needed if you've configured Caddy with auth. |
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- **
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- **
|
|
125
|
-
- **
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- **
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
- `caddy://
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
###
|
|
187
|
-
|
|
188
|
-
```
|
|
189
|
-
> "
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
1
|
+
# @yawlabs/caddy-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@yawlabs/caddy-mcp)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/YawLabs/caddy-mcp/stargazers)
|
|
6
|
+
|
|
7
|
+
**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.
|
|
8
|
+
|
|
9
|
+
Built and maintained by [Yaw Labs](https://yaw.sh).
|
|
10
|
+
|
|
11
|
+
[](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)
|
|
12
|
+
|
|
13
|
+
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
|
|
14
|
+
|
|
15
|
+
## Why this one?
|
|
16
|
+
|
|
17
|
+
Other Caddy MCP servers wrap half the admin API and silently swallow errors. This one doesn't.
|
|
18
|
+
|
|
19
|
+
- **Complete admin API coverage** — every documented endpoint: `/load`, `/config/*`, `/id/*`, `/stop`, `/adapt`, `/pki/ca/*`, `/reverse_proxy/upstreams`, `/metrics`. No placeholder tools that 404.
|
|
20
|
+
- **Safe concurrent writes** — uses ETags (`If-Match`) so your changes never silently overwrite someone else's. Surfaces `HTTP 412 Precondition Failed` as a clear message, not a cryptic error.
|
|
21
|
+
- **Safe-by-default mutations** — `caddy_config_set` defaults to idempotent `overwrite` (PATCH), not `append` (POST). Calling twice doesn't duplicate your route.
|
|
22
|
+
- **Defensive parsing** — `caddy_list_routes` never crashes on malformed config, even if routes are null, handlers are strings, or matchers are non-arrays. Regression-tested.
|
|
23
|
+
- **No leaked credentials in errors** — if `CADDY_ADMIN_URL` contains a token in the path/query, the connect-failed message shows only the origin.
|
|
24
|
+
- **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.
|
|
25
|
+
- **Tool annotations** — every tool declares `readOnlyHint`, `destructiveHint`, and `idempotentHint`, so MCP clients can skip confirmations for safe ops.
|
|
26
|
+
- **Instant startup** — ships as a single bundle with two runtime deps (the MCP SDK + Zod). No 5-minute `node_modules` install.
|
|
27
|
+
- **Input hardening** — adapter names, `@id` values, server names, and CA ids are all regex-validated with length caps. Blocks CRLF header injection and ReDoS.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
**1. Enable the Caddy admin API**
|
|
32
|
+
|
|
33
|
+
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`.
|
|
34
|
+
|
|
35
|
+
**2. Create `.mcp.json` in your project root**
|
|
36
|
+
|
|
37
|
+
macOS / Linux / WSL:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"caddy": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@yawlabs/caddy-mcp@latest"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Windows:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"caddy": {
|
|
56
|
+
"command": "cmd",
|
|
57
|
+
"args": ["/c", "npx", "-y", "@yawlabs/caddy-mcp@latest"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> **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.
|
|
64
|
+
|
|
65
|
+
**3. Restart and approve**
|
|
66
|
+
|
|
67
|
+
Restart Claude Code (or your MCP client) and approve the Caddy MCP server when prompted.
|
|
68
|
+
|
|
69
|
+
That's it. Now ask your AI assistant:
|
|
70
|
+
|
|
71
|
+
> "Proxy api.local to localhost:3000"
|
|
72
|
+
>
|
|
73
|
+
> "What routes are configured on srv0?"
|
|
74
|
+
>
|
|
75
|
+
> "Show me the Prometheus metrics"
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
| Environment variable | Default | Description |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `CADDY_ADMIN_URL` | `http://localhost:2019` | Caddy admin API URL. Set to `http://caddy:2019` inside Docker, or an https URL for remote admin. 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. |
|
|
82
|
+
| `CADDY_API_TOKEN` | (none) | Optional Bearer token for authenticated admin endpoints. Only needed if you've configured Caddy with auth. |
|
|
83
|
+
| `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. |
|
|
84
|
+
| `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. |
|
|
85
|
+
| `CADDY_TIMEOUT` | `10000` | Timeout in ms for all admin API requests except `/load` (which uses `CADDY_LOAD_TIMEOUT`). Non-numeric, `<= 0`, or fractional values below 1ms fall back to the default. |
|
|
86
|
+
| `CADDY_LOAD_TIMEOUT` | `60000` | Timeout in ms for the `/load` endpoint; raise for ACME-heavy bring-ups where provisioning many certificates can exceed the default. Non-numeric, `<= 0`, or fractional values below 1ms fall back to the default. |
|
|
87
|
+
|
|
88
|
+
**Unix socket admin endpoints:**
|
|
89
|
+
|
|
90
|
+
Caddy's recommended hardening is to move the admin API off a loopback port and
|
|
91
|
+
onto a unix socket, where access is governed by filesystem permissions:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
{
|
|
95
|
+
admin unix//var/run/caddy-admin.sock
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Point `CADDY_ADMIN_URL` at the same path (`unix:///var/run/caddy-admin.sock`)
|
|
100
|
+
and requests are sent over the socket instead of TCP. The process running
|
|
101
|
+
caddy-mcp needs read/write permission on the socket file. `CADDY_API_TOKEN`
|
|
102
|
+
still applies if you have auth in front of the endpoint.
|
|
103
|
+
|
|
104
|
+
**Alternate MCP clients:**
|
|
105
|
+
|
|
106
|
+
| Client | Config file |
|
|
107
|
+
|---|---|
|
|
108
|
+
| Claude Code | `.mcp.json` (project root) or `~/.claude.json` (global) |
|
|
109
|
+
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) |
|
|
110
|
+
| Cursor | `~/.cursor/mcp.json` |
|
|
111
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
112
|
+
| VS Code | `.vscode/mcp.json` |
|
|
113
|
+
|
|
114
|
+
Use the same JSON block shown above in any of these.
|
|
115
|
+
|
|
116
|
+
## Tools
|
|
117
|
+
|
|
118
|
+
### Config management (6)
|
|
119
|
+
|
|
120
|
+
- **caddy_config_get** — Read config at any JSON path (or the full config).
|
|
121
|
+
- **caddy_config_set** — Write config at a path. Modes: `overwrite` (PATCH, default, idempotent), `append` (POST), `insert` (PUT, for array positions).
|
|
122
|
+
- **caddy_config_delete** — Delete config at a path. Requires `confirm=true` (deleting a parent path also removes every descendant).
|
|
123
|
+
- **caddy_config_by_id** — Get/set/delete config by `@id` tag — much easier than navigating deep paths. The `delete` action requires `confirm=true`.
|
|
124
|
+
- **caddy_load** — Replace the entire config atomically. 60-second timeout for cert provisioning. Auto-snapshots the prior config.
|
|
125
|
+
- **caddy_revert** — Manage config snapshots for rollback. Actions: `list`, `save`, `apply` (confirm-gated). In-memory, last 10.
|
|
126
|
+
|
|
127
|
+
### Route operations (4)
|
|
128
|
+
|
|
129
|
+
- **caddy_reverse_proxy** — Add a reverse proxy in one call: `from='api.local' to=['localhost:3000']`. Pass an optional `id` for idempotent writes — repeat calls replace the route in place instead of duplicating.
|
|
130
|
+
- **caddy_add_route** — Add a route with full match/handle control (any Caddy handler).
|
|
131
|
+
- **caddy_remove_route** — Remove a route by `@id` (preferred) or by index. Requires `confirm=true`.
|
|
132
|
+
- **caddy_list_routes** — Human-readable route summary. Defensive: never crashes on weird config.
|
|
133
|
+
|
|
134
|
+
### TLS & config conversion (2)
|
|
135
|
+
|
|
136
|
+
- **caddy_tls** — Check or set TLS settings: ACME email, ACME CA URL. PATCH first; on a fresh install, POSTs a minimal config. On an existing config it deep-merges into the issuer path and PUTs the result back, preserving siblings (custom certs, `on_demand`, additional policies). Refuses with a shape-specific error if the existing structure is unexpected — never clobbers.
|
|
137
|
+
- **caddy_adapt** — Convert a config in any registered adapter format to Caddy JSON without applying it. `caddyfile` (built-in, default) plus any adapter module compiled into your Caddy binary — e.g., `nginx` ([caddy-nginx-adapter](https://github.com/caddyserver/nginx-adapter)), `yaml` ([caddy-yaml](https://github.com/abiosoft/caddy-yaml)). Great for previewing or porting from existing configs.
|
|
138
|
+
|
|
139
|
+
### Server operations (6)
|
|
140
|
+
|
|
141
|
+
- **caddy_status** — Connectivity check + config summary (server count, routes, TLS mode).
|
|
142
|
+
- **caddy_list_servers** — List all HTTP servers with names, addresses, route counts, and TLS status.
|
|
143
|
+
- **caddy_upstreams** — Reverse proxy backend health.
|
|
144
|
+
- **caddy_metrics** — Prometheus metrics (request counts, durations, connections, TLS handshakes). Optional `filter` (substring match on metric name, keeps `# HELP` / `# TYPE` lines for retained metrics) and `max_lines` (default 500) keep responses compact on busy servers.
|
|
145
|
+
- **caddy_pki** — CA info and certificate chains (default CA: `local`).
|
|
146
|
+
- **caddy_stop** — Graceful shutdown. Requires `confirm=true` to prevent accidents.
|
|
147
|
+
|
|
148
|
+
## Resources
|
|
149
|
+
|
|
150
|
+
Browsable read-only data — MCP clients can fetch these directly without a tool call:
|
|
151
|
+
|
|
152
|
+
- `caddy://config` — Current full Caddy JSON configuration.
|
|
153
|
+
- `caddy://servers` — Summary of all configured HTTP servers.
|
|
154
|
+
- `caddy://upstreams` — Reverse proxy upstream health status.
|
|
155
|
+
- `caddy://metrics` — Prometheus metrics (text exposition format). Capped at the first 500 lines to keep client context bounded; use the `caddy_metrics` tool with `filter` / `max_lines` for filtered or larger output.
|
|
156
|
+
|
|
157
|
+
## Examples
|
|
158
|
+
|
|
159
|
+
### Add a reverse proxy
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
> "Proxy api.example.com to my app on port 3000"
|
|
163
|
+
→ caddy_reverse_proxy({ from: "api.example.com", to: ["localhost:3000"] })
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Idempotent reverse proxy (safe to re-run from automation)
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
> "Make sure api.example.com points at localhost:3000, with a stable id"
|
|
170
|
+
→ caddy_reverse_proxy({ from: "api.example.com", to: ["localhost:3000"], id: "api-prod" })
|
|
171
|
+
# First call creates the route under @id="api-prod".
|
|
172
|
+
# Subsequent calls with the same id REPLACE in place — no duplicate routes.
|
|
173
|
+
# Refuses with a clear error if "api-prod" is already in use by a non-route
|
|
174
|
+
# config object (TLS issuer, server, etc.) — @ids are config-global in Caddy.
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Filter Prometheus metrics
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
> "Just the HTTP request metrics, please"
|
|
181
|
+
→ caddy_metrics({ filter: "http_requests" })
|
|
182
|
+
# Keeps sample lines whose metric name contains "http_requests",
|
|
183
|
+
# plus their `# HELP` / `# TYPE` lines. Drops the rest.
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Preview a Caddyfile before applying it
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
> "Convert this Caddyfile to JSON so I can review it:
|
|
190
|
+
example.com {
|
|
191
|
+
reverse_proxy localhost:8080
|
|
192
|
+
}"
|
|
193
|
+
→ caddy_adapt({ config: "..." })
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Diagnose slow routes
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
> "Fetch Prometheus metrics and tell me which route is slowest"
|
|
200
|
+
→ caddy_metrics()
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Safely update a route by @id
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
> "Update the route with @id 'api-v2' to point to the new backend"
|
|
207
|
+
→ caddy_config_by_id({ id: "api-v2", action: "set", value: {...} })
|
|
208
|
+
# Uses ETags — you'll get HTTP 412 if someone else changed it first
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Atomic deploy
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
> "Replace the whole config with this Caddyfile"
|
|
215
|
+
→ caddy_adapt({ config: "..." }) # validate first
|
|
216
|
+
→ caddy_load({ config: adaptedJson }) # apply atomically
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Troubleshooting
|
|
220
|
+
|
|
221
|
+
**"Cannot connect to Caddy admin API"**
|
|
222
|
+
|
|
223
|
+
- Make sure Caddy is running. `caddy run` or `systemctl status caddy`.
|
|
224
|
+
- Check the admin endpoint. Default is `http://localhost:2019`. If Caddy is in Docker, use the container hostname.
|
|
225
|
+
- Set `CADDY_ADMIN_URL` in your MCP config `env` to match.
|
|
226
|
+
|
|
227
|
+
**"HTTP 412 Precondition Failed"**
|
|
228
|
+
|
|
229
|
+
- Someone (or something) changed the config between your read and your write.
|
|
230
|
+
- The cached ETag has been invalidated. Re-read the config and retry.
|
|
231
|
+
|
|
232
|
+
**"HTTP 403" on /load or /config writes**
|
|
233
|
+
|
|
234
|
+
- You have `admin.listen` or `admin.origins` restrictions set in your Caddy config, or you're missing an `Authorization` header.
|
|
235
|
+
- Set `CADDY_API_TOKEN` in your MCP config env if Caddy expects a Bearer token.
|
|
236
|
+
|
|
237
|
+
**`SIGUSR1` / `systemctl reload caddy` stops reloading the Caddyfile**
|
|
238
|
+
|
|
239
|
+
- Expected, and not caused by a bug here. Since Caddy 2.11.1, `SIGUSR1` reloads
|
|
240
|
+
from the file on disk **only if the config has never been changed through the
|
|
241
|
+
admin API**. The first write from caddy-mcp (or any other API client) makes
|
|
242
|
+
Caddy consider the running config API-owned, and `SIGUSR1` becomes a no-op.
|
|
243
|
+
- Pick one owner per instance. If the Caddyfile is the source of truth, use
|
|
244
|
+
caddy-mcp read-only tools (`caddy_status`, `caddy_list_routes`, `caddy_adapt`)
|
|
245
|
+
and reload from the file. If caddy-mcp owns the config, apply changes with
|
|
246
|
+
`caddy_load` instead of `SIGUSR1`.
|
|
247
|
+
|
|
248
|
+
**Windows: MCP server doesn't start**
|
|
249
|
+
|
|
250
|
+
- Use the `cmd /c npx ...` pattern from the Quick start section. Node 20+ can't spawn `.cmd` files directly.
|
|
251
|
+
|
|
252
|
+
## Requirements
|
|
253
|
+
|
|
254
|
+
- Node.js 20+
|
|
255
|
+
- Caddy 2.x with admin API enabled (default: `localhost:2019`). Verified against
|
|
256
|
+
Caddy 2.11.4; the `@id` write path relies on `PATCH` semantics that the live
|
|
257
|
+
integration suite pins per release.
|
|
258
|
+
|
|
259
|
+
## Contributing
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
git clone https://github.com/YawLabs/caddy-mcp.git
|
|
263
|
+
cd caddy-mcp
|
|
264
|
+
npm install
|
|
265
|
+
npm run lint # Biome check
|
|
266
|
+
npm run lint:fix # Auto-fix
|
|
267
|
+
npm run build # tsup bundle
|
|
268
|
+
npm test # Vitest (357 unit tests, +9 POSIX-only unix-socket tests; +13 live-Caddy integration tests gated by CADDY_MCP_INTEGRATION=1)
|
|
269
|
+
npm run typecheck # tsc --noEmit
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow, including release process.
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|