Atlas / MCP servers / yawlabs / caddy-mcp

caddy-mcpCAUTION

mcp/yawlabs/caddy-mcp

Caddy admin API MCP server, complete coverage of config, routes, reverse proxies, TLS, PKI, and metrics, ETag-safe

Verdict
CAUTION
Grade
B
Trust score
85 /100
Exposed tools
18 12r · 4w · 2d
Transport
stdio
License
MIT
Stars
11
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](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.

[](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 in Caddy's admin API reference — config, routes, reverse proxies, TLS, PKI, metrics, snapshots.

Built and maintained by Yaw Labs.

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 endpoint in Caddy's admin API reference: /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).
  • 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.
  • **Safe-by-default mutati
Read from source at commit 49846756e638OBSERVED · 2026-10-10
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add caddy-mcp -- npx -y @yawlabs/[email protected]
03

Exposed tools (18)

12 read · 4 write · 2 destructive. Blast radius: 2 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
caddy_adaptreadConvert a config in any registered adapter format to Caddy JSON without loading it. Useful for previewing what a Caddyfile produces, or for porting from nginx/yaml configs when Caddy is built with the matching adapter module (
caddy_add_routewriteAdd a route with full control over match conditions and handlers. Supports any Caddy handler (reverse_proxy, file_server, static_response, redirect, encode, headers, etc.).
caddy_config_by_idreadAccess config by @id tag. Any config object with an
caddy_config_deletedestructiveDelete config at a JSON path. Removes the config node at the specified path. Deleting a parent node also deletes every descendant -- e.g. deleting
caddy_config_getreadRead Caddy config at any JSON path. Returns the full config when path is empty, or a subtree at a specific path (e.g.,
caddy_config_setwriteWrite config at a JSON path. Mode
caddy_list_routesreadList all routes on a Caddy HTTP server with a human-readable summary of matchers and handlers, followed by the raw route JSON.
caddy_list_serversreadList all configured HTTP servers with their names, listen addresses, route counts, and TLS status. Use this to discover server names before calling route tools.
caddy_loadreadReplace the entire Caddy configuration atomically. Accepts a JSON config object, or a Caddyfile string with format=
caddy_metricsreadGet Prometheus metrics from Caddy. Shows request counts, durations, TLS handshake stats, active connections, and more.
caddy_pkireadGet PKI certificate authority info or the CA certificate chain.
caddy_remove_routedestructiveRemove a route. Target by @id (preferred — stable across reorderings) or by array index on a specific server. Index-based removal is a two-step read-then-delete and can race against concurrent edits; prefer @id when possible.
caddy_reverse_proxywriteAdd a reverse proxy route. The most common operation — just specify where traffic comes from and where it goes. Example: from=
caddy_revertreadManage config snapshots for rollback. Snapshots are auto-captured before caddy_load, and before a caddy_config_delete
caddy_statusreadCheck Caddy connectivity and get a config summary: servers, routes, listen addresses, and TLS status.
caddy_stopwriteGracefully shut down the Caddy server. Requires confirm=true to prevent accidental shutdown.
caddy_tlsreadGet or configure TLS/HTTPS settings. Actions:
caddy_upstreamsreadCaddy
04

Trust audit

CAUTIONgrade B · trust 85/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (2 observation(s))
Network
declared (7 observation(s))
Shell
declared (5 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (16)

HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
scripts/update-manifests.mjs:225
const SSH = "ssh -i ~/.ssh/gh_woods -o IdentitiesOnly=yes";
Why it matters. touches a credential store
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
caddy_config_delete, caddy_remove_route
Why it matters. 2 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/tests/launcher.test.ts:219
return new Function(`${pieces}\nreturn runtimePlan;`)() as RuntimePlan;
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/tests/launcher.test.ts:225
return new Function(`${pieces}\nreturn { pickNewest, floor: OAM_MIN };`)() as {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tests/api.test.ts:920
const res = await api.configByIdGet("my-route", "../../load");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tests/api.test.ts:2812
["configByIdSet", (a: typeof import("../api.js")) => a.configByIdSet("my-route", {}, "PATCH", "../../load")],
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tests/api.test.ts:2813
["configByIdDelete", (a: typeof import("../api.js")) => a.configByIdDelete("my-route", "../../stop")],
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tests/integration.test.ts:1282
{ apps: { http: { servers: { "../../..": { "@id": "deep", listen: [":18887"], routes: [] } } } } },
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tests/integration.test.ts:1311
routes: [{ handle: [{ handler: "vars", "../../../../../../../../../load": { "@id": "toload" } }] }],
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
CHANGELOG.md:1059
`CADDY_ADMIN_URL` (default `http://127.0.0.1:2019`) with host and port both
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/tests/api.test.ts:2708
process.env.CADDY_ADMIN_URL = `http://127.0.0.1:${port}`;
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/tests/api.test.ts:3554
process.env.CADDY_ADMIN_URL = `http://127.0.0.1:${port}`;
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/tests/api.test.ts:3782
expect(res.error).toBe(`Cannot connect to Caddy admin API at http://127.0.0.1:${srv.port} — is Caddy running?`);
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/tests/api.test.ts:3812
expect(res.error).toBe(`Cannot connect to Caddy admin API at http://127.0.0.1:${port} — is Caddy running?`);
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/sdk, zod, @biomejs/biome, @types/node, esbuild, postject, tsup, typescript
Why it matters. 9 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CHANGELOG.md:72
SDK's OAuth client could send credentials to an authorization server chosen by
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine

Gates applied: no_behavioural_pass.

Audited 2026-10-10 · audit v0.4.1 · source sha 49846756e638full audit observations/trust-audit/mcp-server/yawlabs__caddy-mcp.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-1049846756e638CAUTIONB85first audit
06

Questions

What is the caddy-mcp MCP server?

Caddy admin API MCP server, complete coverage of config, routes, reverse proxies, TLS, PKI, and metrics, ETag-safe

What tools does caddy-mcp expose?

18 in total: 12 read-only, 4 that write, and 2 that can delete or overwrite (caddy_config_delete, caddy_remove_route). Every one is listed on this page with its risk.

Is caddy-mcp safe to connect to an agent?

With care. The audit graded it B (85/100) and found 16 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 2 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does caddy-mcp need?

It reads CADDY_API_TOKEN, GH_TOKEN and GITHUB_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does caddy-mcp run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @yawlabs/caddy-mcp at 2.6.0.

How current is this page?

The grade is for one exact copy of the source (49846756e638), read on 2026-10-10. The repository is watched and re-audited when it changes.

Advertisement