控制组织的 MCP 服务器访问
用 managed-mcp.json、managedMcpServers、允许列表和拒绝列表限制用户能添加或连接的 MCP 服务器,或给所有用户提供统一服务器。
默认情况下,任何运行 Claude Code 的人都可以连接自己选择的任何 MCP 服务器。Anthropic 在把连接器加入 Anthropic Directory 之前按上架标准审核,但不对任何 MCP 服务器做安全审计或管理。作为管理员,你可以限制在你的组织里能运行哪些服务器,或给每个用户提供服务器。这些限制涵盖 Claude Code 自己加载的服务器,包括它从 claude.ai 获取的连接器;桌面 App 送入其本地和 SSH 会话的连接器是进程内到达的,改由 claude.ai 组织设置管控。
选择模式
| 模式 | 效果 | 配置 |
|---|---|---|
| 禁用 MCP | 除少数在独占控制下加载的服务器外,不加载任何服务器 | 空服务器映射的 managed-mcp.json |
| 固定部署 | 每个用户得到相同的服务器,不能添加其他 | 包含你想要的服务器的 managed-mcp.json |
| 提供服务器 | 每个用户得到你列出的远程服务器,同时保留自己的 | 托管设置里的 managedMcpServers |
| 批准目录 | 公布已批准服务器列表,用户添加想要的,其他的被阻止 | allowedMcpServers + allowManagedMcpServersOnly: true |
| 仅插件服务器 | 用户不能通过 ~/.claude.json 或 .mcp.json 添加服务器;插件服务器仍加载 | strictPluginOnlyCustomization 列表里含 mcp |
| 软允许列表 | 强制一个用户可以在自己的设置里放宽的允许列表 | 不带 allowManagedMcpServersOnly 的 allowedMcpServers |
| 仅拒绝列表 | 阻止已知的坏服务器,其他放行 | deniedMcpServers |
| 不限制 | 用户可以添加任何服务器 | 不部署任何托管 MCP 配置 |
Claude Code 没有用户可浏览和安装的内置 MCP 服务器注册表。对批准目录模式,把已批准列表及其 claude mcp add 命令放在用户能找到的地方(如内部 wiki),或通过插件市场把服务器作为插件分发。
用 managed-mcp.json 独占控制
部署 managed-mcp.json 后,Claude Code 只加载:文件里定义的服务器;通过 managedMcpServers 提供的服务器;启动会话的应用注册的进程内服务器(如 VS Code 扩展自己的服务器、桌面 App 送入的连接器);以及你允许与托管集合并存时的内置 Claude in Chrome 服务器。用户无法添加、修改或使用任何其他 MCP 服务器,包括插件提供的服务器和用 --mcp-config 传入的服务器;该文件还会抑制 Claude Code 自己获取的 claude.ai 连接器,除非你允许它们并存。
部署
managed-mcp.json 是独立文件,不能通过服务端托管设置下发(要通过托管设置下发请用 managedMcpServers)。任何能以管理员权限写系统路径的进程都可以部署,整个设备群通常用设备管理工具(macOS 的 Jamf 或配置描述文件、Windows 的组策略或 Intune、Linux 的你选用的管理工具)。路径:
| 平台 | 路径 |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-mcp.json |
| Linux 和 WSL | /etc/claude-code/managed-mcp.json |
| Windows | C:\Program Files\ClaudeCode\managed-mcp.json |
文件格式与项目 .mcp.json 相同:
{
"mcpServers": {
"github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/" },
"sentry": { "type": "http", "url": "https://mcp.sentry.dev/mcp" },
"company-internal": {
"type": "stdio",
"command": "/usr/local/bin/company-mcp-server",
"args": ["--config", "/etc/company/mcp-config.json"],
"env": { "COMPANY_API_URL": "https://internal.example.com" }
}
}
}机器上的任何用户都能读这个文件,所以不要把 API Key 或其他凭据放进 env 块,改用:${VAR} 展开从每个用户的环境读取密钥;OAuth 或按用户的请求头让每个用户以自己的身份认证;headersHelper 在连接时生成凭据。
如果部署了可读可解析的 managed-mcp.json,而会话又通过 --mcp-config 传入服务器:在工作站上 Claude Code 会在启动时退出并提示 You cannot dynamically configure MCP servers when an enterprise MCP config is present;--strict-mcp-config 在文件已部署时同样导致启动退出。
允许列表和拒绝列表如何作用于托管集合
deniedMcpServers也作用于托管服务器:匹配条目的托管服务器不会加载;用户自己的deniedMcpServers会合并进来,所以用户可以为自己屏蔽某个托管服务器allowedMcpServers不作用于managed-mcp.json里的服务器,唯一例外是定义里用了${VAR}展开的服务器,因为它的有效配置来自每个用户的环境
验证配置
在受管机器上做两项检查:claude mcp list 应只显示 managed-mcp.json 里的服务器和通过 managedMcpServers 提供的服务器(如果用户自己的服务器仍出现,说明 Claude Code 没读到文件,检查路径和父目录权限;如果文件里的服务器没出现且 MCP config diagnostics 一节标注企业配置解析失败,修复它指出的错误后重启);claude mcp add --transport http test https://example.com/mcp 应失败并提示 Cannot add MCP server: enterprise MCP configuration is active and has exclusive control over MCP servers(策略检查在联系任何东西之前就拒绝命令,所以 URL 不必真实)。
完全禁用 MCP
部署一个空服务器映射的 managed-mcp.json,阻止除独占控制下加载的服务器之外的所有服务器:
{ "mcpServers": {} }之后 claude mcp add 会报上面的企业策略错误;用户此前配置的服务器在下次启动会话时停止加载,且没有提示说明是策略所致。
与托管集合并存:claude.ai 连接器和 Claude in Chrome
- 默认部署
managed-mcp.json会抑制 Claude Code 自己获取的 claude.ai 连接器(包括管理员在 claude.ai 管理控制台为组织配置的连接器)。要让它们与文件里的服务器并存,设置"allowAllClaudeAiMcps": true;允许列表和拒绝列表仍作用于这些连接器。该设置只从管理员控制的策略层读取(服务端托管设置、MDM 部署的 plist 或 HKLM 注册表键、系统managed-settings.json),放在用户或项目设置里无效。 - 默认情况下,部署
managed-mcp.json后 Claude Code 在终端会话里阻止内置的 Claude in Chrome 服务器(用户拿不到扩展安装提示,且不显示警告)。要允许,在设备自己的托管设置里设置"allowClaudeInChromeWithManagedMcp": true(放在 MDM 部署的 plist、HKLM 注册表键或系统managed-settings.json里;服务端托管设置、用户可写的 HKCU 注册表和用户/项目设置里的会被忽略)。
通过托管设置提供服务器
要在不独占 MCP 控制的情况下给每个用户一组远程 MCP 服务器,把它们列在托管设置来源(服务端托管设置、Claude apps gateway 策略、MDM 配置描述文件或注册表策略、managed-settings.json)的 managedMcpServers 下,用户保留自己的服务器。值是以服务器名为键的对象,每个条目的形状与项目 .mcp.json 里的 HTTP 或 SSE 服务器相同:
{
"managedMcpServers": {
"search": { "type": "http", "url": "https://search.example.com/mcp" },
"records": {
"type": "http",
"url": "https://records.example.com/mcp",
"headers": { "X-Records-Key": "key-issued-for-all-claude-code-users" }
}
}
}能读到机器上托管设置的任何人(包括用户)都能读这里设置的请求头值,所以使用面向整个受众签发的凭据,或者不写 headers,让每个用户用 OAuth 登录。
条目的有效性
条目通过全部以下检查才会加载,失败的被丢弃并在 /status 里记一条通知,其余条目照常加载:
type是http或sse(streamable-http被接受为http的别名)url是https://URL(拒绝纯http://,包括指向localhost的)- 条目没有
command、args、env或headersHelper成员,所以托管设置文档绝不会命名要在用户机器上运行的程序 - 任何值里都没有
${VAR}引用(这里不展开环境变量,写字面值) - 服务器名只含字母、数字、连字符和下划线,键和值都不含控制字符或不可见格式字符
Claude Desktop 有同名的托管设置,但值是另一种条目形状的数组,不要互相复制;Claude Code 不接受数组形式。
提供的服务器如何加载
- 提供的服务器优先于本地、项目或用户范围里同名的服务器,也优先于指向同一 URL 的插件服务器或 claude.ai 连接器
- 如果同时部署了
managed-mcp.json,两者的服务器一起加载,同名时文件里的条目优先 - 当
strictPluginOnlyCustomization锁定mcp面时,提供的服务器仍然加载 deniedMcpServers作用于提供的服务器(包括来自用户自己设置的条目),所以用户可以为自己屏蔽;提供的服务器不需要allowedMcpServers条目- 没部署
managed-mcp.json时:用户用--mcp-config传入同名服务器会在该次运行中替换提供的那个,并受allowedMcpServers检查;--strict-mcp-config会把提供的服务器和其他所有配置的服务器一起排除
用户能看到和改什么
用户不能编辑或删除提供的服务器:claude mcp remove 会报告该服务器由组织提供;用户仍可在 /mcp 里为自己关闭它(它们列在 Managed MCPs 下)。claude mcp get 和 /mcp 只显示提供服务器 URL 的主机,claude mcp get 只显示请求头的名字而不显示值。
何时连接
通过服务端托管设置下发时,机器有缓存设置的情况下,Claude Code 会扣住该键的缓存副本直到服务器确认会话的设置,并在加载 MCP 服务器前等待确认;确认失败则会话在没有提供服务器的情况下继续,/status 会说明被扣住。首次启动且无缓存时,交互会话在设置到达后立即连接这些服务器,已经开始的 claude -p 运行可能在没有它们的情况下结束。已运行的交互会话会应用你对该键的编辑:新增的服务器无需重启就连接,改动的服务器会用新定义重连,移除的服务器在会话读到变更后断开(-p 运行会保留它直到结束)。
用允许列表和拒绝列表做策略控制
允许列表和拒绝列表过滤哪些已配置的服务器被允许加载,它们不是注册表:服务器仍需由用户、插件或你的组织添加,列表才对它生效。要让允许列表具有权威性,在托管设置来源里同时设置 allowedMcpServers 和 allowManagedMcpServersOnly: true。不带 allowManagedMcpServersOnly 时,所有设置范围的允许列表会合并(包括用户自己的 ~/.claude/settings.json),所以用户可以放宽你的允许列表;拒绝列表无论如何都从所有范围合并。allowManagedMcpServersOnly 与只锁权限规则的 allowManagedPermissionRulesOnly 是两回事。
按 URL、命令或名称匹配
两个列表都是条目数组,每个条目是只有一个键的对象:
| 键 | 匹配 | 用于 |
|---|---|---|
serverUrl | 远程服务器 URL,精确或带 * 通配符 | HTTP 和 SSE 服务器 |
serverCommand | 启动 stdio 服务器的精确命令和参数 | stdio 服务器 |
serverName | 用户指定的标签,仅精确匹配,不展开通配符 | 任一类型,但见下面的警告 |
allowedMcpServers 未设置与设为空数组不同:未设置(默认)允许所有服务器;空数组 [] 不允许任何服务器(跳过允许列表检查的除外);填充则只允许匹配的服务器。deniedMcpServers 未设置或空数组都不阻止任何服务器,填充则阻止匹配的。
警告:
serverName条目(无论在哪个列表)不是安全控制。名字是用户在claude mcp add或编辑配置文件时指定的标签,不是底层服务器,用户可以把任何服务器叫github。要强制策略,用serverUrl或serverCommand。
在 deniedMcpServers 里,serverName 接受任何没有首尾空白的非空字符串,所以可以按显示名阻止 claude.ai 连接器(如 { "serverName": "claude.ai Slack" }),但需要对改名稳健时优先用 serverUrl;在 allowedMcpServers 里,serverName 限于字母、数字、连字符和下划线。
一个服务器如何被评估
加载服务器之前(包括 managed-mcp.json 里的),Claude Code 按顺序运行三个检查(用户在 /mcp 里重连或重新启用时会再运行一次);应用注册的进程内 type: "sdk" 服务器跳过全部三项:
- 合并列表:所有设置范围的允许和拒绝条目合并成一个允许列表和一个拒绝列表;
allowManagedMcpServersOnly为true时只保留托管允许列表,拒绝列表始终从所有范围合并 - 检查拒绝列表:匹配任何拒绝条目(按 URL、命令或名称)的服务器被阻止,没有什么能覆盖拒绝匹配
- 检查允许列表:
allowedMcpServers在任何地方都没设置时,通过拒绝列表的服务器都加载;设置了,则服务器必须匹配与其类型对应的条目:远程(HTTP/SSE)需匹配serverUrl条目(仅当允许列表没有任何serverUrl条目时,serverName匹配才算数);stdio 需匹配serverCommand条目(同样,仅当没有任何serverCommand条目时serverName才算数)
跳过允许列表检查的有三类:组织自己的服务器(每个 managedMcpServers 条目,以及值里没用 ${VAR} 展开的 managed-mcp.json 条目);内置服务器(如 Claude in Chrome、Claude Code 在运行的 VS Code 或 JetBrains IDE 里连接的 ide 服务器、CLI 自己配置的服务器);Claude Tag 会话的 Slack 工具。用户、插件或 claude.ai 添加的每个服务器,以及用户用 --mcp-config 传入的每个服务器,都要被检查。
三条匹配规则:
- 命令精确匹配:每个参数、按顺序都要一致,
["npx", "-y", "server"]不匹配["npx", "server"]或["npx", "-y", "server", "--flag"] serverCommand和serverUrl的值在匹配前展开:策略条目和服务器配置的值都经过${VAR}和${VAR:-default}展开- URL 支持
*通配符:可在模式的任何位置,包括协议。主机名匹配不区分大小写并忽略末尾的 FQDN 点,路径区分大小写
| 模式 | 允许 |
|---|---|
https://mcp.example.com/* | 特定域名上的所有路径 |
https://mcp.example.com | 同样是该域名所有路径(没有路径的模式匹配任何路径) |
https://*.example.com/* | example.com 的任何子域名 |
http://localhost:*/* | localhost 上的任何端口 |
*://mcp.example.com/* | 特定域名的任何协议 |
策略条目的展开来自固定的环境(Claude Code 启动时的环境,加上托管设置里的 env 值),所以项目或用户设置文件里设置的变量改变不了允许列表条目的含义;会改变 URL 条目协议、主机或路径范围的展开会让允许条目被忽略(需要 Claude Code v2.1.219 或更高版本)。
示例:硬允许列表加拒绝列表
{
"allowedMcpServers": [
{ "serverUrl": "https://api.githubcopilot.com/*" },
{ "serverUrl": "https://mcp.sentry.dev/*" },
{ "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
{ "serverCommand": ["python", "/usr/local/bin/approved-server.py"] },
{ "serverUrl": "https://*.internal.example.com/*" }
],
"deniedMcpServers": [
{ "serverName": "dangerous-server" },
{ "serverCommand": ["npx", "-y", "unapproved-package"] },
{ "serverUrl": "https://*.untrusted.example.com/*" }
]
}一旦存在第一个 serverUrl 条目,每个远程服务器都必须匹配某个 URL 模式,用户不能通过给未列出的远程服务器起个被允许的名字蒙混过关;第一个 serverCommand 条目对 stdio 服务器同理。拒绝列表里的 serverName 条目始终生效,名为 dangerous-server 的服务器无论 URL 或命令都被阻止。这个允许列表里放 serverName 条目永远匹配不到任何东西,因为两种传输类型都已有更严格的条目。
官方原文还包括:向用户说明某个限制拦住服务器时会看到什么、如何监控组织实际使用了哪些服务器,以及多个托管来源合并时的细节,以官方为准。