Skip to content

[Grok/dsh 36] 远程 MCP 认证与多类型内容 #168

Description

@Blackman99

Parent

#132

Ticket: 36

Status: ready-for-agent

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

What to build

用户连接支持的远程 MCP 服务并完成认证,使用结构化/图片内容和需要用户回答的请求。

Acceptance criteria

  • 兼容清单中的远程传输、OAuth/认证与凭据撤销,令牌不写入不受保护日志或导出。
  • 内容块、资源/提示及用户询问按参考能力传递给 dsh 与 Surface,不仅保留纯文本。
  • 认证过期、断连、取消、重连、错误结构和用户拒绝不会重复工具副作用或扩大权限。
  • 受控远端协议测试与至少一个真实支持的集成验证齐备;没有真实验证就保留未完成状态。

Blocked by

Delivery contract

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

Activity

  1. Blackman99 commented on Sep 25, 2026

    @Blackman99
    OwnerAuthor

    已实现并推送到 rewrite/grok-dsh-20260920:33c1699b22269b25fb4b2f584018df2b21f5c118(33c1699)

    实现内容(dsh 仍是执行核心,远程服务经 codsh 的 MCP 代理挂给 dsh)

    • 远程传输:streamable HTTP(含 Mcp-Session-Id、404 会话丢失后重新 initialize 一次、协议版本头)与旧版 SSE(GET 事件流 + POST endpoint),headers 支持 ${session_id} 等占位符;POST 与 SSE GET 遇到 3xx 一律拒绝跟随(不把凭据带去别的源);请求头和令牌不进入 plan / mcp list / 日志。
    • OAuth:受保护资源元数据 / 授权服务器元数据发现、动态客户端注册(不支持时提示需要配置 client_id)、PKCE S256、state 常量时间比较、仅 127.0.0.1 回调;令牌存于 $GROK_HOME/mcp_credentials.json(0600,Debug 脱敏),到期前刷新、401 时刷新一次;mcp login|logout <name>、/mcps auth|logout <name>,登出会调用 revocation endpoint 并删除本地凭据;浏览器只打开 http(s) 地址($BROWSER,Windows 用 rundll32 url.dll,FileProtocolHandler)。
    • 多类型内容(按参考的投影规则):图片块和内嵌图片资源以 image 块交给 dsh(--expose-image-base64 时额外附 base64 文本),其他内嵌资源转为 JSON 文本,音频变成说明文字,资源链接等其他块原样透传,未内联的 structuredContent 以紧凑 JSON 追加;错误结果只保留文本。
    • 用户询问(elicitation):TUI 表单卡片(按 schema 渲染 string/number/boolean/enum,校验、d 拒绝、Ctrl+C 取消)与 URL 型确认;编辑器 ACP 通过 x.ai/mcp/elicit 转发,多客户端先答者生效,其余收到 $/cancel_request,无客户端时自动 decline,URL 完成发 x.ai/mcp/elicit_complete。
    • 编辑器 ACP 扩展:x.ai/mcp/auth_status、x.ai/mcp/auth_trigger(登录成功后重启该会话的 MCP 服务)、x.ai/mcp/read_resource(仅限已挂载服务,30 s 超时)。
    • 资源/提示对照:固定参考源码 e8563f8 中可达的资源能力是 ACP x.ai/mcp/read_resource(已实现);参考里 McpStateResourceProvider 虽有定义但未注入,也没有 ListMcpResources/FetchMcpResource 工具实现,MCP prompts 也未被任何界面使用,所以这里不另造模型侧资源工具或 prompts 界面。
    • 文档:README / README.zh / CONTEXT / packages/cli/README / CONTRIBUTING / --help,以及 changeset(codsh-cli、codsh-bundle minor)。

    验证(真实数字)

    • 受控远端协议测试 scripts/rust-mcp-remote.spec.mjs(4/4 通过):本地回环 fixture 覆盖 OAuth 登录、刷新(refresh grant 恰好 1 次)、404 重新初始化(initialize 恰好 2 次,副作用调用只执行 1 次)、图片块、登出撤销;SSE + ${session_id} + 重定向拒绝 + 请求头不进 plan;编辑器 elicitation(表单、URL、错误、非法内容、取消)、auth_status/trigger、read_resource。
    • 真实集成:MCP TypeScript SDK 1.30.0 官方示例 simpleStreamableHttp.js --oauth --oauth-strict(从 dsh 依赖链解析,未联网、未用付费服务)——OAuth 登录、调用 greet、编辑器回答 collect-user-info 表单 elicitation、read_resource、登出,全部通过。
    • PTY:scripts/rust-mcp-remote-pty-test.py 通过(/mcps 显示需要认证 → /mcps auth → 列表 → 表单卡片编辑提交 → d 拒绝 → URL 接受 → /mcps logout);scripts/rust-plugin-mcp-pty-test.py 通过。
    • 检查(基于 cbcbfcf 之上的 33c1699,Linux x86_64):
      • pnpm run typecheck 通过;TMPDIR=/tmp pnpm test:107 个文件中 105 通过、2 跳过;2613 个用例中 2598 通过、0 失败、15 跳过。
      • cargo fmt --check 通过;cargo clippy -D warnings 只剩两个已知问题(filesystem_sandbox.rs 的 tail_marker 未使用、多余的 return),加 -A dead_code -A clippy::needless_return 后通过。
      • cargo test --locked --workspace --offline --no-fail-fast:1772 通过、4 失败、2 忽略。4 个失败都是本单之前就有的、与本改动无关:filesystem_sandbox 的 2 个;privacy::drafts_stay_local… 与 voice::substitute_route…,这两个测试用的本地 HTTP 桩只 read() 一次,请求体分包发送时就收不到。本单没有改 privacy.rs / voice.rs。
    • 安全复查:令牌只在 0600 文件与内存中,Debug/日志/plan/导出不含令牌或自定义请求头;回调仅绑定 127.0.0.1 并校验 state;拒绝 3xx 跟随;浏览器 opener 不经 shell;elicitation 超时/取消/拒绝不会重放工具调用,认证过期只刷新重试一次,不扩大权限。

    未验证

    • macOS / Windows 未实测(Windows 的浏览器打开路径只有代码,未实测)。
    • 未连接任何托管的远程 MCP 服务或真实第三方授权服务器;未运行参考二进制,参考行为依据固定源码 e8563f8。
    • 未处理 URL 型 elicitation 的 -32042 错误重试(README 已注明限制);headless -p 不提供 elicitation。

    范围:main、npm 发布、默认启动路径均未改动;未发布版本,PR #213 未动。

    后续:本单只阻塞 #211;#211 仍被 #186、#188、#201、#203、#206、#209 阻塞,所以本单关闭后没有新解锁的任务。

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