@xihe-lab/tapd-mcp-server 2.0.0-rc.1 → 2.0.0-rc.4
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/README.md +308 -0
- package/dist/bin/tapd-mcp-server.js +0 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -1
- package/dist/server.js.map +1 -1
- package/dist/update-check.d.ts +68 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +246 -0
- package/dist/update-check.js.map +1 -0
- package/dist/update-check.test.d.ts +6 -0
- package/dist/update-check.test.d.ts.map +1 -0
- package/dist/update-check.test.js +164 -0
- package/dist/update-check.test.js.map +1 -0
- package/package.json +15 -14
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# TAPD MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@xihe-lab/tapd-mcp-server)
|
|
4
|
+
[](https://github.com/xihe-lab/tapd-mcp-server/blob/main/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/@xihe-lab/tapd-mcp-server)
|
|
6
|
+
|
|
7
|
+
TAPD 是腾讯敏捷研发管理平台,覆盖需求、计划、研发、测试、发布研发全生命周期。通过 [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 接入 Claude、Cursor 等 AI 助手,用自然语言管理需求、缺陷、任务和迭代。
|
|
8
|
+
|
|
9
|
+
## 系统要求
|
|
10
|
+
|
|
11
|
+
- Node.js >= 18.0.0
|
|
12
|
+
- TAPD Access Token(推荐)或 TAPD API 账号密码
|
|
13
|
+
|
|
14
|
+
## 快速开始
|
|
15
|
+
|
|
16
|
+
### 1. 获取凭证
|
|
17
|
+
|
|
18
|
+
#### 方式一:个人访问令牌(推荐)
|
|
19
|
+
|
|
20
|
+
`TAPD_ACCESS_TOKEN` 为 TAPD 个人令牌:
|
|
21
|
+
|
|
22
|
+
1. 登录 TAPD,进入 **我的设置 → 个人访问令牌**
|
|
23
|
+
2. 点击"创建个人访问令牌"
|
|
24
|
+
3. 令牌只显示一次,注意保存
|
|
25
|
+
|
|
26
|
+
#### 方式二:API 账号密码(兼容)
|
|
27
|
+
|
|
28
|
+
- 未注册:前往 [TAPD 开放平台](https://open.tapd.cn) 注册
|
|
29
|
+
- 已注册未授权 API:登录 TAPD,进入 **公司管理 → API账号管理**,复制 API 账号和 API 密钥
|
|
30
|
+
|
|
31
|
+
### 2. 配置 MCP 客户端
|
|
32
|
+
|
|
33
|
+
#### 方式一:一键安装命令
|
|
34
|
+
|
|
35
|
+
注意替换以下参数(必填项标记为 **必填**,其余可选)。`-s user` 为用户级配置(所有项目生效),改为 `-s project` 则仅当前项目生效:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
claude mcp add -s user tapd \
|
|
39
|
+
--env TAPD_ACCESS_TOKEN=your_access_token \ # 必填:个人访问令牌
|
|
40
|
+
--env TAPD_DEFAULT_WORKSPACE_ID=your_workspace_id \ # 必填:默认项目 ID
|
|
41
|
+
--env TAPD_NICK_NAME=your_nick_name \ # 推荐:用户昵称,用于 owner/creator 默认值
|
|
42
|
+
--env TAPD_DEFAULT_TASK_WORKITEM_TYPE_ID=your_task_type_id \ # 可选:默认 TASK 类型 ID,可通过 tapd_get_workitem_types 查询
|
|
43
|
+
--env TAPD_DEFAULT_STORY_WORKITEM_TYPE_ID=your_story_type_id \ # 可选:默认 STORY 类型 ID
|
|
44
|
+
-- npx -y "@xihe-lab/tapd-mcp-server@latest"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
若忘记替换凭证,重新安装前需先卸载旧的配置:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
claude mcp list
|
|
51
|
+
claude mcp remove tapd
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### 方式二:手动配置
|
|
55
|
+
|
|
56
|
+
编辑 Claude Code 的配置文件(用户目录下 `.claude.json`):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"tapd": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@xihe-lab/tapd-mcp-server@latest"],
|
|
64
|
+
"env": {
|
|
65
|
+
"TAPD_ACCESS_TOKEN": "",
|
|
66
|
+
"TAPD_API_USER": "",
|
|
67
|
+
"TAPD_API_PASSWORD": "",
|
|
68
|
+
"TAPD_API_BASE_URL": "https://api.tapd.cn",
|
|
69
|
+
"TAPD_DEFAULT_WORKSPACE_ID": "",
|
|
70
|
+
"TAPD_NICK_NAME": "",
|
|
71
|
+
"TAPD_DEFAULT_STORY_WORKITEM_TYPE_ID": "",
|
|
72
|
+
"TAPD_DEFAULT_TASK_WORKITEM_TYPE_ID": ""
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
其他客户端配置方式:
|
|
80
|
+
|
|
81
|
+
- **Claude Desktop**:编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS)
|
|
82
|
+
- **Cursor / VS Code**:在项目根目录创建 `.cursor/mcp.json` 或 `.vscode/mcp.json`
|
|
83
|
+
|
|
84
|
+
配置格式与上方相同。
|
|
85
|
+
|
|
86
|
+
### 3. 开始使用
|
|
87
|
+
|
|
88
|
+
配置完成后重启客户端,直接用自然语言与 AI 助手对话:
|
|
89
|
+
|
|
90
|
+
> 查看我的待办需求
|
|
91
|
+
|
|
92
|
+
> 创建一个高优先级缺陷:登录页面报 500 错误
|
|
93
|
+
|
|
94
|
+
> 当前迭代的进度怎么样
|
|
95
|
+
|
|
96
|
+
> 给任务 10001 录入 3 小时工时
|
|
97
|
+
|
|
98
|
+
## 环境变量
|
|
99
|
+
|
|
100
|
+
| 变量 | 必填 | 说明 |
|
|
101
|
+
|------|------|------|
|
|
102
|
+
| `TAPD_ACCESS_TOKEN` | 二选一 | 个人访问令牌(推荐) |
|
|
103
|
+
| `TAPD_API_USER` + `TAPD_API_PASSWORD` | 二选一 | API 账号 + API 密钥 |
|
|
104
|
+
| `TAPD_API_BASE_URL` | 否 | API 基础地址,默认 `https://api.tapd.cn` |
|
|
105
|
+
| `TAPD_DEFAULT_WORKSPACE_ID` | 否 | 默认项目 ID,省去每次传 workspace_id |
|
|
106
|
+
| `TAPD_NICK_NAME` | 否 | 用户昵称,作为 owner/creator 等参数的默认值 |
|
|
107
|
+
| `TAPD_DEFAULT_STORY_WORKITEM_TYPE_ID` | 否 | 默认 STORY 工作项类型 ID |
|
|
108
|
+
| `TAPD_DEFAULT_TASK_WORKITEM_TYPE_ID` | 否 | 默认 TASK 工作项类型 ID |
|
|
109
|
+
|
|
110
|
+
注意:`TAPD_API_USER`/`TAPD_API_PASSWORD`(API 账号密码)与 `TAPD_ACCESS_TOKEN`(个人访问令牌)为两种调用方式,选一种即可。
|
|
111
|
+
|
|
112
|
+
## 支持的能力
|
|
113
|
+
|
|
114
|
+
| 模块 | 工具数 | 可用操作 |
|
|
115
|
+
|------|--------|----------|
|
|
116
|
+
| 需求 | 28 | 查询/创建/更新/复制/批量更新需求;需求分类管理;工作项类型转换;字段信息查询;模板管理;关联缺陷/测试用例;时间关系管理 |
|
|
117
|
+
| 测试 | 28 | 测试用例 CRUD;测试用例分类;测试计划 CRUD;测试执行与结果;用例与计划关联管理 |
|
|
118
|
+
| 缺陷 | 20 | 查询/创建/更新/复制/批量更新缺陷;缺陷关联管理;字段信息查询;模板管理;变更历史 |
|
|
119
|
+
| 项目配置 | 21 | 模块/版本/特性/基线 CRUD;自定义字段配置;项目配置开关 |
|
|
120
|
+
| Wiki | 11 | 查询/创建/更新 Wiki 页面;附件/DrawIO/权限/关注者/标签管理 |
|
|
121
|
+
| 发布 | 11 | 发布计划 CRUD;发布评审创建与管理;评审依据管理;模板查询 |
|
|
122
|
+
| 项目 | 9 | 项目信息查询;成员列表;子项目;文档;日历;自定义字段;第三方项目关联 |
|
|
123
|
+
| 任务 | 7 | 查询/创建/更新/批量更新任务;任务变更历史 |
|
|
124
|
+
| 迭代 | 7 | 查询/创建/更新迭代;迭代变更历史;锁定/解锁 |
|
|
125
|
+
| 工作流 | 7 | 工作流定义查询;状态映射;节点信息;转换规则;首末步骤查询 |
|
|
126
|
+
| 自定义字段 | 7 | 需求/缺陷/任务/测试用例/迭代自定义字段配置查询;字段信息查询 |
|
|
127
|
+
| 轻量级项目 | 6 | 轻量级工作项查询/创建/更新;分类管理;变更历史 |
|
|
128
|
+
| 附件 | 5 | 附件查询/下载;轻量级项目附件管理 |
|
|
129
|
+
| 工时 | 5 | 工时记录查询/创建/更新/删除;工时统计 |
|
|
130
|
+
| 评论 | 4 | 评论查询/创建/更新;评论数量统计 |
|
|
131
|
+
| 用户 | 4 | 个人设置查询;角色列表;第三方用户映射;当前用户信息 |
|
|
132
|
+
| 变更历史 | 4 | 需求/任务变更历史查询;变更数量统计 |
|
|
133
|
+
| 看板 | 4 | 看板工作项创建/查询/更新;看板列查询 |
|
|
134
|
+
| 关联关系 | 4 | 需求关联查询/添加/删除;关联缺陷查询 |
|
|
135
|
+
| 工具类 | 4 | 短ID转长ID;批量获取需求/缺陷/任务详情 |
|
|
136
|
+
| 代码 | 3 | 代码提交记录添加/查询;提交对象详情 |
|
|
137
|
+
| 轻量级项目空间 | 3 | 项目信息查询;成员列表;用户项目列表 |
|
|
138
|
+
| 轻量级评论 | 3 | 评论查询/创建;评论数量统计 |
|
|
139
|
+
| 报表 | 2 | 项目报表列表;状态流转时间统计 |
|
|
140
|
+
| 项目集 | 2 | 项目集关联项目;项目集绑定实体 |
|
|
141
|
+
| 图片 | 1 | 获取图片 URL |
|
|
142
|
+
|
|
143
|
+
共 **210 个工具**,覆盖 **26 个模块**。AI 助手会根据你的自然语言描述自动选择合适的工具。
|
|
144
|
+
|
|
145
|
+
## 富媒体协作
|
|
146
|
+
|
|
147
|
+
在评论、需求/缺陷/任务描述和 Wiki 里 @ 人、贴图、挂附件,四类用法如下(rc.2 新增)。
|
|
148
|
+
|
|
149
|
+
### @ 提及
|
|
150
|
+
|
|
151
|
+
在 md 正文里直接写 `@昵称`(如 `请 @徐昭 今天内确认`),写管道会自动转成 TAPD at-who 提及标记(角标 + 通知)。`@@` 表示字面 `@`(不触发提及);代码段、链接 URL、邮箱里的 `@` 不会被误伤。`tapd_md_to_html` 可传 `workspace_id` 校验昵称是否项目成员(成员接口不可用时自动跳过校验,服务端仍会智能识别);关键通知场景建议同时填 `cc` 兜底。
|
|
152
|
+
|
|
153
|
+
### 图片
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
1. tapd_upload_image(image_path="./截图.png")
|
|
157
|
+
→ { image_src: "/tfl/pictures/202609/截图.png", markdown: "" }
|
|
158
|
+
2. 把返回的 markdown 拼进 description / comment 正文
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
或者一步到位:`tapd_md_to_html(content="......", upload_images=true)`——扫描 md 里本地存在的图片路径,逐个上传图床并替换为 `/tfl/` 远端路径(默认关闭的显式副作用,返回 `uploaded_images` 清单)。读侧用 `tapd_get_image_url` 可把 `/tfl/` 路径换回临时访问 URL。
|
|
162
|
+
|
|
163
|
+
### 附件
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
1. tapd_upload_attachment(file_path="./设计稿.pdf", entity_type="story", entity_id="1139...")
|
|
167
|
+
→ 返回 embed_html(富文本锚点)与 embed_md([📎 设计稿.pdf](attach:<ws>/<id>))
|
|
168
|
+
2. 把 embed_md / embed_html 拼进评论或描述正文
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`tapd_md_to_html` / 写管道会把 `[📎 名称](attach:<ws>/<id>)` 引用自动渲染成 TAPD 附件锚点卡片;读方向 `tapd_html_to_md` 把锚点还原为同名 md 引用。下载走 `tapd_download_attachment`(`/attachments/down`,无需额外授权)。第三方系统文件不传本体、只登记链接:`tapd_attach_external_file`。
|
|
172
|
+
|
|
173
|
+
### 内部链接(零成本)
|
|
174
|
+
|
|
175
|
+
正文里直接写 TAPD 工作项 URL 的 md 链接即可,如 `[需求详情](https://www.tapd.cn/39814312/prong/stories/view/1139814312001001548)`——前端自动卡片化,无需任何转换。
|
|
176
|
+
|
|
177
|
+
### raw_html 直发通道
|
|
178
|
+
|
|
179
|
+
`comment/story/task/bug/wiki` 的 create/update 工具支持 `raw_html: true`:`description` 原样透传(绕过 md→html 自动转换),适合已含 TAPD 原生富文本标记或需要确定性透传的场景。默认 `false` 走 md 管道(@昵称 / 附件引用自动转换)。
|
|
180
|
+
|
|
181
|
+
## 常见问题
|
|
182
|
+
|
|
183
|
+
### AI 助手没有识别到 TAPD 工具
|
|
184
|
+
|
|
185
|
+
确认 Node.js >= 18 已安装,npx 可正常执行。修改配置后需重启客户端。
|
|
186
|
+
|
|
187
|
+
### 工具返回权限不足 (403)
|
|
188
|
+
|
|
189
|
+
在 TAPD 开放平台检查应用权限,确保已勾选所需 API 的访问权限。
|
|
190
|
+
|
|
191
|
+
### 创建任务时提示权限不足
|
|
192
|
+
|
|
193
|
+
如果 OAuth Token 没有 `tasks::create` 权限,可以通过 `tapd_create_story` 工具传入 TASK 类型的 `workitem_type_id` 来创建任务(仅需 `stories::create` 权限):
|
|
194
|
+
|
|
195
|
+
> 用 tapd_create_story 创建一个任务,workitem_type_id 设为 TASK 类型
|
|
196
|
+
|
|
197
|
+
可通过 `tapd_get_workitem_types` 查询项目中可用的 TASK 类型 ID。
|
|
198
|
+
|
|
199
|
+
### 调用工具报「ID 超出 JS 安全整数范围」或首次调用 ID 校验失败
|
|
200
|
+
|
|
201
|
+
TAPD 的需求/缺陷/任务等实体长 ID 为 19-20 位数字(如 `1139814312001001378`),超出 JS 安全整数上限(`Number.MAX_SAFE_INTEGER`,16 位),以 JSON 数值形式传递会丢精度导致查询为空。所有长 ID 参数必须以字符串(带引号)传递。
|
|
202
|
+
|
|
203
|
+
所有工具的长 ID 参数描述均已包含引导提示;若传入安全整数范围内的数值(≤16 位,如短 ID)会自动转为字符串;超出安全范围的数值会返回明确错误提示,请按提示以字符串重传。
|
|
204
|
+
|
|
205
|
+
### 支持 Basic Auth 吗
|
|
206
|
+
|
|
207
|
+
支持。设置 `TAPD_API_USER` 和 `TAPD_API_PASSWORD` 即可,与 Access Token 二选一。
|
|
208
|
+
|
|
209
|
+
## 更新
|
|
210
|
+
|
|
211
|
+
MCP 客户端使用 `npx` 运行时会自动检查并下载最新版本。如需确保使用最新版本:
|
|
212
|
+
|
|
213
|
+
### Claude Code
|
|
214
|
+
|
|
215
|
+
重新安装配置(会自动使用最新版本):
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
claude mcp remove tapd
|
|
219
|
+
claude mcp add -s user tapd \
|
|
220
|
+
--env TAPD_ACCESS_TOKEN=your_access_token \
|
|
221
|
+
--env TAPD_DEFAULT_WORKSPACE_ID=your_workspace_id \
|
|
222
|
+
--env TAPD_NICK_NAME=your_nick_name \
|
|
223
|
+
--env TAPD_DEFAULT_TASK_WORKITEM_TYPE_ID=your_task_type_id \
|
|
224
|
+
--env TAPD_DEFAULT_STORY_WORKITEM_TYPE_ID=your_story_type_id \
|
|
225
|
+
-- npx -y "@xihe-lab/tapd-mcp-server@latest"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Claude Desktop / Cursor
|
|
229
|
+
|
|
230
|
+
修改配置文件中的版本号为 `@latest` 或删除版本锁定(WorkBuddy 的配置文件路径见下文「WorkBuddy」小节):
|
|
231
|
+
|
|
232
|
+
#### WorkBuddy(腾讯 CodeBuddy 办公客户端)
|
|
233
|
+
|
|
234
|
+
WorkBuddy 采用标准 `mcpServers` 配置,支持两级配置文件:
|
|
235
|
+
|
|
236
|
+
| 级别 | 配置文件路径 | 适用场景 |
|
|
237
|
+
|------|-------------|---------|
|
|
238
|
+
| 用户级 | `~/.workbuddy/mcp.json` | 配置一次,所有项目复用(推荐) |
|
|
239
|
+
| 项目级 | `<项目目录>/.workbuddy/mcp.json` | 仅当前项目生效 |
|
|
240
|
+
|
|
241
|
+
操作入口:侧边栏 **插件** → 右上角 **MCP 服务器** → **配置 MCP**,在可视化编辑器中粘贴与上方相同的 `mcpServers` 配置并保存(也可直接编辑上述路径的 JSON 文件)。
|
|
242
|
+
|
|
243
|
+
保存后检查 MCP Server 状态灯:🟢 连接成功;🔴 配置异常(依次检查 JSON 格式、`npx` 环境、凭证有效性)。
|
|
244
|
+
|
|
245
|
+
> 安全提示:`TAPD_ACCESS_TOKEN` 是调用凭证。使用项目级配置时,请将 `.workbuddy/` 加入 `.gitignore`,避免提交到仓库。
|
|
246
|
+
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"mcpServers": {
|
|
250
|
+
"tapd": {
|
|
251
|
+
"command": "npx",
|
|
252
|
+
"args": ["-y", "@xihe-lab/tapd-mcp-server@latest"],
|
|
253
|
+
"env": { ... }
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### npm 全局安装方式
|
|
260
|
+
|
|
261
|
+
如果通过 npm 全局安装使用:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# 查看当前安装版本
|
|
265
|
+
npm list -g @xihe-lab/tapd-mcp-server
|
|
266
|
+
|
|
267
|
+
# 更新到最新版本
|
|
268
|
+
npm update -g @xihe-lab/tapd-mcp-server
|
|
269
|
+
|
|
270
|
+
# 或指定版本安装
|
|
271
|
+
npm install -g @xihe-lab/tapd-mcp-server@1.5.0
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
更新后需重启 MCP 客户端。
|
|
275
|
+
|
|
276
|
+
### npx 缓存清理
|
|
277
|
+
|
|
278
|
+
如果 npx 使用了旧版本缓存,可手动清理后重新运行:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# 清理 npx 缓存
|
|
282
|
+
npx clear-npx-cache
|
|
283
|
+
|
|
284
|
+
# 或手动删除缓存目录
|
|
285
|
+
rm -rf ~/.npm/_npx
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 查看版本信息
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# 查看最新发布版本
|
|
292
|
+
npm view @xihe-lab/tapd-mcp-server version
|
|
293
|
+
|
|
294
|
+
# 查看所有已发布版本
|
|
295
|
+
npm view @xihe-lab/tapd-mcp-server versions
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 查看更新日志
|
|
299
|
+
|
|
300
|
+
查看 [CHANGELOG.md](CHANGELOG.md) 了解各版本的变更内容。
|
|
301
|
+
|
|
302
|
+
## 本地开发
|
|
303
|
+
|
|
304
|
+
`@xihe-lab/tapd-mcp-server` 以 npm 包分发,通过 `npx -y @xihe-lab/tapd-mcp-server` 运行(配置见上文)。本仓为 MCP 入口层(stdio server 接线),工具内核在同组织包 `@xihe-lab/tapd-core` 中演进——新增工具遵循其 `ToolDef[]` 模式(zod schema + handler,按 TAPD 领域模块组织)。
|
|
305
|
+
|
|
306
|
+
## 许可证
|
|
307
|
+
|
|
308
|
+
[Apache-2.0](LICENSE)
|
|
File without changes
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAWnD,wBAAgB,YAAY,IAAI,SAAS,CAYxC;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAmCvE;AAED,wBAAsB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB3D"}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { ToolRegistry, TapdClient } from '@xihe-lab/tapd-core';
|
|
4
|
+
import { checkForUpdate } from './update-check.js';
|
|
4
5
|
let client = null;
|
|
5
6
|
function getTapdClient() {
|
|
6
7
|
client ??= TapdClient.fromEnv();
|
|
@@ -10,7 +11,10 @@ export function createServer() {
|
|
|
10
11
|
const server = new McpServer({
|
|
11
12
|
name: 'tapd-mcp-server',
|
|
12
13
|
version: '1.0.0',
|
|
13
|
-
}
|
|
14
|
+
},
|
|
15
|
+
// 声明 logging 能力:SDK 的 sendLoggingMessage 仅在 capabilities.logging
|
|
16
|
+
// 存在时才真正发出 notifications/message,否则静默丢弃
|
|
17
|
+
{ capabilities: { logging: {} } });
|
|
14
18
|
return server;
|
|
15
19
|
}
|
|
16
20
|
export function registerTools(server, tools) {
|
|
@@ -48,6 +52,14 @@ export async function start(tools) {
|
|
|
48
52
|
registerTools(server, tools);
|
|
49
53
|
const transport = new StdioServerTransport();
|
|
50
54
|
await server.connect(transport);
|
|
55
|
+
// 启动版本自检:异步执行,不阻塞初始化与工具响应;提示经 MCP logging
|
|
56
|
+
// notification 送达(严禁 stderr——Claude Code 会把 server 的 stderr 一律当
|
|
57
|
+
// error 显示)。断网 / registry 不可达时静默跳过;TAPD_MCP_UPDATE_CHECK=off 关闭。
|
|
58
|
+
void checkForUpdate({
|
|
59
|
+
notify: async (message) => {
|
|
60
|
+
await server.server.sendLoggingMessage({ level: 'notice', data: message });
|
|
61
|
+
},
|
|
62
|
+
});
|
|
51
63
|
process.on('SIGINT', () => {
|
|
52
64
|
void server.close();
|
|
53
65
|
process.exit(0);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动版本自检(update check)
|
|
3
|
+
*
|
|
4
|
+
* 背景(调研:tapd-knowledge-base/.claude/mcp-autoupdate-research.md):
|
|
5
|
+
* npx 缓存树只以「根包 spec 的 manifest」为新鲜度探针——`@xihe-lab/tapd-mcp-server@rc`
|
|
6
|
+
* 的 dist-tag 不动,整棵缓存树原样复用,用户可能长期跑在旧版本上而不自知。
|
|
7
|
+
* 本模块在 server 启动后异步查询 npm registry 的 @rc dist-tag,发现新版本时
|
|
8
|
+
* 通过 MCP logging notification(notifications/message)提示用户「重启即更新」。
|
|
9
|
+
*
|
|
10
|
+
* 硬约束:
|
|
11
|
+
* - 严禁 console.error / stderr 输出:Claude Code 会把 MCP server 的 stderr 一律
|
|
12
|
+
* 当 error 显示(anthropics/claude-code#17653)。唯一出口是 MCP 协议的
|
|
13
|
+
* logging notification。
|
|
14
|
+
* - 全程 try-catch + 请求超时兜底:断网 / registry 不可达 / 响应异常一律静默
|
|
15
|
+
* 跳过,绝不影响 server 启动与工具响应。
|
|
16
|
+
* - 环境开关:TAPD_MCP_UPDATE_CHECK=off(或 false / 0)跳过检查,默认开启。
|
|
17
|
+
*/
|
|
18
|
+
export interface LocalVersions {
|
|
19
|
+
/** 自身(@xihe-lab/tapd-mcp-server)版本;解析不到时为 null */
|
|
20
|
+
server: string | null;
|
|
21
|
+
/** 内核(@xihe-lab/tapd-core)版本;解析不到时为 null */
|
|
22
|
+
core: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface RemoteVersions {
|
|
25
|
+
server: string | null;
|
|
26
|
+
core: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface UpdateCheckDeps {
|
|
29
|
+
/** 环境变量来源,默认 process.env(测试注入用) */
|
|
30
|
+
env?: NodeJS.ProcessEnv;
|
|
31
|
+
/** 提示出口,默认由调用方(server.ts)接 MCP logging notification */
|
|
32
|
+
notify?: (message: string) => void | Promise<void>;
|
|
33
|
+
/** registry 探针,默认 https 直连(测试注入用) */
|
|
34
|
+
fetchRc?: (pkgName: string) => string | null | Promise<string | null>;
|
|
35
|
+
/** 版本解析起点模块 URL,默认本模块(测试注入用) */
|
|
36
|
+
fromUrl?: string;
|
|
37
|
+
/** registry 请求超时毫秒数 */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
}
|
|
40
|
+
interface ParsedVersion {
|
|
41
|
+
numbers: [number, number, number];
|
|
42
|
+
/** prerelease 标识段;GA(无 prerelease)为 null */
|
|
43
|
+
pre: (string | number)[] | null;
|
|
44
|
+
}
|
|
45
|
+
export declare function parseVersion(version: string): ParsedVersion | null;
|
|
46
|
+
/**
|
|
47
|
+
* 返回 1 / -1 / 0 表示 a 相对 b 更新 / 更旧 / 相同;任一版本无法解析时返回 0
|
|
48
|
+
*(解析失败不产生结论,避免误报更新)。
|
|
49
|
+
*/
|
|
50
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
51
|
+
export declare function isUpdateCheckDisabled(env?: NodeJS.ProcessEnv): boolean;
|
|
52
|
+
/** registry 基址:尊重 npm 镜像环境变量,缺省 npmjs(与 npm CLI 的 env 形态一致) */
|
|
53
|
+
export declare function resolveRegistryBase(env?: NodeJS.ProcessEnv): string;
|
|
54
|
+
/** registry packument URL(scope 的 `/` 需编码为 %2F) */
|
|
55
|
+
export declare function packumentUrl(registryBase: string, pkgName: string): string;
|
|
56
|
+
/** 读自身与内核的本地安装版本;server 版本解析不到时整体放弃 */
|
|
57
|
+
export declare function readLocalVersions(fromUrl: string): LocalVersions | null;
|
|
58
|
+
/** 查询包在 npm registry 上 @rc dist-tag 指向的版本;任何失败返回 null(静默) */
|
|
59
|
+
export declare function fetchRcVersion(registryBase: string, pkgName: string, timeoutMs?: number): Promise<string | null>;
|
|
60
|
+
/** 本地任一包落后于 registry @rc 时返回提示文案;否则返回 null */
|
|
61
|
+
export declare function buildUpdateNotice(local: LocalVersions, remote: RemoteVersions): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* 启动自检入口:读本地版本 → 查 registry @rc → 有更新则经 notify 提示。
|
|
64
|
+
* 自身保证不抛错、不写 stderr;调用方只需提供 notify(MCP logging notification)。
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkForUpdate(deps?: UpdateCheckDeps): Promise<void>;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=update-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgBH,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,uDAAuD;IACvD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtE,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,UAAU,aAAa;IACrB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,4CAA4C;IAC5C,GAAG,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAOlE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA0B5D;AAMD,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGnF;AAED,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAGhF;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1E;AAwCD,uCAAuC;AACvC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAIvE;AAMD,6DAA6D;AAC7D,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2DxB;AAMD,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,cAAc,GACrB,MAAM,GAAG,IAAI,CAcf;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB9E"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动版本自检(update check)
|
|
3
|
+
*
|
|
4
|
+
* 背景(调研:tapd-knowledge-base/.claude/mcp-autoupdate-research.md):
|
|
5
|
+
* npx 缓存树只以「根包 spec 的 manifest」为新鲜度探针——`@xihe-lab/tapd-mcp-server@rc`
|
|
6
|
+
* 的 dist-tag 不动,整棵缓存树原样复用,用户可能长期跑在旧版本上而不自知。
|
|
7
|
+
* 本模块在 server 启动后异步查询 npm registry 的 @rc dist-tag,发现新版本时
|
|
8
|
+
* 通过 MCP logging notification(notifications/message)提示用户「重启即更新」。
|
|
9
|
+
*
|
|
10
|
+
* 硬约束:
|
|
11
|
+
* - 严禁 console.error / stderr 输出:Claude Code 会把 MCP server 的 stderr 一律
|
|
12
|
+
* 当 error 显示(anthropics/claude-code#17653)。唯一出口是 MCP 协议的
|
|
13
|
+
* logging notification。
|
|
14
|
+
* - 全程 try-catch + 请求超时兜底:断网 / registry 不可达 / 响应异常一律静默
|
|
15
|
+
* 跳过,绝不影响 server 启动与工具响应。
|
|
16
|
+
* - 环境开关:TAPD_MCP_UPDATE_CHECK=off(或 false / 0)跳过检查,默认开启。
|
|
17
|
+
*/
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
import * as https from 'node:https';
|
|
20
|
+
import { createRequire } from 'node:module';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
const SERVER_PKG_NAME = '@xihe-lab/tapd-mcp-server';
|
|
24
|
+
const CORE_PKG_NAME = '@xihe-lab/tapd-core';
|
|
25
|
+
const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
|
|
26
|
+
/** 单次 registry 请求超时:自检是纯增益,超时即静默放弃 */
|
|
27
|
+
const REQUEST_TIMEOUT_MS = 3000;
|
|
28
|
+
/** packument 响应体上限(防御性;超限直接放弃) */
|
|
29
|
+
const MAX_BODY_BYTES = 8 * 1024 * 1024;
|
|
30
|
+
export function parseVersion(version) {
|
|
31
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(version.trim());
|
|
32
|
+
if (!match)
|
|
33
|
+
return null;
|
|
34
|
+
const pre = match[4]
|
|
35
|
+
? match[4].split('.').map((seg) => (/^\d+$/.test(seg) ? Number(seg) : seg))
|
|
36
|
+
: null;
|
|
37
|
+
return { numbers: [Number(match[1]), Number(match[2]), Number(match[3])], pre };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 返回 1 / -1 / 0 表示 a 相对 b 更新 / 更旧 / 相同;任一版本无法解析时返回 0
|
|
41
|
+
*(解析失败不产生结论,避免误报更新)。
|
|
42
|
+
*/
|
|
43
|
+
export function compareVersions(a, b) {
|
|
44
|
+
const pa = parseVersion(a);
|
|
45
|
+
const pb = parseVersion(b);
|
|
46
|
+
if (!pa || !pb)
|
|
47
|
+
return 0;
|
|
48
|
+
for (let i = 0; i < 3; i++) {
|
|
49
|
+
if (pa.numbers[i] !== pb.numbers[i])
|
|
50
|
+
return pa.numbers[i] > pb.numbers[i] ? 1 : -1;
|
|
51
|
+
}
|
|
52
|
+
// x.y.z > x.y.z-rc.N(GA 优先级高于任何 prerelease)
|
|
53
|
+
if (pa.pre === null || pb.pre === null) {
|
|
54
|
+
if (pa.pre === pb.pre)
|
|
55
|
+
return 0;
|
|
56
|
+
return pa.pre === null ? 1 : -1;
|
|
57
|
+
}
|
|
58
|
+
const len = Math.max(pa.pre.length, pb.pre.length);
|
|
59
|
+
for (let i = 0; i < len; i++) {
|
|
60
|
+
const va = pa.pre[i];
|
|
61
|
+
const vb = pb.pre[i];
|
|
62
|
+
if (va === undefined)
|
|
63
|
+
return -1; // 前缀短者更旧
|
|
64
|
+
if (vb === undefined)
|
|
65
|
+
return 1;
|
|
66
|
+
if (va === vb)
|
|
67
|
+
continue;
|
|
68
|
+
// semver 规则:数字标识段 < 字母标识段
|
|
69
|
+
if (typeof va === 'number' && typeof vb === 'number')
|
|
70
|
+
return va > vb ? 1 : -1;
|
|
71
|
+
if (typeof va === 'string' && typeof vb === 'string')
|
|
72
|
+
return va > vb ? 1 : -1;
|
|
73
|
+
return typeof va === 'number' ? -1 : 1;
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// 开关与 registry 解析
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
export function isUpdateCheckDisabled(env = process.env) {
|
|
81
|
+
const raw = (env.TAPD_MCP_UPDATE_CHECK ?? '').trim().toLowerCase();
|
|
82
|
+
return raw === 'off' || raw === 'false' || raw === '0';
|
|
83
|
+
}
|
|
84
|
+
/** registry 基址:尊重 npm 镜像环境变量,缺省 npmjs(与 npm CLI 的 env 形态一致) */
|
|
85
|
+
export function resolveRegistryBase(env = process.env) {
|
|
86
|
+
const raw = (env.npm_config_registry ?? env.NPM_CONFIG_REGISTRY ?? DEFAULT_REGISTRY).trim();
|
|
87
|
+
return (raw === '' ? DEFAULT_REGISTRY : raw).replace(/\/+$/, '');
|
|
88
|
+
}
|
|
89
|
+
/** registry packument URL(scope 的 `/` 需编码为 %2F) */
|
|
90
|
+
export function packumentUrl(registryBase, pkgName) {
|
|
91
|
+
return `${registryBase.replace(/\/+$/, '')}/${pkgName.replace('/', '%2F')}`;
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// 本地版本解析
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
/** 从模块所在目录逐级向上找自身 package.json(兼容 dist/bin、dist、src/tsx 各层级) */
|
|
97
|
+
function findOwnVersion(fromUrl) {
|
|
98
|
+
try {
|
|
99
|
+
let dir = path.dirname(fileURLToPath(fromUrl));
|
|
100
|
+
for (let i = 0; i < 10; i++) {
|
|
101
|
+
try {
|
|
102
|
+
const pkg = JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
103
|
+
if (pkg.name === SERVER_PKG_NAME && typeof pkg.version === 'string')
|
|
104
|
+
return pkg.version;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// 该层无 package.json 或不可读——继续向上
|
|
108
|
+
}
|
|
109
|
+
const parent = path.dirname(dir);
|
|
110
|
+
if (parent === dir)
|
|
111
|
+
break;
|
|
112
|
+
dir = parent;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// 非文件协议(嵌入等场景)——放弃
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
/** 经 node_modules 解析内核包版本;不可达(独立检出等)返回 null */
|
|
121
|
+
function readCoreVersion(fromUrl) {
|
|
122
|
+
try {
|
|
123
|
+
const pkg = createRequire(fromUrl)(`${CORE_PKG_NAME}/package.json`);
|
|
124
|
+
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** 读自身与内核的本地安装版本;server 版本解析不到时整体放弃 */
|
|
131
|
+
export function readLocalVersions(fromUrl) {
|
|
132
|
+
const server = findOwnVersion(fromUrl);
|
|
133
|
+
if (server === null)
|
|
134
|
+
return null;
|
|
135
|
+
return { server, core: readCoreVersion(fromUrl) };
|
|
136
|
+
}
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// registry 探针(https 直连,不走 npm CLI)
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
/** 查询包在 npm registry 上 @rc dist-tag 指向的版本;任何失败返回 null(静默) */
|
|
141
|
+
export function fetchRcVersion(registryBase, pkgName, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
let settled = false;
|
|
144
|
+
const done = (value) => {
|
|
145
|
+
if (!settled) {
|
|
146
|
+
settled = true;
|
|
147
|
+
resolve(value);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
try {
|
|
151
|
+
const request = https.get(packumentUrl(registryBase, pkgName), {
|
|
152
|
+
headers: {
|
|
153
|
+
accept: 'application/vnd.npm.install-v1+json',
|
|
154
|
+
'user-agent': `${SERVER_PKG_NAME} update-check`,
|
|
155
|
+
},
|
|
156
|
+
timeout: timeoutMs,
|
|
157
|
+
}, (res) => {
|
|
158
|
+
if (res.statusCode !== 200) {
|
|
159
|
+
res.resume();
|
|
160
|
+
done(null);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const chunks = [];
|
|
164
|
+
let size = 0;
|
|
165
|
+
res.on('data', (chunk) => {
|
|
166
|
+
size += chunk.length;
|
|
167
|
+
if (size > MAX_BODY_BYTES) {
|
|
168
|
+
request.destroy();
|
|
169
|
+
done(null);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
chunks.push(chunk);
|
|
173
|
+
});
|
|
174
|
+
res.on('end', () => {
|
|
175
|
+
try {
|
|
176
|
+
const doc = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
177
|
+
const rc = doc['dist-tags']?.rc;
|
|
178
|
+
done(typeof rc === 'string' ? rc : null);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
done(null);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
res.on('error', () => done(null));
|
|
185
|
+
});
|
|
186
|
+
request.on('timeout', () => {
|
|
187
|
+
request.destroy();
|
|
188
|
+
done(null);
|
|
189
|
+
});
|
|
190
|
+
request.on('error', () => done(null));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
done(null);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// 组装与入口
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
/** 本地任一包落后于 registry @rc 时返回提示文案;否则返回 null */
|
|
201
|
+
export function buildUpdateNotice(local, remote) {
|
|
202
|
+
const parts = [];
|
|
203
|
+
if (remote.server !== null && local.server !== null && compareVersions(remote.server, local.server) > 0) {
|
|
204
|
+
parts.push(`tapd-mcp-server 有新版本可用(${local.server} → ${remote.server})`);
|
|
205
|
+
}
|
|
206
|
+
if (remote.core !== null) {
|
|
207
|
+
if (local.core === null) {
|
|
208
|
+
parts.push(`tapd-core 有新版本可用(${remote.core})`);
|
|
209
|
+
}
|
|
210
|
+
else if (compareVersions(remote.core, local.core) > 0) {
|
|
211
|
+
parts.push(`tapd-core 有新版本可用(${local.core} → ${remote.core})`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (parts.length === 0)
|
|
215
|
+
return null;
|
|
216
|
+
return `${parts.join(';')}——重启 MCP 会话即可更新(Claude Code 可用 /mcp 菜单 Reconnect)。`;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 启动自检入口:读本地版本 → 查 registry @rc → 有更新则经 notify 提示。
|
|
220
|
+
* 自身保证不抛错、不写 stderr;调用方只需提供 notify(MCP logging notification)。
|
|
221
|
+
*/
|
|
222
|
+
export async function checkForUpdate(deps = {}) {
|
|
223
|
+
try {
|
|
224
|
+
const env = deps.env ?? process.env;
|
|
225
|
+
if (isUpdateCheckDisabled(env))
|
|
226
|
+
return;
|
|
227
|
+
const notify = deps.notify;
|
|
228
|
+
if (!notify)
|
|
229
|
+
return;
|
|
230
|
+
const local = readLocalVersions(deps.fromUrl ?? import.meta.url);
|
|
231
|
+
if (local === null)
|
|
232
|
+
return;
|
|
233
|
+
const registryBase = resolveRegistryBase(env);
|
|
234
|
+
const timeoutMs = deps.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
235
|
+
const fetchRc = deps.fetchRc ??
|
|
236
|
+
((pkgName) => fetchRcVersion(registryBase, pkgName, timeoutMs));
|
|
237
|
+
const [remoteServer, remoteCore] = await Promise.all([fetchRc(SERVER_PKG_NAME), fetchRc(CORE_PKG_NAME)]);
|
|
238
|
+
const notice = buildUpdateNotice(local, { server: remoteServer, core: remoteCore });
|
|
239
|
+
if (notice !== null)
|
|
240
|
+
await notify(notice);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// 自检绝不能干扰 server 启动——所有异常静默吞掉(严禁 stderr)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.test.d.ts","sourceRoot":"","sources":["../src/update-check.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update-check 单元测试:版本比较 / 开关 / registry 解析 / 提示组装 / 端到端注入
|
|
3
|
+
* 运行:tsx src/update-check.test.ts(零网络依赖,registry 探针全部注入 mock)
|
|
4
|
+
*/
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { buildUpdateNotice, checkForUpdate, compareVersions, fetchRcVersion, isUpdateCheckDisabled, packumentUrl, readLocalVersions, resolveRegistryBase, } from './update-check.js';
|
|
7
|
+
const checks = [
|
|
8
|
+
// ---- 版本比较 ----
|
|
9
|
+
['compareVersions: 相同版本为 0', () => {
|
|
10
|
+
assert.equal(compareVersions('2.0.0-rc.3', '2.0.0-rc.3'), 0);
|
|
11
|
+
}],
|
|
12
|
+
['compareVersions: rc 序号按数值比较(rc.3 < rc.10)', () => {
|
|
13
|
+
assert.equal(compareVersions('2.0.0-rc.3', '2.0.0-rc.10'), -1);
|
|
14
|
+
assert.equal(compareVersions('2.0.0-rc.10', '2.0.0-rc.3'), 1);
|
|
15
|
+
}],
|
|
16
|
+
['compareVersions: GA > 同号 rc', () => {
|
|
17
|
+
assert.equal(compareVersions('2.0.0', '2.0.0-rc.5'), 1);
|
|
18
|
+
assert.equal(compareVersions('2.0.0-rc.5', '2.0.0'), -1);
|
|
19
|
+
}],
|
|
20
|
+
['compareVersions: 主次补丁位决定先后', () => {
|
|
21
|
+
assert.equal(compareVersions('1.4.4', '2.0.0-rc.3'), -1);
|
|
22
|
+
assert.equal(compareVersions('2.0.0-rc.3', '2.1.0-rc.1'), -1);
|
|
23
|
+
assert.equal(compareVersions('2.0.1-rc.1', '2.0.0-rc.9'), 1);
|
|
24
|
+
}],
|
|
25
|
+
['compareVersions: 无法解析不产生结论', () => {
|
|
26
|
+
assert.equal(compareVersions('not-a-version', '2.0.0-rc.3'), 0);
|
|
27
|
+
assert.equal(compareVersions('2.0.0-rc.3', ''), 0);
|
|
28
|
+
}],
|
|
29
|
+
// ---- 环境开关 ----
|
|
30
|
+
['isUpdateCheckDisabled: 默认开启', () => {
|
|
31
|
+
assert.equal(isUpdateCheckDisabled({}), false);
|
|
32
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: 'on' }), false);
|
|
33
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: '' }), false);
|
|
34
|
+
}],
|
|
35
|
+
['isUpdateCheckDisabled: off/false/0(含大小写与空白)关闭', () => {
|
|
36
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: 'off' }), true);
|
|
37
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: ' OFF ' }), true);
|
|
38
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: 'false' }), true);
|
|
39
|
+
assert.equal(isUpdateCheckDisabled({ TAPD_MCP_UPDATE_CHECK: '0' }), true);
|
|
40
|
+
}],
|
|
41
|
+
// ---- registry 解析 ----
|
|
42
|
+
['resolveRegistryBase: 缺省 npmjs,尊重 npm_config_registry 并去尾斜杠', () => {
|
|
43
|
+
assert.equal(resolveRegistryBase({}), 'https://registry.npmjs.org');
|
|
44
|
+
assert.equal(resolveRegistryBase({ npm_config_registry: 'https://registry.npmmirror.com/' }), 'https://registry.npmmirror.com');
|
|
45
|
+
assert.equal(resolveRegistryBase({ NPM_CONFIG_REGISTRY: 'https://mirror.example.com/api' }), 'https://mirror.example.com/api');
|
|
46
|
+
assert.equal(resolveRegistryBase({ npm_config_registry: ' ' }), 'https://registry.npmjs.org');
|
|
47
|
+
}],
|
|
48
|
+
['packumentUrl: scope 斜杠编码为 %2F', () => {
|
|
49
|
+
assert.equal(packumentUrl('https://registry.npmjs.org', '@xihe-lab/tapd-core'), 'https://registry.npmjs.org/@xihe-lab%2Ftapd-core');
|
|
50
|
+
}],
|
|
51
|
+
// ---- 本地版本解析 ----
|
|
52
|
+
['readLocalVersions: 能从本模块定位自身 package.json', () => {
|
|
53
|
+
const local = readLocalVersions(import.meta.url);
|
|
54
|
+
assert.ok(local !== null, '应能解析自身版本');
|
|
55
|
+
assert.match(local.server ?? '', /^\d+\.\d+\.\d+/);
|
|
56
|
+
// 工作区(symlink)/npx 树均可解析;独立无 node_modules 的检出允许为 null
|
|
57
|
+
if (local.core !== null)
|
|
58
|
+
assert.match(local.core, /^\d+\.\d+\.\d+/);
|
|
59
|
+
}],
|
|
60
|
+
// ---- 提示组装 ----
|
|
61
|
+
['buildUpdateNotice: 双双落后时合并提示并给重启指引', () => {
|
|
62
|
+
const notice = buildUpdateNotice({ server: '2.0.0-rc.3', core: '2.0.0-rc.3' }, { server: '2.0.0-rc.5', core: '2.0.0-rc.5' });
|
|
63
|
+
assert.ok(notice !== null);
|
|
64
|
+
assert.match(notice, /tapd-mcp-server 有新版本可用(2\.0\.0-rc\.3 → 2\.0\.0-rc\.5)/);
|
|
65
|
+
assert.match(notice, /tapd-core 有新版本可用(2\.0\.0-rc\.3 → 2\.0\.0-rc\.5)/);
|
|
66
|
+
assert.match(notice, /重启 MCP 会话即可更新/);
|
|
67
|
+
}],
|
|
68
|
+
['buildUpdateNotice: 仅内核落后时只提内核', () => {
|
|
69
|
+
const notice = buildUpdateNotice({ server: '2.0.0-rc.5', core: '2.0.0-rc.3' }, { server: '2.0.0-rc.5', core: '2.0.0-rc.4' });
|
|
70
|
+
assert.ok(notice !== null);
|
|
71
|
+
assert.match(notice, /tapd-core 有新版本可用/);
|
|
72
|
+
assert.doesNotMatch(notice, /tapd-mcp-server 有新版本/);
|
|
73
|
+
}],
|
|
74
|
+
['buildUpdateNotice: 已是最新时返回 null', () => {
|
|
75
|
+
assert.equal(buildUpdateNotice({ server: '2.0.0-rc.5', core: '2.0.0-rc.5' }, { server: '2.0.0-rc.5', core: '2.0.0-rc.5' }), null);
|
|
76
|
+
assert.equal(buildUpdateNotice({ server: '2.0.0-rc.5', core: '2.0.0-rc.5' }, { server: null, core: null }), null);
|
|
77
|
+
}],
|
|
78
|
+
['buildUpdateNotice: 本地解析不到内核时仍提示 registry 版本', () => {
|
|
79
|
+
const notice = buildUpdateNotice({ server: '2.0.0-rc.3', core: null }, { server: null, core: '2.0.0-rc.9' });
|
|
80
|
+
assert.ok(notice !== null);
|
|
81
|
+
assert.match(notice, /tapd-core 有新版本可用(2\.0\.0-rc\.9)/);
|
|
82
|
+
}],
|
|
83
|
+
// ---- 端到端(注入探针与出口) ----
|
|
84
|
+
['checkForUpdate: 有更新时经 notify 发出一条提示', async () => {
|
|
85
|
+
const messages = [];
|
|
86
|
+
await checkForUpdate({
|
|
87
|
+
env: {},
|
|
88
|
+
fromUrl: import.meta.url,
|
|
89
|
+
fetchRc: (name) => (name === '@xihe-lab/tapd-core' ? '2.0.0-rc.99' : null),
|
|
90
|
+
notify: (message) => {
|
|
91
|
+
messages.push(message);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
assert.equal(messages.length, 1);
|
|
95
|
+
assert.match(messages[0] ?? '', /重启 MCP 会话即可更新/);
|
|
96
|
+
}],
|
|
97
|
+
['checkForUpdate: TAPD_MCP_UPDATE_CHECK=off 时不探查不提示', async () => {
|
|
98
|
+
let probed = 0;
|
|
99
|
+
const messages = [];
|
|
100
|
+
await checkForUpdate({
|
|
101
|
+
env: { TAPD_MCP_UPDATE_CHECK: 'off' },
|
|
102
|
+
fromUrl: import.meta.url,
|
|
103
|
+
fetchRc: () => {
|
|
104
|
+
probed += 1;
|
|
105
|
+
return '2.0.0-rc.99';
|
|
106
|
+
},
|
|
107
|
+
notify: (message) => {
|
|
108
|
+
messages.push(message);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
assert.equal(probed, 0);
|
|
112
|
+
assert.equal(messages.length, 0);
|
|
113
|
+
}],
|
|
114
|
+
['checkForUpdate: registry 全部不可达时静默跳过', async () => {
|
|
115
|
+
const messages = [];
|
|
116
|
+
await checkForUpdate({
|
|
117
|
+
env: {},
|
|
118
|
+
fromUrl: import.meta.url,
|
|
119
|
+
fetchRc: () => null,
|
|
120
|
+
notify: (message) => {
|
|
121
|
+
messages.push(message);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
assert.equal(messages.length, 0);
|
|
125
|
+
}],
|
|
126
|
+
['checkForUpdate: 探针抛错被吞掉且不影响调用方', async () => {
|
|
127
|
+
const messages = [];
|
|
128
|
+
await assert.doesNotReject(checkForUpdate({
|
|
129
|
+
env: {},
|
|
130
|
+
fromUrl: import.meta.url,
|
|
131
|
+
fetchRc: () => {
|
|
132
|
+
throw new Error('network down');
|
|
133
|
+
},
|
|
134
|
+
notify: (message) => {
|
|
135
|
+
messages.push(message);
|
|
136
|
+
},
|
|
137
|
+
}));
|
|
138
|
+
assert.equal(messages.length, 0);
|
|
139
|
+
}],
|
|
140
|
+
['fetchRcVersion: 连接失败返回 null(不抛错)', async () => {
|
|
141
|
+
const result = await fetchRcVersion('https://127.0.0.1:1', '@xihe-lab/tapd-core', 500);
|
|
142
|
+
assert.equal(result, null);
|
|
143
|
+
}],
|
|
144
|
+
];
|
|
145
|
+
let failed = 0;
|
|
146
|
+
for (const [name, fn] of checks) {
|
|
147
|
+
try {
|
|
148
|
+
await fn();
|
|
149
|
+
console.log(`✓ ${name}`);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
failed += 1;
|
|
153
|
+
console.error(`✗ ${name}`);
|
|
154
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (failed > 0) {
|
|
158
|
+
console.error(`\n${failed}/${checks.length} failed`);
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(`\n${checks.length}/${checks.length} passed`);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=update-check.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.test.js","sourceRoot":"","sources":["../src/update-check.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xihe-lab/tapd-mcp-server",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.4",
|
|
4
4
|
"description": "MCP server for TAPD project management API, enabling AI assistants to manage stories, bugs, tasks, iterations and more via natural language",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/bin/tapd-mcp-server.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"tapd-mcp-server": "./dist/bin/tapd-mcp-server.js"
|
|
9
9
|
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/bin/tapd-mcp-server.js",
|
|
13
|
+
"dev": "tsx src/bin/tapd-mcp-server.ts",
|
|
14
|
+
"test": "tsx src/update-check.test.ts",
|
|
15
|
+
"test:integration": "tsx src/integration-test.ts",
|
|
16
|
+
"type-check": "tsc --noEmit"
|
|
17
|
+
},
|
|
10
18
|
"keywords": [
|
|
11
19
|
"mcp",
|
|
12
20
|
"mcp-server",
|
|
@@ -20,13 +28,12 @@
|
|
|
20
28
|
"license": "Apache-2.0",
|
|
21
29
|
"repository": {
|
|
22
30
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/xihe-lab/tapd-mcp-server.git"
|
|
24
|
-
"directory": "packages/mcp"
|
|
31
|
+
"url": "git+https://github.com/xihe-lab/tapd-mcp-server.git"
|
|
25
32
|
},
|
|
26
33
|
"bugs": {
|
|
27
34
|
"url": "https://github.com/xihe-lab/tapd-mcp-server/issues"
|
|
28
35
|
},
|
|
29
|
-
"homepage": "https://
|
|
36
|
+
"homepage": "https://xihe-lab.com",
|
|
30
37
|
"engines": {
|
|
31
38
|
"node": ">=20.0.0"
|
|
32
39
|
},
|
|
@@ -41,14 +48,8 @@
|
|
|
41
48
|
],
|
|
42
49
|
"dependencies": {
|
|
43
50
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
51
|
+
"@xihe-lab/tapd-core": "2.0.0-rc.4",
|
|
52
|
+
"zod": "^3.25.76"
|
|
46
53
|
},
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
"start": "node dist/bin/tapd-mcp-server.js",
|
|
50
|
-
"dev": "tsx src/bin/tapd-mcp-server.ts",
|
|
51
|
-
"test": "tsx src/integration-test.ts",
|
|
52
|
-
"type-check": "tsc --noEmit"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
54
|
+
"packageManager": "pnpm@12.3.4"
|
|
55
|
+
}
|