新增禅道项目管理系统插件,含项目集/产品/项目/执行、需求 (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
7.6 KiB
name, description
| name | description |
|---|---|
| zentao-shared | 禅道 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:每页数量,不超过 1000pageID:页码,从第 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 过期。
全局确认约定
- 状态流转类操作必须先确认:关闭(close)、解决(resolve)、激活(activate)、 变更(change)这类端点,执行前把要提交的内容/目标状态展示给用户,等到明确确认 ("确认"、"关闭它"、"好的")再调。不要因为用户说了"这个 bug 修完了"就顺手把 resolve 也做了——修复和标记解决是两个决定。
- 删除是不可逆操作,必须先确认:所有
delete_*工具删的都是真实数据,没有回收站, 执行前明确告知会删除什么。 - 先解析 ID 再操作:需要
productID/executionID/taskID这类 ID 的操作,先用 对应的get_*列表工具查出来给用户看,不要凭名字或印象猜 ID。 - 附件目前只支持改名:
put_files_fileID只能改附件文件名(fileName字段), 上传和删除附件不在这套 MCP 工具里,需要引导用户去网页端操作。