关于 zephyr-scale-mcp
zephyr-scale-mcp 为使用自托管 Jira Server 或 Data Center 的团队提供 Zephyr Scale 测试管理 MCP 服务。它通过 REST API 管理测试用例、周期、执行和计划,并针对旧版本接口限制提供专用操作与回退处理。
主要功能
- 01管理测试用例、文件夹和测试计划
- 02创建测试周期并记录执行结果
- 03关联 Jira 问题并查询覆盖情况
- 04处理附件和自动化报告导入
- 05提供只读模式及可选内部 API 工具
适用场景
- 01为 Jira 项目创建和维护测试用例
- 02记录冲刺测试周期的执行结果
- 03查询 Jira 问题的测试覆盖与最近执行
- 04导入 Cucumber JSON 测试报告
MCP 相关
该服务通过 Zephyr Scale REST API v1 向 MCP 客户端提供 54 个测试管理工具;其中 12 个内部 API 工具需显式启用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y zephyr-scale-mcpJIRA_BASE_URLJira base URL without a trailing slash, e.g. https://jira.example.comJIRA_PAT密钥Jira Data Center Personal Access Token (used when JIRA_AUTH=pat, the default)JIRA_AUTH密钥Authentication mode: pat (default) or basicJIRA_USERNAMEUsername for JIRA_AUTH=basicJIRA_PASSWORD密钥Password for JIRA_AUTH=basicZEPHYR_DEFAULT_PROJECT_KEY密钥Project key used when a tool is called without projectKeyZEPHYR_ALLOW_INTERNAL_APItrue registers 11 UNOFFICIAL tools backed by the internal /rest/tests/1.0 API the vendor does not support: editing a test cycle in place (rename/move, add/remove/reorder its cases), editing or DELETING individual executions, linking a cycle to a test plan, the folder tree, folder deletion, exact status names and custom field definitionsZEPHYR_READONLYtrue disables all write toolsJIRA_TLS_REJECT_UNAUTHORIZED密钥false allows self-signed certificates (disables TLS verification)JIRA_TIMEOUT_MSTimeout of a single HTTP request in milliseconds (default 30000)JIRA_MAX_RETRIESRetries for GET requests and for 429/503 responses, honoring Retry-After (default 2)ZEPHYR_LOG_LEVELLog verbosity: debug | info | warn | error (default info; all logs go to stderr)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
zephyr-scale-mcp
适用于自托管 Jira Server / Data Center 的 Zephyr Scale MCP 服务(原名 TM4J)。它通过 {JIRA_BASE_URL}/rest/atm/1.0 上的 Zephyr Scale REST API v1,为 AI Agent 提供 54 个测试管理工具,可供 Claude Code、Claude Desktop、Cursor 以及任何 MCP 客户端使用,涵盖测试用例、文件夹、测试周期、执行、测试计划、附件和自动化导入。
npm:zephyr-scale-mcp · MCP Registry:io.github.vilaabo/zephyr-scale-mcp · 俄语版本 →
⚠️ 适用范围:仅限 Server / Data Center。 Zephyr Scale Cloud(API v2)和 Zephyr Squad 使用不同的 API,不在适用范围内——此服务无法用于它们。
为什么要开发这个项目
大多数 Zephyr MCP 服务面向 Cloud API。如果你的 Jira 部署在本地,你使用的就是 v1 API,而 v1 有不少棘手之处:测试运行创建后不可修改、无法列出文件夹、状态是区分大小写的内部名称、BDD 脚本不接受 Feature: 标头,而且较旧的插件版本缺少整类端点。此服务将这些知识内置其中,不必让 Agent 一次次碰到 400 错误才发现问题。
- 54 个工具(42 个公开工具 + 12 个可选的内部 API 工具),每个工具的说明都会列出端点、调用者无法自行猜出的限制,以及确切的响应结构。
- 弥补 API 盲区的组合工具——
add_test_steps按 ID 合并步骤(读取 → 合并 → 写入),避免内容被静默删除;recreate_test_run_with_items可绕过测试运行的不可变限制,并可保留上次的结果;get_issue_test_coverage、get_test_run_summary、clone_test_case、move_test_cases_to_folder。 - 兼容较旧版本——分页结果端点不可用时自动回退,批量创建端点故障时则逐项回退。这两种情况都来自真实的旧版实例,而非变更日志。
- 可靠的底层机制——严格的 zod 输入验证、支持
Retry-After的指数退避重试、附带可行提示的错误消息、只读模式,以及确保密钥不会出现在日志和工具输出中。 - 1181 个单元测试和契约测试(使用 vitest + msw,不访问网络),另有一个需手动启用、针对真实实例的端到端场景。
快速开始
要求:Node.js >= 20、安装了 Zephyr Scale 插件的 Jira Server/DC,以及 Personal Access Token(Jira 8.14+)或用户名/密码组合。
无需克隆——该软件包已发布到 npm。Claude Code:
claude mcp add zephyr-scale \
--env JIRA_BASE_URL=https://jira.example.com \
--env JIRA_PAT=<personal access token> \
--env ZEPHYR_DEFAULT_PROJECT_KEY=PROJ \
--env ZEPHYR_ALLOW_INTERNAL_API=true \
-- npx -y zephyr-scale-mcp
Claude Desktop / 任意 MCP 客户端(claude_desktop_config.json、.mcp.json):
{
"mcpServers": {
"zephyr-scale": {
"command": "npx",
"args": ["-y", "zephyr-scale-mcp"],
"env": {
"JIRA_BASE_URL": "https://jira.example.com",
"JIRA_PAT": "<personal access token>",
"ZEPHYR_DEFAULT_PROJECT_KEY": "PROJ",
"ZEPHYR_ALLOW_INTERNAL_API": "true"
}
}
}
}
改为从源代码运行
git clone https://github.com/vilaabo/zephyr-scale-mcp.git
cd zephyr-scale-mcp
npm install
npm run build # -> dist/index.js
然后将客户端指向构建产物:"command": "node", "args": ["/path/to/zephyr-scale-mcp/dist/index.js"]。
ZEPHYR_ALLOW_INTERNAL_API=true是可选项,建议启用。 它会注册 12 个额外工具,可执行公共 API 完全无法完成的操作:直接编辑测试运行——重命名或移动测试运行(update_test_run),以及在不更改其键的情况下添加或移除用例(add_test_cases_to_run、remove_test_cases_from_run);此外,还能列出文件夹树(get_folder_tree)、删除文件夹(delete_folder)、编辑较早的执行记录(update_test_result_by_id),以及读取 API 默认要求的确切状态名称(get_status_options)。这些工具调用 Jira 界面本身使用的相同未公开/rest/tests/1.0端点;供应商不提供支持,而且这些端点在其他 Zephyr Scale 版本中可能不同或不存在。如果无法接受这种权衡,请关闭此标志——其他 42 个工具不受影响。
然后让 Agent 运行 health_check。该工具通过 GET /rest/api/2/myself 验证连接和凭据;如果设置了 ZEPHYR_DEFAULT_PROJECT_KEY,还会验证 Zephyr 插件是否能在 /rest/atm/1.0 上响应。
可以让 Agent 执行的操作
- “创建文件夹
/Regression/Payments,并根据本文档中描述的结账流程添加分步测试用例。” - “找出
/Regression中所有 Draft 用例,检查它们,并将已准备好的用例设为 Approved。” - “为 sprint 42 创建一个周期,加入所有冒烟用例,然后根据此报告记录结果——如果脚本包含步骤,就逐步记录。”
- “哪些测试用例涵盖 PROJ-123?它们各自最近一次通过是什么时候?”——从问题追溯到相关用例及其最新执行记录。
- “将这个包含 Cucumber JSON 报告的 ZIP 导入,并在 PROJ 中发布为新周期。”——自动化导入;系统会根据用例的
@TestCaseKey=PROJ-T1标签,将场景与 BDD 用例匹配。 - “在 PROJ-T55 的步骤 3 后添加两个步骤。”——现有步骤及其 ID 会保留。
- “重建周期 PROJ-R7,增加三个用例,保留结果,然后删除原周期。”
配置
| 变量 | 必填 | 默认值 | 用途 |
|---|---|---|---|
JIRA_BASE_URL | 是 | — | Jira 基础 URL,末尾不带 /,例如 https://jira.example.com |
JIRA_AUTH | 否 | pat | pat | basic |
JIRA_PAT | 使用 pat 时 | — | Jira Server/DC 个人访问令牌 |
JIRA_USERNAME、JIRA_PASSWORD | 使用 basic 时 | — | 基本身份验证凭据 |
JIRA_TIMEOUT_MS | 否 | 30000 | 每个请求的超时时间 |
JIRA_MAX_RETRIES | 否 | 2 | 重试 GET 请求以及任何 429/503 响应;遵循 Retry-After,否则采用带抖动的指数退避 |
JIRA_TLS_REJECT_UNAUTHORIZED | 否 | true | false 表示接受自签名证书——这会在整个进程范围内禁用 TLS 验证,并向 stderr 输出警告 |
ZEPHYR_DEFAULT_PROJECT_KEY | 否 | — | 工具调用未提供 projectKey 时使用 |
ZEPHYR_READONLY | 否 | false | true 会使每个写入工具都拒绝操作并返回错误;读取工具仍可正常工作 |
ZEPHYR_ALLOW_INTERNAL_API | 否 | false | true 会注册由内部 /rest/tests/1.0 API 提供支持的 12 个非官方工具 |
ZEPHYR_LOG_LEVEL | 否 | info | debug | info | warn | error |
测试涵盖了两项保证:JIRA_PAT 和 JIRA_PASSWORD 永远不会出现在日志、工具输出或错误消息中——无论它们在输出时采用何种编码:原始形式、JSON 转义形式或 base64 基本身份验证令牌(错误文本仅包含方法和路径——绝不包含可能含有数据的查询字符串);并且 stdout 专用于 MCP 协议,所有日志行都会写入 stderr。一个有意保留的例外:少于 6 个字符的密钥会原样保留,因为对其进行脱敏会在无法保护任何内容的同时破坏无关输出;服务会在启动时对此发出警告。
配置会在启动时验证:所有问题都会一次性报告,进程会以非零代码退出,而不是在配置不完整的情况下启动。
工具
共有 54 个工具。42 个公开工具始终会注册;最后一组中的 12 个工具仅在 ZEPHYR_ALLOW_INTERNAL_API=true 时注册。
测试用例 — 13 个工具
| 工具 | 功能 |
|---|---|
create_test_case | 创建用例,包含 STEP_BY_STEP / PLAIN_TEXT / BDD 脚本、参数、自定义字段和调用测试步骤 |
get_test_case | 读取用例,可通过 fields 缩小范围;步骤 ID 会在此处返回 |
search_test_cases | 使用 TQL 搜索并支持分页;超过 1500 个字符的查询会作为 POST /testcase/search 发送(该接口仅支持 projectKey、key、name) |
update_test_case | 局部更新;testScript.steps 会按 ID 同步(参见限制 7) |
add_test_steps | 在指定位置插入步骤且不丢失现有步骤——读取后按 ID 合并,再写回 |
set_test_script | 替换整个脚本或更改其格式;此操作具有破坏性 |
clone_test_case | 在项目内复制用例并生成新的步骤 ID;不会复制链接、附件和历史记录 |
move_test_cases_to_folder | 按明确指定的键或源文件夹批量移动;某个用例失败不会中止其余操作 |
delete_test_case | 永久删除用例、其脚本和历史记录 |
create_test_cases_bulk | 一次调用创建多个用例;批量接口异常时会逐个回退处理 |
link_issues_to_test_cases | 将用例批量关联到 Jira 问题(仅添加关联) |
get_test_cases_linked_to_issue | 反向查找:问题 → 用例 |
get_issue_test_coverage | 可追溯性报告:问题 → 关联用例 → 每个用例的最新执行记录 |
测试周期(测试运行) — 7 个工具
| 工具 | 功能 | |---|---| | `create_test_run` | 创建一个测试周期及其完整条目列表——也可在同一次调用中为每个条目设置执行结果 | | `get_test_run` | 读取测试周期及其条目 | | `search_test_runs` | 使用 TQL 搜索——对于测试周期,只有 `projectKey` 和 `folder` 可搜索 | | `delete_test_run` | 永久删除测试周期及其所有结果 | | `get_test_run_results` | 分页获取测试周期的执行记录,并在必要时回退到旧版扁平端点 | | `get_test_run_summary` | 获取每个条目的最近一次执行:`byStatus` 计数原样返回;存在字面值为 `Pass` 的状态时,返回 `executionProgressPct` 和 `passRatePct` | | `recreate_test_run_with_items` | 解决测试周期不可变问题的公开方案:使用**新**键重建测试周期并增删用例;也可选择沿用最近的结果并删除原测试周期 |执行(测试结果) — 4 个工具
| 工具 | 功能 |
|---|---|
create_test_result | 为测试周期条目追加一次新的执行,包括每个步骤的 scriptResults |
update_last_test_result | 部分更新某个条目的最近一次执行 |
create_test_results_bulk | 在一次调用中为一个测试周期批量添加多条执行记录 |
get_latest_result_for_test_case | 获取某个用例存储的执行日期最晚的执行记录,涵盖所有测试周期——不一定是最后记录的那条 |
对于在同一测试周期中出现多次的条目(例如按环境或受派人区分),使用 matchEnvironment / matchUserKey 消除歧义,并将其作为查询参数发送。
测试计划 — 5 个工具
| 工具 | 功能 |
|---|---|
create_test_plan | 创建测试计划;返回 { key },例如 PROJ-P123 |
get_test_plan | 读取测试计划及其关联的测试周期和问题 |
update_test_plan | 部分更新 |
delete_test_plan | 永久删除 |
search_test_plans | 使用 TQL 搜索;可搜索字段取决于 Zephyr Scale 版本 |
文件夹 — 2 个工具
| 工具 | 功能 |
|---|---|
create_folder | 根据完整路径创建用例、计划或测试周期文件夹;启用 recursive(默认值为 true)时,如果完整路径请求返回 400,则会逐一创建每个父级路径并重试一次——403、409 和 5xx 响应则原样返回 |
rename_folder | 根据数字 ID 重命名一个文件夹层级(也可设置其自定义字段) |
附件 — 4 个工具
| 工具 | 功能 |
|---|---|
upload_attachment | 将本地文件附加到用例、用例步骤、测试周期、结果或结果步骤(multipart) |
list_attachments | 列出上述任一目标的附件;每条记录都包含其他工具所需的 ID 和 URL |
download_attachment | 根据 ID 或 list_attachments 返回的 URL 保存附件——该 URL 必须属于已配置的 Jira 主机。这是唯一会从内部 API 读取数据的公开工具:附件内容由 /rest/tests/1.0/attachment/{id} 提供,无论是否启用 ZEPHYR_ALLOW_INTERNAL_API,该接口都会存在 |
delete_attachment | 根据数字 ID 永久删除一个附件 |
自动化 — 3 个工具
| 工具 | 功能 |
|---|---|
upload_automation_results | 以 Zephyr 自定义 JSON 格式发布结果 ZIP 文件;始终创建新的测试周期 |
upload_cucumber_results | 发布 Cucumber JSON 报告 ZIP 文件;根据 @TestCaseKey=PROJ-T1 标签匹配场景 |
download_feature_files | 将 BDD 用例导出为 .feature 文件 ZIP;必须提供 tql,且使用带 testCase. 前缀的方言。只有在验证 PK 签名后才会写入归档文件,因此,如果 HTTP 200 响应提供的是 HTML 登录页,操作会失败而不会留下损坏的文件 |
服务与诊断 — 4 个工具
| 工具 | 功能 | |---|---| | `health_check` | 检查 Jira 是否可访问、凭据是否有效,以及 Zephyr 插件是否响应 | | `list_environments` | 项目中的环境 — 结果引用的区分大小写的准确名称 | | `create_environment` | 在项目中创建环境 | | `find_jira_user` | 查找 Jira **用户键**(`JIRAUSER10000`),这是 `owner` / `executedBy` / `assignedTo` 所需的值 |非官方 — 内部 API,选择启用 — 12 个工具
仅在设置 ZEPHYR_ALLOW_INTERNAL_API=true 时注册。这些工具调用 /rest/tests/1.0,即 Jira 界面背后的未公开 API。供应商不支持此 API:其他 Zephyr Scale 版本中的端点可能有所不同,也可能不存在;这些工具返回 404 / 405 就表示如此。以下每种请求格式都经过从 Jira 界面自身的流量中捕获,或在真实实例上实时验证,绝非臆测。此层的错误会附带相应提示。
| 工具 | 功能 |
|---|---|
update_test_run | 重命名周期、将其移动到另一个文件夹(按数字文件夹 ID),或原地更改其计划日期,同时保留其键、项目和结果。公开 API 中不存在 PUT /testrun |
add_test_cases_to_run | 将用例原地追加到现有周期;键和现有结果都会保留 |
remove_test_cases_from_run | 从现有周期中原地移除项目 — 其全部执行历史也会随之删除 |
reorder_test_run_items | 重新排列现有周期中的项目;如果周期已按请求的顺序排列,则不会进行任何写入 |
link_issues_to_test_run | 将 Jira 问题关联到现有周期 — 公开 API 会直接拒绝运行记录中的 issueLinks 字段,因此这是唯一可行的方式 |
link_test_run_to_plan | 创建后将现有周期关联到测试计划(公开 API 仅在创建时接受 testPlanKey) |
delete_test_results | 按数字 ID 删除单次执行。无法删除项目的最后一次执行 |
update_test_result_by_id | 编辑项目历史中的任意执行,包括较早的执行;status 会根据其区分大小写的名称解析为内部 ID |
get_folder_tree | 返回项目的完整文件夹树,其中包含 rename_folder、delete_folder 和 update_test_run 所需的数字 ID。每种实体类型都有各自的树 |
get_status_options | 返回项目的执行状态、用例状态或优先级的准确内部名称 — 公开 API 遇到错误值时会直接忽略 |
get_custom_field_definitions | 按实体类型列出自定义字段定义:名称、类型、必填标记和选项 |
delete_folder | 按数字 ID 删除文件夹。非空文件夹的处理方式因版本而异 — 请先清空文件夹 |
以下是服务器所遵循的约束。每个工具的说明都会重复与其相关的约束,因此 Agent 在调用工具时可以看到。
- 测试运行不可变。 没有
PUT /testrun:测试运行无法重命名或移动,也无法添加或移除用例。测试运行中的项目在创建时便已固定,运行状态根据项目状态推导。可用的变通方式:recreate_test_run_with_items(公开接口,会生成一个新键),或内部接口update_test_run/add_test_cases_to_run/remove_test_cases_from_run(沿用同一个键)。 - 不会隐式创建文件夹。 在未知文件夹中调用
create_test_case、create_test_run和create_test_plan会失败并返回 400。也无法通过公开 API 列出文件夹;重命名文件夹需要使用create_folder返回的数字 ID,或在启用内部 API 后使用get_folder_tree。 owner/executedBy/assignedTo接受 Jira 用户键(JIRAUSER10000),不接受用户名或电子邮件。使用find_jira_user进行解析。- TQL 语法严格:运算符两侧必须有空格,字符串值必须用双引号括起,连接符只能使用
AND(不能使用OR),文件夹路径必须以/开头。测试运行只能按projectKey和folder搜索。对于单选和多选自定义字段,=不起作用——请使用IN。 - 状态、优先级和环境均使用区分大小写的内部名称。 内置状态在 UI 中会以本地化名称显示(你看到的
Draft标签可能是其翻译),自定义状态则显示其字面名称——get_status_options会显示 API 实际接受的名称。公开 API 会静默忽略错误的执行状态。 - BDD 脚本只包含场景正文——直接使用
Given/When/Then/And/But行。包含Feature:/Scenario:包装内容的文本会被拒绝,并返回400 Invalid BDD Script;导出时会自动生成包装内容。 STEP_BY_STEP步骤在PUT时按 ID 同步:没有 ID 的步骤会被创建,带 ID 的步骤会被更新,列表中缺失的所有已存储步骤都会被删除。务必发送完整的最终列表,并沿用从get_test_case获取的 ID——或者让add_test_steps执行读取、合并和写入。- 不接受已弃用的字段:使用
issueLinks代替issueKey,使用actualEndDate代替executionDate,使用executedBy代替userKey。
旧版插件构建的特殊情况
以下情况均在真实的旧版 Zephyr Scale Server 实例上现场观察到,并已纳入测试。
- 周期键可能使用
-C前缀(PROJ-C34),而不是-R。所有运行键参数都按原样接收键值,因此请传入实例显示的键。 GET /testrun/{key}/testresults/page可能不存在。get_test_run_results和get_test_run_summary会回退到已弃用的扁平端点,并在客户端进行分页,同时在响应中添加note。确实不存在的运行仍会返回 404。- 同时发送
scriptResults时,整体status会被忽略。 请先发送步骤结果,再使用update_last_test_result设置整体状态。 POST /testcase/link-issues可能返回 500。 请改用带有issueLinks的update_test_case来关联问题。- 对于任何负载,
POST /testcase/bulk都可能返回 HTTP 500 和空响应正文,即使单条创建可以正常工作。create_test_cases_bulk会回退为逐条创建用例——遇到任何5xx,以及 JSON 格式的404(这表示“此构建中没有此端点”,不同于 Jira 在插件不存在时返回的 HTML 格式404)时都会回退——并报告哪些创建成功了(#1)。其他所有4xx都属于负载错误,不会重试。 - 在此构建中,为不属于运行项目的用例提交结果会将其静默添加到运行中;其他构建则会以 400/404 拒绝此调用。结果工具对此两种情况都有说明。
- 自定义自动化结果格式会经过严格验证。
{"version": 1, "executions": [{"source", "result", "testCase": {"key"}}]}可正常使用;每次执行中额外的字段(例如executionTime)会被拒绝,并报错Invalid Custom Format JSON file。只要场景带有@TestCaseKey=PROJ-T1,Cucumber JSON 报告就能直接使用。 download_feature_files需要tql查询参数——没有该参数时,API 会拒绝此调用。- 无法删除运行项目的最后一次执行记录。
delete_test_results会拒绝此操作;请改为移除项目。 - 自定义字段可能完全不存在——此时定义端点会返回
[]。
开发
npm run typecheck # tsc --noEmit, strict
npm test # 1181 unit + contract tests (vitest + msw), no network
npm run build # tsup -> dist/index.js
npm run smoke # 13 end-to-end tests, ZEPHYR_E2E=1, real instance required
只有在 ZEPHYR_E2E=1 时才会运行冒烟测试场景。该场景需要真实的 JIRA_BASE_URL、凭据,以及一个专用的 ZEPHYR_DEFAULT_PROJECT_KEY——它会创建和删除真实实体,并留下 /mcp-smoke-* 文件夹,因为公共 API 无法删除文件夹。
src/
├── index.ts # bootstrap: config, tool registration, stdio transport
├── config.ts # environment validation
├── http.ts # fetch wrapper: auth, timeouts, retries, error normalization,
│ # multipart and binary bodies
├── schemas.ts # shared parameter schemas, field shapes, recurring description constants
├── toolkit.ts # defineTool(): strict zod input, read-only guard,
│ # JSON / isError response shaping, shared helpers
├── internal.ts # the UNOFFICIAL /rest/tests/1.0 layer: key -> id resolution,
│ # run-item plumbing, status resolution, error hints
├── runResults.ts # paged run results with the legacy fallback
├── log.ts # leveled logger, stderr only
└── tools/ # one module per tool family: testCases, testRuns, testResults,
# testPlans, folders, attachments, automation, misc,
# runMaintenance, resultsMaintenance, internalRefs
test/ # one test module per source module + negative contract tests
# and the gated smoke scenario
版本管理与变更日志
版本为 1.0.0。从此版本起,工具名称、参数名称和响应结构均为公开契约,只会在主版本中更改。请参阅 CHANGELOG.md。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。