# 解决方案文档 > 本工程的坑(pitfalls)、疑难问题、解决方法与验证方法论。每条含「现象 → 原因 → 解决」与对应官方/本仓库文档地址(如适用)。所有条目均经真实环境验证(dsh 0.1.0-rc.6)。 ## 一、配置与加载类 ### 1.1 `!!js` 表达式求值位置受限(关键坑) - **现象**:`!!js` 写在插件 `config` 之外(如 entry 元数据)不生效或行为异常 - **原因**:dsh 的 Loader 只对 `config` 字段(及 `disabled`)插值表达式;历史上 `disabled` 也出现过"表达式对象被当真值"的事故 - **解决**:`!!js` 只用于 `config` 值;条件性启用/禁用请用 overlay 或 `disabled: !!js '...'` - **官方文档**:[cordis-primer.md#loader-configuration](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cordis-primer.md) · 事故复盘:[postmortem 0002](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md) ### 1.2 bundle 已安装又叠加 `--patch` → 启动失败 - **现象**:`dsh --profile
--patch `;不装就用 `--patch`
- **实测**:dsh 0.1.0-rc.6 复现并确认
### 1.3 EXA_API_KEY 未设置时发坏 header
- **现象**:`headers: { x-api-key: !!js 'process.env.EXA_API_KEY' }` 在未设变量时发送字面 `"undefined"`
- **原因**:JS 表达式求值后为 `undefined`,被序列化成字符串头
- **解决**:条件表达式 `!!js 'process.env.EXA_API_KEY ? { "x-api-key": process.env.EXA_API_KEY } : {}'` —— 无 key 时空对象(匿名免费额度),有 key 自动附头
- **验证**:A/B 实测——匿名搜索成功;伪 key 被 Exa 拒为 `401 Invalid API key`(证明 header 送达且被使用)
### 1.4 工具集与鉴权/白名单的关系(匿名、有 key、白名单三者)
- **现象**:① 匿名 `tools/list` 只有 2 个工具;② 设置 `EXA_API_KEY` 后工具集**不变**;③ 匿名下 advanced 也**不可见**
- **原因**:Exa 服务端对"默认工具集"的界定与鉴权**解耦**——可选工具必须经 URL `?tools=` 白名单显式启用(实测:`?tools=...,web_search_advanced_exa` 后 3 工具;`?tools=...,agent_run` 后 agent_run 出现)
- **解决**:覆盖 `mcp-exa` 行的 `url` 加上所需白名单;`agent_run` 还需 API key(匿名白名单调用报 `-32000 Authentication required`)
- **实测**(2026-08-14,真实 API key):匿名与带 key 默认均 2 工具;**advanced 匿名即可用**(白名单即启用);agent_run 需 key + 白名单
- **官方文档**:[Exa MCP 文档](https://exa.ai/docs/reference/exa-mcp)("Tool enablement (optional)" 一节)
### 1.5 `serverName` 冲突
- **现象**:报 `serverName "exa" is already in use by another mcp-client instance`
- **原因**:同一进程内两个 mcp-client 实例占用同一命名空间
- **解决**:改名其中一个实例的 `serverName`
- **官方文档**:[mcp-client README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.md)
### 1.6 安装/卸载需要 pnpm
- **现象**:`dsh plugin ...` 报 pnpm 找不到
- **原因**:`dsh plugin` 转发给 pnpm 执行
- **解决**:`npm install -g pnpm`;或走 `--patch` / 合并 profile patch 的免安装路线
- **官方文档**:[publish.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md)
### 1.7 `dsh plugin add`(github: 协议)偶发不生效——网络抖动时序
- **现象**:`dsh plugin --profile add github:MicroHEROX/dsh-exa-mcp` 偶发:依赖未写入、或已写入但 `dsh.profile.bundles` 未追加;`remove` 后偶发 bundles 残留悬空引用导致 `cannot resolve profile bundle` 启动失败
- **根因(实测定位)**:**不是插件问题,也不是 CLI 稳定 bug**——github.com 网络抖动(ECONNRESET/ETIMEDOUT 的 git HEAD 探测重试)窗口内:① pnpm 安装失败(`dsh` 只在 stderr 打一行 `pnpm failed`,易被忽略);② pnpm 输出 Done 但 git checkout 异步落地,`reconcilePlugins` 跑在空 node_modules 上 → 不追加,此后不再补偿;③ 中途失败回滚 manifest 依赖项。网络正常时(实测 5s 完成)add/remove/reconcile **全流程正确**
- **解决**:① 网络不稳时优先 `--patch` overlay 或本地路径安装(`link:`/`file:` 无网络依赖,始终正常);② github: 安装后按 README 提供的一行命令**验证并修复** manifest;③ 已上报官方建议(Discussions #656:reconcile 等待 git checkout 落地、pnpm 失败提示更醒目)
- **附带**:手动维护 manifest 的 BOM 问题见 1.8
### 1.8 PowerShell `ConvertTo-Json` 写 UTF-8 BOM 破坏 dsh JSON
- **现象**:手动改 profile `package.json` 后 `dsh` 报 `SyntaxError: Unexpected token ''`
- **原因**:PS 5.1 `ConvertTo-Json | Set-Content -Encoding UTF8` 写 BOM;dsh 的 JSON 读取不做 BOM 剥离
- **解决**:用 node `fs.writeFileSync(p, JSON.stringify(j,null,2)+'\n', 'utf8')` 无 BOM 写入
- **备注**:仅影响手工维护 profile manifest 的工程操作,不影响 `dsh plugin` 本身
## 二、运行时与调用类
### 2.1 搜索报 429
- **现象**:`HTTP 429` / 免费额度限流提示
- **原因**:匿名层限流
- **解决**:设置 `EXA_API_KEY`([申请地址](https://dashboard.exa.ai/api-keys))
- **官方文档**:[Exa MCP 文档](https://exa.ai/docs/reference/exa-mcp)
### 2.2 工具调用超时(agent 研究类任务)
- **现象**:`toolCallTimeoutMs` 到期中止
- **原因**:默认 60 s 对多步 agent 研究不够
- **解决**:本插件默认 180000;仍不够按 id 覆盖 `toolCallTimeoutMs`
- **官方文档**:[mcp-client README#Config](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.md)
### 2.3 MCP 错误透传(-32602 / isError)
- **现象**:`tool/result` 携带 `isError: true`,内容为 Exa 的校验/鉴权错误原文
- **原因**:mcp-client 把 MCP 错误原样经注册表错误路径返回(**正确行为**,曾用于发现 mock 参数名错误)
- **解决**:无需处理;错误信息已含可操作细节(如 `urls expected array`)
- **官方文档**:[mcp-client README#Behavior](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.md)
### 2.4 OAuth 不可用
- **现象**:想用 `mcp.exa.ai/mcp?login` 登录流程
- **原因**:dsh mcp-client 桥不实现 OAuth 握手
- **解决**:改用 API key(`x-api-key` header)
- **官方文档**:[mcp-client README#Known-Limitations](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.md)
### 2.5 Web UI「Session log」面板会触发会话导出下载
- **现象**:点击 Web UI 顶部的 **Session log** 按钮后,浏览器自动下载 `dsh-session-session- --patch ... --dump-config` | bundle 层合成、行完整、`!!js` 保留 |
| 启动 | web/headless 真实 boot | mcp-client `await connection.ready` 通过 ⇒ 连接+发现成功 |
| 行为 | mock LLM + 会话日志断言 | 工具注册名、真实调用、结果/错误路径 |
| 生命周期 | `dsh plugin add / remove / add` | 安装、卸载、重装幂等 |
### 4.2 行为测试的关键技巧
- **mock LLM**(OpenAI 兼容 SSE,本地端口):无 API key 也能驱动真实 agent 循环;mock 记录请求 `tools` 数组 → 直接断言模型可见工具集与 schema;有状态 mock(search → fetch → 总结)验证多步调用
- **会话日志即真相**:`tool/call`(`data.name`/`data.arguments`)、`tool/result`(文本 + `isError`)结构化断言
- **注意**:`session.jsonl.zstd` 是**多帧** zstd——Node `zstdDecompressSync` 只解第一帧;用 python `zstandard` 的 `stream_reader` 解全部帧(本工程踩过);或经 Web UI「Session log」导出明文 jsonl(见 2.5)
- **A/B 鉴权测试**:伪 key → Exa `401 Invalid API key`,与匿名成功对照,证明 header 路径
- **web UI 全交互**(WebBridge 驱动真实浏览器):选工作区 → 发消息 → UI 消息流出现 `Tool call mcp__exa__*` 卡片(含参数)→ 回复与统计(轮/步/耗时)→ 落盘会话日志与 mock 请求双重印证;UI 的"选择工作区"输入框是 `readOnly`,需先经目录选择器
- **`agent_run` 实测要点**:需 API key + `?tools=` 白名单;返回 `runId`(`agent_run_*`)支持续跑;`outputSchema` 可约束输出(`structured` + `grounding` 引用回传);匿名白名单调用报 `-32000 Authentication required`;实调用按用量计费(本工程仅跑 1 次最小任务,12.1s 完成)
### 4.3 安全与隔离原则
- 测试一律使用**隔离 DSH_HOME** + 临时安装的 CLI,不触碰真实 `~/.dsh`(含凭据、会话)
- 不在 patch/文档中写入真实 key;key 只经环境变量注入
- 清理残留前核对归属(会话/存储内容解压确认,时间戳交叉验证)
## 五、官方文档索引(本文档引用)
| 主题 | 地址 |
|---|---|
| dsh 总览/安装 |