关于 Caddy MCP Server
Caddy MCP Server 将 MCP 客户端连接到 Caddy 管理 API,用于管理 Web 服务器。工具和资源涵盖配置、路由、反向代理、TLS、PKI 与指标,并为并发及破坏性更改提供防护。
主要功能
- 01覆盖 Caddy 管理 API 端点
- 02管理配置与路由
- 03检查反向代理和指标
- 04管理 TLS 与 PKI
- 05通过 ETag 保护并发写入
- 06工具标注及更改快照
适用场景
- 01更新 Caddy 路由且避免重复添加
- 02检查已配置的路由与上游
- 03查看 TLS、PKI 或服务器指标
- 04安全恢复配置更改
MCP 相关
向 MCP 客户端提供 18 个工具和 4 个资源,用于封装 Caddy 管理 API。工具声明只读、破坏性及幂等提示;配置更改可使用 ETag 和快照。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
18收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| path | string | 否 | 配置路径(例如 'apps/http/servers/srv0') |
详细介绍
@yawlabs/caddy-mcp
单击即可将其添加到本地 Yaw MCP 配置中,这样每次启动 Yaw Terminal 会话时都能使用。也可以在下方手动安装。
通过 Claude Code、Cursor 和任何 MCP 客户端管理 Caddy Web 服务。 提供 18 个工具和 4 个资源,涵盖 Caddy 管理 API 参考中的所有端点,包括配置、路由、反向代理、TLS、PKI、指标和快照。
由 Yaw Labs 构建并维护。
为什么选这个?
其他 Caddy MCP 服务只包装了半数管理 API,而且会悄悄吞掉错误。这个不会。
- 完整覆盖管理 API — 涵盖 Caddy 管理 API 参考中的所有端点:
/load、/config/*、/id/*、/stop、/adapt、/pki/ca/*、/reverse_proxy/upstreams、/metrics。没有会返回 404 的占位工具。刻意不包装 Caddy 的 Go 运行时调试端点(/debug/pprof/*、/debug/vars)——如需查看泄漏趋势,可使用带有filter: "go_goroutines"或"go_memstats"的caddy_metrics,这些数据来自同一个管理注册表;如需堆栈转储、CPU 性能分析和跟踪,请直接 curl 管理端点(Caddy 性能分析文档)。 - 并发写入安全 — 使用 ETag(
If-Match),确保更改不会悄悄覆盖其他人的内容。遇到HTTP 412 Precondition Failed时会显示清晰的提示,而非晦涩的错误。 - 默认安全的修改操作 —
caddy_config_set默认使用幂等的overwrite(PATCH),而不是append(POST)。重复调用不会产生重复路由。对配置根节点的写入会替换整个配置,包括管理端点,因此除非设置confirm=true,否则会拒绝该操作;并且会像caddy_load一样先创建快照。 - 防御性解析 — 即使路由为 null、处理器为字符串或匹配器不是数组,
caddy_list_routes也不会因格式错误的配置而崩溃。已通过回归测试。 - 错误中不会泄露凭据 — 如果
CADDY_ADMIN_URL的路径或查询参数中包含令牌,连接失败消息只会显示来源地址。 - 提供备用错误信息 — TLS 写入的 PATCH 失败且 PUT 备用请求也失败时,会返回两者的错误正文,让你了解实际出了什么问题。
- 工具注解 — 每个工具都声明了
readOnlyHint、destructiveHint和idempotentHint,因此 MCP 客户端可以跳过对安全操作的确认。 - 即时启动 — 以单个 bundle 发布,只有两个运行时依赖(MCP SDK 和 Zod)。无需花 5 分钟安装
node_modules。 - 强化输入校验 — 适配器名称、
@id值、服务名称和 CA ID 均经过正则校验并设有长度上限。可阻止 CRLF 标头注入和 ReDoS。
快速开始
1. 启用 Caddy 管理 API
Caddy 默认会在 localhost:2019 上启用管理 API。如果你在 Docker 中或远程主机上运行 Caddy,请通过 CADDY_ADMIN_URL 将其公开。
2. 在项目根目录中创建 .mcp.json
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"]
}
}
}
为什么 Windows 需要额外步骤? 从 Node 20 开始,
child_process.spawn无法直接执行.cmd文件(Windows 上的npx就是这种文件)。使用cmd /c包装是标准的解决方法。此文件可以安全提交,因为其中不包含机密信息。
3. 重启并批准
重启 Claude Code(或你的 MCP 客户端),并在收到提示时批准 Caddy MCP 服务。
就是这样。现在可以向你的 AI 助手提问:
“将 api.local 代理到 localhost:3000”
“srv0 上配置了哪些路由?”
“显示 Prometheus 指标”
配置
| 环境变量 | 默认值 | 描述 |
|---|---|---|
CADDY_ADMIN_URL | http://localhost:2019 | Caddy 管理 API URL。在 Docker 内设置为 http://caddy:2019,或设置为 TLS 终止反向代理后方管理端点的 https URL——有关 Caddy 对非自身回环地址应用的 Host / Origin 规则,请参阅故障排除。Caddy 原生远程管理监听器(admin.remote,默认值为 :2021)不受支持:它要求 TLS 客户端证书,而 caddy-mcp 不会提供该证书。也接受 Unix 套接字,格式可以是 unix:///var/run/caddy-admin.sock,也可以是 Caddy 自己使用的 unix//var/run/caddy-admin.sock 写法——见下文。 |
CADDY_API_TOKEN | (无) | 可选的 Bearer 令牌,每个请求都会以 Authorization: Bearer <token> 的形式发送。Caddy 的管理 API 本身没有令牌身份验证功能,并会忽略此标头——只有在管理端点前方有身份验证代理时才需要它;如果 caddy-mcp 直接连接 Caddy,请不要设置此值。如果此标头确实到达管理监听器,Caddy 2.0 到 2.11.2 会在 INFO 级别的 admin.api“received request”日志行中以明文记录它——除 /metrics 外的所有路径均如此;自 2.2.1 起,/metrics 只会在 DEBUG 级别记录。请运行 Caddy 2.11.3 或更高版本(该版本会将其记录为 REDACTED),或者在代理完成身份验证后让代理移除此标头(Caddy:header_up -Authorization;nginx:proxy_set_header Authorization "";)。 |
CADDY_MCP_SNAPSHOT_DIR | (无) | 用于持久化 caddy_revert 快照的目录。未设置时,快照仅存储在内存中,服务器重启后会丢失。快照是完整的 Caddy 配置,可能包含机密,因此该目录需显式选择,而非使用默认值。 |
CADDY_MAX_RETRIES | 2 | 瞬时故障的重试次数:网络错误以及 502/503/504(只有 Caddy 前方的代理会发送这些状态码)。Caddy 自身返回的 500 是确定性拒绝,永远不会重试,4xx 和 412 也不会重试。可能因重放而改变结果的请求同样会跳过重试:对 /config/* 和 /id/* 的 POST 请求(它们会追加内容或替换已有键——重试可能导致路由重复),以及对数组索引(如 .../routes/0)执行的 PUT 或 DELETE 请求(重放会插入第二条路由,或删除滑入该索引的路由)。这也包括对裸路径 /id/<id> 的 PUT 请求,Caddy 会将其解析为已识别元素的数组索引。无论路径采用何种写法,这些请求都会被匹配——包括带尾部斜杠的路径,或带有 Caddy 在选择方法前会移除的尾部 /... 段的路径,因此 .../routes/0/... 和 PUT /id/<id>/... 也包含在内。超时触发的配置更改永远不会重试(见 CADDY_LOAD_TIMEOUT)。连接被拒绝时,所有方法都会重试,因为没有发送任何内容。对 /load、/adapt、/stop 的 POST 请求仍会重试。重试次数硬性上限为 5;超过上限的值会触发一次性 stderr 提示,以便看出已应用上限。设置为 0 可禁用重试。 |
CADDY_TIMEOUT | 10000 | 不更改配置的管理 API 请求超时时间,单位为毫秒:GET 请求、/adapt、/stop、PKI、上游和指标。配置更改使用 CADDY_LOAD_TIMEOUT。非数值、<= 0 或小于 1ms 的小数值都会回退到默认值。 |
CADDY_LOAD_TIMEOUT | 55000 | 所有更改配置的请求的超时时间,单位为毫秒:POST /load,以及 /config/* 和 /id/* 下的所有 POST/PUT/PATCH/DELETE 请求。每个请求都会在 Caddy 内执行一次完整的同步重载;这可能需要较长时间——每当更改关闭一个监听器时,Caddy 都会在重载期间休眠 apps.http.shutdown_delay 指定的时间,而且更改也可能需要等待另一次重载完成。此处发生超时后永远不会重试:即使客户端放弃,Caddy 仍会继续应用更改,因此错误会说明结果未知,并提示重试前重新读取配置(在这种情况下,caddy_load 和 caddy_revert 会保留其快照)。请将此值设为低于 MCP 客户端的请求超时时间(MCP SDK 默认值为 60 s),否则错误会在客户端放弃请求后才到达,因此永远不会显示;默认值比它低 5 s。非数值、<= 0 或小于 1ms 的小数值都会回退到默认值。 |
| Unix socket 管理端点: |
Caddy 建议通过将管理 API 从 loopback 端口迁移到 unix socket 来加强安全性,并通过文件系统权限控制访问:
{
admin unix//var/run/caddy-admin.sock
}
将 CADDY_ADMIN_URL 指向同一路径(unix:///var/run/caddy-admin.sock),请求就会通过 socket 而不是 TCP 发送。运行 caddy-mcp 的进程需要对 socket 文件具有读写权限。此处请勿设置 CADDY_API_TOKEN,除非该 socket 上实际监听着一个需要身份验证的代理:通过 unix 路径时,caddy-mcp 通常连接的是 Caddy 自己的 socket,此时令牌不起作用;而在 Caddy 2.11.3 之前,令牌还会以明文形式记录在日志中。
运行时(oam 或 Node):
caddy-mcp 命令会优先使用可用的 oam,否则使用 Node 运行。它绝不会在低于 0.18.0 的 oam 上运行服务。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
CADDY_MCP_RUNTIME | auto | auto:使用版本为 0.18.0 或更高的最新 oam,否则使用 Node。oam:使用 oam,否则报错退出。node:始终使用 Node——当问题只在 oam 下出现时,可用此选项绕过。 |
CADDY_MCP_SANDBOX | (未设置) | 1 表示在 oam 的 --permission 沙箱下运行服务:网络访问仅限于 CADDY_ADMIN_URL 的主机和端口,文件系统访问仅限于 CADDY_MCP_SNAPSHOT_DIR,且不允许创建子进程。需要 oam;在 auto 模式下,没有 oam 的机器会以非沙箱模式运行,因此如果必须确保启用沙箱,请同时设置 CADDY_MCP_RUNTIME=oam。沙箱目前无法访问基于 unix socket 的 CADDY_ADMIN_URL。 |
OAM_BIN | (未设置) | 要使用的 oam 二进制文件路径。否则,启动器会检查 OAM_INSTALL_DIR、已安装的位置(~/.oam/bin,以及 Windows 上的 %LOCALAPPDATA%\oam\bin)和 PATH,并选择最新版本。 |
可通过 oam self-update 更新过时的 oam。在默认使用 oam 运行服务的 Yaw MCP 下,可通过 yaw-mcp set <namespace> runtime=node 将此服务切换到 Node。
其他 MCP 客户端:
| 客户端 | 配置文件 |
|---|---|
| Claude Code | .mcp.json(项目根目录)或 ~/.claude.json(全局) |
| 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 |
在以上任一客户端中使用上面展示的同一 JSON 代码块。
工具
配置管理(6)
- caddy_config_get — 读取任意 JSON 路径上的配置(或完整配置)。
- caddy_config_set — 在指定路径写入配置。模式:
overwrite(PATCH,默认模式,幂等;键必须存在,并替换该路径下的整个子树)、append(POST:向数组追加内容,但会替换现有的非数组键,且无法创建缺失的父级)、insert(PUT:在数组位置插入,或严格地连同所有缺失的父级一起创建键;若键已存在则返回 409——这是创建服务器或应用的方式,即使实例没有配置也可使用)。在以/...结尾的路径上(例如apps/http/servers/srv0/routes/...)使用append并提供数组值时,会在一次请求中追加每个元素——要么全部成功,要么全部失败,只重新加载一次;若路径不以/...结尾,数组值会作为单个元素添加,而 Caddy 会拒绝加载routes或listen等带类型的数组。指向配置根目录的路径(''、'/'、'config'、'/config/'、仅含斜杠的变体,或上述任一路径后接单独的...段)表示整个配置,并要求confirm=true:在根目录上使用overwrite和append会像caddy_load一样用value替换整个配置,包括admin块,除非value中包含该块——随后 Caddy 会将其管理端点重新绑定到新配置的admin.listen;若未设置,则绑定到默认地址;若设置了admin.disabled,则不绑定任何地址。指向其他地址的CADDY_ADMIN_URL将停止工作。根目录写入会先自动为之前的配置创建快照(如果能够读取),以便caddy_revert还原;其他路径均不会创建快照。只有在根目录执行caddy_config_delete后,才能在根目录使用insert(否则返回 409);而overwrite正好相反:根目录删除后会返回 404,直到通过append、insert或caddy_load重新创建配置。 - caddy_config_delete — 删除指定路径上的配置。需要
confirm=true(删除父路径也会移除所有后代路径)。指向配置根目录的路径(''、'/'、'config'、'/config/'、仅含斜杠的变体,或上述任一路径后接单独的...段)表示整个配置:它会卸载所有应用和服务器以及admin块,之后 Caddy 会将其管理端点重新绑定到默认地址(localhost:2019,或 Caddy 环境中的$CADDY_ADMIN)——如果CADDY_ADMIN_URL指向其他地址,之后 caddy-mcp 和caddy_revert都将无法访问 Caddy。根目录删除会先自动为之前的配置创建快照(如果能够读取),以便 Caddy 仍可访问时由caddy_revert还原;其他路径均不会创建快照。若要替换配置而不是卸载它,请使用caddy_load。 - caddy_config_by_id — 通过
@id标签获取、设置或删除配置,比在深层路径中导航容易得多。delete操作需要confirm=true。每次set和delete都会先询问 Caddyid的解析位置,并拒绝不在配置树内解析的id。如果它解析到配置根目录——通常是因为它就是配置自身的顶层@id,值为字符串或数字——则表示整个配置:不带子路径(或仅带...)的set和delete会替换或卸载整个配置,行为与根目录上的caddy_config_set/caddy_config_delete完全相同——两者都要求confirm=true,都会先为之前的配置创建快照,并报告管理端点的位置。其内部的子路径则是普通写入。 - caddy_load — 原子性地替换整个配置。与每次配置更改一样,此操作受
CADDY_LOAD_TIMEOUT限制(默认 55 秒)。会自动为之前的配置创建快照;若加载超时且结果未知,则保留该快照。会列出 Caddyfile 适配器的警告,并将失败的加载报告为错误,即使 Caddy 返回了 HTTP 200——Caddy 2.11.4 在 Caddyfile 适配出现警告时就会如此处理(caddyserver/caddy#7246)。format可以是json(默认)或caddyfile;标准版 Caddy 只注册了caddyfile适配器,因此对于编译到自定义构建中的其他适配器,请先使用caddy_adapt进行适配,再加载 JSON(参见下方的原子部署示例)。 - caddy_revert — 管理用于回滚的配置快照。操作:
list、save、apply(需确认)。快照保存在内存中,最多保留最近 10 个。在执行caddy_load之前,以及在执行指向配置根目录的caddy_config_delete、caddy_config_set或caddy_config_by_id之前自动捕获快照。若apply超时且结果未知,则会将回滚前的配置保留为快照 [0],所有较旧的快照索引依次加 1;错误信息会指出目标快照现在所在的位置。
路由操作(4)
- caddy_reverse_proxy — 一次调用即可添加反向代理:
from='api.local' to=['localhost:3000']。可传入可选的id,以实现幂等写入——重复调用会原位替换路由,而不是创建重复项。 - caddy_add_route — 添加具有完整匹配/处理控制的路由(任何 Caddy 处理器)。
- caddy_remove_route — 按
@id(首选)或索引移除路由。需要confirm=true。 - caddy_list_routes — 以易读的形式概述路由。具有防御性:遇到异常配置也绝不会崩溃。
TLS 与配置转换(2)
- caddy_tls — 检查或设置 TLS 参数。操作包括:
status、set_email(ACME 邮箱)、set_acme_ca(ACME CA URL)、set_acme_profile(ACME 配置档案,Caddy 2.10+——上游实验性功能:ACME 配置档案规范仍是草案,且 Caddy 标记该字段可能会变更。Caddy 加载时接受任何配置档案名称,因此如果 CA 未提供该名称,只有在签发时才会失败,错误会记录在 Caddy 自身的日志中),以及只读操作ech_status(位于apps/tls/encrypted_client_hello的加密客户端问候配置,Caddy 2.10+)。设置操作会先执行 PATCH;如果尚未设置apps/tls,则会 PUT 一个最小配置,同时创建所有缺失的父级,因此即使实例完全没有配置也能使用。对于已有配置,会将更改深度合并到签发方路径,再 PATCH 回去,并保留同级配置(自定义证书、on_demand、其他策略)。如果现有结构不符合预期,则会返回针对该结构的错误——绝不覆盖配置。 - caddy_adapt — 将任何已注册适配器格式的配置转换为 Caddy JSON,但不应用配置。
caddyfile(内置,默认),以及编译进 Caddy 二进制文件的任何适配器模块——例如nginx(caddy-nginx-adapter)、yaml(caddy-yaml)。非常适合预览或从现有配置迁移。有一点需要注意:在 Caddy 2.11.4 及更早版本中,Caddyfile 的order全局选项并非仅用于预览。它会修改该 Caddy 进程的指令顺序,因此会影响同一进程中后续的 Caddyfile 适配和加载;即使order行执行失败,它仍会移除其中指定的指令(caddyserver/caddy#7995,上游已修复,但截至 2.11.4 尚未发布)。
服务端操作(6)
- caddy_status — 连通性检查和配置摘要(服务数量、路由、TLS 模式)。TLS 标签会根据存储的配置重现 Caddy 自身的自动 HTTPS 规则,而不是根据监听端口推测,因此可能显示为
enabled、enabled (no listener gets TLS: all are on the HTTP port)、auto (HTTPS)、auto (HTTPS: host matchers on a non-HTTP port)、mixed (TLS on non-HTTP listeners only)、off (HTTP only)、off (no host matchers)、off (automatic HTTPS disabled)或off (empty tls_connection_policies)。两个带说明的enabled状态源于 Caddy 按套接字而非按服务处理 TLS(app.go:535):HTTP 端口监听器会忽略连接策略,因此,仅绑定该端口的服务虽配置了 TLS,却不会提供 TLS。 - caddy_list_servers — 列出所有 HTTP 服务的名称、地址、路由数量和 TLS 状态。标签与
caddy_status相同,但此工具只读取apps/http/servers,因此假定默认的http_port80 /https_port443——对于使用自定义端口的实例,只有caddy_status能正确显示标签。 - caddy_upstreams — 反向代理后端健康状态,即 Caddy 的
/reverse_proxy/upstreams数组原样返回。在 Caddy 2.11.2+ 中,这并非已配置的 upstream 列表:动态 upstream 在动态来源最后一次返回后仍会保留约 1 小时(因此,某个地址可能在引用它的配置失效后仍然存在);如果某个后端有正在处理的请求,且其解析后的地址与条目的拨号文本不同,该后端可能会出现两次。额外副本始终显示fails 0,并重复显示num_requests——请勿对各条目的num_requests求和。 - caddy_metrics — Prometheus 指标(请求数量、持续时间、连接数、TLS 握手)。可选的
filter(按指标名称子字符串匹配,保留所筛选指标对应的# HELP/# TYPE行)和max_lines(默认值为 500)可让繁忙服务的响应保持精简。 - caddy_pki — CA 信息和证书链(默认 CA:
local)。 - caddy_stop — 平滑关闭。需要设置
confirm=true以防误操作。
资源
可浏览的只读数据——MCP 客户端无需调用工具即可直接获取:
caddy://config— 当前完整的 Caddy JSON 配置。caddy://servers— 所有已配置 HTTP 服务的摘要。caddy://upstreams— 反向代理 upstream 健康状态,原样返回。与caddy_upstreams相同,受 2.11.2+ 版本注意事项影响:动态 upstream 会残留,正在处理请求的条目可能重复;请勿对num_requests求和。caddy://metrics— Prometheus 指标(文本展示格式)。为限制客户端上下文大小,最多返回前 500 行;如需筛选或获取更多内容,请使用caddy_metrics工具并设置filter/max_lines。
示例
添加反向代理
> "Proxy api.example.com to my app on port 3000"
→ caddy_reverse_proxy({ from: "api.example.com", to: ["localhost:3000"] })
幂等反向代理(可安全地通过自动化重复运行)
> "Make sure api.example.com points at localhost:3000, with a stable id"
→ caddy_reverse_proxy({ 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.
筛选 Prometheus 指标
> "Just the HTTP request metrics, please"
→ caddy_metrics({ filter: "http_requests" })
# Keeps sample lines whose metric name contains "http_requests",
# plus their `# HELP` / `# TYPE` lines. Drops the rest.
应用前预览 Caddyfile
> "Convert this Caddyfile to JSON so I can review it:
example.com {
reverse_proxy localhost:8080
}"
→ caddy_adapt({ config: "..." })
诊断缓慢的路由
> "Fetch Prometheus metrics and tell me which route is slowest"
→ caddy_metrics()
按 @id 安全更新路由
> "Update the route with @id 'api-v2' to point to the new backend"
→ caddy_config_by_id({ id: "api-v2", action: "set", value: {...} })
# Uses ETags — you'll get HTTP 412 if someone else changed it first
原子部署
> "Replace the whole config with this Caddyfile"
→ caddy_adapt({ config: "..." }) # validate first
→ caddy_load({ config: adaptedJson }) # apply atomically
故障排除
“无法连接到 Caddy 管理 API”
- 确保 Caddy 正在运行。使用
caddy run或systemctl status caddy。 - 检查管理端点。默认地址为
http://localhost:2019。如果 Caddy 在 Docker 中运行,请使用容器主机名。 - 在 MCP 配置的
env中设置CADDY_ADMIN_URL,使其与之匹配。 - 使用 SSH 隧道时,两端映射相同的端口(
ssh -L 2019:localhost:2019 <host>),并将CADDY_ADMIN_URL保持为默认值。Caddy 会检查Host标头是否与自身的监听地址一致,因此隧道使用不同的本地端口时,会返回403 host not allowed: localhost:<port>。 - 如果位于反向代理之后,请将代理的
host:port添加到远程 Caddy 的admin.origins中。Caddy 会同时检查Host和Origin,而设置admin.origins会替换默认的localhost/127.0.0.1/::1条目,因此如果本地工具仍需访问,也要列出localhost:2019。非环回或通配符admin.listen(例如上文 Docker 中的http://caddy:2019)同样不允许任意Host,因此也需要设置admin.origins。 - 将
CADDY_ADMIN_URL指向 Caddy 原生的远程管理监听器(admin.remote,默认值为:2021)会在进行任何 HTTP 交换前失败,因为该监听器要求提供 TLS 客户端证书,而 caddy-mcp 不会提供证书。即使 Caddy 正在运行并已接受连接,也会显示此消息。
“HTTP 412 Precondition Failed”
- 在你读取配置后、写入之前,有人(或某个程序)更改了配置。
- 缓存的 ETag 已失效。请重新读取配置并重试。
任何请求都返回“HTTP 401”或“HTTP 403”
- Caddy 自身的检查会在每个管理请求中运行,包括读取请求,并且总会返回 JSON
{"error":...}响应体。如果你收到此错误,问题出在 Caddy:admin.listen/admin.origins允许列表(host not allowed: ...、client is not allowed to access from origin ...、required Origin header is missing or invalid——参见上文关于隧道和代理的条目),或者在admin.remote上,其 mTLS 身份和权限检查。 - 没有响应体的 401/403 来自 Caddy 前面的某个组件,例如代理、网关或 SSO 层。
CADDY_API_TOKEN仅适用于此处,因此缺少令牌或令牌错误可能是原因之一,代理的其他访问规则也可能是原因。 - Caddy 的管理 API 本身不支持 bearer 令牌身份验证,因此设置
CADDY_API_TOKEN无法解决包含 Caddy 错误响应体的 401/403。
caddy_adapt 或 format: "caddyfile" 的 caddy_load 返回 “directive 'X' is not an ordered HTTP handler”
- 有两种原因,Caddy 的错误信息无法区分:
- 该指令没有已注册的顺序——通常是插件指令。请添加
order全局选项,或将其包装在route块中。 - 在 Caddy 2.11.4 及更早版本中,如果同一 Caddy 进程中较早发生或并发发生的 Caddyfile 适配使用了
order,就会从进程级指令顺序中移除该指令。重启 Caddy 可恢复默认顺序(caddyserver/caddy#7995,尚未发布)。
- 该指令没有已注册的顺序——通常是插件指令。请添加
- 第二种原因会导致刚在一分钟前完成适配的 Caddyfile,在未做任何修改的情况下开始失败。Caddy 自身的建议(“尝试使用 order 全局选项”)能修复第一种原因,也能掩盖第二种原因。
SIGUSR1 / systemctl reload caddy 停止重新加载 Caddyfile
- 这是预期行为,并非此处存在错误。自 Caddy 2.11.1 起,只有在从未通过管理 API 更改过配置时,
SIGUSR1才会从磁盘上的文件重新加载配置。caddy-mcp(或任何其他 API 客户端)首次写入后,Caddy 会将运行中的配置视为由 API 管理,SIGUSR1因而不再执行任何操作。 - 每个实例只指定一个管理方。如果 Caddyfile 是事实来源,请使用 caddy-mcp 的只读工具(
caddy_status、caddy_list_routes、caddy_adapt),并从文件重新加载配置。如果由 caddy-mcp 管理配置,请使用caddy_load应用更改,而不是使用SIGUSR1。 - 关于 Caddy 2.11.4 及更早版本,还有一点需要说明:
caddy_adapt对配置是只读的,但对适配器并非如此。Caddyfile 的order全局选项会改变该进程中的指令顺序,而无效的order行可能导致后续进程内适配失败——SIGUSR1重新加载和caddy run --watch都会进行进程内适配。打包提供的systemctl reload caddy会运行caddy reload,它在 CLI 进程中进行适配,因此不受影响。
Windows:MCP 服务无法启动
- 使用快速入门部分中的
cmd /c npx ...模式。Node 20+ 无法直接启动.cmd文件。
要求
-
Node.js 20+
-
Caddy 2.11.3 或更高版本,并启用管理 API(默认值:
localhost:2019)。 建议使用最新的 2.11.x;已针对 Caddy 2.11.4 验证。该最低版本要求有两个与管理端有关的原因:- Caddy 2.11.2 及更早版本会以 INFO 级别记录每个管理请求的标头,因此,如果来自
CADDY_API_TOKEN的Authorization标头到达管理监听器,令牌就会以明文形式写入 Caddy 日志 (caddyserver/caddy#7578)。 - Caddy 2.11.1 及更早版本会静默接受重复的
@id。并发执行的caddy_reverse_proxy创建操作,或对路由 id 使用mode: "insert"的caddy_config_by_id设置操作,都会导致两个元素共享同一个@id,而/id/只会解析到其中一个。
较旧的 2.x 版本大多可用,但有两个例外,都与 Caddy 发送
ETag的方式有关。Caddy 2.8.0 及更高版本会将它作为响应标头发送。Caddy 2.5.2 至 2.7.x 会将它作为 HTTP 尾部发送,而此客户端无法读取;更早版本则不会发送。因此,在 Caddy 2.8.0 之前:If-Match(ETag)并发保护处于停用状态,因为不会缓存 ETag 并将其回传;- 每个
caddy_config_by_id的set和delete操作都会被拒绝,因为该工具会读取 ETag,以确定 Caddy 在写入前将@id解析到何处;如果无法读取,则会安全地拒绝操作。
@id写入路径依赖PATCH语义,实时集成测试套件会针对各个版本固定验证这些语义。 - Caddy 2.11.2 及更早版本会以 INFO 级别记录每个管理请求的标头,因此,如果来自
贡献
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 (782 unit tests, +39 POSIX-only unix-socket and launcher tests; +39 live-Caddy integration tests gated by CADDY_MCP_INTEGRATION=1)
npm run typecheck # tsc --noEmit
完整工作流(包括发布流程)请参阅 CONTRIBUTING.md。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。