@yawlabs/caddy-mcp 1.2.5 → 1.2.7
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 +2 -2
- package/dist/index.js +23 -14
- package/dist/server.js +23 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ That's it. Now ask your AI assistant:
|
|
|
80
80
|
|---|---|---|
|
|
81
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
82
|
| `CADDY_API_TOKEN` | (none) | Optional Bearer token for authenticated admin endpoints. Only needed if you've configured Caddy with auth. |
|
|
83
|
-
| `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. Set to `0` to disable. |
|
|
83
|
+
| `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. |
|
|
84
84
|
| `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. |
|
|
85
85
|
|
|
86
86
|
**Alternate MCP clients:**
|
|
@@ -234,7 +234,7 @@ npm install
|
|
|
234
234
|
npm run lint # Biome check
|
|
235
235
|
npm run lint:fix # Auto-fix
|
|
236
236
|
npm run build # tsup bundle
|
|
237
|
-
npm test # Vitest (
|
|
237
|
+
npm test # Vitest (188 unit tests; +8 live-Caddy integration tests gated by CADDY_MCP_INTEGRATION=1)
|
|
238
238
|
npm run typecheck # tsc --noEmit
|
|
239
239
|
```
|
|
240
240
|
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,23 @@ function setEtag(path, etag) {
|
|
|
21
21
|
}
|
|
22
22
|
etagCache.set(path, etag);
|
|
23
23
|
}
|
|
24
|
+
function invalidateRelated(path) {
|
|
25
|
+
etagCache.delete(path);
|
|
26
|
+
for (const key of Array.from(etagCache.keys())) {
|
|
27
|
+
if (key === path) continue;
|
|
28
|
+
if (path.startsWith(`${key}/`) || key.startsWith(`${path}/`)) {
|
|
29
|
+
etagCache.delete(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const isIdWrite = path.startsWith("/id/");
|
|
33
|
+
const isConfigWrite = path.startsWith("/config/");
|
|
34
|
+
if (isIdWrite || isConfigWrite) {
|
|
35
|
+
const otherNamespace = isIdWrite ? "/config/" : "/id/";
|
|
36
|
+
for (const key of Array.from(etagCache.keys())) {
|
|
37
|
+
if (key.startsWith(otherNamespace)) etagCache.delete(key);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
function getBaseUrl() {
|
|
25
42
|
return (process.env.CADDY_ADMIN_URL || DEFAULT_URL).replace(/\/+$/, "");
|
|
26
43
|
}
|
|
@@ -107,14 +124,9 @@ async function attemptRequest(method, path, body, contentType, timeout) {
|
|
|
107
124
|
setEtag(path, etag);
|
|
108
125
|
}
|
|
109
126
|
if (isWrite && res.ok && isConfigPath) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} else {
|
|
114
|
-
etagCache.delete(path);
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
etagCache.delete(path);
|
|
127
|
+
invalidateRelated(path);
|
|
128
|
+
if ((method === "PATCH" || method === "PUT") && etag) {
|
|
129
|
+
setEtag(path, etag);
|
|
118
130
|
}
|
|
119
131
|
}
|
|
120
132
|
if (!res.ok) {
|
|
@@ -428,7 +440,7 @@ function registerResources(server) {
|
|
|
428
440
|
contents: [
|
|
429
441
|
{
|
|
430
442
|
uri: "caddy://config",
|
|
431
|
-
mimeType: "application/json",
|
|
443
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
432
444
|
text: res.ok ? JSON.stringify(res.data, null, 2) : `Error: ${res.error}`
|
|
433
445
|
}
|
|
434
446
|
]
|
|
@@ -444,7 +456,7 @@ function registerResources(server) {
|
|
|
444
456
|
contents: [
|
|
445
457
|
{
|
|
446
458
|
uri: "caddy://upstreams",
|
|
447
|
-
mimeType: "application/json",
|
|
459
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
448
460
|
text: res.ok ? JSON.stringify(res.data, null, 2) : `Error: ${res.error}`
|
|
449
461
|
}
|
|
450
462
|
]
|
|
@@ -492,7 +504,7 @@ function registerResources(server) {
|
|
|
492
504
|
contents: [
|
|
493
505
|
{
|
|
494
506
|
uri: "caddy://servers",
|
|
495
|
-
mimeType: "application/json",
|
|
507
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
496
508
|
text: res.ok ? JSON.stringify(res.data ?? {}, null, 2) : `Error: ${res.error}`
|
|
497
509
|
}
|
|
498
510
|
]
|
|
@@ -842,9 +854,6 @@ function registerRouteTools(server) {
|
|
|
842
854
|
]
|
|
843
855
|
};
|
|
844
856
|
}
|
|
845
|
-
if (isParentMissing(putRes)) {
|
|
846
|
-
return serverNotFoundError(srv);
|
|
847
|
-
}
|
|
848
857
|
return formatResult(putRes);
|
|
849
858
|
}
|
|
850
859
|
if (!isUnknownId(existing)) {
|
package/dist/server.js
CHANGED
|
@@ -19,6 +19,23 @@ function setEtag(path, etag) {
|
|
|
19
19
|
}
|
|
20
20
|
etagCache.set(path, etag);
|
|
21
21
|
}
|
|
22
|
+
function invalidateRelated(path) {
|
|
23
|
+
etagCache.delete(path);
|
|
24
|
+
for (const key of Array.from(etagCache.keys())) {
|
|
25
|
+
if (key === path) continue;
|
|
26
|
+
if (path.startsWith(`${key}/`) || key.startsWith(`${path}/`)) {
|
|
27
|
+
etagCache.delete(key);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const isIdWrite = path.startsWith("/id/");
|
|
31
|
+
const isConfigWrite = path.startsWith("/config/");
|
|
32
|
+
if (isIdWrite || isConfigWrite) {
|
|
33
|
+
const otherNamespace = isIdWrite ? "/config/" : "/id/";
|
|
34
|
+
for (const key of Array.from(etagCache.keys())) {
|
|
35
|
+
if (key.startsWith(otherNamespace)) etagCache.delete(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
22
39
|
function getBaseUrl() {
|
|
23
40
|
return (process.env.CADDY_ADMIN_URL || DEFAULT_URL).replace(/\/+$/, "");
|
|
24
41
|
}
|
|
@@ -105,14 +122,9 @@ async function attemptRequest(method, path, body, contentType, timeout) {
|
|
|
105
122
|
setEtag(path, etag);
|
|
106
123
|
}
|
|
107
124
|
if (isWrite && res.ok && isConfigPath) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
} else {
|
|
112
|
-
etagCache.delete(path);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
etagCache.delete(path);
|
|
125
|
+
invalidateRelated(path);
|
|
126
|
+
if ((method === "PATCH" || method === "PUT") && etag) {
|
|
127
|
+
setEtag(path, etag);
|
|
116
128
|
}
|
|
117
129
|
}
|
|
118
130
|
if (!res.ok) {
|
|
@@ -426,7 +438,7 @@ function registerResources(server) {
|
|
|
426
438
|
contents: [
|
|
427
439
|
{
|
|
428
440
|
uri: "caddy://config",
|
|
429
|
-
mimeType: "application/json",
|
|
441
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
430
442
|
text: res.ok ? JSON.stringify(res.data, null, 2) : `Error: ${res.error}`
|
|
431
443
|
}
|
|
432
444
|
]
|
|
@@ -442,7 +454,7 @@ function registerResources(server) {
|
|
|
442
454
|
contents: [
|
|
443
455
|
{
|
|
444
456
|
uri: "caddy://upstreams",
|
|
445
|
-
mimeType: "application/json",
|
|
457
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
446
458
|
text: res.ok ? JSON.stringify(res.data, null, 2) : `Error: ${res.error}`
|
|
447
459
|
}
|
|
448
460
|
]
|
|
@@ -490,7 +502,7 @@ function registerResources(server) {
|
|
|
490
502
|
contents: [
|
|
491
503
|
{
|
|
492
504
|
uri: "caddy://servers",
|
|
493
|
-
mimeType: "application/json",
|
|
505
|
+
mimeType: res.ok ? "application/json" : "text/plain",
|
|
494
506
|
text: res.ok ? JSON.stringify(res.data ?? {}, null, 2) : `Error: ${res.error}`
|
|
495
507
|
}
|
|
496
508
|
]
|
|
@@ -840,9 +852,6 @@ function registerRouteTools(server) {
|
|
|
840
852
|
]
|
|
841
853
|
};
|
|
842
854
|
}
|
|
843
|
-
if (isParentMissing(putRes)) {
|
|
844
|
-
return serverNotFoundError(srv);
|
|
845
|
-
}
|
|
846
855
|
return formatResult(putRes);
|
|
847
856
|
}
|
|
848
857
|
if (!isUnknownId(existing)) {
|