← 全部极客知识库

主流 Agent 入门教程 / DeepSeek Harness

12. 案例三-接入工具

原文备份 · 第 13 / 21 篇 · 查看极客时间原知识库 ↗

本篇目录 · 3 节

来源:DeepSeek Harness

本文属于《DeepSeek Harness 入门教程(实战版)》· 第四部分 · 沿着项目掌握核心能力

第 12 章 案例三:用 Skill 固化方法,用 MCP 接入工具

上一章结束时,日报助手已经是一个可运行、可测试的 Node.js 项目。现在会遇到两个很实际的问题:

  1. 每次维护项目,都要重复说“不安装依赖、测试不联网、同步 README”;
  2. DSH 自带的工具之外,以后还可能需要连接数据库、文件服务或公司内部系统。

第一个问题用 Skill 解决,第二个问题用 MCP 解决。本章不停留在概念上,你会完成两个闭环:

  • 在项目中创建真正能被 DSH 发现的 daily-report-maintainer Skill,再用它完成一次小改动;
  • 在隔离的 CLI/Web Profile 中接入官方 MCP Filesystem Server,只授予一个练习目录,完成工具调用和越界拒绝验证。

这里不接入需要账号、付费或密钥的外部服务。我们先把机制和边界学清楚,以后换成真实业务系统时,判断方法不变。

12.1 先分清四个名词

Skill、MCP、插件和 Agent 预设经常同时出现,但它们处在不同层。

机制 它解决什么 会不会自动增加能力
Skill 告诉 Agent 一类任务应怎么做 不会;它是指令,仍使用现有工具
MCP Server 对外提供标准化的工具或资源 会;连接后模型获得新工具
插件 向 DSH 运行时提供或组合能力 取决于插件角色
Agent 预设 为新任务选定插件、工具与指令组合 本身是组合,不是外部协议

DSH 里的 MCP 其实正好跨越两层:外部程序是 MCP Server,@deepseek-ai/dsh-mcp-client 则是把它接入 DSH 工具注册表的插件。所以“配了 MCP”不等于“写了一份 Skill”,也不等于“创建了 Agent 预设”。

12.2 确认项目起点

回到 daily-report 工作区。本章默认你已完成第 11 章,因此至少应该看到:

daily-report/
├── PROJECT.md
├── README.md
├── package.json
├── sources.json
├── daily-report.md
├── src/
└── test/

具体的 src 和 test 文件名可能不同,这不影响继续。先在系统终端进入该目录,执行:

npm test

只有基线测试通过才继续。如果这里已经失败,先回第 11 章修复;否则后面无法判断是 Skill 引导的改动出了问题,还是原项目本来就是坏的。

12.3 创建一份真正的项目 Skill

DSH 的本地 Skill 不是随便放在 skills/ 下的 Markdown。当前文件系统提供方会扫描几个明确的根目录,项目级 DSH Skill 的首选位置是:

<projectRoot>/.dsh/skills/<skill-name>/SKILL.md

它也支持在 .dsh/skills 顶层使用平铺的 <name>.md,但目录 bundle 更适合以后增加 references/、scripts/ 或 assets/。Skill 名称必须使用 kebab-case,文件必须有 name 和 description frontmatter;嵌套更深的 **/SKILL.md 不会被递归发现。官方 Skill 文件系统说明

在标准模式、Workspace Write 权限的当前任务中发送:

请在当前 daily-report 项目中创建一份项目级 Skill,路径必须是:
.dsh/skills/daily-report-maintainer/SKILL.md

文件内容必须与下面一致。不要创建脚本,不要改动项目其他文件。

