Skip to main content
Glama
zephyr-squad-server-mcp

zephyr-squad-server-mcp

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-mcp

Related 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_URL

✅

—

Jira base URL, e.g. https://jira.company.com (no /rest suffix).

JIRA_PERSONAL_TOKEN

one of

—

Personal Access Token → Authorization: Bearer … (recommended for DC).

JIRA_USERNAME + JIRA_PASSWORD

one of

—

Basic-auth fallback (password or API token). Used only if JIRA_PERSONAL_TOKEN is empty.

ZEPHYR_API_PATH

/rest/zapi/latest

ZAPI base path on the Jira host.

ZEPHYR_TIMEOUT

30

Per-request timeout (seconds).

ZEPHYR_VERIFY_SSL

true

Verify TLS certs. Set false only for trusted internal self-signed hosts.

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.md for 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_cycles

List test cycles for a project/version.

get_cycle

Get one cycle's details (id -1 = the Ad hoc cycle).

create_cycle

Create a test cycle.

update_cycle

Update a cycle's fields (id is sent in the body).

delete_cycle

Delete a cycle (async; auto-polls to completion by default).

export_cycle

Get a CSV download link for a cycle's executions.

copy_executions_to_cycle

Copy executions into a cycle (async; auto-polls to completion by default).

move_executions_to_folder

Move executions from a cycle into a folder (async; auto-polls to completion by default).

list_cycle_folders

List folders within a cycle.

create_folder

Create a folder under a cycle.

update_folder

Update a folder's name/description.

delete_folder

Delete a folder from a cycle (async; auto-polls to completion by default).

list_executions

List executions in a cycle (optionally a folder).

update_execution

Set an execution's status (PASS/FAIL/WIP/BLOCKED/…).

list_test_steps

List the test steps of a test issue.

create_test_step

Add a test step to a test issue.

list_step_results

List per-step results for an execution.

search_executions

Run a ZQL query and return matching executions.

get_execution_status_counts

Status-count rollup for a project/version (by cycle).

get_execution_status_counts_by_assignee

Per-assignee status counts for cycle(s).

list_executions_by_issue

A single test's executions across all cycles.

list_execution_defects

Defects linked to an execution.

get_tests_by_requirement

Tests covering requirement(s); flags orphans.

get_executions_by_test

Executions for a test (coverage history).

get_executions_by_defect

Executions linked to a defect.

get_defect_statistics

Per-defect execution/req/test rollups.

update_test_step

Edit a test step's action/data/result.

delete_test_step

Delete a test step.

create_execution

Schedule a test into a cycle.

add_tests_to_cycle_from_list

Bulk-add an explicit list of tests to a cycle as new UNEXECUTED executions (async).

add_tests_to_cycle_from_filter

Bulk-add tests matched by a saved ZQL filter to a cycle as new UNEXECUTED executions (async).

add_tests_to_cycle_from_cycle

Add tests from another cycle as new UNEXECUTED executions (async).

update_step_result

Set a step result's status/comment.

link_execution_defects

Link Jira defects to executions (async).

assign_execution

Assign an execution to a user.

delete_execution

Delete an execution by id.

get_job_progress (helper)

Manually poll any async job by token.

list_projects (helper)

List projects (name → id discovery).

list_versions (helper)

List a project's versions (name → id discovery).

get_zephyr_test_issue_type (helper)

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 test

docs/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 env

Test against TestPyPI first:

uv publish --publish-url https://test.pypi.org/legacy/ --token "$TESTPYPI_TOKEN"

License

MIT — see LICENSE.

Available Tools

40 tools
add_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.

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

    A3.7/5.0

    Scored across 40 tools

    Disambiguation5/5

    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.

    Naming Consistency5/5

    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.

    Tool Count3/5

    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.

    Completeness4/5

    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

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers