MCP 鉴权:OAuth 两侧分工
看懂文档那句话:"This page is the server side. A client that discovers your authorization server and fetches the token — see OAuth clients ."
目的 为将来把你的 MCP server 部署成公网 HTTP 服务做准备——那时"谁能调我的工具"就成了必答题,而文档把答案拆在了 server / client 两页里,得先看懂分工。
学完标准 看完你应该能回答:
完整流程 11 步,每一步是谁在干活?哪些步是"本页(server 侧)"教的,哪些步是"《OAuth clients》页"教的?→ 视图 ①
你现在的 stdio server 为什么不需要 这一套?什么时候才需要?→ 视图 ②
为什么是 token 而不是密码?为什么客户端能"自动发现"授权服务器?→ 视图 ③
深度预算 4 个视图。这是"将来时"的知识——你当前的 stdio 模式用不到,目标是建立地图,不是背细节。
① 完整流程:逐帧时序图
② stdio 为什么不需要这套
③ 为什么必须这样设计
④ 预测练习
一次"从被拒到放行"的完整旅程
四个角色:用户 (在浏览器里点同意的人)、MCP 客户端 (如 Claude Code)、你的 MCP server 、授权服务器 (发 token 的,通常是 Auth0 / Keycloak 这类现成产品)。每一步的徽章告诉你:这是文档哪一页教的活。点「下一步」。
👤 用户浏览器
🖥 MCP 客户端Claude Code 等
🛠 你的 MCP server受保护资源
🔐 授权服务器Auth0 / Keycloak…
客户端的活(OAuth clients 页)
server 侧的活(本页)
授权服务器的活(现成产品)
用户亲自操作
按「下一步」开始 客户端第一次调用你的 server,还没有任何凭证。
下一步 →
← 上一步
重置
📜 线上真实往来(累积)
# HTTP 报文摘要会随步骤出现在这里
💡 数一数徽章就看懂了那句文档: 紫色步骤(声明自己受保护、指路、验 token)= "This page is the server side";青色步骤(发现授权服务器、走流程拿 token、带 token 重试)= "A client that discovers your authorization server and fetches the token" → 《OAuth clients》页。琥珀色的授权服务器你通常不用自己写 ——用现成产品,你只负责和它对接。
你现在的 stdio server,为什么一行鉴权都不用写?
鉴权要回答的问题是:"这个请求是谁发来的?他有资格吗?" ——两种传输方式下,这个问题的处境完全不同。
stdio(你现在的模式)
server 是客户端亲手启动的子进程 ——能启动它,说明你已经登录了这台电脑
通信走 stdin/stdout 管道,只有父进程摸得到 ,外人物理上无法插话
信任由操作系统的进程边界 保证,天然只有一个调用者
结论:不需要 OAuth。"谁在调用"这个问题在进程创建那一刻已经回答完了。
Streamable HTTP(公网部署)
server 挂在一个 URL 上,全世界任何人都能对它发请求
请求可能来自你、你同事、爬虫、攻击者——网络包不自带身份
工具可能碰真实数据(数据库、内部 API),放错人进来就是事故
结论:必须鉴权。每个请求都要出示凭证,server 每次都要验。
📌 什么时候需要回来读这两页文档? 触发条件就一个:你把 server 从 stdio 改成 HTTP 对外提供服务的那天。在那之前,OAuth 这整套对你是"知道存在即可"。这也是文档设计的信号:鉴权章节只出现在 HTTP 传输的章节树下,stdio 教程里提都不提。
为什么必须长这样
和协程页一样的玩法:左边是客观约束 ,右边是 OAuth/MCP 的设计选择 。取消勾选某个约束,只靠它支撑的设计会变灰——检验哪些是"必然",哪些只是"惯例"。
约束(试着关掉)
C1 server 公网可达,任何人都能对它发请求,网络包不自带身份
C2 用户的密码只能交给它的主人(授权服务器),绝不能给第三方应用经手
C3 客户端事先不认识你的 server——不知道你用哪家授权服务器、端点在哪(MCP 客户端要能连上任意 server)
C4 桌面客户端是"公开客户端":代码在用户手里,藏不住任何密钥
被逼出来的设计
凭 token 而不是凭密码
每个请求都要证明身份(C1),但密码不能到处传(C2)→ 用户只在授权服务器登录一次,换出一张范围受限、会过期、可吊销 的 token 给客户端用。泄露了也只是废掉一张票,不是丢掉账户。
C1 C2
约束被关掉了——如果请求天然可信或密码可以随便给,直接传密码更简单,token 失去理由。
发现机制:401 指路 + /.well-known 元数据
客户端不认识你(C3),所以协议规定了"问路"的标准动作:被拒时 server 在 WWW-Authenticate 头里给出元数据地址,元数据里写着授权服务器在哪、端点是什么。任何客户端对任何 server 都能自动走通,无需人工配置。
C3
约束被关掉了——如果客户端和 server 是一家人、配置写死即可,就不需要发现机制。
PKCE:一次性的"暗号对"
桌面客户端藏不住固定密钥(C4)→ 每次授权前现场生成随机 verifier,把它的哈希(challenge)带去授权;换 token 时出示原文。中途截获授权码的人没有 verifier,换不走 token。用一次性随机数替代了藏不住的长期秘密。
C4
约束被关掉了——如果客户端能安全保管密钥(如后端服务器),经典的 client_secret 就够了。
三角分工:server 只验票,不发票
发 token 涉及登录页、用户库、密钥轮换——安全上极难做对。所以架构上把"发票"外包给专业的授权服务器(C1 的风险集中到专业选手),你的 server 只做无状态验票。这正是那句文档的由来:两页文档,两侧分工。
C1 C3
约束被关掉了——没有公网风险时,server 自己随便发个 API key 也未尝不可。
预测,然后验证
老规矩:先在心里给出答案,再点揭晓。