```markdown
---
name: daily-report-maintainer
description: 修改日报助手的配置、输出格式或命令行为,并保持测试与 README 同步。
user-invocable: true
---

# Daily Report Maintainer

处理日报助手的行为变更时,请遵守:

1. 先读取 PROJECT.md、package.json、README.md 和相关源码,再修改。
2. 保持 ES Modules 和零第三方依赖;不要运行 npm install。
3. 行为变更必须补充或更新测试,用法变更必须同步 README.md。
4. 自动测试使用假 fetch,不访问真实网络,不在项目根目录留下测试报告。
5. 先运行直接相关的聚焦测试,再运行 npm test。
6. 除非用户单独批准,不要运行会访问 GitHub 的 npm start。
7. 最终报告列出改动文件、实际测试结果,并单列“未执行的外部操作”。

创建后重新读取该文件,确认 frontmatter 和 7 条规则都完整。


这份 Skill 只是文本指令,没有脚本和新工具,因此不会绕过工作区权限或审批。它真正的价值是把项目约定从每次的长提示词中抽出来,让后续任务可复用、可更新。

## 12.4 验证 Skill 已被发现,而不是只创建了文件

本地 Skill 提供方会监视根目录,新增或更改有效 Skill 后通常不用重启 DSH。为了避免旧任务已有上下文干扰,在 `daily-report` 工作区下新建一个标准模式任务。

在输入框中输入 `/daily-report-maintainer`。如果内联建议里出现这个名称,说明目录已发现它。把下面的完整任务作为同一条消息发送:

/daily-report-maintainer

请在当前日报 Markdown 的生成时间下方增加一行汇总,显示“数据源数量”和“release 总数”。

要求:

  1. 根据当前实际源码做最小改动,不改数据获取策略;
  2. 更新渲染相关测试和 README.md;
  3. 只运行无网络测试,本次不批准 npm start;
  4. 完成后按 Skill 要求报告。

DSH 的 `tool-skill` 会给 Agent 提供可用 Skill 的名称与描述目录,完整正文按需加载。用户在消息中显式写出 `/name` 时,该 Skill 的完整内容会注入当前步骤,无需模型再调用一次 `skill` 工具。[官方 Skill 加载工具说明](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/tool-skill/README.zh.md)

一次合格执行应该出现下面的特征:

- Agent 先读当前项目文件,而不是凭空假设渲染函数名;
- 实际差异集中在 Markdown 渲染、相关测试和 README;
- 先跑相关测试,再跑 `npm test`;
- 轨迹中没有 `npm install`、`npm start` 或 GitHub 网络请求;
- 最终报告单列“未执行的外部操作”,并注明 `npm start` 未运行。

最后在系统终端亲自执行:

npm test


再打开代码差异,确认 `sources.json` 和网络请求模块没有被改动。这次不运行 `npm start`,因为我们要验证 Skill 中的“外部操作需单独批准”确实影响了执行边界。

### Skill 没出现时先查什么

1. 检查路径是 `.dsh/skills/daily-report-maintainer/SKILL.md`,不是 `skills/daily-report-maintainer.md`;
2. 检查 frontmatter 两侧的 `---`,以及 `name` 是否与目录名一致的 kebab-case;
3. 新建任务再试,避免旧目录投影造成误判;
4. 在“设置 → 插件 → 插件列表”中确认 Skill registry、filesystem provider 和 `tool-skill` 没有加载错误。

无效 frontmatter 的 Skill 会被跳过并记录警告,模型目录未必会把具体解析错误直接展示给你。所以排查顺序应该先看路径和 frontmatter,不是反复让模型“再搜一遍”。

## 12.5 MCP 部分为什么使用隔离 Profile

Skill 会被按需加载;MCP Server 连接成功后,它的工具名称、描述和参数 schema 会加入模型的工具列表。连接的 Server 越多,模型每次要理解的工具定义就越多。

为了不把练习 Server 永久加到你的 Desktop 或日常 Web Profile,本章采用一个临时组合:

独立 mcp-lab Profile + 项目内 patch + 一个 mcp-scratch 允许目录


这条路线需要系统 Node.js 和 `npx`。只安装了 Desktop 的读者,请先按 macOS 或 Windows 安装章的 CLI/Web 小节确认:

npx @deepseek-ai/dsh@0.1.7-rc.2 --version


官方 MCP Client 的可复现配置方式,就是为每个 Server 插入一条 `@deepseek-ai/dsh-mcp-client` 配置。本地程序使用 `stdio`,远程服务使用 `streamable-http`;连接后工具名称是 `mcp__<serverName>__<rawName>`。[官方 MCP Client 说明](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.zh.md)

## 12.6 为 MCP 准备一个最小权限目录

在 `daily-report` 项目根目录创建一个空目录 `mcp-scratch`。

macOS 与 Linux:

mkdir -p mcp-scratch


Windows PowerShell:

New-Item -ItemType Directory -Force mcp-scratch


接下来需要它的**绝对路径**。

macOS 与 Linux:

cd mcp-scratch pwd cd ..


Windows PowerShell:

(Resolve-Path .\mcp-scratch).Path


记录输出。Windows 用户写入 YAML 时可以把路径改为正斜杠,例如 `C:/Users/mei/dsh-learning/daily-report/mcp-scratch`,避免反斜杠转义带来混淆。

为什么不把整个用户主目录交给 Filesystem Server?因为 MCP Server 是 DSH 之外的进程。Workspace Write 是 DSH 原生文件和 Shell 路径的边界,不应被当成所有外部 Server 的通用沙箱。这次的强边界来自 Filesystem Server 启动参数中唯一允许的 `mcp-scratch` 目录。

## 12.7 创建 MCP patch,但先不启动

在项目中新建 `.dsh/mcp-filesystem.yml`,内容如下。请把 `<MCP_SCRATCH_ABSOLUTE_PATH>` 替换成上一步得到的绝对路径,不要保留尖括号。

  • insert:
    • id: mcp-daily-report-fs name: '@deepseek-ai/dsh-mcp-client' config: serverName: daily_report_fs transport: stdio command: npx args: - '-y' - '@modelcontextprotocol/server-filesystem@2026.7.10' - '<MCP_SCRATCH_ABSOLUTE_PATH>' toolCallTimeoutMs: 60000 failOnStartupError: true

本练习固定使用官方已发布的 `@modelcontextprotocol/server-filesystem@2026.7.10`,而不是每次随机获取 `latest`,这样便于复现教程环境。它是 Model Context Protocol 官方参考 Server,能读写启动参数列出的目录。[官方 Filesystem Server 源码](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) · [2026.7.10 发布记录](https://github.com/modelcontextprotocol/servers/releases/tag/2026.7.10)

第一次启动时,`npx -y` 会从 npm 下载并执行该固定版本及依赖。这是真实的外部代码执行,不是一条无害的配置读取。如果你的环境不允许从 npm 执行包,就不要继续这一部分;可以仅完成前面的 Skill 实操,再由管理员审核和预装 MCP Server。

## 12.8 先做配置检查,再起服务

打开新的系统终端,确认当前目录是 `daily-report`。首次创建隔离 Profile 时执行:

npx @deepseek-ai/dsh@0.1.7-rc.2 --profile mcp-lab --from-default-profile web --patch ./.dsh/mcp-filesystem.yml --dump-config


这条命令会从官方 `web` 模板初始化 `mcp-lab` Profile,组合 patch 并输出最终配置,不启动 Web 服务。在输出中搜索 `mcp-daily-report-fs`、`daily_report_fs` 和你的绝对路径,三者都应出现。

如果你之前已经创建过 `mcp-lab`,`--from-default-profile web` 会明确拒绝覆盖已有 Profile。此时不要删目录,只需去掉初始化参数后重试:

npx @deepseek-ai/dsh@0.1.7-rc.2 --profile mcp-lab --patch ./.dsh/mcp-filesystem.yml --dump-config


配置检查通过后,再启动它:

npx @deepseek-ai/dsh@0.1.7-rc.2 --profile mcp-lab --patch ./.dsh/mcp-filesystem.yml --port 3081


启动器参数 `--profile` 和 `--patch` 必须放在 Web 应用参数 `--port` 前面。正常情况下,终端会打印服务地址并打开页面;没有自动打开时,手动访问 `http://127.0.0.1:3081`。如果 3081 已被占用,换一个未占用的本地端口。[官方 CLI 启动与 patch 说明](https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/cli/reference/README.zh.md)

