> ## Documentation Index
> Fetch the complete documentation index at: https://mcp.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 安全性

> Inspector 的威胁模型，集中说明 Web 后端、Docker、机密信息存储、stdio 服务器和 mcpdo 守护进程

Inspector 是一个会持有真实凭据并启动真实进程的开发者工具。本页汇总它保护什么、信任什么以及边界在哪里，帮助你决定哪种设置适合你的机器。配置和配方页面会链接到这里，而不是重复这些原因。

简要结论：

* **Web 后端可以启动进程。** API 令牌是该能力与所有能够访问端口的对象之间的屏障。
* **有操作系统钥匙串时，机密信息会进入钥匙串。** 没有钥匙串时，机密信息会进入一个**除非提供密钥否则为明文**的文件，而且这是自动发生的。
* **stdio 服务器以你的身份运行。** Inspector 能读取的内容，所启动的服务器通常也能读取。
* **mcpdo 守护进程是持有活动连接的长期进程**，由令牌和同用户文件权限保护。

## Web 后端及其 API 令牌

Web 客户端是由 Node 服务器支持的浏览器应用，该服务器负责 MCP 连接。它可以按请求启动 stdio 进程，因此每个 `/api/*` 路由都需要每次启动专用的 bearer 令牌（`x-mcp-remote-auth: Bearer <token>`）。浏览器如何获取令牌，请参阅[会话令牌](/docs/draft/tools/inspector/web#the-session-token)。

令牌能保护和不能保护的内容如下：

* **令牌是非浏览器客户端的真正守门机制。** 来源允许列表（`ALLOWED_ORIGINS`）可以阻止其他网页驱动后端，但不带 **`Origin`** 请求头的请求（curl、脚本以及任何非浏览器客户端）会完全跳过该检查。
* **`GET /` 会披露令牌。** 后端会将令牌注入所提供的 HTML，使重新加载或书签继续工作。因此任何能够加载该页面的人都可以读取令牌，这就是绑定地址比令牌值更重要的原因。设置自定义 `MCP_INSPECTOR_API_TOKEN` 不会改变这一点，因为自定义令牌也会以同样方式披露。
* **`DANGEROUSLY_OMIT_AUTH=true` 会完全移除守门机制。** 任何能够访问端口的对象都可以以你的身份启动进程，并使用 Inspector 持有的任何 OAuth 令牌。只有 `true` 或 `1` 会关闭身份验证；包括 `false` 在内的其他值都会保持开启。
* **只有 `/api/*` 受到令牌保护。** 页面本身、静态资源以及 `GET /healthz` 无需令牌即可提供。`/healthz` 只返回 `{"status":"ok"}`，供容器和编排器探测。

### 后端监听位置

后端默认绑定 `127.0.0.1`。除非设置 `DANGEROUSLY_BIND_ALL_INTERFACES=true`，否则绑定所有接口（`0.0.0.0`、`::` 以及等效写法）会被拒绝。绑定某一个特定地址无需该选择加入，因为它只暴露一个有意指定的地址，而不是一次性暴露所有地址。请参阅[在网络上托管](/docs/draft/tools/inspector/recipes#hosting-on-a-network)。

> [!WARNING]
>
> 切勿将 `DANGEROUSLY_OMIT_AUTH` 与非环回绑定组合使用。如果需要让其他人访问 Inspector，请在它前面放置真正的访问控制边界：需要身份验证的反向代理、SSH 隧道或私有网络。

## Docker

[Docker 镜像](/docs/draft/tools/inspector/recipes#docker)会改变上面描述的两个方面。

### 仅在环回地址上发布端口

容器内的 Inspector 必须绑定 `0.0.0.0` 才能通过 `-p` 访问，因此镜像设置了 `DANGEROUSLY_BIND_ALL_INTERFACES=true`。这个选择加入只影响**容器**接口，不影响主机接口。哪些主机接口可以看到 Inspector，取决于发布端口的方式：

| 发布标志 | 可访问范围 |
| - | - |
| `-p 127.0.0.1:6274:6274` | 仅当前机器。 |
| `-p 6274:6274`（裸写） | **主机的所有接口**，即整个网络。 |

裸写 `-p` 会将能够创建进程的后端以及会披露令牌的页面暴露到本地网络。发布每个端口（`6274`，以及 MCP Apps 监听器的 `6275` / `6278`）时都应保留 `127.0.0.1:` 前缀。

### 数据卷会将机密信息放到磁盘

容器没有操作系统钥匙串。没有挂载 `/home/node/.mcp-inspector` 卷时，机密信息会在会话期间保留在**内存**中，容器退出后丢失。为了保留服务器列表而挂载该目录，会同时将机密信息切换到卷上的 `secrets.json` 文件；该文件**除非提供密钥否则为明文**。root、主机上 `docker` 组的每个成员（其权限等同于 root），以及获得该卷备份、快照或副本的任何人都可以读取它。

请通过 `MCP_INSPECTOR_SECRET_KEY_FILE` 以文件形式提供密钥（使用 Docker 或 Compose secret），不要使用环境变量：通过 `-e MCP_INSPECTOR_SECRET_KEY=…` 传入的密钥可被能够运行 `docker inspect` 或 `docker exec` 的任何人看到。配方页展示了两种方式。

## 机密信息存储

Inspector 不会将凭据写入 `mcp.json`、`client.json` 和 `oauth.json`，这样共享、提交或同步这些文件就不会泄露凭据。以下内容会作为机密信息存储：

* 已获取的 OAuth 令牌（访问、刷新和 ID 令牌），受[`MCP_INSPECTOR_PERSIST_TOKENS`](/docs/draft/tools/inspector/configuration#secret-store-variables)限制，以及企业管理授权中的 IdP 会话令牌；
* 每个服务器的 OAuth 客户端密钥和企业 IdP 客户端密钥；
* 动态注册的客户端密钥及其注册访问令牌；
* 每个 stdio 服务器的 `env:` 值。

**`headers` 不是机密信息。** 它们会按原样保存到 `mcp.json`，因此携带凭据（API key 或静态 `Authorization` 值）的请求头仍会保留在文件中。

存储方式如何选择以及如何更改，请参阅[机密信息存储位置](/docs/draft/tools/inspector/configuration#where-secrets-are-stored)。本节说明相关风险。

### 自动回退到明文

> [!WARNING]
>
> 当无法访问操作系统钥匙串时（没有 libsecret 或正在运行的 Secret Service 的 Linux、没有 D-Bus 会话的无头服务器或 SSH 会话、Android／Termux），Inspector 会**自动**将机密信息存储到 `~/.mcp-inspector/secrets.json`。你不需要主动请求这种行为；除非提供密钥，否则该文件**不会加密**。
>
> 唯一的提示是选择存储方式时 stderr 上的警告，以及 Web 客户端设置对话框中的页脚。

这应被视为风险，而不仅是配置事实。文件以 `0600` 权限写入，这只能阻止其他非 root 用户读取。要关闭这一风险，请执行以下任一操作：

* 恢复钥匙串（安装 libsecret 并运行 Secret Service，例如 `gnome-keyring`，或在桌面会话中运行）；
* 使用 `MCP_INSPECTOR_SECRET_KEY_FILE` 中的生成密钥加密文件；
* 设置 `MCP_INSPECTOR_SECRET_STORE=memory`，每次会话重新输入机密信息。

### 文件存储可以防范什么

文件存储用于没有钥匙串的机器，安全性弱于钥匙串。即使经过加密，也应将把机密信息保存在其中视为中等风险。

**没有密钥（明文，权限 `0600`）：**

| 威胁 | 能否防范？ |
| - | - |
| 权限保持不变时，机器上的其他非 root 用户 | 是 |
| root，以及容器主机上 `docker` 组的每个成员 | 否 |
| 拥有文件副本的人：备份、快照、同步的主目录或提交中的副本 | 否 |
| 以你的用户身份运行的任何程序，包括 Inspector 启动的 stdio 服务器 | 否 |

**有密钥（AES-256-GCM，使用每次写入随机生成的盐通过 scrypt 拉伸密钥）：**

| 威胁 | 能否防范？ |
| - | - |
| 文件单独泄露（备份、快照、副本或提交），且密钥熵足够高并未与文件一起泄露 | 是 |
| 能够读取密钥存放位置的人 | 否 |
| 主机上的 root 或 `docker` 组：它们可以读取文件、密钥或保存解密值的进程内存 | 否 |
| 以同一用户身份运行的代码 | 否 |
| 弱口令：持有文件的人可以快速离线猜测，因为每次保存的 scrypt 成本保持较低 | 否 |

密钥存放位置决定第二行的风险。使用 `MCP_INSPECTOR_SECRET_KEY` 时，密钥位于 Inspector 环境中，同用户或 root 可以通过 `/proc/<pid>/environ` 读取；容器中可以通过 `docker inspect` / `docker exec` 读取，也可能存在于用于启动它的 shell profile、`.env` 文件或 Compose 文件中。使用 `MCP_INSPECTOR_SECRET_KEY_FILE` 会将风险缩小到能够读取密钥文件的人，但 Inspector 必须读取它，因此同一用户仍然可以读取。如果密钥与机密文件位于同一目录、备份、卷或仓库中，加密就没有实际收益。

简而言之，加密会将“文件泄露”变成“文件**和**密钥同时泄露”。它无法防范已经拥有机器或容器 root 权限，或已经拥有 Inspector 用户权限的人。如果这不可接受，请使用钥匙串或内存存储。

以下两种失败模式会明确报错，而不是静默处理：

* 如果密钥文件缺失、不可读或为空，如果 `MCP_INSPECTOR_SECRET_KEY_FILE` 设置为空值，或者同时设置了两个密钥变量，存储方式会**拒绝读写**，而不是回退到明文。
* 如果口令发生变化或丢失，现有文件将无法解密。Inspector 会将其读取为空，并**拒绝覆盖**，因此请恢复口令，或删除文件后重新输入值。

## stdio 服务器以你的身份运行

stdio MCP 服务器是 Inspector 以你的用户权限启动的进程，与任何 MCP 主机的行为相同。

* \*\*环境：\*\*Inspector 不会将自己的整个环境传给服务器。stdio 服务器只会获得短的允许列表（macOS 和 Linux 上的 `HOME`、`LOGNAME`、`PATH`、`SHELL`、`TERM`、`USER`）以及配置的 `env:`。因此 `MCP_INSPECTOR_SECRET_KEY` 中的密钥不会直接传给它。
* \*\*但它使用同一用户：\*\*服务器可以自行打开 `secrets.json`，读取 `oauth.json` 和目录，通常也可以通过 `/proc/<pid>/environ` 读取 Inspector 的环境。环境允许列表是卫生措施，不是隔离边界。

只连接你愿意让其访问这些机密信息的 stdio 服务器。若不完全信任某个服务器，请将其命令包装在容器中，例如将 `docker run -i --rm --network none <image>` 作为 stdio 命令。HTTP 和 SSE 服务器不会运行本地代码，因此不需要进程隔离。

## mcpdo 连接守护进程

[mcpdo](/docs/draft/tools/inspector/mcpdo) 通过将连接交给后台守护进程 `mcpdod`，在命令之间保持连接。它会在第一次需要命令时**自动启动**（`mcpdo connect` 或任何针对连接的命令），不需要单独的“启动守护进程”步骤。本节说明该进程暴露的内容。

### 客户端如何访问它，以及谁还能访问

| 平台 | 端点 |
| - | - |
| macOS／Linux | 守护进程目录中的 Unix socket `mcpdod.sock`（默认为 `~/.mcp-inspector`）。 |
| Windows | 从守护进程目录派生的命名管道 `\\.\pipe\mcp-conn-<hash>`。其外围没有目录权限，因此令牌是守门机制。 |

没有 TCP 端口，因此机器外部无法访问守护进程。在 Unix 上，守护进程目录会创建为或收紧为权限 `0700`、由你拥有，并且必须是真实目录而不能是符号链接。里面的 socket 和锁文件权限为 `0600`，因此其他非 root 用户无法访问；root 以及以你的身份运行的进程可以访问。

目录按以下顺序选择：`MCP_INSPECTOR_DAEMON_DIR`、`MCP_STORAGE_DIR`、`~/.mcp-inspector`。如果 socket 路径超过平台限制（macOS 约 104 字节、Linux 108 字节），会提前拒绝，并在错误中指出要缩短的变量。

### 如何验证命令

每个请求都必须携带 bearer 令牌，不存在未授权请求路径。

* \*\*共享模式（默认）：\*\*启动守护进程的 `mcpdo` 命令生成随机的 256 位令牌，并通过环境传给守护进程。守护进程将其发布到目录中权限为 `0600` 的 `mcpdod.token`，因此同一用户运行的任意 `mcpdo` 命令都可以读取。该文件系统权限边界与 socket 的同用户边界相同。
* **私有模式：**`eval "$(mcpdo private)"` 会在 `$TMPDIR/mcp-conn-<uid>/` 下创建新的 `0700` 目录，并向当前 shell 导出 `MCP_INSPECTOR_DAEMON_DIR` 和 `MCP_INSPECTOR_DAEMON_TOKEN`，使它拥有自己的守护进程和连接。由于 `$TMPDIR` 可能共享，使用前会检查父目录的所有权和符号链接。

令牌比较采用常量时间算法。超过 1 MiB 的请求行会被拒绝。向运行中的守护进程提交错误令牌的命令会明确失败，且不会替换该守护进程。

> [!NOTE]
>
> 私有模式可以隔离不同 shell 之间的连接和守护进程状态，但它**不是**针对同一用户其他进程的安全边界：任何拥有你的 UID 且知道守护进程目录的进程都可以读取令牌。需要硬边界时，请使用单独的用户账户或容器。

### 它在内存中持有什么

在守护进程运行期间，每个打开的连接都会持有：

* 活动中的 MCP 连接，以及对于 stdio 服务器由守护进程作为父进程启动的子进程；
* 连接解析后的配置，包括从机密信息存储中读取的 stdio `env:` 值；
* HTTP 连接正在使用的 OAuth 令牌；重新拨号断开的传输时，它还会从存储中重新读取令牌；
* 非交互式命令停放的 elicitation，直到回答或 10 分钟后过期。

守护进程使用启动它的 `mcpdo` 命令的环境启动。它会继承该 shell 的变量（包括设置时的 `MCP_INSPECTOR_SECRET_KEY` 和自己的 IPC 令牌 `MCP_INSPECTOR_DAEMON_TOKEN`），并在整个生命周期内保留，即使你之后在 shell 中修改了这些变量。它启动的 stdio 服务器仍然只会收到上文所述的允许列表，以及从运行 `mcpdo connect` 的 shell 快照出的 `env:`。

在没有钥匙串的主机上，mcpdo 不会自动回退到内存存储。它的前端命令和守护进程是不同进程，按进程存储无法在二者之间传递令牌，因此 mcpdo 使用**共享的 `secrets.json` 文件**，并遵循上文“除非提供密钥否则为明文”的规则。显式设置 `MCP_INSPECTOR_SECRET_STORE=memory` 仍然优先。mcpdo 每次 `connect` 打印一次存储警告，而不是每条命令都打印。

### 生命周期

* \*\*启动：\*\*第一次需要命令时启动。如果两个命令同时启动，`O_EXCL` 锁（`mcpdod.lock`）保证只有一个成功。已退出守护进程留下的锁会被回收，运行中的守护进程永远不会被接管。
* \*\*停止：\*\*运行 `mcpdo daemon stop` 或发送 `SIGINT` / `SIGTERM`。最后一个连接关闭约 **60 秒**后也会自动退出。没有最大生命周期：只要有连接打开，守护进程就会保持运行。
* \*\*正常停止：\*\*拒绝新工作，为正在执行的请求提供短暂宽限期，关闭每个连接，并删除 socket、令牌文件和锁。
* \*\*崩溃：\*\*它持有的所有连接都会丢失，stdio 服务器会失去 stdin，通常随即退出。已存储的 OAuth 令牌和机密信息不受影响。下一条 `mcpdo` 命令会启动新的守护进程，清理旧 socket、回收锁并写入新令牌；必须重新运行 `mcpdo connect` 建立连接。

使用 `pgrep mcpdod` 查找遗留的守护进程。它会将进程标题设置为 `mcpdod`。

### 写入磁盘的内容

所有内容都位于权限为 `0700` 的守护进程目录中：

| 文件 | 权限 | 内容 |
| - | - | - |
| `mcpdod.sock` | `0600` | IPC socket（仅 Unix）。 |
| `mcpdod.lock` | `0600` | 单实例锁，保存守护进程 PID。 |
| `mcpdod.token` | `0600` | IPC bearer 令牌。启动时写入，正常关闭时删除。 |
| `mcpdod.log` | `0600` | 守护进程 stderr，每次启动重新创建。启动失败和机密信息存储警告会写入其中。 |

守护进程通过与其他客户端相同的 `oauth.json` 和机密信息存储写入 OAuth 状态和机密信息，因此[机密信息存储](#secret-storage)中的所有内容同样适用。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.