CLI 客户端
社区译文;来源: MCP 80041ab0
每次 CLI 运行都会连接到一个服务器,执行你用 --method 指定的那一个请求,打印结果,然后退出。因此它非常适合 CI 流水线、shell 一行命令,以及需要立即验证服务器改动的编码代理。
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list下面的示例使用已安装的 mcp-inspector 二进制文件。若没有全局安装,请像上面那样给每条命令加上前缀 npx @modelcontextprotocol/inspector。
选择服务器
CLI 接受位置参数形式的命令(stdio)、--server-url(HTTP/SSE),或来自 catalog 或配置文件的具名服务器:
# stdio: everything positional is the command to spawn
mcp-inspector --cli node build/index.js --method tools/list
# HTTP
mcp-inspector --cli https://api.example.com/mcp --transport http --method tools/list
# From a file
mcp-inspector --cli --config ./mcp.json --server myserver --method tools/list当服务器来自文件时,其逐服务器设置(headers、超时、OAuth、协议世代以及 roots)会作用于该连接,解析方式与 TUI 和 web 客户端完全一致。--header flag 会覆盖该次运行中文件的 headers,同时保留其超时和 OAuth 设置。
后续示例把你选用的上述任一形式,连同它的 --transport 或 --config/--server flag,简写为 <server>。
roots/set 方法。为某个服务器配置的 roots 会在连接时被声明,因此调用 roots/list 的服务器(例如 @modelcontextprotocol/server-filesystem 用它来获知其允许的目录)就能拿到它们。关于 --catalog 与 --config 的区别、-- 分隔符以及共享的服务器选择 flag,参见配置与 flag。
方法
--method | 必需的配套参数 | 说明 |
|---|---|---|
initialize | 无 | 仅连接的探测:{serverInfo, protocolVersion, capabilities, instructions}。 |
tools/list | 无 | --strict 会将其 schema 可移植性检查变成门禁(参见 CI 门禁)。 |
tools/call | --tool-name,以及可选的 --tool-arg / --tool-args-json | |
resources/list | 无 | |
resources/read | --uri | |
resources/templates/list | 无 | |
resources/directory/read | --uri,以及可选的 --cursor | 一次读取一页;回传上一页的 nextCursor。 |
prompts/list | 无 | |
prompts/get | --prompt-name,以及可选的 --prompt-args | |
logging/setLevel | --log-level | 仅限 legacy 世代;modern 服务器改为逐请求选择加入。 |
skills/list | 无 | --verify 会检查返回的 skills(参见 CI 门禁)。 |
skills/get | --uri | 同样支持 --verify 选项。 |
servers/list | 无 | 不连接任何服务器即可读取 catalog。 |
servers/show | --server | 同样不连接,针对单个条目。 |
servers/add | --server,以及一个位置目标或 --server-url | 不连接即可写入 catalog(参见编辑 catalog)。 |
servers/edit | --server,以及要修改的内容 | 同上。 |
servers/remove | --server | 同上。 |
仅支持流或会话的方法(例如 logging/tail)会被拒绝,因为会退出的进程无法保持流打开。
传递参数
--tool-arg 接受 key=value,并会在值能被 JSON 解析时强制转换它,因此 count=1 和 zip=10001 都会发送数字。不是合法 JSON 的值(zip=012、一个裸词)会作为字符串发送,随后该字符串会被转换为工具输入 schema 为该属性声明的类型,因此对数值型 zip 使用 zip=012 仍会发送 12:
mcp-inspector --cli <server> --method tools/call --tool-name mytool \
--tool-arg key=value --tool-arg count=1 --tool-arg 'options={"format":"json"}'--tool-args-json 一次性接受完整的参数对象,并跳过 key=value 解析,因此 {"zip":"10001"} 发送的是字符串 "10001" 而不是数字。schema 转换仍会作用于字符串值,所以只有当 schema 把该属性类型声明为字符串(或未声明)时,它才会保持字符串形式。这两个 flag 互斥:
mcp-inspector --cli <server> --method tools/call --tool-name mytool \
--tool-args-json '{"zip":"10001"}'输出
--format text(默认)为人类做美化打印。--format json 会在 stdout 上输出单个 JSON 对象且不带任何横幅,因此整段输出可以干净地通过管道:
mcp-inspector --cli <server> --method tools/list --format json | jq '.result.tools[].name'探测 MCP Apps
--app-info 不调用工具即可报告某个工具是否带有 MCP App UI(其 ui:// 资源、CSP 和权限),因此流水线可以在调用任何东西之前决定是否需要浏览器:
# One tool -> one JSON line
mcp-inspector --cli <server> --method tools/call --tool-name my_tool --app-info
# {"hasApp":true,"toolName":"my_tool","resourceUri":"ui://...","csp":{...},"permissions":{...}}
# Every tool -> NDJSON, one line each, over a single connection
mcp-inspector --cli <server> --method tools/list --app-info | jq -c 'select(.hasApp)'退出码用于区分不同结果:带有 App 的工具退出 0,没有 App 的工具退出 2,工具不存在退出 5,因此拼写错误不会被误认为"没有 App"。探测失败(UI 资源不可读、resourceUri 格式错误)会记录在 resourceError 字段中而不是中止,因此单个坏工具永远不会毁掉整个列表。
CLI 无法渲染 App,因此默认情况下它不会在 initialize 时声明 MCP Apps 扩展。只向声明支持 App 的客户端暴露 App 工具的服务器,因而会显得"没有 App"(退出 2)。加上 --advertise-apps 即可在该次运行中声明该扩展。
--format 如何设置,tools/list --app-info 始终输出 NDJSON(每个工具一行);--format json 只改变 tools/call --app-info 的单工具输出格式。退出码与错误信封
每个非零退出都映射到一个稳定的失败类别,因此调用方可以依据原因分支处理,而无需抓取文字描述:
| 代码 | 含义 |
|---|---|
0 | 成功。 |
1 | 用法错误或意外错误(兜底),包括机密存储或 OAuth 状态文件不可读。 |
2 | 工具上没有找到 MCP App(--app-info 探测)。 |
3 | 服务器要求身份验证(HTTP 401/403,或 SDK 授权错误)。 |
4 | 服务器不可达(DNS、连接被拒绝、超时、fetch failed)。 |
5 | 工具错误:tools/call 返回 isError: true,或未找到该工具。 |
6 | --strict 发现严重级别为 error 的工具 schema 可移植性问题。 |
7 | --verify 发现某个 skill 违反 SEP-2640(一致性、摘要或大小不匹配)。 |
8 | --verify 在其读取边界内无法检查每一个 skill。 |
9 | --verify --require-digests 发现某个 skill 未提供任何摘要。 |
任何非零退出时,CLI 还会向 stderr 写入一行 JSON:
{
"error": {
"code": "auth_required",
"message": "Unauthorized",
"status": 401,
"url": "https://api.example/mcp"
}
}该信封始终包含 code 和 message,并在已知时包含 cause(底层错误,例如 DNS 失败)、status(HTTP 状态码)和 url。URL 中的查询字符串机密会被脱敏。code 是该失败的稳定名称,例如 auth_required、unreachable、tool_not_found、tool_is_error、no_app、schema_unportable、store_unavailable、oauth_state_unrecognized,以及兜底的 error 等。
因为它只有一行,调用方可以用 2>&1 | tail -1 | jq .error 解析它。
返回 isError: true 的 tools/call 仍会打印其负载,但退出码为 5,因此 && 链不会在调用失败后继续执行。
脚本中的授权
默认情况下,CLI 会运行与 TUI 相同的 loopback OAuth 流程:它打开浏览器并等待 localhost 回调,而 CI 任务无法完成这一回调。有两个 flag 可以让非交互运行变得可预测:
--stored-auth-only:绝不启动交互式 OAuth 或 step-up,也绝不自动打开浏览器。若共享存储中存在 token 就使用它,否则立即以auth_required失败。这正是 CI 需要的 flag。--use-stored-auth:复用 web Inspector 已在本机获取的 token,若存有 refresh token 则先刷新它。它按 URL 查找 token,因此需要--server-url。
两者都未使用,且 stdin 或 stderr 上没有 TTY 时,CLI 会快速失败并返回 auth_required,而不是为一个无人完成的回调挂起十五分钟。
完整流程、web 到 CLI 的 handoff 以及 --print-handoff,参见授权。
配方
在 CI 中验证服务器
set -euo pipefail
# Fail the build if the server can't be reached or doesn't expose the tool
mcp-inspector --cli --config ./ci-servers.json --server my-server \
--stored-auth-only --method tools/list --format json \
| jq -e '.result.tools | map(.name) | index("get_weather")' > /dev/nullCI 门禁
有三个 flag 能把检查变成非零退出,各自使用不同代码,以便任务区分不同失败:
--strict(配合tools/list):在 stderr 上完整报告工具 schema 可移植性问题(路径、问题、建议修复),只要其中任何一项为 error 严重级别就以6退出。不使用它时,tools/list只打印一行计数。在--format json下,发现结果会以schemaFindings形式并入输出。--verify(配合skills/list或skills/get):运行 SEP-2640 一致性和摘要检查,为每个 skill 在 stdout 上写一份 JSON 报告,违规时退出7,若读取边界导致无法检查完所有 skill 则退出8。--skill-catalog-max-skills和--skill-catalog-max-bytes用于设置这些边界。--require-digests(配合--verify):对于未提供任何摘要的 skill 退出9,而不是把它报告为不可验证并退出0。
mcp-inspector --cli <server> --method tools/list --strict > /dev/null
mcp-inspector --cli <server> --method skills/list --verify --require-digests按失败类别分支
if out=$(mcp-inspector --cli "$URL" --transport http --method tools/list 2>err.json); then
echo "$out"
else
case $? in
3) echo "needs auth: run the web inspector once to sign in" ;;
4) echo "server unreachable" ;;
*) jq .error < err.json ;;
esac
fi对所有带 UI 的工具做冒烟测试
mcp-inspector --cli "$URL" --transport http --method tools/list --app-info \
| jq -r 'select(.hasApp) | .toolName'不连接即可检查 catalog
mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/list
mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/show --server my-serverservers/show 会脱敏含机密的字段(env 值、敏感 headers、OAuth 客户端 secret),但它不会清洗嵌入在服务器 url 中的凭据(userinfo 或查询 token),也不会清洗 stdio args 中的凭据。在把原始 URL 和 detail 字段粘贴到 issue 之前,请将其视为敏感信息。编辑 catalog
servers/add、servers/edit 和 servers/remove 在不连接任何服务器的情况下写入 catalog。它们走的是与 web 客户端服务器列表相同的代码路径,因此 env 值和客户端 secret 会完全像从 UI 操作那样落入机密存储,并且正在运行的 web 客户端会收到该变更。
# Add: the positional target or --server-url describes the entry, not a server to connect to
mcp-inspector --cli node build/index.js -e API_KEY=secret --method servers/add --server my-server
# Edit: change the target, -e, --cwd, --header, or --protocol-era, or rename it
mcp-inspector --cli --method servers/edit --server my-server --rename my-renamed-server
# Remove the entry and its stored secrets
mcp-inspector --cli --method servers/remove --server my-renamed-server只能写入可写的 catalog(--catalog、MCP_CATALOG_PATH 或默认路径);--config 会被拒绝。使用内存机密存储时,提供 -e 值(以及 --rename)的写入会被拒绝,因为运行退出后这些机密就会丢失。
代理
连接远程 HTTP/SSE 服务器时会遵循常规代理变量:HTTPS_PROXY / HTTP_PROXY(及它们的小写形式)选择代理,NO_PROXY 豁免主机。无需任何 Inspector 专用 flag,并且代理 agent 是惰性加载的,因此不使用代理的运行不会有任何开销。web 客户端的后端同样如此。