feat(mcp): 支持基于 mcp.json 的 MCP 工具检查、发现与调用(一期设计)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- go
- Domain
- backend-api-design, cli
Research direction
Start with cmd/root.go and inspect internal/config/context.go, internal/api/auth_header.go, internal/requestexec/body_input.go, and internal/output/envelope.go and jq.go for existing CLI patterns. Then evaluate the official github.com/modelcontextprotocol/go-sdk against the stated Go version and Streamable HTTP protocol versions. Done means implementing the documented commands, configuration and authentication rules, parameter handling, pagination, lifecycle, output, and error behavior, with local mock coverage and a manual real environment acceptance checklist.
Written by the indexing model from the issue text.
Description
背景与目标
新增 bk-cli mcp,让用户和 Agent 通过命令行连接已配置的 MCP server,检查连接、发现工具、查看工具帮助并显式调用工具。以 MCP server 返回的工具定义为依据,不为每个 server 手工开发 system action。
一期面向远程 Streamable HTTP server,认证来自选定 mcp.json 中各 server 自己的 headers。不实现公共客户端 OAuth 自动登录,不隐式复用 bk-cli context 凭据。
本文是待实现的完整一期设计;创建 Issue 不代表功能已完成或真实服务联调已通过。示例中的域名、server 名称及票据均为占位值。
1. 设计基线与兼容边界
设计日期:2026-10-20。代码检查基于 779108d13b6693d00cc5a4a7d361b5fe6f9e84a1;创建前远端 master 为 ee4d3eb74e8e70fc233af0b03fb524c020426fe3,两者差异仅为已有 Skill 的 jq 使用文档。
当前可复用的基础:
- 配置目录:默认
~/.bk-cli/,支持BK_CLI_CONFIG_DIR。 - 认证头映射:个人 token 使用 Bearer,原有凭据使用
X-Bkapi-Authorization。MCP 命令只复用校验/脱敏等独立能力,不加载这些 context 凭据来生成请求头。 - body 输入:已有内联 JSON、
@file、stdin 输入习惯;当前函数为包内函数,不能假设存在可直接调用的导出 API。 - 输出封装、jq 投影:复用 envelope、结构化错误和最终结果投影。
- 根命令:新增独立的
mcp命令组,不注册为cmd/system下的蓝鲸业务系统。
现有 api / system action 的认证、URL 拼装、context、输出和退出码契约不随本功能变化。不把 MCP 请求伪装成普通网关 REST 调用。
2. 第一期范围
包含
- 从单个 JSON 文件加载多个命名 server,按名称选择目标。
type: "http"对应 Streamable HTTP;支持其 JSON 和text/event-stream响应形式。- 显式 headers、headers 中声明的环境变量引用,以及无认证 server。
--check、--tools、server 帮助、tool 帮助、tool 调用。- 按工具
inputSchema生成可表达的具名参数,并提供完整 JSON 输入兜底。 - 工具列表完整分页、单次执行超时、取消、连接清理。
- 结构化输出、MCP 错误判定、认证信息脱敏和已有
--jq能力。 - 离线 dry-run:使用完整
--body预览调用,不连接 server。 - 本地 mock 验证和人工触发的真实环境验收清单。
不包含
- OAuth 登录、浏览器跳转、授权码/device flow、token 自动刷新或其他客户端登录缓存导入。
- 当前 context 凭据、tenant、stage、网关 URL 模板、认证环境变量的隐式回退。
- stdio 子进程、旧版 HTTP+SSE transport、自动 transport 探测/降级。Streamable HTTP 内的 SSE 响应仍属一期范围。
- 自动扫描/合并 Cursor、Claude、VS Code 等客户端配置。
- 跨 server 批量调用、自动调用全部工具、定时执行、工作流编排。
- resources/prompts 操作、sampling、elicitation、异步 task 轮询、媒体自动落盘。
- 常驻 daemon、跨进程连接池、持久化工具 Schema 缓存。
- 自动解释任意业务 JSON 中的
code/result/status,或把任务 ID 视为任务完成。
3. 命令形式
统一采用 bk-cli mcp <server> [选项或工具]。不新增 mcp check <server>、mcp tools <server> 这样的操作子命令。
| 命令 | 行为 |
|---|---|
bk-cli mcp / bk-cli mcp --help |
本地通用帮助、配置位置、示例;不要求配置存在,不连接 server |
bk-cli mcp <server> / bk-cli mcp <server> --help |
读取选定配置,展示该 server 的静态使用说明及 --check/--tools/<tool> --help 指引;不连接 server、不要求票据环境变量已设置 |
bk-cli mcp <server> --check |
校验配置、完成协议连接/协商、完整读取工具列表;输出分阶段结果 |
bk-cli mcp <server> --tools |
完整发现工具,输出名称、描述、inputSchema 及可用的其他工具元数据 |
bk-cli mcp <server> <tool> --help |
连接目标并读取工具 Schema,显示参数、必填项、类型、示例和 JSON 输入指引;不执行工具 |
bk-cli mcp <server> <tool> --param value |
发现工具、解析/校验参数,执行一次 tools/call |
bk-cli mcp <server> <tool> --body '<json>' |
使用完整 arguments 对象调用 |
bk-cli mcp --config <path> <server> ... |
本次只使用指定配置文件 |
示例:
bk-cli mcp report-prod --check
bk-cli mcp report-prod --tools
bk-cli mcp report-prod search_reports --help
bk-cli mcp report-prod search_reports --keyword '网关错误' --limit 20
bk-cli mcp report-prod search_reports --body '{"keyword":"网关错误","limit":20}'
bk-cli mcp report-prod search_reports --body @params.json
bk-cli mcp report-prod search_reports --body - < params.json
bk-cli mcp --config ./.mcp.json report-prod --tools
规则:
--check、--tools和<tool>调用三种执行模式互斥;多余位置参数、未知选项报错。--help/-h只进入对应帮助路径,不进入 check/call,不读取 body 文件或 stdin;互斥模式组合仍报使用错误。--check/--tools不接受--body或工具参数。- server/tool 名称大小写敏感,按配置名和协议原名精确匹配,不自动改写下划线、连字符或点号。
- server 配置名应为可稳定作为单个命令词的非空名称,不以
-开头,不含空白/控制字符;配置名只是本地别名。 - 不因某个工具无法生成 flags 而隐藏它;仍在工具目录中展示并允许完整 JSON 调用。
通用 flags
--timeout <duration>:正值 duration,默认沿用现有 60 秒常量,但不读取 context。覆盖本次远程操作总耗时(包括发现分页与调用),不是每页重新获得完整预算。--verbose/-v:诊断输出到 stderr,认证信息脱敏。--insecure:仅显式开启时跳过目标 HTTPS 证书验证,与现有开关语义一致。--jq:用于 check、tools、call、dry-run 的最终 JSON envelope;复用既有解析、预算及失败处理。帮助不做结果投影。--context:在 MCP 路径上显式使用时返回unsupported_option,避免给人“已切换 MCP 认证”的错觉;未显式传入时完全不访问 active context。- 不新增
--header、--stage、--tenant或独立 token flags;一期认证和附加 headers 统一来自选定 server 配置。
4. 配置加载
路径与优先级
只选择一个配置文件,不做合并:
- 显式
bk-cli mcp --config <path>。 - 否则使用
internal/config.BaseDirectory()下的mcp.json:设置BK_CLI_CONFIG_DIR时取该目录,否则取~/.bk-cli/mcp.json。
项目配置通过 --config ./.mcp.json 显式使用;一期不自动向父目录查找,不自动读取当前目录或其他客户端配置。选定文件不存在、不可读或格式错误时直接报错,不再尝试另一个来源。
相对配置路径按当前工作目录解析,诊断展示最终文件位置。--body @file 同样按当前工作目录解析,与配置文件所在目录无关。
不把文件放在 contexts/<name>/ 下;context use 不改变 MCP 连接、认证或默认配置文件。
文件结构
{
"mcpServers": {
"report-prod": {
"type": "http",
"url": "https://mcp.example.com/report/application/mcp/",
"headers": {
"X-Bkapi-Authorization": "${REPORT_BK_AUTH}"
}
},
"report-personal": {
"type": "http",
"url": "https://mcp.example.com/report/application/mcp/",
"headers": {
"Authorization": "Bearer ${REPORT_PERSONAL_TOKEN}"
}
},
"public-docs": {
"type": "http",
"url": "https://mcp.example.com/public/mcp/"
}
}
}
REPORT_BK_AUTH 是完整认证 JSON 字符串,例如应用凭据或 {"access_token":"..."}。也允许直接配置认证字符串:
{
"X-Bkapi-Authorization": "{\"bk_app_code\":\"your_app_code\",\"bk_app_secret\":\"your_app_secret\",\"bk_ticket\":\"your_ticket\"}"
}
加载契约:
- 一期使用严格 JSON,不支持 JSONC、include、extends 或客户端特有的
inputs/命令执行表达式。 - 要求顶层
mcpServers;servers等其他格式明确提示不支持,不静默转换。 - 拒绝重复 JSON key、重复 server key、大小写不同但等价的 header key;不采用“最后一个覆盖前面”的隐式行为。
type必须显式为http;不支持的类型或会被忽略的未知配置字段报错,避免用户误以为配置生效。url必须为绝对 HTTP(S) URL,不允许 userinfo 和 fragment;路径、尾部斜线和合法 query 保持原样,不套网关模板、不拼 stage 或自动追加/mcp。headers必须是字符串映射,可省略或为空对象。禁止用户覆盖由协议/HTTP 栈管理的Host、Content-Length、Content-Type、Accept、连接控制头和 MCP session/version 等协议头。- 文件语法及配置结构整体校验;环境变量展开和凭据校验仅针对当前选中的 server。无关 server 的未设置环境变量不应阻止目标调用。
- 不自动创建带占位票据的配置,不修改或回写用户原文件。
环境变量
- 一期仅支持所选 server 的 header 值中的
${ENV_NAME};支持同一字符串中的多个引用。环境变量名称遵循常见字母/数字/下划线规则。 - 单次文本展开,不执行 shell、不递归展开,不自动读取
.env,不支持${env:NAME}、${input:NAME}、默认值或命令替换。 - 使用
$${表示字面${;展开结果不再当作模板解释。 - 缺少引用变量时报
missing_environment_variable;空认证值报配置错误,不能降级为匿名。 X-Bkapi-Authorization的展开结果必须仍是合法 JSON 对象;推荐整段认证 JSON 通过一个环境变量传入,避免嵌套 JSON 转义问题。- 即使环境里存在
BK_CLI_PERSONAL_TOKEN等变量,也只在配置显式引用时读取;不自动读取现有 auth login 环境回退来源。 - 含真实票据的配置不提交版本库,使用仅当前用户可读写的文件权限;共享配置使用占位值/环境引用,不把展开后的值写回文件。
5. 认证契约
认证唯一来源是目标 server 的 headers(包括其显式环境引用)。
| 配置 | 行为 |
|---|---|
Authorization: Bearer <personal-token> |
原样使用该凭据,不验证业务有效期、不自动刷新 |
X-Bkapi-Authorization: {"bk_app_code":"x","bk_app_secret":"y","bk_ticket":"z"} |
使用原有应用 + ticket 认证 |
将上述 bk_ticket 换为 bk_token |
使用原有应用 + token 认证 |
X-Bkapi-Authorization: {"access_token":"z"} |
使用原有 access_token 认证,不自动转换成 Bearer |
| 无认证头 | 不附加认证,允许匿名 server |
| 两种认证头同时存在 | 忽略头名大小写后识别冲突,本地报错,不选择某一份身份 |
| 空认证头/空 Bearer/非法蓝鲸认证 JSON | 本地报错,不回退 context 或匿名模式 |
headers 保持通用透传能力:第三方的合法 Authorization scheme、自定义 API key header 可直接传递;只对可识别的 Bearer 和蓝鲸认证做对应格式校验,不凭未知 header 推断身份。
蓝鲸认证一期明确支持上述形态:应用模式要求非空 code、secret,以及 ticket/token 二选一;access_token 模式独立使用,不与应用字段混合。字段均为字符串;错误不打印票据。此本地校验不证明凭据有效或有权限。
所有实际 MCP HTTP 请求统一使用同一份已解析 headers,包括旧协议初始化、工具发现分页、工具调用及需要的会话操作。不得只在 tools/call 时添加认证。
响应处理:
401:认证缺失或失效,提示修改所选文件中对应 server 的 headers/环境变量。不浏览器登录、不读其他客户端 token、不刷新、不换身份重试。403:保留安全的服务端权限错误,提示检查该身份的 server/tool/业务权限;不把所有 403 都描述为 token 过期。- 工具发现成功只证明服务端接受本次发现请求;匿名也可能成功,不单独声称 token 已验证,更不表示所有工具或业务资源均获授权。
凭据仅发送到配置的目标 endpoint;一期不自动跟随 HTTP 重定向,避免手工配置的敏感头随重定向外发,并提示更新 URL。HTTPS 默认校验证书。
认证头名称大小写不敏感地脱敏,覆盖 check、help、dry-run、verbose、响应 headers 和错误信息。解析错误不得回显原 header 或整个配置。原始工具业务结果按现有 CLI 原样保留,不承诺通用内容级 DLP;诊断不得主动复制凭据到结果。
6. 参数映射
具名 flags
以 tools/list 返回的 inputSchema 为准,保留字段原名:
| Schema | CLI | JSON arguments |
|---|---|---|
| string | --keyword '网关错误' |
"keyword": "网关错误" |
| integer | --limit 20 |
"limit": 20 |
| number | --ratio 0.5 |
"ratio": 0.5 |
| boolean | --enabled=true / --enabled=false |
"enabled": true/false |
| array | --ids '[1,2,3]' |
"ids": [1,2,3] |
| object | --filter '{"status":"running"}' |
"filter": {"status":"running"} |
| null、联合类型、难以映射的 Schema/字段名 | 完整 --body |
保留 JSON 的原始表达 |
规则:
- 支持
--name value和--name=value;布尔值以显式=true/false为规范写法,不引入隐式取反或--no-*命名规则。 - 只传用户显式提供的字段;未提供不能自动变成
false/0/"",也不自动注入 Schema 的default注解。 - 字符串
"00123"保持字符串,不靠字面量猜类型。数值路径不得经 float64 导致大整数精度损失;超出实现支持范围时明确拒绝,不能静默截断。 - 对同一个具名参数重复赋值报错;数组使用 JSON,不用逗号拆分或重复 flag 拼接。
- 必填字段、明确的基础类型和 enum 在调用前校验;不能因 CLI 的默认值造成虚假的必填项通过。
- 能安全识别的本地 Schema 约束应校验;一期不承诺完整 JSON Schema 方言、组合关键字或所有
$ref的本地验证,不为解析$ref自动访问远程网络。 - 无法无歧义映射的字段不生成 flag,帮助注明使用
--body;服务端仍为最终参数校验方。
完整 JSON
--body '<json>'、--body @file、--body - 表示完整的 tools/call.params.arguments 对象,不是 JSON-RPC 报文,也不是直接请求上游业务 API 的 HTTP body。
- 顶层必须是 JSON 对象;空输入、数组、标量、非法 JSON 和重复字段报错。无参数调用使用
{}。 - 提供
--body时,以完整 JSON 为准,不与具名参数合并,不用被覆盖的 flags 生成默认值或判定必填项;识别到的被覆盖参数不发送。未知选项仍报错。 - 与现有 body override 行为保持一致。可识别的具名参数仍需有合法 CLI token 结构;不把拼错的 flag 当成可忽略内容。
- 必填校验针对最终对象;基础校验可以执行时执行。复杂 Schema 使用 JSON 路径并交由服务端验证,不能宣称做过实际上未支持的本地完整验证。
- 文件和 stdin 输入采用相同 JSON 解析及数字保真规则;读取错误发生在
tools/call之前。stdin 只读一次,--help不消耗 stdin。 - JSON 字符串中的中文、引号、换行、反斜杠、
$()和反引号作为数据处理,不交给 shell 再执行。
保留名与冲突
保留 CLI 自身实际存在及约定预留的 flag 名,包括 help/check/tools/config/body/timeout/jq/context/dry-run/verbose/insecure/format 等。实现以统一集合为准,并覆盖短选项。
工具字段与保留名冲突时,不生成对应 flag、不覆盖 CLI 选项、不自动改名;字段通过 --body 原名传入。工具名称/工具的其他参数仍可用,--tools 和 tool 帮助应解释该限制。
7. 执行、协议与生命周期
执行顺序:
- 解析本地模式与通用 flags,先发现互斥组合及非法 jq 表达式。
- 选定唯一配置、查找 server、校验目标及认证;仅按需展开 header 环境变量。
- 创建独立 MCP client/HTTP transport,设置超时与取消;不读取 context。
- 按协商协议完成必要初始化;发现工具时完整处理
tools/list分页。 - 对 help 返回 Schema 帮助;对 check/tools 返回诊断/列表;对 call 构造最终 arguments 后只调用指定工具一次。
- 判断协议/工具结果,生成最终 envelope,再做 jq 投影;结束时关闭连接及本次会话。
协议实现优先评估官方 github.com/modelcontextprotocol/go-sdk,不手写一套 JSON-RPC/Streamable HTTP 协议栈。当前候选 v1.8.0 的 go.mod 要求 Go 1.25.0,与本仓库 Go 1.25.5 的声明一致;这只是静态版本证据,不是已完成依赖兼容验证。
一期兼容测试明确覆盖 Streamable HTTP 上的 2025-03-26、2025-06-18、2025-11-25 和 2026-07-28 工具发现/同步调用路径。由固定 SDK 版本处理版本协商差异,不把所有版本都强行套到同一初始化/会话流程;不支持的版本报错。SDK 支持其他 transport/扩展不意味着 CLI 一期对外支持它们。
- 若收到需要用户补充输入、sampling、elicitation 或异步 task 等非一期能力的响应,明确报告能力未支持,并保留可用的原始结果/任务标识;不自动交互、轮询或重复执行。不能将未完成结果标为工具已成功完成。
tools/list处理nextCursor直到结束,检查重复/循环游标和分页上限;上限应在实现中固定、记录并测试。任何中途失败/截断不得输出“完整发现成功”。空 tools 列表可以是成功。- 全量工具目录中重名工具应报协议/目录冲突,不任意选一个。工具集可能随认证变化,一期不做持久缓存。
- discovery 与 call 尽量在同一次 client 生命周期内完成;发现后工具被删除时保留远端错误,不自动刷新后重试调用。
- 超时/取消、结果解析失败、输出失败都不能触发自动重发
tools/call。请求发出后失去结果时标明执行结果未知。 - 不预先连接其他 server,不在根命令注册阶段联网;远端故障不能导致其他 bk-cli 命令不可用。
8. 检查与输出契约
--check
执行本地配置/认证格式校验、协议连接和完整工具发现,不调用任何业务 tool。
成功结果示意:
{
"ok": true,
"data": {
"server": "report-prod",
"config_file": "/home/example/.bk-cli/mcp.json",
"transport": "http",
"checks": {
"config": "passed",
"connection": "passed",
"protocol": "passed",
"tools": "passed"
},
"authentication": {
"source": "server_headers",
"discovery_accepted": true
},
"tool_count": 12,
"complete": true
}
}
匿名配置的 source 为 none;discovery_accepted 表示此次请求被接受,不是对 token 有效性的独立验证。进入远程检查后失败时,整体 ok:false,已完成阶段保留,失败阶段标 failed,后续阶段标 not_run,提供结构化错误;文件/配置等早期错误沿用下文的本地错误通道。不能靠 HTTP 200 或 tools 数量单独判定成功。
--tools 与调用
--tools输出完整目录及server/tool_count/complete;保留工具inputSchema、可用的outputSchema/annotations 等元数据,以便 Agent 选择工具。- 调用输出包含
data.server、data.tool、data.result;result保留 SDK 支持的 MCP 结果字段,包括content、structuredContent、isError、_meta等,不默认把 text 内容再猜测为业务 JSON。 ok:true仅表示本次检查/发现完成,或本次 MCP 同步工具调用完成且未报告工具错误;不推断业务成功或异步任务完成。- HTTP 成功但 JSON-RPC error、无效 MCP 响应、
isError:true,均为失败。isError:true的原始结果仍可供调用方检查。 - 不伪造 HTTP status。多请求操作的阶段和失败位置通过 data/error 表达,不能只展示最后一个 200 掩盖先前失败。
- 二进制/图片/音频等 content 保留为协议 JSON,不自动展示、下载或写文件。
输出渠道和退出码:
| 情况 | 输出/退出 |
|---|---|
| 帮助 | stdout 文本,退出 0 |
| 本地输入/配置/参数校验失败,未形成远端结果 | stderr 结构化错误,stdout 不输出业务结果,退出 1 |
| check/tools/call 成功 | stdout 一个最终 envelope,退出 0 |
| 远程操作开始后的连接/认证/协议/工具错误 | stdout 一个 ok:false envelope,保留阶段/工具结果,退出 2;不重复打印第二份完整错误 |
| jq 运行/输出失败 | 沿用现有输出层契约,退出 2;不能触发工具重试。jq 编译错误属于本地输入错误,退出 1 |
诊断日志走 stderr。新增错误码使用 snake_case,建议固定如下机器契约,沿用输出层已有 jq 错误码:
- 本地/使用错误,退出 1:
invalid_mcp_config、mcp_config_not_found、mcp_server_not_found、missing_environment_variable、mcp_auth_conflict、invalid_mcp_arguments、unsupported_option、mcp_tool_not_found(完整发现后本地确认工具不存在)。 - 远程/运行错误,退出 2:
mcp_auth_required、mcp_permission_denied、mcp_connection_error、mcp_timeout、mcp_protocol_error、mcp_discovery_incomplete、mcp_tool_error、mcp_capability_unsupported。 - 配置的 transport 不支持属于
invalid_mcp_config;协议协商失败或发现后远端工具消失属于mcp_protocol_error。已知凭据收到 401 时,同一mcp_auth_required提示凭据可能失效,不伪造具体失效原因。
--jq 仅作用于最终完整结果:工具结果判定/目录聚合先完成,失败 envelope 不被投影隐藏,投影错误保留已完成请求的原结果并明确提示不要盲目重试。本功能不改变其他命令既有的 HTTP/业务退出行为。
离线 dry-run
没有持久 Schema 缓存时,具名 flags 的类型来自远端,不能同时承诺“离线”与“动态类型映射”。
一期明确选择:
- 仅支持
<server> <tool> --body <完整对象> --dry-run,无参数工具使用--body '{}'。 - 不发送初始化、
tools/list或tools/call;只校验本地配置、认证格式和 JSON 结构。 - 输出目标 URL、脱敏后的业务 headers、工具名、arguments、
dry_run:true,明确标注未验证远端工具存在性、Schema、认证有效性及业务权限。 - dry-run 不伪造协商版本、会话 ID 或 JSON-RPC 请求成功;协议管理字段由真实执行时的 SDK 生成。
- dry-run 要求完整
--body,并拒绝所有具名工具 flags(即使同时提供 body),避免在离线模式下猜测哪些选项是工具参数;--check/--tools与 dry-run 互斥。
9. 实现边界与建议分工
以下为拟新增位置,均非当前已有实现:
cmd/mcp/:命令路由、模式互斥、动态帮助/参数入口、输出调用。internal/mcpclient/:配置与 header 解析、MCP transport/session、发现分页、Schema 参数适配、结果分类;按职责拆文件,不引入没有具体用途的 provider/plugin 框架。cmd/root.go:注册独立 MCP 命令。已有 system 专用参数归一化逻辑不能未经检查直接套用。internal/output:复用 envelope/jq/error;只有实际调用需要时才做最小通用改动,不修改既有 APIResponse 的成功语义。- body/file/stdin 解析若需要复用,通过最小共享边界提取并保留旧命令行为测试,不让 MCP 执行器依赖网关 runtime/context。
tests/integration/cases/mcp/:作为新的非 system 命令测试目录,并同步 integration guidance;mock 优先扩展既有mock_api/app.py,不默认新增第二套服务。
实现前应锁定 SDK 版本并检查许可证、依赖变化、MCP 版本能力、数字保真和跨平台构建;不能仅因引入 SDK 就开启 OAuth/stdio 或自动请求重试。必要的 JSON Schema 库先评估 SDK 的现有依赖,避免无意引入两套验证器。
文档同步包含 README.md、README_EN.md、docs/user-guide.md、docs/design.md、AGENTS.md;新增中文使用说明 skills/bk-cli-mcp/SKILL.md,共享 Skill 仅补入口和通用行为。MCP 是根命令组,不应混入业务 system 扩展注册流程。
10. 自动化测试与验收矩阵
使用 Ginkgo/Gomega、临时目录、隔离的 BK_CLI_CONFIG_DIR 和本地 HTTP/mock server。测试必须能断言实际请求数量、请求方法/协议参数及 headers,不能只检查输出文案。
| 编号 | 场景 | 验收要求 |
|---|---|---|
| C01 | 默认目录、配置目录环境覆盖、显式 --config |
路径选择正确,显式文件优先且无隐式合并/扫描 |
| C02 | 缺文件、坏 JSON、重复 key、错误字段/transport/URL/header | 明确本地错误,零网络请求,不回退其他文件 |
| C03 | 切换/缺少/损坏 context,显式 --context |
前三者不影响 MCP;显式 context 报不支持,无凭据加载 |
| C04 | 环境引用、缺变量、空票据、字面 ${、无关 server 缺变量 |
只展开目标;不执行命令、不回写、不泄露原值 |
| A01 | 个人 Bearer、应用+ticket、应用+token、access_token 四种形式 | 请求使用配置值,初始化/分页/call 均一致,不出现另一套凭据 |
| A02 | 无认证头,分别访问匿名和需要认证的 server | 匿名成功;401 明确失败,不回退 context/OAuth |
| A03 | 两个认证头、大小写变体、重复等价头、空 Bearer/非法蓝鲸 JSON | 本地拒绝,零网络请求 |
| A04 | 401、403、跨地址重定向、TLS 失败 | 错误分类正确,不自动登录、换身份、跟随重定向或重试调用 |
| A05 | dry-run/verbose/错误/响应 headers | 认证头值不泄露;配置解析错误不回显密钥 |
| D01 | 根/server 帮助、server 裸命令 | 不联网、不消费 stdin;根帮助无配置也可用 |
| D02 | tool 帮助 | 只发现 Schema,不调用工具;网络/认证失败有明确错误 |
| D03 | 单页、多页、空 tools | 完整列表及数量正确,空列表成功,check 不调用 tool |
| D04 | 重复游标、游标循环、超过上限、中途失败、重名工具 | 不挂死、不伪报完整结果,返回失败与已完成阶段 |
| P01 | string/int/number/bool/array/object | 类型正确;中文、空字符串、false、0 和未传值彼此区分 |
| P02 | 大整数、指数、前导零字符串 | 不经过 float64 静默丢精度;字符串原样保留 |
| P03 | required、enum、类型错误、重复 flag、未知 flag | 在 tools/call 前失败,不因默认值掩盖缺参 |
| P04 | 内联 JSON、文件、stdin、空/非法/非对象/重复字段输入 | 同一 arguments 契约;stdin 只读一次,失败不执行 tool |
| P05 | body 覆盖具名参数、保留名字段、复杂 Schema | 不隐式合并;原名字段能用 body 调用;不隐藏工具 |
| P06 | shell 敏感字符/换行/引号/反斜杠 | 参数是数据,不二次执行;文件输入可规避 shell 转义 |
| R01 | 协议版本矩阵、JSON/SSE 响应、旧版 session 生命周期 | 协商与请求格式正确,退出清理,无旧 transport 自动降级 |
| R02 | MCP 成功、HTTP 错误、JSON-RPC error、isError=true、畸形结果 | envelope/退出码正确,工具错误原结果保留 |
| R03 | 超时/取消/结果丢失/输出失败 | 不重发工具;必要时报告执行结果未知;连接释放 |
| R04 | 不支持的交互/异步响应 | 不伪报完成,不自动交互/轮询,保留返回标识 |
| O01 | jq 成功/编译失败/运行失败/失败 envelope | 先校验 jq,最终结果只投影一次,不隐藏错误或重发请求 |
| O02 | 离线 dry-run 及拒绝组合 | 零网络请求、认证脱敏、标明未验证远端;拒绝纯 flags 的离线映射 |
| I01 | 构建后的 CLI + 集成 mock | 从文件加载到 check/tools/help/call 路径完整执行,不访问真实环境 |
集成场景建议至少建立 MCP-001 基本流程、MCP-002 认证及隔离、MCP-003 参数/错误、MCP-004 分页/超时和 MCP-005 离线行为;按已有 harness 的 scenario 与 case 两种入口执行。mock server 需要支持真正的 MCP wire 交互;普通 HTTP 200 echo 不能代替协议测试。
11. 真实环境验收
真实联调单独人工触发,不纳入默认 CI,不把真实 URL/票据写入测试文件、日志或 Issue。
- 准备一个具备已知只读工具的远程 MCP server,分别配置四种蓝鲸票据形态(服务端允许的模式)。
- 执行
--check,验证连接/协议/目录完成;记录协议版本、工具数量和错误边界,不记录票据。 - 执行
--tools和指定 tool 的--help,确认发现结果、参数和 Schema 一致。 - 显式调用一个已知无副作用的工具,依据该工具声明的业务契约判断结果。
- 用缺失、失效、权限不足的测试身份验证 401/403,不把工具列表成功当作全部权限成功。
- 切换 bk-cli context 后重复检查,确认目标配置和认证不变。
若某种认证或协议版本缺少实际服务验证条件,应明确记录“仅 mock 通过 / 未做真实联调”,不能据此宣称该生产部署已支持。
12. 实施顺序与完成条件
建议在同一功能范围内按以下顺序推进:
- 配置选择、严格解析、环境引用、认证隔离与脱敏。
- MCP SDK/transport 接入,完成协议兼容 fixture、check 和 tools 分页。
- 动态帮助、参数映射、body 输入与显式调用。
- 输出/退出码、jq、离线 dry-run、超时/取消及结果未知处理。
- 补齐集成用例、使用文档及真实只读联调记录。
实际实现的验证门禁(当前仅写设计,以下尚未执行):
# 仓库有 .envrc 时先 source .envrc
make fmt
make lint
make test
make test-cover
make build
go test ./tests/integration/runner -count=1
make test-integration SCENARIO=MCP-001
# 再执行其他新增 MCP 场景,并至少用 CASE=实际文件路径执行一次
新增 internal 包需要满足仓库现有 coverage 门槛;不得修改阈值来代替行为验证。只有改动影响相关检查时才重复执行,不运行真实生产工具作默认测试。
完成条件:
- 命令形态保持
bk-cli mcp <server> --check/--tools/--help与<server> <tool>。 - 第一阶段的全部范围有实现与测试;排除项没有通过隐式行为被引入。
- 配置和认证来源可解释,切换 context 不改变 MCP 身份。
- tools 完整发现、复杂 arguments、保留名冲突和数字保真均有覆盖。
- 不把 HTTP 成功、发现成功或任务 ID 当作业务完成;失败退出和原始结果可用于自动化判断。
- 帮助/检查不执行业务工具,离线 dry-run 零网络请求,任何失败都不自动重发调用。
- 仓库门禁与 mock 集成通过;真实联调完成情况和缺口分别记录。
- 中英文 README、设计/使用文档和中文 MCP Skill 与命令保持一致。
参考与相关需求
- MCP Tools:工具目录、Schema、调用与错误语义。
- MCP Authorization:认证能力与协议传输层的边界;本期只使用预配置凭据。
- 官方 Go SDK v1.8.0:协议版本表及依赖候选;实际接入前仍需版本/依赖验证。
- Codestz/mcpx、MCPorter:动态 CLI、配置与调用的实现参考,不据此承诺相同功能范围。
- Claude Code 配置、Cursor 配置:配置位置与环境引用是客户端约定,没有统一的全行业文件路径。
- #29:已有个人 token 能力;本期复用认证约定,不复用 context 登录态。
- #34:已有 jq 投影;本期复用最终输出能力。
- #32:更广的请求/业务/异步结果语义另行演进;本期只定义新 MCP 命令自身可证明的结果,不改变其他命令契约。
- Dominant language
- Go
- Stars
- 7
- Forks
- 6
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 14
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from TencentBlueKing/bk-cli
-
Difficulty 5/5 Over a week Newbie friendliness 32/100
TencentBlueKing/bk-cli#33 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 28/100
TencentBlueKing/bk-cli#32 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
TencentBlueKing/bk-cli#31 ·
Maintainers usually reply within 1 day
-
agent 安全与执行治理Open
Difficulty 5/5 Over a week Newbie friendliness 35/100
TencentBlueKing/bk-cli#8 · 1 comment ·
Maintainers usually reply within 1 day
-
支持 bk-cli doctorOpen
Difficulty 4/5 3-5 days Newbie friendliness 48/100
TencentBlueKing/bk-cli#7 · 1 comment ·
Maintainers usually reply within 1 day
All issues in TencentBlueKing/bk-cli
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
area/frameworks area/steve kind/bug team/frameworks
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Exclude merge queue branches from push trigger in ci-workflow.yaml to eliminate duplicate CI runsOpenbug infra ready-for-triage triaged
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
redhat-et/ProtoBot#312 · 2 comments · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day