Files
yixiong-claude-marketplace/plugins/zentao/skills/zentao-shared/SKILL.md
T
SkyJourneyandClaude Sonnet 5 9d9e31c98e [feat] Add zentao plugin (Claude Code + Codex dual scaffold)
新增禅道项目管理系统插件,含项目集/产品/项目/执行、需求
(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
2026-08-25 13:50:41 +08:00

154 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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/workflowGroupmodel 取值受限:
│ 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 工具里,需要引导用户去网页端操作。