MCP Registry 管理实战:服务器编辑、状态管理、Takedown 下线与生产数据库访问
【免费下载链接】registryA community driven registry service for Model Context Protocol (MCP) servers.项目地址: https://gitcode.com/GitHub_Trending/registry43/registry
本文基于registry(Model Context Protocol 官方服务器注册中心)仓库中的管理运维文档 docs/administration/admin-operations.md,完整讲解管理员与审核员(moderator)如何对注册中心内容执行编辑、状态变更与下线(takedown)操作。读完后,你将掌握:如何通过auth.sh完成 OIDC 到 Registry JWT 的令牌交换、如何用 REST API 精准修改单个版本或批量变更所有版本的状态、如何使用takedown.sh安全地下线服务器,以及如何通过 GKE 端口转发直连生产 PostgreSQL 并开启只读保护。所有操作均需遵循 MCP Registry 审核政策。
前置条件
执行任何管理操作前,需要满足以下条件:
- 拥有带
@modelcontextprotocol.io邮箱的管理员账号(如果你是维护者并希望申请账号,可在项目 Discord 中提出) - 已安装并配置好
gcloudCLI - 已安装
curl和jq - 已安装
kubectl及gke-gcloud-auth-plugin(用于数据库访问)
认证:OIDC 令牌交换为 Registry JWT
管理操作的第一步是获取 Registry 令牌。仓库提供了 tools/admin/auth.sh 辅助脚本:
# Run this, then run the export command it outputs ./tools/admin/auth.sh脚本的完整工作流程(见 tools/admin/auth.sh)是:
- 若
gcloud projects list失败,先触发gcloud auth login完成登录; - 通过
gcloud auth print-identity-token获取 Google Cloud identity token; - 将其作为
oidc_tokenPOST 到${REGISTRY_URL}/v0/auth/oidc(REGISTRY_URL默认为https://registry.modelcontextprotocol.io); - 用
jq解析响应中的registry_token,并打印出形如export REGISTRY_TOKEN='...'的导出命令供你手动执行; - 若解析不到令牌,脚本打印完整响应并以非零状态退出。
源码层面的认证机制
从 internal/api/handlers/v0/auth/oidc.go 可以看到,/v0/auth/oidc端点(exchange-oidc-token)接收任意已配置 OIDC 提供方的 ID token,经StandardOIDCValidator(基于go-oidc库)验证签名与声明后,支持通过OIDCExtraClaims配置对额外声明(如 groups、roles、aud)做强制校验——列表型声明只要与期望值有任一交集即通过(见claimMatches实现)。随后buildPermissions根据服务端的OIDCPublishPerms/OIDCEditPerms配置生成权限列表,写入 JWT 声明并签发短生命周期的 Registry JWT。
几个对管理员很重要的权限细节(见 internal/auth/jwt.go 与 internal/auth/types.go):
- Registry 权限模型只有两种动作:
publish与edit,每个权限携带一个资源模式(ResourcePattern,如io.github.username/*); - 资源模式为
*的权限被视为全局权限(管理员),可跳过命名空间黑名单(BlockedNamespaces)检查; - 从
NewJWTManager的初始化代码看,令牌有效期被硬编码为 5 分钟。因此如果你的curl请求偶尔返回 401,先重新运行一次auth.sh刷新令牌再操作。
编辑特定服务器版本
当你需要修改某个具体版本的细节(如修正描述、更新状态、修改 packages 字段)时使用本节流程。
第一步:下载指定版本
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" export VERSION="<version-string>" # e.g., "1.0.0" (optional, defaults to latest) # URL encode the server name (replace / with %2F) ENCODED_SERVER_NAME=$(echo "$SERVER_NAME" | sed 's|/|%2F|g') # Get specific version curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/${VERSION}" > server.json # Or get the latest version (use the special version "latest") curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/latest" > server.json第二步:进行修改
打开server.json并编辑该版本的详情。服务器名和版本号不可修改——这一约束在后端被强制执行:internal/api/handlers/v0/edit.go 中,若请求体里的name与现有服务器名不一致会返回 400Cannot rename server,若请求体version与 URL 路径参数不一致会返回 400Version in request body must match URL path parameter。服务器名是该条目的不可变标识符。
第三步:更新版本
# Update specific version (requires the full server.json body) curl -X PUT "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/${VERSION}" \ -H "Authorization: Bearer ${REGISTRY_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(cat server.json)"从 edit.go 的实现可以看到 PUT 编辑端点(edit-server)的完整校验链:
- 校验
Authorization: Bearer头格式与 JWT 有效性(401); - URL 解码
serverName与version路径参数(400); - 查询现有版本以对照权限(已下线的版本在此返回 404,需先通过 status 端点恢复);
- 校验当前用户对该服务器具有
edit权限(否则 403); - 禁止重命名、校验版本一致性;
- 对完整请求体执行 schema 校验(
validators.ValidateServerJSON),失败时返回 422 并提示call /validate for details。
只改状态:使用 status 端点
如果只想改一个版本的状态,不必走全量编辑,直接调用 status 端点即可,它不需要完整的服务器配置:
curl -X PATCH "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/${VERSION}/status" \ -H "Authorization: Bearer ${REGISTRY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"status": "deprecated", "statusMessage": "Superseded by v2"}'该端点(update-server-status,见 internal/api/handlers/v0/status.go)的请求体约束值得注意:
status为必填,取值仅限active、deprecated、deleted;statusMessage可选,最长 500 字符,用于说明状态变更原因;- 当目标状态为
active时不允许携带statusMessage(返回 400); - 若新状态与现有状态(含消息)完全相同,视为无操作,返回 400
No changes to apply; - 权限要求是
publish或edit任一即可,比 PUT 编辑端点(仅要求edit)更宽; - 查询时会包含已删除的服务器(
includeDeleted=true),因此已下线的服务器可以通过该端点恢复为active。
编辑整个服务器(所有版本)
批量状态变更:一次请求覆盖所有版本
对服务器所有版本的状态变更只需要一个请求,服务端的语义是单事务——要么全部版本更新成功,要么失败时一个都不变。响应中通过updatedCount字段报告被更新的版本数量,并附上全部更新后的版本列表(见UpdateAllVersionsStatusResponse,status.go)。
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" ENCODED_SERVER_NAME=$(echo "$SERVER_NAME" | sed 's|/|%2F|g') curl -X PATCH "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/status" \ -H "Authorization: Bearer ${REGISTRY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"status": "deleted", "statusMessage": "Removed per moderation policy"}'实现上,update-server-all-versions-status端点(status.go)会先取出该服务器任意一个版本来校验权限,再用GetAllVersionsByServerName拉取全部版本做批量转换校验——如果没有任何版本会发生变化则拒绝请求(400),最后调用服务层的UpdateAllVersionsStatus(接口定义见 internal/service/service.go)在单事务内完成写入。
批量内容变更:必须逐版本执行
内容类编辑(例如从描述中清除敏感文本)没有批量端点,必须对每个版本使用编辑端点(要求完整服务器配置)逐个应用。
第一步:列出所有版本
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" ENCODED_SERVER_NAME=$(echo "$SERVER_NAME" | sed 's|/|%2F|g') curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions" > all_versions.json第二步:提取版本号
# Extract all versions from the server jq -r '.servers[].server.version' all_versions.json > versions.txt第三步:对每个版本应用修改
while read VERSION; do echo "Processing version: $VERSION" # Download the version, edit it, then send the full body back curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/${VERSION}" > version.json # Apply your changes to version.json here, then: curl -X PUT "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/${VERSION}" \ -H "Authorization: Bearer ${REGISTRY_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(cat version.json)" done < versions.txt # Clean up temporary files rm -f versions.txt all_versions.json version.json快捷操作(Quick Operations)
获取服务器的最新版本
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" ENCODED_SERVER_NAME=$(echo "$SERVER_NAME" | sed 's|/|%2F|g') curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/latest" > latest_version.json export VERSION=$(jq -r '.server.version' latest_version.json) echo "Latest version: $VERSION"下线(Takedown)特定版本
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" export VERSION="<version-string>" # e.g., "1.0.0" export REGISTRY_TOKEN="<your-token>" REGISTRY_TOKEN="$REGISTRY_TOKEN" SERVER_NAME="$SERVER_NAME" VERSION="$VERSION" ./tools/admin/takedown.sh下线服务器的所有版本
ALL_VERSIONS=true会在单个请求内把所有版本标记为 deleted。tools/admin/takedown.sh 明确要求VERSION与ALL_VERSIONS二者必须显式指定其一——这样遗忘VERSION时不会意外把整个服务器全部下线:
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" export REGISTRY_TOKEN="<your-token>" REGISTRY_TOKEN="$REGISTRY_TOKEN" SERVER_NAME="$SERVER_NAME" ALL_VERSIONS=true ./tools/admin/takedown.sh从脚本源码看,完整的防误操作设计包括:
SERVER_NAME与REGISTRY_TOKEN缺失时打印用法并退出(exit 1);VERSION与ALL_VERSIONS同时设置时直接报错set either VERSION or ALL_VERSIONS, not both;- 两者都未设置时同样报错并打印 usage;
- 可选环境变量:
STATUS(active | deprecated | deleted,默认deleted,因此该脚本同样可用于恢复或弃用)、STATUS_MESSAGE(随状态变更记录的说明,最长 500 字符)、REGISTRY_URL(默认为官方注册中心地址,可指向自部署实例); - 请求体由
jq -n构造(自动做 JSON 转义),发送 PATCH 后用-w '%{http_code}'捕获 HTTP 状态码,非 2xx 即报错退出,响应体始终打印到终端便于核对updatedCount。
只下线最新版本
export SERVER_NAME="<server-name>" # e.g., "com.example/my-server" export REGISTRY_TOKEN="<your-token>" ENCODED_SERVER_NAME=$(echo "$SERVER_NAME" | sed 's|/|%2F|g') # Resolve the latest version, then take down that specific version VERSION=$(curl -s "https://registry.modelcontextprotocol.io/v0/servers/${ENCODED_SERVER_NAME}/versions/latest" | jq -r '.server.version') REGISTRY_TOKEN="$REGISTRY_TOKEN" SERVER_NAME="$SERVER_NAME" VERSION="$VERSION" ./tools/admin/takedown.sh下线时附带原因记录
REGISTRY_TOKEN="$REGISTRY_TOKEN" SERVER_NAME="$SERVER_NAME" ALL_VERSIONS=true \ STATUS_MESSAGE="Removed per moderation policy" ./tools/admin/takedown.sh关于“下线”的语义,参考 审核政策:设置status为"deleted"后,服务器元数据仍可通过注册中心 API 访问,聚合器(aggregator)据此将其从索引中移除;仅在极端情况(如元数据本身违法)才会覆盖或擦除元数据。这也解释了为什么 status 端点要包含已删除服务器——它们可以被恢复。
连接生产数据库
出于调试或数据分析需要,管理员可以直连生产 PostgreSQL 数据库。务必谨慎操作,并优先使用只读方式。
前置准备
如尚未安装 GKE 认证插件:
gcloud components install gke-gcloud-auth-plugin建立连接
# Get cluster credentials gcloud container clusters get-credentials mcp-registry-prod --zone us-central1-b --project mcp-registry-prod # Get the database password kubectl get secret registry-pg-app -o jsonpath='{.data.password}' | base64 -d # Port-forward and connect (enter the password from above) kubectl port-forward svc/registry-pg-rw 15432:5432 & sleep 2 psql -h localhost -p 15432 -U app -d app只读访问
为防止误写,连上后应立即将会话设为只读:
SET default_transaction_read_only = on;在断开连接之前,任何写操作都会失败报错。
关键规则速查
| 场景 | 方式 | 依据 |
|---|---|---|
| 仅改单个版本内容 | PUT /v0/servers/{name}/versions/{version},需完整配置 | edit.go |
| 仅改单个版本状态 | PATCH .../versions/{version}/status,无需完整配置 | status.go |
| 改所有版本状态 | PATCH /v0/servers/{name}/status,单事务,响应含updatedCount | status.go |
| 改所有版本内容 | 无批量端点,按版本循环执行编辑流程 | 文档 Notes 一节 |
| 状态取值 | active/deprecated/deleted;active时禁止statusMessage | 请求体枚举定义 |
| 服务器名 | 任何版本中均不可修改(不可变标识符) | Cannot rename server400 校验 |
| 权限要求 | 状态端点:publish 或 edit;编辑端点:edit | jwt.go |
补充说明:从 internal/api/router/v0.go 可以看出,上述 servers、edit、status 与 auth 端点会同时在/v0和/v0.1两个前缀下注册,因此管理脚本中的REGISTRY_URL路径前缀可随目标 API 版本调整。
最后强调 admin-operations.md Notes 一节的核心结论,便于快速决策:版本级变更只影响该版本;服务器级状态变更通过PATCH /v0/servers/{serverName}/status一次请求覆盖全部版本;服务器级内容变更没有批量端点、必须逐版本应用;状态变更用PATCH .../status,而PUT编辑端点要求提交完整服务器配置;**内容清除(scrubbing)**走版本级编辑流程;服务器名在任何版本中都不可变更。
【免费下载链接】registryA community driven registry service for Model Context Protocol (MCP) servers.项目地址: https://gitcode.com/GitHub_Trending/registry43/registry
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考