MCP Server 真上云以后,我最不建议做的事就是继续用 API Key:Cloud Run 这套 OAuth + IAM 值得照着抄
昨天 Google Cloud 的 Wednesday Build Hour 主题之一就是:
Build and Deploy MCP Servers on Google Cloud
这个方向非常现实。
过去一年大量 MCP Server 都是这样跑的:
本地
stdio
开发者机器
Demo 没问题。
一旦要给整个团队、多个 Agent、生产流量使用,问题立刻变了:
谁能连?
谁能调用哪个 Tool?
用谁的身份?
能不能写?
怎么审计?
怎么撤权?
怎么限流?
MCP Server 上云真正难的不是:
docker build
而是身份。
Google 当前 Cloud Run 的远程 MCP 文档里有一个我很赞同的设计:Cloud Run remote MCP 不接受 API Key,认证和授权走 OAuth 2.0 + IAM。
而且官方明确建议:
给使用 MCP Tool 的 Agent 建独立身份。
我觉得这比“把 MCP 部署到 Cloud Run”本身更值得抄。
为什么我不喜欢生产 MCP 继续用一把 API Key
很多内部服务一开始都这么做:
Authorization: Bearer sk-internal-xxx
所有 Agent 共用。
简单。
然后半年以后你会发现:
Sales Agent
Finance Agent
Coding Agent
HR Agent
拿的是同一把 Key。
这时你已经回答不了:
谁调用了 delete?
哪个 Agent 读了这个客户?
某个 Agent 离职后怎么撤权?
这次调用到底代表哪个用户?
API Key 只能告诉你:
“知道这个 Secret 的东西进来了”
它很难表达:
身份
角色
资源
动作
用途
Agent 越多,这个问题越严重。
Cloud Run MCP 当前的做法很清楚:OAuth 2.0 + IAM
Google 文档里对远程 Cloud Run MCP 的认证写得很直接:
OAuth 2.0
+
Identity and Access Management
支持 Google Cloud Identity。
而不是:
API Key
这个选择其实代表了一种架构思想:
Agent 不是匿名脚本
Agent 是一个需要身份的主体
我觉得未来生产 Agent 基本都会走这条路。
最容易做错的是“用人的身份跑所有 Agent”
例如开发者在自己电脑上:
gcloud auth login
然后 Agent 用这个人的 Token 调 MCP。
测试很方便。
生产很危险。
因为最后权限变成:
张三能做什么
Agent 就能做什么
而人的权限往往比 Agent 需要的大得多。
更合理的是:
一个 Agent / 一类 Agent
拥有独立 Service Identity
例如:
sales-research-agent@...
deployment-agent@...
invoice-agent@...
这样权限可以按能力收缩。
Google 甚至把 Cloud Run MCP Scope 分成只读和读写
当前文档里有两个非常清晰的 Scope:
只读:
https://www.googleapis.com/auth/run.readonly
读写:
https://www.googleapis.com/auth/run
这种区分看起来很基础,但很多 Agent Tool 设计根本没有。
Tool 往往只有:
cloud_run
然后里面既可以:
list_services
也可以:
delete_service
deploy_revision
update_traffic
模型只要拿到这个 Tool,就拿到一整套能力。
我更建议从 Registry 层就拆:
cloudrun.read
cloudrun.deploy
cloudrun.traffic.update
cloudrun.delete
每个 Capability 有自己的风险等级和 Scope。
Capability 不应该等于 Tool Name
这是 MCP 进入企业以后必须解决的问题。
MCP Server 暴露:
tools/list
返回若干 Tool。
但企业治理真正需要的是:
Capability
例如:
{
"capability": "cloudrun.service.read",
"mcp_server": "cloudrun-prod",
"tool": "get_service",
"risk": "LOW",
"oauth_scope": [
"https://www.googleapis.com/auth/run.readonly"
]
}
另一个:
{
"capability": "cloudrun.service.delete",
"mcp_server": "cloudrun-prod",
"tool": "delete_service",
"risk": "CRITICAL",
"approval": "REQUIRED"
}
这比把 MCP Tool 原样扔给模型安全得多。
一个 Agent 最好不要拥有长期 Token
正确流程更像:
Agent Run
↓
Policy Engine
↓
需要 cloudrun.read
↓
Credential Broker
↓
签发短期凭证
↓
调用 MCP
↓
凭证过期
不要:
把长期 Service Account Key
塞进 Agent 环境变量
长期 Key 一旦:
- 日志泄露;
- Prompt Injection 诱导读取;
- 沙箱逃逸;
- 镜像泄露;
影响时间可能非常长。
短期身份至少能收敛窗口。
本地 MCP Client 怎么安全连远程 Server
Cloud Run 文档给出的一个实用方式是:
gcloud run services proxy mcp-server \
--region=us-central1
这个 Proxy 会在本地建立:
127.0.0.1
并使用当前身份为请求完成认证转发。
开发阶段很方便。
但我会把它限制在:
开发者本地调试
而不是生产架构。
生产 Agent 到 MCP 应该直接服务间认证。
Agent 和 MCP Server 都跑 Cloud Run 时,我会优先服务到服务认证
Cloud Run 文档给了三种思路:
Sidecar
Service-to-Service
Cloud Service Mesh
我的判断:
Sidecar
适合:
Tool 只服务一个 Agent
强绑定
低延迟
不需要独立扩缩容
独立 Service
更适合:
多个 Agent 共用
独立部署
独立版本
独立扩缩容
Service Mesh
适合:
MCP 数量多
服务间策略复杂
已有 Mesh 基础设施
不是越复杂越高级。
如果只有两个 MCP Server,为了“企业级”强行上 Mesh,可能只会增加运维。
MCP Server 应该默认 --no-allow-unauthenticated
Google 的 Cloud Run Tutorial 直接给出的部署命令就是:
gcloud run deploy mcp-server \
--no-allow-unauthenticated \
--region=us-central1 \
--source .
这行参数很值得保留。
因为不少 Demo 为了快速连通会用:
allow unauthenticated
然后忘了改。
MCP Server 和普通 Web API 不一样。
它背后可能不是公开数据,而是:
数据库
云资源
工单
CRM
文件
代码
一旦匿名调用开放,风险非常高。
IAM 只能解决“谁能访问 Server”,还不够
这是一个容易产生错觉的地方。
假设某 Agent 有:
roles/run.invoker
它能调用 MCP Server。
但进入 MCP Server 以后,还要继续判断:
这个主体能不能调用 delete_service?
所以至少两层:
Layer 1:
MCP Server Admission
Layer 2:
Tool Authorization
不能因为通过了 Cloud Run IAM,就让里面所有 Tool 全开。
我会在 MCP Gateway 前加一层 Policy
请求进入:
Agent
→ MCP Gateway
→ Policy
→ MCP Server
Policy 输入:
{
"subject": "deployment-agent",
"tenant": "prod-a",
"capability": "cloudrun.deploy",
"resource": "service/orders",
"purpose": "release-1842",
"risk": "HIGH"
}
Policy 输出:
{
"allowed": true,
"approval_required": true,
"max_calls": 1
}
还需要用户身份传播
一个 Agent 自己有 Service Identity,但它通常代表某个真实用户执行。
所以调用链最好同时保留:
Agent Identity
User Identity
Tenant
Purpose
例如审计:
{
"agent": "deployment-agent",
"user": "zhangsan",
"tenant": "team-a",
"tool": "deploy_service",
"purpose": "release-1842"
}
否则所有日志最后都是:
deployment-agent 做的
无法追到真正授权来源。
MCP 的 List Tool 也需要治理
很多客户端会先调用:
tools/list
然后把所有 Tool Schema 塞给模型。
生产环境我更建议:
先根据身份和任务过滤
再返回 Tool List
例如 Finance Agent 根本看不到:
delete_cloud_run_service
不是看到了以后靠 Prompt 说:
“请不要调用。”
而是:
根本不暴露
这就是 Capability Discovery 应该做的事情。
Tool Schema 本身也可能泄露信息
一个内部 Tool 描述:
delete_customer_from_prod_legacy_crm
即使没调用,也暴露:
内部系统名
架构
业务对象
所以 Tool Discovery 也属于授权数据。
不能认为:
“只是 list,不算敏感。”
远程 MCP 还必须考虑版本
本地 stdio Server 更新以后,通常:
我自己机器自己用
影响范围有限。
远程 MCP Server 更新:
几十个 Agent 同时受影响
所以应该有:
mcp-server:v17
tool-schema:v6
并支持兼容期。
不要直接原地修改 Tool 参数:
- project_id
+ project
然后让所有 Agent 第二天一起坏掉。
我会给 MCP Server 做最小 SLO
至少监控:
Availability
P95 Latency
Tool Error Rate
Auth Denied Rate
Schema Error
Rate Limit
Cost
再加安全指标:
Unauthorized Capability
Cross-tenant Attempt
Approval Bypass
Credential Failure
Audit Log 必须和 Agent Run 对得上
每个调用带:
run_id
step_id
tool_call_id
最后才能从 Agent Trace 跳到 MCP Audit。
否则事故排查会变成:
Agent 日志有一次调用
Cloud 日志也有一次调用
但不知道是不是同一个
一个我现在会直接采用的生产模板
Agent
↓
Capability Resolver
↓
Policy Engine
↓
Short-lived Identity
↓
Remote MCP
↓
Backend API
每层职责非常清楚。
Capability Resolver:
发现能用什么
Policy:
能不能用
Identity:
以谁的权限用
MCP:
协议化调用
Backend:
真正执行
最后一个判断
MCP 最大的价值是把 Tool 接入方式标准化。
但标准化连接,并不等于标准化权限。
本地 Demo 阶段最重要的是:
能不能连上
生产阶段最重要的是:
谁能连
能看到什么
能做什么
代表谁
能做几次
出了问题怎么撤
Google Cloud 当前远程 MCP 直接采用 OAuth + IAM,而且建议 Agent 使用独立身份,我觉得这个方向是对的。
如果你的生产 MCP 还只有:
一个 URL
+
一把所有 Agent 共用的 API Key
下一步最值得改的不是再接第 20 个 Tool。
而是先把身份补上。
更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界:
https://www.zyentor.com/