第一次启动会下载 MCP Server,可能需要一些时间。`failOnStartupError: true` 会让这条 MCP 配置在连接或工具同步失败时明确激活失败,而不是让我们对着一个空工具列表猜原因。

## 12.9 验证 MCP 工具真的进了 Agent

在新打开的 `mcp-lab` Web 页面中选中 `daily-report` 工作区。这是一个新 Profile,如果模型列表为空,按第 8 章的最短路线配置一个模型;不要把 API Key 写入项目 patch。

新建标准模式任务,发送:

请检查当前任务可用的工具,只列出名称以 mcp__daily_report_fs__ 开头的工具。 不要调用它们,不要读写文件。


工具清单中应该出现类似:

mcp__daily_report_fs__list_allowed_directories mcp__daily_report_fs__list_directory mcp__daily_report_fs__write_file mcp__daily_report_fs__read_text_file


具体数量会随 Filesystem Server 版本变化,但前缀应该稳定。只在设置里看到 `dsh-mcp-client` 不算验证成功;模型的实际工具目录中有这组限定名称,才说明 Server 已连接并完成工具发现。

如果列表为空,先回看启动终端的错误,再打开“设置 → 插件 → 插件列表”查找 `mcp-daily-report-fs` 的加载状态。

## 12.10 用 MCP 写入文件,再独立验收

