zephyr-squad-server-mcp
This server enables AI agents to manage Zephyr for Jira (Server/Data Center) test management operations via the ZAPI REST API.
Test Cycle Management: List, get, create, update, and delete test cycles; export cycle data as CSV; copy executions into a cycle (preserving status and defect links); move executions into folders.
Folder Organization: List, create, update, and delete folders within test cycles.
Execution Control: List, create, update status (PASS, FAIL, WIP, BLOCKED, UNEXECUTED), assign, and delete executions; bulk-add tests from an explicit list, ZQL filter, or another cycle (async); search executions using ZQL queries; get status count rollups by cycle, version, or assignee.
Defect Integration: Link Jira defects to executions; list defects per execution; get defect statistics with per-defect rollups of execution status, requirements, and tests.
Test Step Management: List, create, update, and delete test steps on a Zephyr test issue; list and update step results (status/comment per step) within an execution.
Coverage & Reporting: Find which tests cover given requirements (flags orphans); view a test's full execution history across all cycles; list executions linked to a specific defect.
Discovery & Helpers: List projects and versions; discover the Zephyr "Test" issue type ID for a project; poll async job progress for long-running ZAPI operations.
Provides tools for managing Zephyr Squad test cycles, folders, executions, test steps, step results, and ZQL search within Jira, enabling AI agents to drive Zephyr for Jira Server/Data Center test management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zephyr-squad-server-mcp list test cycles for project PROJ in version 1.0"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
zephyr-squad-server-mcp
An MCP server that lets an AI agent drive Zephyr for Jira — Server / Data Center (ZAPI), the test-management suite for Jira. It exposes the most common test-management operations (cycles, folders, executions, test steps, step results, ZQL search) as well-described tools over stdio, so it plugs into Claude Desktop, Claude Code, and any other MCP client.
This targets the Server/DC flavor (
/rest/zapi/latest). It is not for Zephyr Squad Cloud, which uses a different JWT-signed API.
Install
The server is published on PyPI and is easiest to run with
uv:
uvx zephyr-squad-server-mcp # run directly, no install
# or
uv tool install zephyr-squad-server-mcp
# or, in a venv
pip install zephyr-squad-server-mcpRelated MCP server: Zephyr Scale MCP Server
Configuration
The connection rides on your Jira instance's authentication (shared by ZAPI and
the Jira core REST API). Configure via environment variables or a .env file
(see .env.example):
Variable | Required | Default | Description |
| ✅ | — | Jira base URL, e.g. |
| one of | — | Personal Access Token → |
| one of | — | Basic-auth fallback (password or API token). Used only if |
|
| ZAPI base path on the Jira host. | |
|
| Per-request timeout (seconds). | |
|
| Verify TLS certs. Set |
The server fails fast with a clear error if the base URL or authentication is missing.
Client configuration (stdio)
Add to your MCP client config (e.g. Claude Desktop claude_desktop_config.json
or Claude Code .mcp.json):
{
"mcpServers": {
"zephyr-squad": {
"command": "uvx",
"args": ["zephyr-squad-server-mcp"],
"env": {
"JIRA_URL": "https://jira.company.com",
"JIRA_PERSONAL_TOKEN": "your-personal-access-token"
}
}
}
}For local development against a checkout, point command at uv:
{
"mcpServers": {
"zephyr-squad": {
"command": "uv",
"args": ["run", "--directory", "/path/to/zephyr-squad-server-mcp", "zephyr-squad-server-mcp"],
"env": { "JIRA_URL": "https://jira.company.com", "JIRA_PERSONAL_TOKEN": "…" }
}
}
}Tools
All id-bearing tools accept either a numeric id or a human-friendly
key/name for project (key like SONY or its name), version (name like
Version 1.0, or -1/Unscheduled), and issue (key like SONY-1386).
Resolved ids are cached for the session, so the first call does the lookup and
later calls reuse it.
Full reference: see
docs/tools.mdfor every tool's arguments, types, defaults, the exact ZAPI endpoint it calls, and sync/async behavior. The table below is a quick index.
Tool | What it does |
| List test cycles for a project/version. |
| Get one cycle's details (id |
| Create a test cycle. |
| Update a cycle's fields (id is sent in the body). |
| Delete a cycle (async; auto-polls to completion by default). |
| Get a CSV download link for a cycle's executions. |
| Copy executions into a cycle (async; auto-polls to completion by default). |
| Move executions from a cycle into a folder (async; auto-polls to completion by default). |
| List folders within a cycle. |
| Create a folder under a cycle. |
| Update a folder's name/description. |
| Delete a folder from a cycle (async; auto-polls to completion by default). |
| List executions in a cycle (optionally a folder). |
| Set an execution's status (PASS/FAIL/WIP/BLOCKED/…). |
| List the test steps of a test issue. |
| Add a test step to a test issue. |
| List per-step results for an execution. |
| Run a ZQL query and return matching executions. |
| Status-count rollup for a project/version (by cycle). |
| Per-assignee status counts for cycle(s). |
| A single test's executions across all cycles. |
| Defects linked to an execution. |
| Tests covering requirement(s); flags orphans. |
| Executions for a test (coverage history). |
| Executions linked to a defect. |
| Per-defect execution/req/test rollups. |
| Edit a test step's action/data/result. |
| Delete a test step. |
| Schedule a test into a cycle. |
| Bulk-add an explicit list of tests to a cycle as new UNEXECUTED executions (async). |
| Bulk-add tests matched by a saved ZQL filter to a cycle as new UNEXECUTED executions (async). |
| Add tests from another cycle as new UNEXECUTED executions (async). |
| Set a step result's status/comment. |
| Link Jira defects to executions (async). |
| Assign an execution to a user. |
| Delete an execution by id. |
| Manually poll any async job by token. |
| List projects (name → id discovery). |
| List a project's versions (name → id discovery). |
| Discover the Zephyr Test issue-type id per project (use case 1.1). |
Dates use Jira's dd/MMM/yy format (e.g. 4/Dec/12). Execution-status codes:
-1=UNEXECUTED, 1=PASS, 2=FAIL, 3=WIP, 4=BLOCKED, 5=PENDING, 6=APPROVED, 7=CANCELLED.
Development
uv sync # create venv + install deps (incl. dev group)
uv run pytest # unit tests (httpx mocked with respx — no live Jira needed)
uv run ruff check # lint
uv run mcp dev src/zephyr_squad_server_mcp/server.py # MCP Inspector smoke testdocs/getzephyr.apib is the ZAPI API Blueprint used as the
reference for request/response shapes during development. It was retrieved from the
official public documentation at https://getzephyr.docs.apiary.io/ (© SmartBear
Software). An older version is also available in the
zfjdeveloper/zapi-docs repository.
The Inspector (mcp dev) launches the MCP Inspector via npx, so it needs
Node.js / npx on your PATH. The tool list loads without any Jira config, but
invoking a tool builds the client on first use — so set JIRA_URL and
auth (a .env is read automatically) before running tools.
Publishing to PyPI
uv build # produces wheel + sdist in dist/
uv publish --token "$UV_PUBLISH_TOKEN" # or set UV_PUBLISH_TOKEN in the envTest against TestPyPI first:
uv publish --publish-url https://test.pypi.org/legacy/ --token "$TESTPYPI_TOKEN"License
MIT — see LICENSE.
Available Tools
40 toolsadd_tests_to_cycle_from_cycleA
Add tests from another cycle as new UNEXECUTED executions in this cycle.
Tests are sourced from from_cycle_id / from_version_id and can be narrowed
by components, labels, priorities, statuses (comma-separated filter
strings) and has_defects (bool). project/version accept keys/names or ids
(prefer ids to skip a lookup; -1 = Unscheduled). Async: with wait=True
(default) polls to completion and returns the final job payload; with wait=False
returns {jobProgressToken}.
Important: new executions always start with status UNEXECUTED regardless of
the source cycle's results. If you need to carry over the original execution
statuses and defect links, use copy_executions_to_cycle instead.
Inputs: cycle_id (required), project (required), version (required), from_cycle_id (required), +10 more.
add_tests_to_cycle_from_filterB
Add tests matching a saved ZQL filter to a cycle as new UNEXECUTED executions.
search_id is the numeric id of a saved ZQL filter.
project/version accept keys/names or ids (prefer ids to skip a lookup;
-1 = Unscheduled). Async: with wait=True (default) polls to completion
and returns the final job payload; with wait=False returns {jobProgressToken}.
New executions always start with status UNEXECUTED.
Inputs: cycle_id (required), project (required), version (required), search_id (required), +4 more.
add_tests_to_cycle_from_listA
Add an explicit list of tests to a cycle as new UNEXECUTED executions.
issues is a list of Zephyr Test issue keys/ids (e.g. ["PROJ-1", "PROJ-2"]);
a comma-separated string is also accepted and split automatically.
project/version accept keys/names or ids (prefer ids to skip a lookup;
-1 = Unscheduled). Async: with wait=True (default) polls to completion
and returns the final job payload; with wait=False returns {jobProgressToken}.
New executions always start with status UNEXECUTED. To carry over existing
execution statuses and defect links from another cycle, use
copy_executions_to_cycle instead.
Inputs: cycle_id (required), project (required), version (required), issues (required), +4 more.
assign_executionA
Assign an execution to a user.
assignee is a Jira username/account id. (execution_id is the schedule id
from list_executions.) Returns the API's (empty) acknowledgement.
Inputs: execution_id (required), assignee (required).
copy_executions_to_cycleA
Copy executions into cycle cycle_id, preserving their original status and defect links.
Unlike add_tests_to_cycle_from_cycle, this tool carries over the execution
status (PASS, FAIL, etc.) and defect associations from the source executions.
Set clear_status_flag=True to reset statuses to UNEXECUTED, or
clear_defect_mapping_flag=True to drop defect links on copy. If you want
fresh UNEXECUTED executions without any prior results, prefer
add_tests_to_cycle_from_cycle instead.
project/version accept keys/names or ids (prefer ids to skip a lookup;
-1 = Unscheduled). Async: with wait=True (default) polls to completion
and returns the final job payload; with wait=False returns {jobProgressToken}.
Inputs: cycle_id (required), executions (required), project (required), version (required), +4 more.
create_cycleA
Create a new test cycle.
Dates use Jira's dd/MMM/yy format (e.g. 4/Dec/12). project/version
accept keys/names or ids (prefer ids when you have them, to skip a lookup).
The new cycle is created in version — pass it explicitly (use -1
only if you really want the Unscheduled version). Returns
{id, responseMessage}.
Inputs: name (required), project (required), version (required), build, +6 more.
create_executionA
Schedule a test (create an execution) in a cycle.
issue is the Zephyr test issue (key or id; prefer the id when you have it).
cycle_id is the target cycle (-1 = Ad hoc). project/version accept
keys/names or ids (prefer ids when you have them, to skip a lookup; -1 =
Unscheduled). Optionally set
folder_id and assignee. Returns a map keyed by the new execution id.
Inputs: issue (required), cycle_id (required), project (required), version (required), +3 more.
create_folderA
Create a folder under a cycle.
project/version accept keys/names or ids (prefer ids when you have
them, to skip a lookup; -1 = Unscheduled). Returns {id, responseMessage}.
Inputs: cycle_id (required), name (required), project (required), version (required), +1 more.
create_test_stepA
Add a test step to a Zephyr test issue.
issue accepts a Jira issue key or numeric issueId (prefer the id when you
have it, to skip a lookup). step is the action,
data the test data, result the expected result. Returns the created step.
Inputs: issue (required), step (required), data, result.
delete_cycleA
Delete a test cycle by id (asynchronous; returns/polls a job token).
Set is_folder_cycle_delete=True only when deleting a cycle that lives
inside a folder. This is an asynchronous ZAPI operation: it returns a
jobProgressToken. With wait=True (default) the tool polls the job to
completion and returns the final job-progress payload; with wait=False
it returns the raw {jobProgressToken} so you can poll later with
get_job_progress (type cycle_delete_job_progress).
Inputs: cycle_id (required), is_folder_cycle_delete, wait, timeout.
delete_executionA
Delete an execution by its numeric id.
Args: execution_id: numeric id of the execution to delete.
Returns: {"success": "Successfully deleted execution(s) "}
Inputs: execution_id (required).
delete_folderA
Delete a folder from a cycle (asynchronous; returns/polls a job token).
folder_id is the numeric ID from list_cycle_folders; cycle_id is
its parent cycle. project/version accept keys/names or ids (prefer ids
when you have them, to skip a lookup; -1 = Unscheduled). With
wait=True (default) the tool polls the job to completion and returns the
final job-progress payload; with wait=False it returns the raw
{jobProgressToken} to poll later with get_job_progress.
Inputs: folder_id (required), cycle_id (required), project (required), version (required), +2 more.
delete_test_stepB
Delete a test step. Returns the remaining steps for the issue.
Inputs: issue (required), step_id (required).
export_cycleA
Get a download link for a cycle's executions as a CSV export.
project/version accept keys/names or ids (prefer ids when you have them,
to skip a lookup; -1 = Unscheduled). Pass folder_id to export a
single folder within the cycle (omit for the whole cycle). Returns
{url: "…/Cycle-RC1.csv"} — a download link, not the file bytes; hand
the URL to the user or fetch it separately.
Inputs: cycle_id (required), project (required), version (required), folder_id.
get_cycleA
Get a single test cycle's details by its numeric id.
Passing -1 returns the hardcoded Ad hoc cycle.
Inputs: cycle_id (required).
get_defect_statisticsA
Get execution/requirement/test statistics for one or more defects.
defects is a Jira key/id or a comma-separated string / list of them.
Returns per-defect rollups (execution status totals, requirement & test
counts) — useful for defect-density and closure-rate narratives.
Inputs: defects (required).
get_executions_by_defectA
List executions linked to a given defect (incl. step-level defects).
defect is a Jira bug key or id. Returns {executions, totalCount}.
Inputs: defect (required), max_records, offset.
get_executions_by_testA
List executions for a given test issue (its execution history & defects).
test is a Jira test issue key or id. Use to flag tests that have never
been executed (audit coverage).
Inputs: test (required), max_records, offset.
get_execution_status_countsA
Status-count rollup for a project/version (PASS/FAIL/WIP/BLOCKED/UNEXECUTED).
With cycles set (comma-separated cycle ids, e.g. "51,52") returns the
status breakdown for those cycles. Without cycles, returns a per-cycle
breakdown for every cycle in the version. project/version accept
keys/names or ids (prefer ids when you have them, to skip a lookup; -1 =
Unscheduled). Useful for release Go/No-Go and compliance summaries.
Inputs: project (required), version (required), cycles, folders, +3 more.
get_execution_status_counts_by_assigneeB
Per-assignee status counts for the given cycle(s).
cycles is a comma-separated list of cycle ids. project/version accept
keys/names or ids (prefer ids when you have them, to skip a lookup; -1 =
Unscheduled). Returns a map of assignee -> {UNEXECUTED, PASS, FAIL, WIP,
BLOCKED}. Use to spot
workload imbalance or reviewers/testers who are a bottleneck.
Inputs: project (required), version (required), cycles, offset, +1 more.
get_job_progressA
Poll an asynchronous ZAPI job once by its progress token.
type identifies the job kind, e.g.
bulk_execution_copy_move_job_progress (copy/move executions) or
cycle_delete_job_progress. Returns the current progress payload
(progress reaches 1.0 when complete; message holds the result).
Inputs: token (required), type (required).
get_tests_by_requirementA
Find the Zephyr tests that cover one or more requirement issues.
requirements is a Jira issue key/id, or a comma-separated string / list
of them (e.g. "PROJ-1,PROJ-2" or ["PROJ-1", "PROJ-2"]). Returns, per
requirement, the linked tests and a defect count — use to flag orphaned
requirements (empty tests) and to map AC coverage.
Inputs: requirements (required).
get_zephyr_test_issue_typeA
Discover the Zephyr "Test" issue-type id per project (for use case 1.1).
Returns {options: [{label, type, value}, ...]} where label is the
project key/name and value is that project's Zephyr Test issue-type
id. Use this to find the issue-type id the Jira/Atlassian MCP needs when
creating Zephyr Test issues (Zephyr does not create Jira issues itself).
Inputs: no named parameters.
link_execution_defectsA
Link Jira defect(s) to execution(s) (asynchronous; returns/polls a token).
executions are execution ids; defects are Jira issue keys (e.g. ABC-41).
Each defect is attached to each execution. With wait=True (default) polls to
completion; with wait=False returns {jobProgressToken}.
Inputs: executions (required), defects (required), wait, timeout.
list_cycle_foldersA
List the folders within a cycle.
project/version accept keys/names or ids (prefer ids when you have
them, to skip a lookup; -1 = Unscheduled). Returns a list of folders,
each with ID, folderName, folderDescription, and execution summaries.
Inputs: cycle_id (required), project (required), version (required), limit, +1 more.
list_cyclesA
List test cycles for a project and version.
project accepts a Jira project key (e.g. SONY), a project name, or a
numeric projectId. version accepts a version name, a numeric versionId,
or -1/Unscheduled. Prefer the numeric ids when you have them, to skip a
lookup. Returns a map keyed by versionId; each cycle entry
is keyed by cycleId (the Ad hoc cycle is -1).
Inputs: project (required), version (required), offset, expand.
list_execution_defectsB
List Jira defects currently linked to an execution.
execution_id is the numeric id from list_executions/search_executions.
Returns a map keyed by execution id -> {defectKey -> defect summary}.
Inputs: execution_id (required).
list_executionsA
List the executions in a cycle (optionally narrowed to a folder).
project/version accept keys/names or ids (prefer ids when you have them,
to skip a lookup; -1 = Unscheduled). Returns {status, executions, recordsCount} where status maps status ids to their definitions.
Inputs: cycle_id (required), project (required), version (required), folder_id, +2 more.
list_executions_by_issueB
List all executions of a single test issue, across every cycle.
issue accepts a Jira issue key (e.g. SONY-1386) or numeric id — passed
straight through (the endpoint accepts either). Returns the test's full
execution history, useful for flaky-test diagnosis and coverage checks.
Inputs: issue (required), action, offset, max_records, +1 more.
list_projectsA
List all Jira projects visible to Zephyr (name/key -> projectId).
Returns {options: [{label, value, type}, ...]} where label is the
project name and value is its numeric id. Use this to discover ids; most
tools also accept a project key/name directly.
Inputs: no named parameters.
list_step_resultsA
List the per-step results for an execution.
execution_id is the numeric id of an execution (from list_executions
or search_executions). Returns the step-result records, each with a
status code (-1=UNEXECUTED, 1=PASS, 2=FAIL, 3=WIP, 4=BLOCKED).
Inputs: execution_id (required), expand.
list_test_stepsB
List the test steps of a Zephyr test issue.
issue accepts a Jira issue key (e.g. SONY-1386) or a numeric issueId
(prefer the id when you have it, to skip a lookup).
Returns {stepBeanCollection: [...]}.
Inputs: issue (required), offset, limit.
list_versionsA
List the versions of a project (name -> versionId).
project accepts a key, name, or numeric id (prefer the id when you have
it, to skip a lookup). Returns
{unreleasedVersions, releasedVersions} where each entry has label
(version name) and value (versionId). -1 is the Unscheduled version.
Inputs: project (required).
move_executions_to_folderA
Move executions from a cycle into an internal folder.
Moves all executions in the cycle when schedules is omitted, or only
the listed execution ids when schedules is provided. project/version
accept keys/names or ids (prefer ids when you have them, to skip a lookup;
-1 = Unscheduled). This is an asynchronous ZAPI operation: it returns a
jobProgressToken. With wait=True (default) the tool polls the job to
completion and returns the final job-progress payload; with wait=False it
returns the raw {jobProgressToken} so you can poll later with
get_job_progress.
Inputs: cycle_id (required), folder_id (required), project (required), version (required), +3 more.
search_executionsC
Run a ZQL query and return matching executions.
Example ZQL: project = "SONY" AND executionStatus = FAIL. Returns
{executions, totalCount, ...}.
Inputs: zql_query (required), offset, max_records, expand.
update_cycleA
Update an existing test cycle's fields.
The cycle id is sent in the body (PUT /cycle, no id in the path) —
only the fields you pass are included; omit a field to leave it unchanged.
Dates use Jira's dd/MMM/yy format (e.g. 8/Aug/14). To change the
version pass version (a name or id); a version name also needs
project to resolve it (a numeric version needs neither). Returns
{error, success, noPermission}.
Inputs: cycle_id (required), name, build, environment, +6 more.
update_executionA
Set an execution's status by its numeric id.
status is a ZAPI execution-status code:
-1=UNEXECUTED, 1=PASS, 2=FAIL, 3=WIP, 4=BLOCKED, 5=PENDING,
6=APPROVED, 7=CANCELLED. Returns the updated execution.
Inputs: execution_id (required), status (required).
update_folderA
Update a folder's name and/or description.
The API requires the folder's full context, so cycle_id and
project/version (which accept keys/names or ids — prefer ids when you
have them, to skip a lookup; -1 = Unscheduled) must be supplied alongside
folder_id, the
numeric ID from list_cycle_folders.
Only the optional fields you pass are sent; omit one to leave it
unchanged. Returns {id, responseMessage}.
Inputs: folder_id (required), cycle_id (required), project (required), version (required), +2 more.
update_step_resultA
Set the status (and optional comment) of one step result.
Get step_result_id from list_step_results. status codes:
-1=UNEXECUTED, 1=PASS, 2=FAIL, 3=WIP, 4=BLOCKED. Step results are created
automatically when an execution is opened, so there is no separate create.
Inputs: step_result_id (required), status (required), comment.
update_test_stepA
Update fields of an existing test step.
Only the provided fields are sent (omit to leave unchanged). step is the
action, data the test data, result the expected result. issue accepts a
key or id (prefer the id when you have it, to skip a lookup). Returns the
updated step.
Inputs: issue (required), step_id (required), step, data, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 40 tools
Every tool has a clearly distinct purpose. Even similar tools like add_tests_to_cycle_from_cycle and copy_executions_to_cycle have explicit descriptions differentiating their behavior (UNEXECUTED vs. preserving status). Agents should reliably select the correct tool.
All tools follow a consistent verb_noun pattern in snake_case. Verbs like list_, create_, update_, delete_, add_, copy_, move_ are appropriately chosen. Even longer names like get_execution_status_counts_by_assignee maintain consistency.
40 tools is heavy for a single server, with many specialized operations (e.g., multiple ways to add tests). While the domain justifies many tools, the count is borderline excessive and may overwhelm agents. A more curated set (20-25) would improve focus.
The tool set covers CRUD for cycles, folders, executions, test steps, plus search, status reports, defect linking, and async job polling. Minor gaps exist: no tool to unlink defects from executions, and test steps cannot be reordered. Overall, core workflows are well supported.
Maintenance
Related MCP Connectors
Official MCP server for Qase — manage test cases, runs, suites, defects via AI tools.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that exposes the QMetry Test Management for Jira Cloud REST API as tools for MCP-compatible clients. It enables users to manage test cases, test cycles, test executions, test plans, folders, and automation rules through natural language interactions.3064 npmMIT
- AlicenseBqualityCmaintenanceAn MCP server for Zephyr Scale test management supporting Jira Cloud and Data Center. It enables creating, reading, and managing test cases and test runs via the Atlassian REST API with official API-compliant schemas.16283 npm7MIT
- AlicenseNot gradedqualityFmaintenanceMCP server for Zephyr Scale test management tool, enabling test case, test plan, test cycle, and test execution management.46 npm2MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for Zephyr Scale test management enabling test case, test run, folder, and assignment operations via natural language.2MIT