给 MCP 服务加上访问控制与密钥管理,避免工具被随意调用
MCP 的安全风险大多不是协议本身,而是部署方式:很多 MCP Server 默认以本地子进程方式被客户端拉起,没有认证,只要能启动它就能调用全部工具。
一旦你把同一个服务改成监听网络端口,或者把带 shell、文件读写能力的工具开放出去,就等于把一台没有门锁的机器挂在网上。
所以 MCP安全配置的核心是三件事:控制谁能连、控制能调什么、留下可查的记录。
下面按“先判断暴露面、再配认证、然后收权限、最后验证”的顺序展开,适用于自建 MCP Server(Python 或 Node 实现均可)并准备给多个客户端或远程环境使用的场景。
如果只是本机单个客户端用 stdio 启动,风险面小很多,但仍建议做工具白名单。
先确认服务到底暴露在哪一层
动手配置前,先回答一个问题:客户端是通过 stdio 拉起进程,还是通过 HTTP/SSE 连接端口?
前者不存在网络监听,后者必须做认证。
检查方式很直接:
# 看进程监听端口
ss -lntp | grep -i mcp
# 或查看启动命令里有没有 http、sse、port 参数
ps -ef | grep -i mcp
如果输出里出现 0.0.0.0:8000 这类监听,说明服务对同网段甚至公网可达。
此时先做两件事:
- 用防火墙把端口限制到可信来源,例如仅允许跳板机或内网网段访问;
- 不要用默认端口和默认路径直接暴露,改端口只能降低扫描命中率,不能替代认证。
判断标准:只要监听地址不是 127.0.0.1,就按“需要认证”处理,不要因为“只在内网”而省略。
给每个客户端单独发密钥
网络模式下,最省事也最容易出错的做法是全局一个 token。
正确做法是每个客户端一个密钥,便于单独吊销和审计。
实现上通常是在服务端读取环境变量或配置文件中的密钥表,在请求头里校验。
一个可落地的配置片段(服务端环境变量形式):
MCP_AUTH_ENABLED=true
MCP_API_KEYS=clientA:sk_xxx,clientB:sk_yyy
MCP_REQUIRE_HEADER=Authorization
客户端侧则在配置里带上请求头,例如:
{
"mcpServers": {
"my-tool": {
"url": "https://mcp.example.internal/sse",
"headers": { "Authorization": "Bearer sk_xxx" }
}
}
}
注意几个易错点:
- 密钥不要写进会提交到 Git 的配置文件,用环境变量或本地不纳管文件;
- 校验失败时返回统一的 401,不要在响应里区分“密钥不存在”和“密钥错误”;
- 密钥要能轮换,至少留一个
MCP_API_KEYS支持多值的时间窗口。
按工具收紧权限,而不是只做全局限流
认证只解决“谁进来了”,不解决“进来后能干什么”。
MCP 的危险面集中在文件系统、命令执行、数据库写入这几类工具上。
建议在服务端维护一份工具白名单,默认拒绝未列出的工具。
可以按下面思路设计:
- 只读工具(查询、搜索)对普通客户端开放;
- 写操作工具(创建文件、执行命令、改数据库)只对特定密钥开放;
- 高风险工具在生产环境直接不注册,从代码层关闭,而不是靠提示词约束模型别调用。
如果服务端支持按请求判断,可以让密钥与工具集合绑定,例如 clientA 只能调用 read_*,clientB 才能调用 write_*。
这比在客户端侧限制更可靠,因为客户端配置可以被随意修改。
边界提醒:工具权限收紧后,模型可能会因为“工具不可用”而报错,这属于预期行为,不要为了消错把权限重新放开。
日志与验证:确认拦截真的生效
配置完不能只看服务启动成功。
用两类请求验证:
- 不带密钥请求接口,应返回 401 或连接被拒;
- 用低权限密钥调用高权限工具,应被拒绝并记录日志。
可以用 curl 做一次最小验证(把地址换成实际端点):
curl -i https://mcp.example.internal/sse -H "Authorization: Bearer wrong_key"
预期看到 401,而不是正常的事件流响应。
同时在服务端日志里确认记录了来源 IP、密钥标识和结果,但不要记录完整密钥,只记录前缀或哈希。
日常复查建议纳入监控:认证失败次数突增、单密钥调用频率异常、出现未注册工具的调用尝试,都值得告警。
几个常见疑问
本地 stdio 启动的 MCP 服务还需要做这些吗?
如果服务只由本机受信客户端拉起、不监听端口,网络认证可以省略,但工具白名单仍建议保留,避免某个工具误删文件或执行命令。
用反向代理加 Basic Auth 够不够?
能挡住未授权访问,但无法区分不同客户端、无法按工具授权,审计粒度也粗。
适合临时使用,正式环境还是建议在服务端做密钥与工具级控制。
密钥泄露后怎么处理?
从 MCP_API_KEYS 中移除对应项并重启或热加载配置,然后检查该密钥近期的调用日志,确认是否有越权工具调用记录。
MCP安全配置没有一次性完成的说法,真正有效的是“默认拒绝 + 最小权限 + 可追溯”。
先把监听面收窄,再给每个客户端独立密钥,最后按工具划分权限并用请求验证拦截效果,这套流程做完,MCP 服务才算具备接入网络的基本条件。