继续在同一任务中发送:

这一次只允许使用名称以 mcp__daily_report_fs__ 开头的 MCP 工具,不要使用原生文件工具或 Shell。

  1. 先调用 list_allowed_directories,报告 Server 唯一允许的目录;
  2. 列出该目录的当前内容;
  3. 在该目录中创建 mcp-check.txt,内容必须是:MCP connection verified
  4. 通过 MCP 再读回该文件,原样报告内容。

不要修改其他文件。


执行轨迹中应该明确出现 `mcp__daily_report_fs__...` 工具卡片。`write_file` 具有覆盖文件的能力,如果当前批准策略显示确认卡片,要同时核对工具名、绝对路径和内容;不同组合的审批呈现可能不同,不要把“没弹卡片”当成服务端边界已经安全的证明。

工具返回成功后,在系统终端的 `daily-report` 目录中独立执行:

node -e "const fs=require('node:fs'); const p='mcp-scratch/mcp-check.txt'; const s=fs.readFileSync(p,'utf8'); if(s!=='MCP connection verified') process.exit(1); console.log('MCP file OK')"


成功时应看到:

MCP file OK


这条命令不经过 MCP,所以它独立证明了外部 Server 的调用确实落到了磁盘,而不是 Agent 只用文字回答“写好了”。

## 12.11 故意做一次越界失败

现在反过来验证 Server 不能读取 `mcp-scratch` 之外的项目文件。发送:

请只使用 mcp__daily_report_fs__read_text_file,尝试读取 mcp-scratch 的上级目录中的 PROJECT.md。 不要改用原生 read、Shell 或其他工具绕过这个限制。 请保留实际错误并解释它证明了什么。


预期结果是 MCP 工具调用失败,错误指向路径不在允许目录内。这次失败是成功验收的一部分:

- 前一步证明“允许范围内能工作”;
- 这一步证明“允许范围外会拒绝”。

如果 Agent 改用原生文件工具读到了 `PROJECT.md`,那不能证明 MCP 边界失效,只能说明 Agent 没有遵守这次验收的工具限制。请重新发送任务,并在轨迹中确认实际调用的是 MCP 限定名工具。

## 12.12 停用与回退

实验完成后,回到运行 `mcp-lab` 的终端,按 `Ctrl+C` 停止该 Web Profile。终端应返回命令提示符,3081 页面随后无法继续连接。

因为 MCP 条目是通过这次启动的 `--patch` 叠加进去的:

