@shirlytaylor73/superharness 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/bin/lib/codex-installer.js +228 -0
- package/bin/lib/interactive-select.js +96 -0
- package/bin/superharness.js +67 -0
- package/package.json +52 -0
- package/plugins/superharness/.claude-plugin/plugin.json +19 -0
- package/plugins/superharness/.codex-plugin/plugin.json +31 -0
- package/plugins/superharness/.mcp.json +9 -0
- package/plugins/superharness/CODE_OF_CONDUCT.md +79 -0
- package/plugins/superharness/LICENSE +21 -0
- package/plugins/superharness/README.md +57 -0
- package/plugins/superharness/agents/code-reviewer.md +48 -0
- package/plugins/superharness/archived-skills/using-superpowers/SKILL.md +140 -0
- package/plugins/superharness/archived-skills/using-superpowers/references/codex-tools.md +25 -0
- package/plugins/superharness/archived-skills/using-superpowers/references/copilot-tools.md +52 -0
- package/plugins/superharness/archived-skills/using-superpowers/references/gemini-tools.md +33 -0
- package/plugins/superharness/archived-skills/using-superpowers/references/hermes-tools.md +44 -0
- package/plugins/superharness/commands/free.md +6 -0
- package/plugins/superharness/commands/rollback.md +30 -0
- package/plugins/superharness/commands-codex/free.md +29 -0
- package/plugins/superharness/commands-codex/rollback.md +33 -0
- package/plugins/superharness/hooks/hooks-codex.json +50 -0
- package/plugins/superharness/hooks/hooks.json +50 -0
- package/plugins/superharness/hooks/lib/free-mode-check.mjs +27 -0
- package/plugins/superharness/hooks/run-hook.cmd +58 -0
- package/plugins/superharness/hooks/workflow-context +4 -0
- package/plugins/superharness/hooks/workflow-context.mjs +184 -0
- package/plugins/superharness/hooks/workflow-post-transition +4 -0
- package/plugins/superharness/hooks/workflow-post-transition.mjs +89 -0
- package/plugins/superharness/hooks/workflow-pre-tool-use +4 -0
- package/plugins/superharness/hooks/workflow-pre-tool-use.mjs +97 -0
- package/plugins/superharness/hooks/workflow-stop +4 -0
- package/plugins/superharness/hooks/workflow-stop.mjs +136 -0
- package/plugins/superharness/scripts/rollback.mjs +86 -0
- package/plugins/superharness/scripts/set-free-mode.mjs +77 -0
- package/plugins/superharness/skills/brainstorming/SKILL.md +182 -0
- package/plugins/superharness/skills/brainstorming/scripts/frame-template.html +214 -0
- package/plugins/superharness/skills/brainstorming/scripts/helper.js +88 -0
- package/plugins/superharness/skills/brainstorming/scripts/server.cjs +338 -0
- package/plugins/superharness/skills/brainstorming/scripts/start-server.sh +153 -0
- package/plugins/superharness/skills/brainstorming/scripts/stop-server.sh +55 -0
- package/plugins/superharness/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/plugins/superharness/skills/brainstorming/visual-companion.md +286 -0
- package/plugins/superharness/skills/chinese-code-review/SKILL.md +277 -0
- package/plugins/superharness/skills/chinese-commit-conventions/SKILL.md +364 -0
- package/plugins/superharness/skills/chinese-documentation/SKILL.md +448 -0
- package/plugins/superharness/skills/chinese-git-workflow/SKILL.md +547 -0
- package/plugins/superharness/skills/dispatching-parallel-agents/SKILL.md +186 -0
- package/plugins/superharness/skills/exploration/SKILL.md +197 -0
- package/plugins/superharness/skills/finishing/SKILL.md +200 -0
- package/plugins/superharness/skills/intake/SKILL.md +134 -0
- package/plugins/superharness/skills/mcp-builder/SKILL.md +255 -0
- package/plugins/superharness/skills/parallel-execution/SKILL.md +368 -0
- package/plugins/superharness/skills/parallel-execution/implementer-prompt.md +144 -0
- package/plugins/superharness/skills/parallel-execution/spec-reviewer-prompt.md +84 -0
- package/plugins/superharness/skills/parallel-execution/wave-final-manual-qa-prompt.md +61 -0
- package/plugins/superharness/skills/parallel-execution/wave-final-quality-prompt.md +59 -0
- package/plugins/superharness/skills/parallel-execution/wave-final-scope-fidelity-prompt.md +69 -0
- package/plugins/superharness/skills/parallel-execution/wave-final-spec-prompt.md +56 -0
- package/plugins/superharness/skills/planning/SKILL.md +265 -0
- package/plugins/superharness/skills/planning/plan-document-reviewer-prompt.md +80 -0
- package/plugins/superharness/skills/receiving-code-review/SKILL.md +213 -0
- package/plugins/superharness/skills/requesting-code-review/SKILL.md +107 -0
- package/plugins/superharness/skills/requesting-code-review/code-reviewer.md +146 -0
- package/plugins/superharness/skills/serial-execution/SKILL.md +183 -0
- package/plugins/superharness/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/plugins/superharness/skills/systematic-debugging/SKILL.md +320 -0
- package/plugins/superharness/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/plugins/superharness/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/plugins/superharness/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/plugins/superharness/skills/systematic-debugging/find-polluter.sh +63 -0
- package/plugins/superharness/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/plugins/superharness/skills/systematic-debugging/test-academic.md +14 -0
- package/plugins/superharness/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/plugins/superharness/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/plugins/superharness/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/plugins/superharness/skills/test-driven-development/SKILL.md +371 -0
- package/plugins/superharness/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/plugins/superharness/skills/trivial/SKILL.md +118 -0
- package/plugins/superharness/skills/using-git-worktrees/SKILL.md +218 -0
- package/plugins/superharness/skills/verification/SKILL.md +139 -0
- package/plugins/superharness/skills/workflow-runner/SKILL.md +172 -0
- package/plugins/superharness/skills/writing-skills/SKILL.md +655 -0
- package/plugins/superharness/skills/writing-skills/anthropic-best-practices.md +1149 -0
- package/plugins/superharness/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/plugins/superharness/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/plugins/superharness/skills/writing-skills/persuasion-principles.md +187 -0
- package/plugins/superharness/skills/writing-skills/render-graphs.js +168 -0
- package/plugins/superharness/skills/writing-skills/testing-skills-with-subagents.md +385 -0
- package/plugins/superharness/workflow/default-workflow.yaml +84 -0
- package/plugins/superharness/workflow-state-server/bootstrap.js +44 -0
- package/plugins/superharness/workflow-state-server/package-lock.json +2853 -0
- package/plugins/superharness/workflow-state-server/package.json +22 -0
- package/plugins/superharness/workflow-state-server/render-context.js +124 -0
- package/plugins/superharness/workflow-state-server/schema.sql +39 -0
- package/plugins/superharness/workflow-state-server/server.js +290 -0
- package/plugins/superharness/workflow-state-server/state.js +424 -0
- package/plugins/superharness/workflow-state-server/validate-workflow.js +165 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: intake
|
|
3
|
+
description: 会话入口和 triage——在新会话起点或任务完成回到默认态时使用,听需求、必要时澄清、把任务路由到 exploration / trivial / brainstorming,或当场回答无需切态的纯问答
|
|
4
|
+
metadata:
|
|
5
|
+
type: workflow-state
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Intake — 入口分流
|
|
9
|
+
|
|
10
|
+
## 角色
|
|
11
|
+
|
|
12
|
+
你处在新会话起点(或者上一个任务结束后回到的默认态)。三件事:
|
|
13
|
+
|
|
14
|
+
1. **听** 用户表达需求
|
|
15
|
+
2. **必要时回问 1-2 个澄清问题**(不要过度盘问)
|
|
16
|
+
3. **把任务路由**到下一个状态(或当场答完不切态)
|
|
17
|
+
|
|
18
|
+
intake 不写代码、不做计划、不做深度探索。它的唯一价值是把请求精确地交给对的下家。
|
|
19
|
+
|
|
20
|
+
## 决策表
|
|
21
|
+
|
|
22
|
+
| 用户意图 | 该走 | transition_state 到 |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| 纯问答 / 解释 / 查 API 用法 / 闲聊 / 概念解释 | 当场答 | (**不切态**) |
|
|
25
|
+
| 看看 X 是怎么实现的 / 跨文件读懂某个模块 / 做技术调研 / 比较方案 | 只读探索 | `exploration` |
|
|
26
|
+
| 改个 typo / 调整一行配置 / 单文件小修复 / ≤3 文件 ≤50 行 | 快速改动 | `trivial` |
|
|
27
|
+
| 新功能 / bugfix / 多文件变更 / 涉及 API/schema/依赖 | 正式开发 | `brainstorming` |
|
|
28
|
+
|
|
29
|
+
## 反过度分类(红线)
|
|
30
|
+
|
|
31
|
+
intake 最容易犯的错是"为了走流程而切态"。以下都是**红线**,违反就停下重判:
|
|
32
|
+
|
|
33
|
+
- **用户问问题,你切到 brainstorming**——错。问题就答,answer-only 不调用 `transition_state`。
|
|
34
|
+
- **不确定大小直接切 trivial**——错。回问一句确认:"这只是改 X 一处,还是还要碰 Y 和 Z?"
|
|
35
|
+
- **看到代码相关请求就切 exploration**——错。"为什么我这段 Python 报错"是答疑,不是探索;探索是用户主动想"走一遍代码理解一下"。
|
|
36
|
+
- **把澄清问题做成 10 连问**——错。最多 1-2 个澄清问题,确认完就路由;继续盘问该走 `brainstorming`。
|
|
37
|
+
|
|
38
|
+
## 反例对照
|
|
39
|
+
|
|
40
|
+
**例 1:纯问答**
|
|
41
|
+
- 用户:"async/await 和 promise.then 有啥区别?"
|
|
42
|
+
- 错:切 `exploration` 去翻代码——这是概念问题,代码里也找不到答案。
|
|
43
|
+
- 对:当场答,不切态。
|
|
44
|
+
|
|
45
|
+
**例 2:模糊小修复**
|
|
46
|
+
- 用户:"帮我把那个超时时间调一下。"
|
|
47
|
+
- 错:直接切 `trivial` 开干——不知道改哪、改成多少。
|
|
48
|
+
- 对:回问"是 X 文件里的 `timeout=5000` 那个吗?要改成多少?" → 拿到答案后再切 `trivial`。
|
|
49
|
+
|
|
50
|
+
**例 3:被低估的"小"改动**
|
|
51
|
+
- 用户:"帮我把 `getUserById` 的返回类型加个字段。"
|
|
52
|
+
- 错:当 `trivial` 处理——公共 API 变更,所有调用点都要动。
|
|
53
|
+
- 对:先回问"这个函数有多少调用点?" → 如果跨多文件就切 `brainstorming`,不要走 `trivial`。
|
|
54
|
+
|
|
55
|
+
**例 4:被高估的"功能"**
|
|
56
|
+
- 用户:"帮我新加一个功能:把 log 里的颜色关掉。"
|
|
57
|
+
- 错:切 `brainstorming` 走完整流程——其实就是一个 flag。
|
|
58
|
+
- 对:回问"是想加一个 `--no-color` 还是直接默认关掉?" → 拿到答案后切 `trivial`。
|
|
59
|
+
|
|
60
|
+
## answer-only 模式
|
|
61
|
+
|
|
62
|
+
判定为纯问答时:
|
|
63
|
+
|
|
64
|
+
- **不**调用 `transition_state`
|
|
65
|
+
- **不**调用 `classify_request`
|
|
66
|
+
- 直接答完,等用户下一条消息
|
|
67
|
+
- 答完后状态还是 `intake`,下一条消息照常再 triage 一次
|
|
68
|
+
|
|
69
|
+
什么算"纯问答":
|
|
70
|
+
|
|
71
|
+
- 概念解释、原理科普、API 用法、报错含义
|
|
72
|
+
- 项目里的"X 在哪/做什么"——这种用 Read/Grep 答完就行,不需要切 exploration
|
|
73
|
+
- 闲聊、问候、确认收到
|
|
74
|
+
|
|
75
|
+
什么**不算**纯问答(要切态):
|
|
76
|
+
|
|
77
|
+
- "顺便帮我改一下" → 切 `trivial` 或 `brainstorming`
|
|
78
|
+
- "完整读一遍这个模块给我讲讲" → 切 `exploration`
|
|
79
|
+
- "对比一下方案 A 和方案 B" → 切 `exploration`
|
|
80
|
+
|
|
81
|
+
## 切态时的 reason 要求
|
|
82
|
+
|
|
83
|
+
每次 `transition_state` 的 `reason` 字段必须包含两部分:
|
|
84
|
+
|
|
85
|
+
1. **用户原话摘要**(10-30 字,原话或贴近原话)
|
|
86
|
+
2. **判定理由**(为什么走这一档而不是另一档)
|
|
87
|
+
|
|
88
|
+
格式示例:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
"用户说『帮我把 README 里的 typo 改一下』;单文件、无逻辑改动,走 trivial 而不是 brainstorming"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
"用户说『我想看看 workflow-state-server 是怎么处理并发的』;只读理解需求,走 exploration"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
reason 是**审计记录**,不是占位符。`"ok"` / `"start"` / `"用户请求"` 这种都会进 transition_log 留痕,不要写。
|
|
99
|
+
|
|
100
|
+
## 出口
|
|
101
|
+
|
|
102
|
+
| 出口 | 用途 |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `exploration` | 只读探索:读懂代码、做调研、比较方案,**不写**任何文件 |
|
|
105
|
+
| `trivial` | 轻量改动:≤3 文件 ≤50 行,自带验证,不走 plan |
|
|
106
|
+
| `brainstorming` | 正式开发:新功能、bugfix、多文件变更——需要先做需求分析和规划 |
|
|
107
|
+
|
|
108
|
+
**不要**从 intake 直接跳 `planning` / `serial_execution` / `parallel_execution` / `verification` / `finishing`——这些状态都不在 intake 的允许出口里,需求未确认就跳到实现是反模式。需要正式开发**总是先去 `brainstorming`**。
|
|
109
|
+
|
|
110
|
+
## 红线清单
|
|
111
|
+
|
|
112
|
+
以下情况停下来,**不要**继续:
|
|
113
|
+
|
|
114
|
+
- 切态没填 reason 或填了占位符(`"ok"` / `"start"` / 空字符串)
|
|
115
|
+
- 切到 `planning` / `serial_execution` / `parallel_execution` / `verification` / `finishing` 任意一个——这些不是 intake 的合法出口
|
|
116
|
+
- 用户只是问问题,你却调用了 `transition_state`
|
|
117
|
+
- 不知道大小硬切 `trivial`——先回问 1 句确认范围
|
|
118
|
+
- 连问 3 个以上澄清问题——该走 `brainstorming` 了,那里有完整的盘问框架
|
|
119
|
+
|
|
120
|
+
## 流程
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
收到用户消息
|
|
124
|
+
│
|
|
125
|
+
├─ 是纯问答? ──→ 当场答,不切态,状态停留 intake
|
|
126
|
+
│
|
|
127
|
+
├─ 范围/意图明确?
|
|
128
|
+
│ │
|
|
129
|
+
│ ├─ 是 ──→ 按决策表 transition_state
|
|
130
|
+
│ │
|
|
131
|
+
│ └─ 否 ──→ 回问 1-2 句确认 ──→ 拿到答案后按决策表 transition_state
|
|
132
|
+
│
|
|
133
|
+
└─ 连续澄清 >2 轮? ──→ 切 brainstorming,让它接管深度盘问
|
|
134
|
+
```
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-builder
|
|
3
|
+
description: MCP 服务器构建方法论 — 系统化构建生产级 MCP 工具,让 AI 助手连接外部能力
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MCP 服务器构建
|
|
7
|
+
|
|
8
|
+
系统化设计、实现、测试和部署 Model Context Protocol 服务器的方法论。
|
|
9
|
+
|
|
10
|
+
## 1. 协议核心概念
|
|
11
|
+
|
|
12
|
+
MCP 定义三种原语:
|
|
13
|
+
|
|
14
|
+
- **Tools(工具)**:AI 助手主动调用的函数,有副作用。如搜索、创建、删除操作。
|
|
15
|
+
- **Resources(资源)**:AI 助手只读访问的数据源,用 URI 标识。如 `users://{id}/profile`。
|
|
16
|
+
- **Prompts(提示词模板)**:预定义交互模板,引导用户触发工作流。
|
|
17
|
+
|
|
18
|
+
**选择原则:** 执行操作 → Tool | 读取数据 → Resource | 引导交互 → Prompt
|
|
19
|
+
|
|
20
|
+
## 2. 项目结构规范
|
|
21
|
+
|
|
22
|
+
### TypeScript
|
|
23
|
+
```
|
|
24
|
+
my-mcp-server/
|
|
25
|
+
├── src/
|
|
26
|
+
│ ├── index.ts # 入口,注册 tools/resources
|
|
27
|
+
│ ├── tools/ # 按功能拆分
|
|
28
|
+
│ ├── resources/
|
|
29
|
+
│ └── lib/ # 客户端封装、校验逻辑
|
|
30
|
+
├── tests/
|
|
31
|
+
├── package.json
|
|
32
|
+
└── tsconfig.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
关键依赖:`@modelcontextprotocol/sdk` + `zod`
|
|
36
|
+
|
|
37
|
+
### Python
|
|
38
|
+
```
|
|
39
|
+
my-mcp-server/
|
|
40
|
+
├── src/my_mcp_server/
|
|
41
|
+
│ ├── server.py
|
|
42
|
+
│ ├── tools/
|
|
43
|
+
│ └── lib/
|
|
44
|
+
├── tests/
|
|
45
|
+
└── pyproject.toml
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
关键依赖:`mcp` + `pydantic`
|
|
49
|
+
|
|
50
|
+
## 3. Tool 设计原则
|
|
51
|
+
|
|
52
|
+
### 命名
|
|
53
|
+
- `snake_case` 格式,动词开头:`search_users`、`create_issue`、`delete_file`
|
|
54
|
+
- 名称自解释,AI 助手靠名称选工具,模糊命名导致误调用
|
|
55
|
+
|
|
56
|
+
### 参数
|
|
57
|
+
- 每个参数有类型约束和 `.describe()` 描述
|
|
58
|
+
- 可选参数给默认值,减少 AI 决策负担
|
|
59
|
+
- 用枚举代替布尔开关
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
server.tool("search_issues", {
|
|
63
|
+
query: z.string().describe("搜索关键词"),
|
|
64
|
+
status: z.enum(["open", "closed", "all"]).default("open").describe("状态筛选"),
|
|
65
|
+
limit: z.number().min(1).max(100).default(20).describe("返回上限"),
|
|
66
|
+
}, async ({ query, status, limit }) => { /* ... */ });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 描述
|
|
70
|
+
说明**用途 + 返回内容 + 限制**,这是 AI 选择工具的关键依据:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
server.tool("search_users",
|
|
74
|
+
"根据姓名或邮箱搜索用户。返回 ID、姓名、邮箱列表。模糊匹配,最多 50 条。",
|
|
75
|
+
schema, handler);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 输出
|
|
79
|
+
- 结构化数据 → JSON,人类可读内容 → Markdown
|
|
80
|
+
- 始终用 `content: [{ type: "text", text: "..." }]` 格式返回
|
|
81
|
+
|
|
82
|
+
## 4. 输入验证和错误处理
|
|
83
|
+
|
|
84
|
+
用 Zod/Pydantic 做 Schema 级校验,业务级校验放 handler 开头:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
server.tool("get_user", { id: z.string() }, async ({ id }) => {
|
|
88
|
+
try {
|
|
89
|
+
const user = await db.getUser(id);
|
|
90
|
+
if (!user) {
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: `用户 ${id} 不存在,请检查 ID。` }],
|
|
93
|
+
isError: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return { content: [{ type: "text", text: JSON.stringify(user, null, 2) }] };
|
|
97
|
+
} catch (err) {
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text: `查询失败:${err.message}` }],
|
|
100
|
+
isError: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**错误处理四原则:**
|
|
107
|
+
1. 永远不让服务器崩溃 — try/catch 包裹所有外部调用
|
|
108
|
+
2. 返回可操作的错误信息 — 告诉 AI 问题是什么、能做什么
|
|
109
|
+
3. 使用 `isError: true` — 让 AI 知道调用失败
|
|
110
|
+
4. 区分错误类型 — 参数错误、权限不足、资源不存在、服务不可用
|
|
111
|
+
|
|
112
|
+
## 5. 资源管理和生命周期
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// 资源注册
|
|
116
|
+
server.resource("user-profile", "users://{userId}/profile", async (uri) => {
|
|
117
|
+
const profile = await db.getProfile(extractId(uri));
|
|
118
|
+
return { contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(profile) }] };
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 生命周期:先初始化 → 再 connect → 监听关闭信号
|
|
122
|
+
const db = await Database.connect(config.dbUrl);
|
|
123
|
+
await server.connect(new StdioServerTransport());
|
|
124
|
+
process.on("SIGINT", async () => { await db.disconnect(); await server.close(); process.exit(0); });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
关键点:使用连接池、所有外部调用设超时、优雅关闭清理资源。
|
|
128
|
+
|
|
129
|
+
## 6. 测试策略
|
|
130
|
+
|
|
131
|
+
### 单元测试 — 业务逻辑与 MCP 注册分离
|
|
132
|
+
```typescript
|
|
133
|
+
// tools/search.ts 导出纯函数
|
|
134
|
+
export async function searchUsers(query: string, limit: number) { /* ... */ }
|
|
135
|
+
|
|
136
|
+
// search.test.ts 独立测试
|
|
137
|
+
test("返回匹配结果", async () => {
|
|
138
|
+
const results = await searchUsers("alice", 10);
|
|
139
|
+
expect(results[0].name).toContain("Alice");
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 集成测试 — 用 SDK Client 做端到端验证
|
|
144
|
+
```typescript
|
|
145
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
146
|
+
await server.connect(serverTransport);
|
|
147
|
+
const client = new Client({ name: "test", version: "1.0.0" });
|
|
148
|
+
await client.connect(clientTransport);
|
|
149
|
+
const result = await client.callTool("search_users", { query: "test" });
|
|
150
|
+
expect(result.isError).toBeFalsy();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### MCP Inspector — 交互式调试
|
|
154
|
+
```bash
|
|
155
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
在浏览器中查看所有 tools/resources,手动调用并查看结果。
|
|
159
|
+
|
|
160
|
+
**测试要点:** 每个 Tool 覆盖正常 + 异常路径、边界值、外部服务失败模拟。
|
|
161
|
+
|
|
162
|
+
## 7. 安全考虑
|
|
163
|
+
|
|
164
|
+
**权限控制:**
|
|
165
|
+
- 最小权限原则,读写 Tool 分离
|
|
166
|
+
- 危险操作要求确认参数(如 `confirm: true`)
|
|
167
|
+
|
|
168
|
+
**输入安全:**
|
|
169
|
+
- SQL 注入 → 参数化查询,绝不拼接
|
|
170
|
+
- 路径遍历 → 校验路径,禁止 `../`
|
|
171
|
+
- 命令注入 → 用 `execFile` 而非 `exec`
|
|
172
|
+
|
|
173
|
+
**敏感数据:**
|
|
174
|
+
- 密钥通过环境变量传入,不硬编码
|
|
175
|
+
- 日志不打印完整敏感信息
|
|
176
|
+
- 返回数据做脱敏处理
|
|
177
|
+
|
|
178
|
+
**沙箱:** 文件操作限制目录、网络请求限制白名单、设置资源配额。
|
|
179
|
+
|
|
180
|
+
## 8. 部署和分发
|
|
181
|
+
|
|
182
|
+
### npm 发布
|
|
183
|
+
```json
|
|
184
|
+
{ "bin": { "mcp-server-myservice": "dist/index.js" }, "files": ["dist"] }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
用户配置:
|
|
188
|
+
```json
|
|
189
|
+
{ "mcpServers": { "myservice": { "command": "npx", "args": ["@yourorg/mcp-server-myservice"], "env": { "API_KEY": "xxx" } } } }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### pip 发布
|
|
193
|
+
```toml
|
|
194
|
+
[project.scripts]
|
|
195
|
+
mcp-server-myservice = "my_mcp_server.server:main"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Docker — 适用于复杂依赖或隔离场景
|
|
199
|
+
```dockerfile
|
|
200
|
+
FROM node:20-slim
|
|
201
|
+
WORKDIR /app
|
|
202
|
+
COPY package*.json ./ && RUN npm ci --production
|
|
203
|
+
COPY dist ./dist
|
|
204
|
+
ENTRYPOINT ["node", "dist/index.js"]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## 9. 调试技巧
|
|
208
|
+
|
|
209
|
+
**关键:MCP 用 stdio 通信,不能用 `console.log`,会破坏协议流。**
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// 错误
|
|
213
|
+
console.log("debug");
|
|
214
|
+
// 正确
|
|
215
|
+
console.error("[DEBUG]", info);
|
|
216
|
+
// 更好
|
|
217
|
+
server.sendLoggingMessage({ level: "info", data: "处理中" });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**常见问题:**
|
|
221
|
+
|
|
222
|
+
| 症状 | 原因 | 解决 |
|
|
223
|
+
|------|------|------|
|
|
224
|
+
| 启动无响应 | transport 未连接 | 检查 `server.connect()` |
|
|
225
|
+
| Tool 不出现 | 注册在 connect 之后 | 先注册再 connect |
|
|
226
|
+
| AI 不调用 Tool | 描述不清晰 | 改善名称和描述 |
|
|
227
|
+
| 参数总错 | Schema 不明确 | 添加 `.describe()` |
|
|
228
|
+
| 调用超时 | 外部服务慢 | 加超时和缓存 |
|
|
229
|
+
|
|
230
|
+
**调试流程:** Inspector 验证基本功能 → 手动调用确认输入输出 → 连接真实 AI 客户端观察调用模式 → 根据实际行为调整设计。
|
|
231
|
+
|
|
232
|
+
## 10. 构建检查清单
|
|
233
|
+
|
|
234
|
+
### 设计
|
|
235
|
+
- [ ] 明确 Tools vs Resources vs Prompts 分工
|
|
236
|
+
- [ ] Tool 命名 `动词_名词`,描述说明用途和返回内容
|
|
237
|
+
- [ ] 参数简洁,可选参数有合理默认值
|
|
238
|
+
|
|
239
|
+
### 实现
|
|
240
|
+
- [ ] 输入用 Zod/Pydantic 校验
|
|
241
|
+
- [ ] 外部调用有 try/catch 和超时
|
|
242
|
+
- [ ] 错误返回 `isError: true` 并附可操作信息
|
|
243
|
+
- [ ] 不用 `console.log`(用 stderr 或 SDK 日志)
|
|
244
|
+
- [ ] 敏感数据走环境变量
|
|
245
|
+
|
|
246
|
+
### 测试
|
|
247
|
+
- [ ] 核心逻辑有单元测试
|
|
248
|
+
- [ ] 有集成测试验证 MCP 协议交互
|
|
249
|
+
- [ ] 用 MCP Inspector 手动验证过
|
|
250
|
+
- [ ] 用真实 AI 客户端测试过
|
|
251
|
+
|
|
252
|
+
### 部署
|
|
253
|
+
- [ ] README 含安装和配置说明
|
|
254
|
+
- [ ] 提供客户端配置 JSON 示例
|
|
255
|
+
- [ ] 遵循 semver,无硬编码密钥
|