新增禅道项目管理系统插件,含项目集/产品/项目/执行、需求 (story/epic/requirement)、Bug、任务、测试、计划与发布、反馈工单 八个工作流技能,自动配置 MCP 连接(禅道「个人中心 → 获取凭证」 自助生成 14 天 Token)。 MCP Server 是团队自建的 zentao-mcp 网桥(部署在 pm.ops.yixiong-tech.com/mcp),基于开源 openapi-mcp-server 二次开发。 Claude 侧走 userConfig 钥匙链 + 自定义 token 头;Codex 侧受限于官方 插件格式只支持 bearer_token_env_var,走 Authorization: Bearer——网桥 那边已经加了 preferred_header/bearer_mode 配置项统一归一化处理,两条 路径都验证过连通。 三轮审查(静态字段对照 openapi.json、跨文件一致性、真实端点实测) 修正过程中发现的问题,技能文档里引用的工具名全部跟服务器真实注册 的 118 个工具核对过。 同步更新:.claude-plugin/marketplace.json、.agents/plugins/marketplace.json、 README.md、CLAUDE.md 的插件索引与说明;README 补充「获取凭证」操作 截图(已脱敏)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016pFx6jnym6kRWRQ5JyDUNv
154 lines
7.6 KiB
Markdown
154 lines
7.6 KiB
Markdown
---
|
||
name: zentao-shared
|
||
description: "禅道 MCP 共享基础:payload 包装约定、路径/查询参数规则、ID 层级关系、状态字段规则、确认约定。所有 zentao-* 技能必须先读本文件。"
|
||
---
|
||
|
||
# 禅道 MCP 共享规则
|
||
|
||
所有 `zentao-*` 技能的**必读前置**。
|
||
|
||
---
|
||
|
||
## 一条最重要的约定:参数以工具自身的 inputSchema 为准
|
||
|
||
**本文件与各技能文档都不重画完整字段表。** 每个工具的字段名、必填项、取值范围以它在 MCP
|
||
里注册的 `inputSchema`/`description` 为唯一真相;技能只描述**调用顺序、ID 如何传递、
|
||
payload 怎么包、哪里必须停下来等用户确认**。
|
||
|
||
> 上一代其他插件(寰汐)踩过这个坑:技能文档手画参数表,字段名/枚举值/必填项跟后端
|
||
> docstring 逐渐漂移,用户侧表现为频繁的「参数缺失」报错。工具签名变了而文档没跟上,
|
||
> 是必然发生而非可能发生的事——禅道这边直接不画表,从源头避免。
|
||
|
||
---
|
||
|
||
## 工具命名
|
||
|
||
Claude Code 里工具名带前缀:`mcp__zentao__post_bugs`;其他平台通常是裸名 `post_bugs`。
|
||
本文档统一写**裸名**,实际调用时按你所在平台的约定加前缀。
|
||
|
||
命名规律是 `{method}_{路径按 / 拆分拼接}`,路径参数去掉冒号:
|
||
|
||
```
|
||
GET /bugs/:bugID → get_bugs_bugID
|
||
POST /bugs → post_bugs
|
||
PUT /tasks/:taskID/start → put_tasks_taskID_start
|
||
DELETE /stories/:storyID → delete_stories_storyID
|
||
GET /products/:productID/stories → get_products_productID_stories
|
||
```
|
||
|
||
---
|
||
|
||
## 路径参数完全不出现在 inputSchema 里(最隐蔽的坑)
|
||
|
||
**`inputSchema` 里只有 `payload`(有请求体的话)和 query 参数,路径参数(`bugID`/
|
||
`productID`/`taskID`……)不会被声明为任何属性**——用真实工具现场验证过:
|
||
`get_bugs_bugID`/`delete_bugs_bugID`/`get_products_productID` 的 `inputSchema.properties`
|
||
都是空的。想传路径参数,**必须自己从工具名最后一段解析出参数名**(`get_bugs_bugID` →
|
||
要传 `bugID`),schema 本身看不出这个要求。
|
||
|
||
**更麻烦的是不传或传错不会报错**:现场测试 `get_bugs_bugID({})`(故意不传 `bugID`)
|
||
返回的是 `HTTP 200`、内容为空字符串,跟正常"这个 ID 查不到东西"长得一样,非常容易被
|
||
误判成"这条数据不存在"而不是"参数传漏了"。调用返回空结果时,**先检查是不是路径参数
|
||
传漏了或传错了名字**,再怀疑数据本身。
|
||
|
||
**命名还有例外,不能全靠"猜工具名去掉动词就是参数名"**:`get_epics_storyID` /
|
||
`get_requirements_storyID`(业务需求/用户需求详情)的路径参数**字面就叫 `storyID`**,
|
||
不是更直觉的 `epicID`/`requirementID`——这是禅道官方 API 本身的历史命名,照抄字面
|
||
参数名,不要自己"纠正"。
|
||
|
||
---
|
||
|
||
## 参数结构:payload 包装约定
|
||
|
||
请求体字段也**不会摊平在 inputSchema 顶层**,而是统一包在一个 `payload` 对象里;
|
||
路径参数(上一节说的,虽然不在 schema 里但仍要传)和 query 参数才是顶层字段。三种形态:
|
||
|
||
```
|
||
POST(新建,无路径参数):
|
||
post_bugs({ payload: { productID: 2, title: "...", openedBuild: ["trunk"] } })
|
||
|
||
PUT(改,带路径参数):
|
||
put_bugs_bugID({ bugID: 123, payload: { title: "..." } })
|
||
put_tasks_taskID_start({ taskID: 456, payload: { realStarted: "2026-08-25" } })
|
||
|
||
GET(查,query 参数摊平在顶层,没有 payload——这类工具可选参数多,其余技能文档统一用
|
||
"函数签名速查"写法举例,不是真的按位置传参,仍然是每个字段按名字传):
|
||
get_products_productID_stories(productID: 2, browseType: "allstory", recPerPage: "50", pageID: "1")
|
||
|
||
DELETE(删,通常只有路径参数):
|
||
delete_bugs_bugID({ bugID: 123 })
|
||
```
|
||
|
||
**把 body 字段错误地摊平到顶层(不包 payload)是最常见的调用失败原因**,报错通常表现为
|
||
"参数缺失"——先检查是不是漏包了 `payload`。
|
||
|
||
---
|
||
|
||
## 分页
|
||
|
||
**不是所有 GET 都分页**,列表类接口(约一半)才有,详情类没有。有的话固定是这两个参数:
|
||
|
||
- `recPerPage`:每页数量,不超过 1000
|
||
- `pageID`:页码,从第 1 页开始
|
||
|
||
**没有 `limit` 这个参数名**——传了不存在的参数名会被静默丢弃(不报错、不生效),日志里
|
||
`upstream_query_params` 会是空的,看起来"调用成功但没起作用",容易误判。默认页大小以
|
||
具体工具的 inputSchema 说明为准,不要凭经验假设。
|
||
|
||
---
|
||
|
||
## ID 层级关系
|
||
|
||
```
|
||
program 项目集(可选,product 不强制挂靠)
|
||
└─ product 产品(创建只需 name 必填,program/其他都可选)
|
||
├─ project 项目(创建必填 name/model/begin/end/workflowGroup;model 取值受限:
|
||
│ scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)
|
||
│ └─ execution 执行/迭代(创建必填 project,即 execution 必须先有 project 才能建,
|
||
│ 不能直接挂在 product 下)
|
||
├─ story 用户故事 / epic 业务需求 / requirement 用户需求(三条需求线,见 zentao-story)
|
||
├─ bug
|
||
├─ testcase 测试用例 / testtask 测试单
|
||
├─ productplan 产品计划 / build 版本 / release 发布
|
||
├─ feedback 反馈 / ticket 工单 / system 应用
|
||
└─ task 任务(挂在 execution 下)
|
||
```
|
||
|
||
创建下级实体前,先查上级列表拿到 ID 展示给用户确认,不要凭名字猜 ID(`get_products`
|
||
→ `get_products_productID_stories` 这类"先列表后详情/子资源"的两步调用是常态)。
|
||
|
||
**没有 `GET /projects/:projectID` 单条项目详情接口**——只有 `get_projects` 列表,要看
|
||
某个项目的信息,从列表里按 ID 过滤,不要尝试拼一个不存在的详情工具名。
|
||
|
||
---
|
||
|
||
## 状态字段
|
||
|
||
**禅道各实体的状态是模块内固定的字符串常量**,不是可配置的两层模型——具体取值以对应
|
||
工具的字段说明为准(比如 story 是 `draft/active/closed/change`,bug 是否 resolved/closed
|
||
各有专门的 `put_*_*ID_resolve` / `put_*_*ID_close` 端点)。**不要凭直觉写状态字符串**,
|
||
这些字段大多有 DB 级约束,写错直接报错,具体状态机在各自的 zentao-story/zentao-bug/
|
||
zentao-task 里有说明。
|
||
|
||
---
|
||
|
||
## 鉴权
|
||
|
||
MCP 连接用的 Token 在禅道网页「头像下拉菜单 → 获取凭证」自助生成,**14 天有效期**,到期
|
||
需要重新生成并更新插件配置里的 Token。如果调用突然全部 401,先怀疑 Token 过期。
|
||
|
||
---
|
||
|
||
## 全局确认约定
|
||
|
||
1. **状态流转类操作必须先确认**:关闭(close)、解决(resolve)、激活(activate)、
|
||
变更(change)这类端点,执行前把要提交的内容/目标状态展示给用户,等到明确确认
|
||
("确认"、"关闭它"、"好的")再调。不要因为用户说了"这个 bug 修完了"就顺手把
|
||
resolve 也做了——修复和标记解决是两个决定。
|
||
2. **删除是不可逆操作,必须先确认**:所有 `delete_*` 工具删的都是真实数据,没有回收站,
|
||
执行前明确告知会删除什么。
|
||
3. **先解析 ID 再操作**:需要 `productID`/`executionID`/`taskID` 这类 ID 的操作,先用
|
||
对应的 `get_*` 列表工具查出来给用户看,不要凭名字或印象猜 ID。
|
||
4. **附件目前只支持改名**:`put_files_fileID` 只能改附件文件名(`fileName` 字段),
|
||
上传和删除附件不在这套 MCP 工具里,需要引导用户去网页端操作。
|