Skip to content

[Grok/dsh 35] 本地 MCP 发现与工具调用 #167

Description

@Blackman99

Parent

#132

Ticket: 35

Status: ready-for-agent

User Stories: 39, 41(见父规格)

What to build

用户配置并信任本地 MCP 服务,查看初始化状态,通过 dsh 查找和调用实际工具,并能重启或停用服务。

Acceptance criteria

  • 兼容直接配置的服务,初始化、可用工具目录和错误真实可见;插件贡献接入另票,不阻塞直接配置 MCP。
  • 搜索/调用工具的名称、schema、参数与结果保真,并受同一权限、Hook、取消链约束。
  • 缺程序、崩溃、超大输出、重启、撤权和停用后工具移除都可外部验证。
  • 使用真实测试 MCP 进程完成从配置到工具副作用和界面结果的全过程。

Blocked by

Delivery contract

用户于2026-09-20批准当前测试与任务拆分。按父规格的已安装产物/真实终端和公开协议测试验收;实际实现须带适用的文档、Changeset及必要检查。ready-for-agent表示任务已定义,不表示前置任务已完成,也不授权自动开始本轮实施、购买付费资源或发布软件版本。

Activity

  1. Blackman99 commented on Sep 25, 2026

    @Blackman99
    OwnerAuthor

    Ticket 35 / #167 已合入 rewrite/grok-dsh-20260920 的 1f7de23。这次是快进推送(e2b56a8..1f7de23),没有强推。提交已 rebase 到 #151(e2b56a8)和 #172(7f927ee)之上,冲突两边都保留了(acp.rs、main.rs、rust.mjs、overlay 和 mock LLM)。

    本地 MCP 由 dsh 执行:codsh 负责发现和配置 MCP 服务器,每个服务器包一层 stdio 代理,再交给 dsh 挂载。工具调用走 dsh 原有的权限、Hook 和取消链路。

    • 发现来源:
      • 用户配置 [mcp],以及项目 .grok/config.toml(需要信任)
      • .mcp.json
      • Claude / Cursor 兼容配置(通过 compat 或 GROK_CLAUDE_MCPS_ENABLED / GROK_CURSOR_MCPS_ENABLED 开关)
      • 编辑器 ACP 传入的 mcpServers
    • 生效规则:disabled_mcp_servers 和 enabled=false 生效。撤销项目信任后,项目里的服务器会被移除。
    • CLI:codsh --rust mcp list|add|remove|enable|disable|doctor(支持 --json)。
      • doctor 会真实启动服务器,报告初始化结果和工具数量。
    • TUI:
      • /mcps(别名 /mcp)可列出状态,以及执行 enable、disable、restart、refresh,操作后重新挂载并续接当前会话。一轮进行中不允许操作。
      • 服务器缺失、崩溃、初始化失败会显示启动提示;plain 模式写到 stderr。
    • 代理:
      • 有启动超时 startup_timeout_sec / GROK_MCP_STARTUP_TIMEOUT_SECS / MCP_TIMEOUT,也有工具超时 tool_timeout_sec。
      • 状态和 stderr 写在 $DSH_HOME/mcp/ 下。
      • 初始化错误记为 initialize failed (code): msg。
      • 挂载失败的服务器会被剔除后重试,其余服务器照常可用。
    • dsh 插件 rust-acp-mcp.mjs:
      • 提供工具目录,以及 search_tool(BM25)和 use_tool(嵌套 ctx.tools.execute,父调用即当前工具调用,因此权限审批、Hook 和取消都同链)。
      • 输出上限用 max_output_bytes / GROK_MAX_MCP_OUTPUT_BYTES / MAX_MCP_OUTPUT_BYTES 控制,超出部分写到 $DSH_HOME/mcp/output/<callId>,并附参考实现的截断提示。
    • 权限和 Hook:规则里的工具名会去掉 mcp__ 前缀后匹配,search_tool 和 use_tool 按只读处理(嵌套的实际工具仍要单独审批)。Hook 看到的是去掉前缀后的真实工具名。
    • 文档(README 中英文、CONTEXT、CONTRIBUTING、packages/cli/README)已更新。变更集是 .changeset/rust-dsh-mcp-local.md(patch)。

    验证(Linux x86_64,Node 22.19,干净环境):

    • pnpm typecheck:通过。

    • pnpm test:86 个文件,2332 通过、1 失败。失败的是 reference-evidence.spec.mjs 的 "drives interactive help":高负载下跑了 8.1s,超过默认 5s 超时。单独用 --testTimeout=60000 跑通过,和本改动无关。

    • 新增 scripts/rust-mcp.spec.mjs:10/10 通过,其中 3 个单元测试、7 个用例使用真实 dsh 加真实 MCP 测试进程(e2e/fixtures/rust-mcp-fixture.mjs,无需密钥)。覆盖完整链路(配置 → dsh → MCP 副作用 → 界面/ACP):

      • ACP 批准和拒绝,文件副作用按预期发生或不发生
      • use_tool、search_tool 保留名字、schema、参数和结果
      • 工具报错、取消
      • deny 规则和 Hook 阻断
      • 程序缺失、崩溃、初始化失败,doctor 报告,崩溃后 restart 恢复
      • 通过配置和环境变量设置输出上限(溢出文件已写出)
      • tool_timeout_sec
      • CLI 的 enable、disable、add、remove(禁用后工具从目录中消失)
      • 项目信任和撤销

      与 scripts/rust-acp-protocol.spec.mjs 一起跑共 48/48 通过。

    • cargo fmt --check:通过。

    • cargo clippy -D warnings:失败,原因只有 filesystem_sandbox.rs 里已有的两处问题(tail_marker 未使用、多余的 return)。加 -A dead_code -A clippy::needless_return 后全部通过,本改动的代码没有警告。

    • cargo test --locked --workspace --no-fail-fast:503 + 498 + 42 + 61 + 2 + 379 通过,4 个失败,都不是本改动引入的:

      • filesystem_sandbox 的 2 个用例(strict_requests_network_isolation...、trusted_project_custom_applies...)是已有问题。
      • privacy::drafts_stay_local...、voice::substitute_route... 是已有的不稳定用例。我在未改动的基线 e2b56a8 上单独跑,同样会失败。
      • 新增的 12 个 mcp、mcp_proxy 和 permission 单测全部通过。
    • TUI 的 /mcps 列表、disable、enable 和启动提示,是在这台 Linux 机器上用临时 Python PTY 脚本手动验证的,脚本未提交。

    未验证:

    • macOS 专用的 scripts/rust-*-pty-test.py 和已安装产物(installed-artifact)脚本:没有在这台 Linux 机器上运行。这些脚本要求 macOS 环境或证据。
    • macOS、Windows,test:e2e,真实编辑器或图形界面,付费模型。

    已知限制和留给后续的部分:

    • 每次调用受 dsh 60s 上限约束。
    • structuredContent 不单独渲染,use_tool 只在没有文本时返回它。
    • 超过 64 字符的工具名会被哈希缩短。
    • dsh 原生的 mcp__* 工具仍然可见。
    • 只支持 stdio,不启动 SSE/HTTP,远程 MCP 认证和多类型内容留给 [Grok/dsh 36] 远程 MCP 认证与多类型内容 #168,插件 MCP 贡献留给 [Grok/dsh 72] 插件 MCP 贡献接入 #204。
    • managed 的 MCP allow/deny 和 disabled_mcp_tools 还没有应用。
    • 启动器只放行白名单里的环境变量。
    • $DSH_HOME/mcp/output 里的溢出文件不会自动清理。
    • 挂载失败重试时,可能多留一条 dsh 会话记录。

    main、npm 发布和默认版本都没有改动,PR #213 也没有动。

    后续:#168(远程 MCP 认证与多类型内容)和 #204(插件 MCP 贡献接入)现在不再被本工单阻塞。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions