:CIMD 授权实战,把 client_id 换成 HTTPS URL(文末附github源码链接))
MCP 实战手记系列四· 代码实操系列一讲了 DCR 被弃用、CIMD 上位当时留了钩子client_id 到底长什么样、自己搭要几行代码。这篇来兑现。重实操代码我亲手跑过。引子一个容易被忽略的授权点系列三迁移时发现 MCP 端点裸奔、凭证硬编码。再往深想MCP 里客户端是谁没说清。DCR 那套动态注册坑比用的人多。一、DCR 到底烂在哪每连一次就注册一个新 client_id数据库越涨越大客户端过期了服务器不知道僵尸 ID 一堆同一应用换个设备又是一个 ID未认证的注册端点本身就是 DoS 靶子CIMD 一句话清掉别注册了client_id 直接是 HTTPS URL。二、CIMD 原理授权时服务器去 GET 这个 URL 拿回元数据client_name、redirect_uris按需获取、可缓存。一个应用一个 URL换设备换用户不产生多个 ID也无注册端点被滥用。它只解决操作问题不解决冒充恶意客户端伪造回调冒充合法应用CIMD 拦不住文末说。三、元数据文档长什么样{client_id:https://app.example.com/.well-known/mcp-client,client_name:机房监控助手,redirect_uris:[https://app.example.com/callback],token_endpoint_auth_method:none,scope:mcp:read}注意client_id即文档自身 URL。四、动手最小可用 4 步代码在com.ethanliang.mcp.cimd仓库 tagv04。步骤 1客户端把元数据挂到 URL 上一个 Controller 返回 JSONclient_id 即本端点地址RestControllerclassClientMetadataController{GetMapping(/.well-known/mcp-client)ClientMetadatametadata(){returnnewClientMetadata(http://localhost:8084/.well-known/mcp-client,机房监控助手,List.of(http://localhost:8084/callback),none,mcp:read);}}本地 demo 用http://localhost:8084才能跑通生产换 https 域名并打开cimd.require-https。步骤 2服务端加拦截器读 client_idMCP 规范建议把客户端身份放进请求头如Mcp-Client-Id网关据路由与鉴权头名以 SDK 为准这篇统一用它publicbooleanpreHandle(req,res,chain){StringclientIdreq.getHeader(Mcp-Client-Id);if(clientIdnull){res.setStatus(401);returnfalse;}ClientMetadatametafetchMetadata(clientId);// GET 那个 URL带 5 分钟缓存if(!validate(meta,clientId)){res.setStatus(401);returnfalse;}req.setAttribute(clientName,meta.clientName());returntrue;}步骤 3校验先卡协议和主机白名单再查元数据字段白名单是防 SSRF 第一关——只 GET 认可的 hostbooleanvalidate(ClientMetadatam,StringclientId){if(requireHttps!clientId.startsWith(https://))returnfalse;// 生产强制 httpsif(m.redirectUris()null||m.redirectUris().isEmpty())returnfalse;if(m.clientName()null||m.clientName().isBlank())returnfalse;returnallowedHosts.contains(hostOf(clientId));// 白名单防 SSRF 第一关}步骤 4信任校验过的clientName放进请求属性业务直接取不再碰 client_id 本身。五、怎么验证真的没注册端点带正确Mcp-Client-Id发请求返回 200日志打印clientName机房监控助手client_id 指向不存在的 URL返回 401元数据缺redirect_uris返回 401六、踩坑记录实跑踩坑报错原文保留① RestTemplate 没默认超时恶意或慢 URL 拖满 Tomcat 线程。解法RestTemplate设 connect/read 超时或换 WebClient 带timeout()。② 本地用自签 HTTPSGET 元数据报证书错。解法demo 关校验生产必须可信证书。③ client_id 是 URL 不是密码别拿它当 token 校验CIMD 不防冒充需配平台级应用签名。④ 必须缓存元数据每次请求都 GET延迟高还容易把元数据服务打挂。解法用 Caffeine 按 client_id 缓存 5 分钟仓库已落地见ClientIdMetadataInterceptor。⑤ 客户端能指定任意 URL 让你 GET典型 SSRF打169.254.169.254云元数据、打内网 admin。解法host 白名单是第一道关只 GET 认可的 host生产再把requireHttps打开、并拒绝私有/链路本地地址。这一步不能省。七、CIMD 没解决什么它只去掉注册端点运维负担。身份冒充靠平台级应用证明macOS / Windows 签名加软件声明客户端后端签 JWT。demo 里服务端顺手托管了客户端元数据真实环境由客户端自托管服务器只按白名单 GET 并校验这是把鉴权简化成「每请求拉元数据」的示意生产放到授权服务器、只在 token 签发时取一次。小结client_id 变 URL注册端点消失DCR 坑一次性清掉代码很少一个 Controller 加一个拦截器半天能跑安全边界要认清CIMD 管登记不管冒充生产接 EMA完整可运行代码Gitee 仓库 GitHub 镜像tag:v04目录04-cimd-auth。MCP 实战手记系列路线图#篇目状态1总纲篇MCP 到哪一步了✅2跑通第一个 MCP Server✅3把 MCP Server 改成无状态✅4CIMD 授权实战本篇✅5MCP Apps让工具返回能点能填的界面规划6自建 MCP 网关一个端点聚合所有工具规划7安全篇端点鉴权、凭证管理与接入检查清单规划关注我更新第一时间看到。你在 MCP 授权上踩过什么坑评论区见有价值的我整理进后续篇目。参考客户端注册演进从 DCR 到 CIMDMCP 2026-07-28 规范更新