运行维护
关停会取消后台连接,等待旧配置运行实例完成排空后再关闭共享存储;请求仍遵循配置的排空超时。
- 以
/healthz检查进程存活,以/readyz检查身份验证器和 required 后端就绪;两者含义不同。详见HTTP 端点。 - YAML 可热改字段使用 SIGHUP;监听器、身份地址、管理配置以及 Vault/门户等静态设置变化需重启。已初始化的托管数据库是后端配置来源,之后修改 YAML backends 不生效。详见热重载与关停。
- 备份数据库及匹配的
MCPHUB_CONFIG_KEY,启用 Vault 时协调备份 Vault 数据。恢复后核对授权、账号和配置状态;创建部署时选择数据库驱动。 - 查看请求记录缺口、审批投递失败与归档积压;请求历史和最近配置变更不能替代独立审批审计归档。
Docker 部署
Dockerfile 使用 golang:1.26.8-bookworm 构建静态二进制,再放入 gcr.io/distroless/static-debian12:nonroot;最终容器没有 shell,进程以 nonroot 用户运行。
docker build -t mcphub:local .
docker run --rm \
--name mcphub \
-p 127.0.0.1:8080:8080 \
--env-file .env \
-v "$PWD/config.yaml:/etc/mcphub/config.yaml:ro" \
mcphub:local serve --config /etc/mcphub/config.yaml
容器内监听地址应与端口映射匹配(示例为 :8080)。--env-file 只为进程注入环境变量,配置以只读方式挂载;请限制宿主机 config.yaml 和 .env 的权限。镜像入口点已经是 /usr/local/bin/mcphub,因此 serve/validate 直接作为参数传入。
SQLite 管理模式需要可写数据库卷,两种存储都需要 MCPHUB_CONFIG_KEY。本地模式绑定容器回环,普通端口映射无法访问它。远程容器部署使用 mode: remote、内建管理员账号与 HTTPS 代理,参见PostgreSQL Compose 示例。
HTTP 端点与 RFC 9728
假设 server.public_url: https://hub.example.com/mcp:
| 地址 | 认证 | 语义 |
|---|---|---|
GET /healthz |
无 | 进程仍有运行时就返回 200 {"status":"ok"};用于存活探针。 |
GET /readyz |
无 | 所有 required 后端和认证 verifier 都 ready 时返回 200,否则 503。JSON 包含 backends_ready、backends_total、required_ready、required_total、auth_verifier_ready。 |
GET /.well-known/oauth-protected-resource/mcp |
无 | RFC 9728 Protected Resource Metadata 的路径感知地址;推荐将此地址暴露给客户端。 |
GET /.well-known/oauth-protected-resource |
无 | 同一 metadata 的根路径兼容别名。反向代理应把两个地址都路由到 MCPHub。 |
/mcp |
Bearer JWT | Stateless MCP Streamable HTTP 入口;只接受 POST,兼容客户端也使用同一 /mcp POST 语义。现代客户端可以在 POST 响应中使用 request-scoped SSE;MCPHub 不提供 standalone GET SSE 或 DELETE session 会话端点。目录和调用按 token scope 过滤。 |
Metadata 的 resource 是完整 public_url,authorization_servers 是 auth.issuer,scopes_supported 是所有后端 required scope 的并集,bearer_methods_supported 只有 header。未带 token 的 MCP 请求会收到 401 challenge,其中 resource_metadata 指向 https://hub.example.com/.well-known/oauth-protected-resource/mcp;缺 scope 时为 403 insufficient_scope。
跨域请求只接受 public_url 的 origin 或 allowed_origins 中的精确 origin。预检响应只允许 POST(由 OPTIONS 返回预检响应)和实现列出的 MCP/追踪头;不支持 *。其他路径返回 404。
SIGHUP 热重载与关停
serve 运行在 Unix 时可发送:
kill -HUP <mcphub-pid> # 重读同一个 --config 文件
kill -TERM <mcphub-pid> # 优雅关停
SIGHUP 会先完整加载、环境展开和校验配置,再构建 candidate runtime;失败时保留旧 runtime。新 runtime 的 required 后端必须首次连接成功;旧 runtime 会在 drain_timeout 内等待活动请求后关闭;runtime 代际最终关闭时,会先取消绑定到该代际的 request context,再关闭其 Hub/backend 状态,避免 session 晚到登记竞态。该取消会立即让底层 write deadline 到期,打断 drain 后仍在慢速或未读取的 subscription write;普通请求仍保留 request_timeout deadline。可热重载的包括 allowed origins、目录/请求/关停参数、后端列表及后端认证、scope 和后端本地 tool_rules。以下字段变化会被拒绝,必须重启:
server.listenserver.public_url- 全部
auth(包括auth.sso) - 全部
client_authorization和vault - 全部
admin字段
这些值决定监听器、存储/加密身份、RFC 9728/JWT audience 和 OIDC verifier,不能只替换内存中的 runtime。管理模式下 SIGHUP 只重载 YAML 静态字段,backend 始终从所选数据库组合;首次导入后 YAML backend 变化会被忽略。
SIGHUP candidate 启动使用可取消的 context;关停开始时仍在连接的 candidate 会被取消。candidate 的 required backend 必须先连接成功才能替换当前代际;每个 candidate 或已退役 runtime 都会关闭自己持有的 backend session 和连接。
SIGINT 和 SIGTERM 会先停止接收新请求,再保留当前 runtime 与 backend context,让 HTTP 请求在 drain_timeout 内完成 drain。HTTP drain 超时后,MCPHub 会强制关闭剩余 HTTP 连接;随后代际关闭会先取消绑定到该代际的 request context,再关闭 backend 状态。
SIGHUP 创建 unavailable optional backend 时,只有目录来源身份未变才会继承上一代内存目录:backend ID 和 URL、allow_insecure_http、全部固定 header、完整 credentials 配置,以及 OAuth 配置是否存在和 type、issuer、client_id、client_secret、scopes 必须完全一致。任意凭证、OAuth 或 tenant-selection header 变化都会阻止复用;required、required_scopes、tool_rules、timeout 等不标识目录来源的字段不阻止复用;继承的目录不会把新 backend 标记为 ready。