- 你的官方 Desktop Profile 没有被修改;
- 平时使用的 `web` Profile 也没有被修改;
- 不带 `--patch` 启动 `mcp-lab` 时,不会加载这个 MCP Server;
- `.dsh/mcp-filesystem.yml` 与 `mcp-scratch/mcp-check.txt` 作为练习产物保留,便于以后复盘。

如果你想再次验证回退,可以不带 patch 启动同一 Profile,新建任务后再查工具列表:

npx @deepseek-ai/dsh@0.1.7-rc.2 --profile mcp-lab --port 3081


这一次不应再出现 `mcp__daily_report_fs__...` 工具。不要在旧任务中判断:工具调用历史会保留在会话中,只有新任务的当前工具列表能证明 MCP 已不再加载。

## 12.13 这两种扩展该怎么选

现在可以用一个很实际的问题来判断:**Agent 缺的是方法,还是缺的是工具?**

- 已经有读文件、写代码和跑测试的工具,只是每次容易忘记项目约定:写 Skill。
- 现有工具无法访问某个数据库、文档系统或内部 API:评估 MCP Server。
- 需要改变 DSH 的运行时服务、界面或组合方式:评估插件。
- 需要为一类任务固定一套工具和行为方式:创建 Agent 预设。

还要多问一句:不接这个外部工具,任务是否已能可靠完成?本章的 Filesystem MCP 和 DSH 原生文件工具有意重复,是为了在不引入账号和密钥的情况下学会连接、限权、调用和回退。真实项目里没有新需求时,不应保持这种重复工具长期启用。

## 12.14 常见问题

### patch 提示 YAML 解析失败

先检查尖括号占位符是否已替换,路径是否保持在引号内,以及缩进是否使用空格。再运行 `--dump-config`,不要通过反复启动 Web 来试错。

### 启动时提示找不到 `npx`

MCP Client 是 DSH 进程,Filesystem Server 则是它要启动的外部子进程。确认在同一个系统终端中 `node -v`、`npm -v`、`npx -v` 都能输出版本。Windows 若受 PowerShell 执行策略影响,参考第 6 章的 `npx.cmd` 路线,不要改成管理员权限运行整个 DSH。

### 首次连接一直等待或失败

先在系统终端确认 npm 能访问当前 registry。不要把 DSH 模型 API 可用当成 npm 也一定可用,这是两条不同的网络路径。保留启动终端中第一条完整错误,根据包下载、子进程启动或 MCP 握手阶段分层排查。

### 工具出现了,调用却失败

先展开工具卡片看实际错误。MCP Client 在连接中断期间可能仍保留最后已知工具名,但调用会失败,直到重连成功。同时检查路径是否真的在 `mcp-scratch` 内;对越界路径的拒绝不应通过扩大到用户主目录来“修复”。

## 12.15 本章验收

进入下一章前,请确认:

- `.dsh/skills/daily-report-maintainer/SKILL.md` 已被 DSH 发现,不是普通的散落 Markdown;
- 已用 `/daily-report-maintainer` 完成一次真实小改动,并独立运行 `npm test`;
- 能解释 Skill 只增加指令,不增加工具或权限;
- 已用 `--dump-config` 检查过隔离的 `mcp-lab` 配置;
- 模型工具列表中出现 `mcp__daily_report_fs__...` 限定名工具;
- MCP 成功写入 `mcp-scratch/mcp-check.txt`,并已用系统终端独立验收;
- 已证明 MCP Server 不能越界读取 `PROJECT.md`;
- 已停止实验 Profile,并知道不带 patch 即可回退该 MCP 工具组;
- 能根据“缺方法还是缺工具”选择 Skill 或 MCP。

项目现在多了一份可复用维护 Skill,你也完成了一次有真实工具、有权限边界、有独立验收和可回退路径的 MCP 接入。下一章会改变任务的执行结构:让主 Agent 把两个相互独立的评审任务委派给子智能体,再审查他们的依赖、输出和失败边界。

---

← 上一章:案例二:从需求到可运行的第一版 | 回目录 | 下一章:案例四:把两项审查交给子智能体 →