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

7.6 KiB
Raw Blame History

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_productIDinputSchema.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_productsget_products_productID_stories 这类"先列表后详情/子资源"的两步调用是常态)。

没有 GET /projects/:projectID 单条项目详情接口——只有 get_projects 列表,要看 某个项目的信息,从列表里按 ID 过滤,不要尝试拼一个不存在的详情工具名。


状态字段

禅道各实体的状态是模块内固定的字符串常量,不是可配置的两层模型——具体取值以对应 工具的字段说明为准(比如 story 是 draft/active/closed/changebug 是否 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 工具里,需要引导用户去网页端操作。