配方
社区译文;来源: MCP 80041ab0
连接 stdio 与 HTTP 服务器
stdio
stdio 服务器是由 Inspector 启动的进程。所有位置参数合起来就是命令行:
mcp-inspector node build/index.js -- --verbose --config /etc/myserver.conf请在任何要传给你自己的服务器的参数之前放 --。没有该分隔符时,--verbose 会被 Inspector 解析,永远到不了服务器。
用 -e 为进程提供环境变量,用 --cwd 提供工作目录:
mcp-inspector -e API_KEY=abc123 -e REGION=us-east-1 --cwd ~/projects/my-server \
node build/index.js服务器的 stderr 会进入 Console 标签页(web)或 Console 标签页(o,TUI),大多数 stdio 服务器都把诊断信息放在那里,因此当连接莫名失败时先检查那里。
HTTP 与 SSE
mcp-inspector --server-url https://api.example.com/mcp --transport http \
--header "X-Tenant: acme"--transport 接受 http(Streamable HTTP)和 sse。如果服务器受保护,参见授权:无需事先做任何设置,因为当服务器返回 401 时,Inspector 会执行那里描述的 OAuth 流程并重试连接。
对于 HTTP 服务器,还要决定其协议世代。默认是 legacy;在 Server Settings 中(或 catalog 文件中的 protocolEra)设为 modern 或 auto 即可演练 2026-07-28 的行为。对于临时目标,在启动时用 --protocol-era legacy|auto|modern 传入。
导入现有客户端配置
在 Servers 界面,Add Servers 可以导入你已在别处配置好的 MCP 服务器,而无需重新输入。它直接解析 Claude Desktop、Cursor、Cline 和 VS Code 的客户端配置,也能读取服务器自己的 MCP Registry server.json。
导入会合并进活动的 catalog(Inspector 的可写服务器列表)。当导入服务器所用的 id 已被占用时,你可以选择覆盖、跳过或重命名它。如果你完全不想动自己的 catalog,可以改为针对外部文件以只读方式启动:
mcp-inspector --config ~/Library/Application\ Support/Claude/claude_desktop_config.json--config 保证文件按原样提供,永不写入、填充或迁移。

审查 MCP App
MCP Apps 是携带 UI 组件的工具。对于自动化审查者(CI 或代理),凡是返回 JSON 的检查都使用 CLI,只有为了查看渲染后的组件才打开浏览器。
不调用工具即可探测安全态势
mcp-inspector --cli --transport http --server-url https://example.com/mcp \
--method tools/call --tool-name <tool> --app-info --advertise-apps--advertise-apps 让 CLI 在 initialize 时声明支持 MCP Apps。它默认关闭,因为 CLI 无法渲染 app;但否则那些只向支持 app 的客户端展示其 app 工具的服务器会被报告为"没有 app"。
stdout 上输出一行 JSON;若工具有 app 则退出 0,否则退出 2,因此 && 链会短路:
{
"hasApp": true,
"toolName": "get_pros",
"resourceUri": "ui://pros/view.html",
"csp": { "connectDomains": ["https://api.example.com"] },
"permissions": { "clipboard": false },
"prefersBorder": true,
"resourceMimeType": "text/html"
}csp 和 permissions(以及资源声明时的 domain)位于 UI 资源上而不是工具上,因此 --app-info 读取的是那个资源。工具永远不会被调用。
获取完整结果负载,仍然不需要浏览器
mcp-inspector --cli --transport http --server-url https://example.com/mcp \
--method tools/call --tool-name <tool> --tool-args-json '{"zip":"10001"}' --format json启动一次仅限 loopback 的 web Inspector
TOKEN="$(openssl rand -hex 24)"
HOST=127.0.0.1 CLIENT_PORT=6274 MCP_SANDBOX_PORT=6275 \
MCP_AUTO_OPEN_ENABLED=false MCP_INSPECTOR_API_TOKEN="$TOKEN" \
mcp-inspector --web &固定 MCP_SANDBOX_PORT 可以让地址保持明确:app 的 UI 由单独的沙箱端口提供,而你的自动化需要知道它在哪。
用一个深层链接导航到渲染后的组件
http://127.0.0.1:6274/?serverUrl=<encoded url>&transport=http&autoConnect=<TOKEN>&openApp=<tool>&appArgs=<base64url(JSON)>&autoOpen=<TOKEN>appArgs 是该工具的参数,以 base64url 编码的 JSON 表示,每个深层链接参数都在深层链接中说明。autoConnect 和 autoOpen 都必须等于会话 token,因为 autoOpen 会直接从 URL 触发工具调用,需要与 autoConnect 相同的门禁。
等待确定性信号而不是睡眠
Apps 界面提供了一套稳定的自动化约定。请轮询这些属性而不是 sleep:
| 选择器 | 属性 | 取值 |
|---|---|---|
[data-testid="apps-form"] | data-app-status | idle,然后是 loading,然后是 ready 或 error(为 error 时 data-app-error 携带原因) |
[data-testid="connection-status"] | data-status | disconnected、connecting,然后是 connected 或 error(data-error-message 含详情) |
[data-testid="connection-status"] | data-deeplink | parsed、rejected 或 none(none 表示未给出深层链接,rejected 表示某个链接被拒绝) |
Docker
已向 GitHub Container Registry 发布适用于 linux/amd64 和 linux/arm64 的容器镜像:
docker run --rm -p 127.0.0.1:6274:6274 ghcr.io/modelcontextprotocol/inspector从容器日志中读取会话 token,或用 -e MCP_INSPECTOR_API_TOKEN=<value> 固定它。
镜像默认使用 --web,绑定到 0.0.0.0:6274 且关闭浏览器自动打开,并以非 root 的 node 用户(uid 1000)运行。它设置了 DANGEROUSLY_BIND_ALL_INTERFACES=true,因为容器必须绑定通配地址才能通过 -p 访问。
127.0.0.1: 前缀。 裸写 -p 6274:6274 会在所有主机接口上发布,把一个会启动进程的后端,以及那个披露其 token 的页面,暴露在你的本地网络上。镜像的 DANGEROUSLY_BIND_ALL_INTERFACES 只覆盖容器的接口,不覆盖主机的。参见只在 loopback 上发布端口。要使用 Apps 标签页,还需发布 MCP Apps 沙箱端口 6275,以及为声明 _meta.ui.domain 的 app 发布 6278。请让容器内外使用相同的端口号发布,因为浏览器拿到的就是容器内端口:
docker run --rm -p 127.0.0.1:6274:6274 -p 127.0.0.1:6275:6275 \
ghcr.io/modelcontextprotocol/inspector保留你的服务器与机密
服务器列表、OAuth 状态和机密位于 /home/node/.mcp-inspector,即在容器的可写层中,因此 --rm 会丢弃它们,每次运行都从空开始。在那里挂载一个卷即可保留它们:
docker run --rm -p 127.0.0.1:6274:6274 \
-v mcp-inspector-data:/home/node/.mcp-inspector \
ghcr.io/modelcontextprotocol/inspector容器没有操作系统钥匙串,因此机密的存放位置取决于该卷:
| 情形 | 机密存储 | 重启后是否保留? |
|---|---|---|
/home/node/.mcp-inspector 未挂载卷 | 内存 | 否,仅限本次会话 |
| 挂载了该卷 | 卷上的 secrets.json,权限 0600 | 是 |
如果你改用绑定挂载主机目录而不是具名卷,它会保留主机的所有权,因此在 Linux 上需加上 --user "$(id -u):$(id -g)",或把它 chown 给 uid 1000,否则保存会因 EACCES 失败。不要单独绑定挂载机密文件:它不会被识别为持久存储,也无法被原子替换。
挂载该卷会启用机密的文件存储,而没有密钥时该文件是明文。 每个获取到的 OAuth token,以及你保存的每个客户端 secret 和 stdio env: 值,都会被写入卷上的 secrets.json。root 以及主机 docker 组的每个成员都能读取它,任何拿到该卷的备份、快照或副本的人也能读取。
请为它提供密钥,生成到只有你能读取、且位于该卷及其备份和任何仓库之外的文件中:
mkdir -p ~/.config/mcp-inspector
(umask 077 && openssl rand -base64 32 > ~/.config/mcp-inspector/secret-key)即使加密,磁盘上的机密仍带有中等风险。参见文件存储防范哪些风险。
请以文件方式通过 MCP_INSPECTOR_SECRET_KEY_FILE 把密钥交给容器,而不是作为环境变量。用 -e MCP_INSPECTOR_SECRET_KEY=… 传入的密钥,任何能运行 docker inspect 或 docker exec 的人都能读取。
docker run
docker run --rm -p 127.0.0.1:6274:6274 \
-v mcp-inspector-data:/home/node/.mcp-inspector \
-v "$HOME/.config/mcp-inspector/secret-key:/run/secrets/mcp_inspector_secret_key:ro" \
-e MCP_INSPECTOR_SECRET_KEY_FILE=/run/secrets/mcp_inspector_secret_key \
ghcr.io/modelcontextprotocol/inspectorCompose secrets
services:
inspector:
image: ghcr.io/modelcontextprotocol/inspector
ports: ["127.0.0.1:6274:6274"]
volumes: ["mcp-inspector-data:/home/node/.mcp-inspector"]
environment:
MCP_INSPECTOR_SECRET_KEY_FILE: /run/secrets/mcp_inspector_secret_key
secrets: [mcp_inspector_secret_key]
secrets:
mcp_inspector_secret_key:
file: ${HOME}/.config/mcp-inspector/secret-key
volumes:
mcp-inspector-data:不使用 Swarm 时,Compose secrets 是保留主机文件所有者与权限的绑定挂载,因此 0600 的密钥文件必须属于 uid 1000。在你的 uid 不同的 Linux 主机上,请运行 sudo chown 1000 ~/.config/mcp-inspector/secret-key,而不是放宽其权限。每次运行都要提供同一个密钥。
如果密钥文件缺失、不可读或为空,或两个密钥变量都被设置,Inspector 会拒绝读写机密文件,而不是回退到明文,并在日志和设置对话框的页脚说明原因。关于该存储的其他一切(选择顺序、位置、权限)见机密存储于何处。
健康检查与其他模式
镜像的 HEALTHCHECK 会探测 HOST 所绑定地址上的 web UI。--cli 和 --tui 没有 web 服务器,因此该探测会从容器参数中识别这些模式,并在它们运行期间报告健康。外部编排器(Kubernetes 探针、Compose 的 healthcheck)可以调用 web 端口上的 GET /healthz,该端点不需要 token,只返回 {"status":"ok"}。
下面的 <target> 是一个临时目标:位置形式的 stdio 命令,或 --server-url <url> --transport http。
docker run --rm ghcr.io/modelcontextprotocol/inspector --cli <target> --method tools/listALLOWED_ORIGINS。 使用 -p 127.0.0.1:8080:6274 时,浏览器的来源变成 http://localhost:8080,它不再匹配容器内端口,连接会返回 403。要么运行 -e CLIENT_PORT=8080 -p 127.0.0.1:8080:8080,要么设置 -e ALLOWED_ORIGINS=http://localhost:8080,http://127.0.0.1:8080。在网络中托管
Inspector 默认绑定 127.0.0.1,且其后端会启动进程,因此请把暴露到网络视为一个深思熟虑的决定。
除非设置 DANGEROUSLY_BIND_ALL_INTERFACES=true,Inspector 拒绝绑定通配的全接口地址(0.0.0.0、:: 以及所有等价写法)。绑定特定地址无需选择加入即可,因为那是一次有意的暴露,而不是一次暴露所有接口——后者正是 DNS 重绑定攻击所针对的形态。
| 目标 | 做法 |
|---|---|
| 从局域网内另一台机器访问 | HOST=192.168.1.50。默认来源允许列表会跟随绑定主机,因此 http://192.168.1.50:6274 无需进一步配置即可被接受。 |
| 位于 TLS 或反向代理之后 | 浏览器的 Origin 会变成公开来源,不再匹配绑定主机。设置 ALLOWED_ORIGINS=https://inspector.example.com,对 MCP Apps 还要设置 MCP_SANDBOX_FULL_ADDRESS(见下文)。 |
| 通配绑定(容器) | 设置 DANGEROUSLY_BIND_ALL_INTERFACES=true。loopback 访问开箱即用;通过非 loopback 地址访问则需要 ALLOWED_ORIGINS。 |
ALLOWED_ORIGINS 是替换默认列表,而不是与之合并。请列出你会用到的每个来源,包括你想保留的 loopback 形式:
ALLOWED_ORIGINS=http://localhost:6274,http://127.0.0.1:6274,http://192.168.1.50:6274每个条目都必须包含 scheme;缺少 scheme 的值会被丢弃并给出警告。空值不会禁用检查;它会回退到默认值。没有任何开关可以关闭来源校验。
离开 loopback 时还有两点注意事项:
- MCP Apps 也需要其沙箱端口可达。 它是一个独立的监听器(默认
6275,用MCP_SANDBOX_PORT设置),因此要随 web 端口一起暴露或转发它。 - 位于 TLS 或反向代理之后时,要为 MCP Apps 提供它们的公开地址。 默认情况下沙箱被声明为
http://<bind host>:6275,https://页面会把它作为混合内容拦截。请设置MCP_SANDBOX_FULL_ADDRESS(例如https://inspector-sandbox.example.com/sandbox),对于声明_meta.ui.domain的 app 还要设置MCP_APP_ORIGIN_FULL_ADDRESS(例如https://inspector-apps.example.com)。每个地址都需要自己的主机名或端口;与 Inspector 同源的地址会被拒绝。 - MCP Apps 无法在裸 IPv6 字面量下渲染。 带方括号的 IPv6 字面量不是合法的 CSP host-source,因此请通过名称或 IPv4 地址浏览。
无论哪种形态:都要保持身份验证开启。不要在任何除你之外的人可以访问的实例上设置 DANGEROUSLY_OMIT_AUTH。理由见安全。
用 mcpdo 保持连接打开
当一次探索跨越许多调用时(在单个会话上走多步流程、盯着一条日志、代理在会话中途使用服务器工具),为每次 --cli 调用重连会很碍事。mcpdo 会替你保持连接:
mcpdo connect my-server
mcpdo @my-server tools/call --task start_job size:=large # task-augmented; blocks until the task finishes
mcpdo @my-server tools/call get_job_report
mcpdo @my-server logging/tail # long-lived; Ctrl-C to stop
mcpdo disconnect my-server一个连接一次只运行一个调用,因此来自其他 shell 对同一连接的命令会排队等待。
持有该连接的守护进程会自动启动,并在最后一个连接关闭后约一分钟退出。在共享机器上使用之前请阅读 mcpdo 连接守护进程。
开发工作流
一套在实践中效果良好的循环:
从 CLI 开始
--method initialize 用一秒时间、以机器可读的答案确认服务器能启动、完成握手并报告你期望的能力。多数"它就是不能用"的情况都出在这里。
转向 web 客户端做探索
schema 驱动的表单、渲染后的结果,以及旁边的 Protocol 标签页,让找到工具行为异常的那个场景变得很快。
测试边界情况
无效输入、缺失的必需 prompt 参数、并发调用,以及对 HTTP 服务器而言的两种协议世代。验证错误与成功一样是有意设计的。
用 CLI 固化下来
把你发现的东西变成 CI 断言:把 CLI 的 --format json 输出连同 --stored-auth-only 一起管道给 jq -e,这样缺少 token 会快速失败,而不是启动交互式 OAuth。完整命令见在 CI 中验证服务器。