zephyr-scale-mcp
This MCP server provides an interface for managing Zephyr Scale test assets on self-hosted Jira Server/Data Center via REST API v1, enabling AI agents to manage the full test lifecycle.
Test Cases: Create, read, update, search (TQL), delete, bulk create, add steps, set/replace script (STEP_BY_STEP, PLAIN_TEXT, BDD/Gherkin), link/unlink Jira issues, and get linked test cases.
Folders: Create folders with recursive parent auto-creation; rename folders by numeric ID.
Test Runs (Cycles): Create (with items and results), read, search (TQL), delete, get paginated results, and recreate with modified items (workaround for run immutability).
Test Results: Create new executions, update last result, bulk create, and get the latest result for a test case. Supports per-step results, environments, executors, custom fields, and issue links.
Test Plans: Full CRUD + search (TQL).
Attachments: Upload, list, and delete attachments for test cases, steps, runs, and results.
Automation: Upload automation results (Zephyr zip), upload Cucumber JSON results (zip), and download BDD feature files (zip).
Service & Utility: List/create environments, find Jira users by username/display name/email, and perform a health check.
Unofficial (opt-in): Get folder tree via internal API (requires ZEPHYR_ALLOW_INTERNAL_API=true).
Provides tools to manage test cases, folders, test runs, and test results in Zephyr Scale for Jira Server/Data Center. Supports creating, reading, updating, deleting test cases, adding test steps, searching via TQL, creating test runs with results, and managing environments and users.
Click on "Install 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-scale-mcpCreate a test case for user login"
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-scale-mcp
MCP server for Zephyr Scale on self-hosted Jira Server / Data Center (formerly TM4J). It gives an AI agent — Claude Code, Claude Desktop, Cursor, any MCP client — 54 tools over your test management: test cases, folders, test cycles, executions, test plans, attachments and automation imports, through the Zephyr Scale REST API v1 at {JIRA_BASE_URL}/rest/atm/1.0.
npm: zephyr-scale-mcp · MCP Registry: io.github.vilaabo/zephyr-scale-mcp · Русская версия →
⚠️ Scope: Server / Data Center only. Zephyr Scale Cloud (API v2) and Zephyr Squad are different APIs and are out of scope — this server will not work against them.
Why this exists
Most Zephyr MCP servers target the Cloud API. If your Jira is on-premise you get the v1 API instead, and v1 has teeth: test runs are immutable after creation, folders cannot be listed, statuses are case-sensitive internal names, BDD scripts reject a Feature: header, and older plugin builds are missing whole endpoints. This server encodes that knowledge instead of leaving the agent to discover it one 400 at a time.
54 tools (42 public + 12 opt-in internal-API tools), each with a description that states the endpoint, the constraints a caller cannot guess, and the exact response shape.
Composite tools for the API's blind spots —
add_test_stepsmerges steps by id (read → merge → write) so nothing is silently deleted;recreate_test_run_with_itemsworks around run immutability and can carry the last results over;get_issue_test_coverage,get_test_run_summary,clone_test_case,move_test_cases_to_folder.Degradation on older builds — automatic fallback when the paginated results endpoint is absent, and a per-item fallback when the bulk create endpoint is broken. Both were found on a real legacy instance, not in a changelog.
Plumbing that fails loudly — strict zod input validation,
Retry-After-aware retries with exponential backoff, error messages carrying actionable hints, read-only mode, secrets kept out of logs and tool output.1181 unit and contract tests (vitest + msw, no network) plus a gated end-to-end scenario against a real instance.
Related MCP server: mcp-zephyr-scale
Quick start
Requirements: Node.js >= 20, Jira Server/DC with the Zephyr Scale plugin, and a Personal Access Token (Jira 8.14+) or a username/password pair.
Nothing to clone — the package is on 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-mcpClaude Desktop / any MCP client (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.jsThen point the client at the build: "command": "node", "args": ["/path/to/zephyr-scale-mcp/dist/index.js"].
ZEPHYR_ALLOW_INTERNAL_API=trueis optional and recommended. It registers 12 extra tools that reach the things the public API cannot do at all: editing a test run in place — renaming or moving it (update_test_run) and adding or removing cases without changing its key (add_test_cases_to_run,remove_test_cases_from_run) — plus listing the folder tree (get_folder_tree), deleting folders (delete_folder), editing older executions (update_test_result_by_id) and reading the exact status names the API silently expects (get_status_options). These call the same undocumented/rest/tests/1.0endpoints the Jira UI itself uses; the vendor does not support them and they may differ or be absent on another Zephyr Scale version. Leave the flag off if that trade-off is not acceptable — the other 42 tools are unaffected.
Then ask the agent to run health_check. It verifies connectivity and credentials via GET /rest/api/2/myself and, when ZEPHYR_DEFAULT_PROJECT_KEY is set, that the Zephyr plugin answers on /rest/atm/1.0.
What you can ask your agent to do
"Create the folder
/Regression/Paymentsand add step-by-step test cases for the checkout flow described in this document.""Find every Draft case in
/Regression, review them, and set the ready ones to Approved.""Create a cycle for sprint 42 with all smoke cases, then record the results from this report — step by step where the script has steps."
"Which test cases cover PROJ-123, and when did each of them last pass?" — traceability from the issue to its cases and their latest executions.
"Take this ZIP of Cucumber JSON reports and publish it as a new cycle in PROJ." — automation import; scenarios are matched to BDD cases by their
@TestCaseKey=PROJ-T1tag."Add two steps to PROJ-T55 after step 3." — existing steps and their ids survive.
"Recreate cycle PROJ-R7 with three more cases, keep the results, and delete the original."
Configuration
Variable | Required | Default | Purpose |
| yes | — | Jira base URL without a trailing |
| no |
|
|
| with | — | Jira Server/DC Personal Access Token |
| with | — | Basic-auth credentials |
| no |
| Per-request timeout |
| no |
| Retries for GET and for any |
| no |
|
|
| no | — | Used whenever a tool is called without |
| no |
|
|
| no |
|
|
| no |
|
|
Two guarantees the tests cover: JIRA_PAT and JIRA_PASSWORD never appear in logs, tool output or error messages — in any encoding they can take on the way out: raw, JSON-escaped, or the base64 basic-auth token (error text carries the method and path only — never the query string, which may contain data) — and stdout is reserved for the MCP protocol, every log line goes to stderr. One deliberate exception: a secret shorter than six characters is left alone, because redacting it would corrupt unrelated output while protecting nothing; the server warns about it at startup.
Configuration is validated at startup: all problems are reported at once and the process exits with a non-zero code rather than starting half-configured.
Tools
54 tools. The 42 public ones are always registered; the 12 in the last group only with ZEPHYR_ALLOW_INTERNAL_API=true.
Tool | What it does |
| Create a case with a |
| Read a case, optionally narrowed by |
| TQL search with pagination; a query longer than 1500 characters is sent as |
| Partial update; |
| Insert steps at a position without losing the existing ones — read, merge by id, write back |
| Replace the whole script or change its format; destructive by design |
| Copy a case inside its project with fresh step ids; links, attachments and history are not copied |
| Bulk-move by explicit keys or by source folder; a failing case does not abort the rest |
| Permanent delete of the case, its script and its history |
| Create many cases in one call, with a per-case fallback on broken bulk endpoints |
| Bulk-link cases to Jira issues (additive) |
| Reverse lookup: issue → cases |
| Traceability report: issue → linked cases → latest execution of each |
Tool | What it does |
| Create a cycle with its complete item list — optionally with each item's execution result in the same call |
| Read a cycle including its items |
| TQL search — for runs only |
| Permanent delete of the cycle and all its results |
| Page through the executions of a cycle, with the legacy flat-endpoint fallback |
| Last execution per item: |
| The public workaround for run immutability: rebuild under a new key with cases added or removed, optionally carrying the last results over and deleting the original |
Tool | What it does |
| Append a new execution to a run item, including per-step |
| Partial update of the most recent execution of an item |
| Many executions for one cycle in a single call |
| The execution of a case with the greatest stored execution date, across all cycles — not necessarily the one recorded last |
Items that exist several times in a run (per environment or per assignee) are disambiguated with matchEnvironment / matchUserKey, sent as query parameters.
Tool | What it does |
| Create a plan; returns |
| Read a plan with its linked runs and issues |
| Partial update |
| Permanent delete |
| TQL search; the searchable field set varies by Zephyr Scale version |
Tool | What it does |
| Create a case / plan / cycle folder from a full path; with |
| Rename one folder segment by its numeric id (and optionally set its custom fields) |
Tool | What it does |
| Attach a local file to a case, a case step, a cycle, a result or a result step (multipart) |
| List the attachments of any of those targets; each record carries the id and url the other tools need |
| Save an attachment by id or by the url |
| Permanently delete one attachment by numeric id |
Tool | What it does |
| Publish a ZIP of results in Zephyr's custom JSON format; always creates a new cycle |
| Publish a ZIP of Cucumber JSON reports; scenarios are matched by their |
| Export BDD cases as a ZIP of |
Tool | What it does |
| Jira reachability, credentials, and whether the Zephyr plugin answers |
| The project's environments — the exact case-sensitive names results reference |
| Create an environment in the project |
| Resolve the Jira user key ( |
Registered only with ZEPHYR_ALLOW_INTERNAL_API=true. These call /rest/tests/1.0, the undocumented API behind the Jira UI. The vendor does not support it: endpoints may differ or be absent on another Zephyr Scale version, and a 404/405 from one of these tools means exactly that. Every request shape below was either captured from the Jira UI's own traffic or verified live against a real instance — never guessed. Errors from this layer carry a hint saying so.
Tool | What it does |
| Rename a cycle, move it to another folder (by numeric folder id) or change its planned dates in place, keeping its key, items and results. No |
| Append cases to an existing cycle in place; the key and the existing results survive |
| Remove items from an existing cycle in place — their whole execution history dies with them |
| Reorder the items of an existing cycle; a cycle already in the requested order makes no write at all |
| Link Jira issues to an existing cycle — the public API rejects an |
| Associate an existing cycle with a test plan after creation (the public API accepts |
| Delete individual executions by numeric id. The last execution of an item cannot be deleted |
| Edit any execution in an item's history, including older ones; |
| The full folder tree of a project with the numeric ids |
| The exact internal names of the project's execution statuses, case statuses or priorities — the values the public API silently ignores when they are wrong |
| Custom field definitions per entity type: names, types, required flags, options |
| Delete a folder by numeric id. What happens to a non-empty folder is version-specific — empty it first |
Working around API v1
These are the constraints the server is built around. Every tool description repeats the ones relevant to it, so the agent sees them at call time.
Test runs are immutable. There is no
PUT /testrun: a run cannot be renamed, moved, or have cases added or removed. Its items are fixed at creation and the run status is derived from item statuses. Escape hatches:recreate_test_run_with_items(public, produces a new key) or the internalupdate_test_run/add_test_cases_to_run/remove_test_cases_from_run(same key).Folders are never created implicitly.
create_test_case,create_test_runandcreate_test_planfail with 400 on an unknown folder. Folders also cannot be listed through the public API, and renaming needs the numeric id returned bycreate_folder— orget_folder_treewith the internal API enabled.owner/executedBy/assignedTotake a Jira user key (JIRAUSER10000), never a username or an e-mail.find_jira_userresolves it.TQL is strict: spaces around operators are mandatory, string values go in double quotes,
ANDis the only connector (noOR), and folder paths start with/. Test runs are searchable byprojectKeyandfolderonly. For single/multi-choice custom fields=does not work — useIN.Statuses, priorities and environments are case-sensitive internal names. Built-in statuses are shown localized in the UI (the label you see for
Draftmay be a translation) while custom ones use their literal names —get_status_optionsshows what the API actually expects. A wrong execution status is silently ignored by the public API.A BDD script is the scenario body only — bare
Given/When/Then/And/Butlines. Text wrapped inFeature:/Scenario:is rejected with400 Invalid BDD Script; the wrapper is generated on export.STEP_BY_STEPsteps are synchronized by id onPUT: a step without an id is created, a step with an id is updated, and every stored step missing from the list is deleted. Always send the complete final list with ids carried over fromget_test_case— or letadd_test_stepsdo the read-merge-write.Deprecated fields are intentionally not accepted: use
issueLinksinstead ofissueKey,actualEndDateinstead ofexecutionDate,executedByinstead ofuserKey.
Quirks of older plugin builds
All of the following was observed live on a real legacy Zephyr Scale Server instance and is covered by tests.
Cycle keys may use the
-Cprefix (PROJ-C34) instead of-R. Every run-key parameter takes the key as-is, so pass whatever your instance shows.GET /testrun/{key}/testresults/pagemay not exist.get_test_run_resultsandget_test_run_summaryfall back to the deprecated flat endpoint and paginate client-side, adding anoteto the response. A run that genuinely does not exist still surfaces as a 404.An overall
statussent together withscriptResultsis ignored. Send the step results first, then set the overall status withupdate_last_test_result.POST /testcase/link-issuesmay answer 500. Link throughupdate_test_casewithissueLinksinstead.POST /testcase/bulkmay answer HTTP 500 with an empty body for any payload while single creation works.create_test_cases_bulkfalls back to creating the cases one by one — on any5xx, and on a JSON404(which means "no such endpoint on this build", unlike the HTML404Jira serves when the plugin is absent) — and reports which ones succeeded (#1). Every other4xxis a payload error and is not retried.Posting a result for a case that is not among the run's items silently adds it to the run on this build; other builds reject the call with 400/404. The result tools document both.
The custom automation-results format is validated strictly.
{"version": 1, "executions": [{"source", "result", "testCase": {"key"}}]}works; extra per-execution fields such asexecutionTimeare rejected withInvalid Custom Format JSON file. Cucumber JSON reports work as-is when the scenario carries@TestCaseKey=PROJ-T1.download_feature_filesrequires thetqlquery parameter — the API rejects the call without it.The last execution of a run item cannot be deleted.
delete_test_resultsrejects it; remove the item instead.Custom fields may be absent entirely — the definitions endpoint then returns
[].
Development
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 requiredThe smoke scenario is skipped unless ZEPHYR_E2E=1. It needs a real JIRA_BASE_URL, credentials and a dedicated ZEPHYR_DEFAULT_PROJECT_KEY — it creates and deletes real entities and leaves /mcp-smoke-* folders behind, since the public API cannot delete folders.
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 scenarioVersioning and changelog
Version 1.0.0. Tool names, parameter names and response shapes are a public contract from this release on and change only in a major version. See CHANGELOG.md.
License
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityAmaintenanceAn 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.Last updated161635MIT
- Alicense-qualityFmaintenanceMCP server for Zephyr Scale test management tool, enabling test case, test plan, test cycle, and test execution management.Last updated272MIT
- Alicense-qualityCmaintenanceEnables AI assistants to interact with Zephyr Scale Cloud for test management, including test cases, cycles, plans, folders, priorities, and statuses via the MCP protocol.Last updated2MIT
- Alicense-qualityDmaintenanceMCP server for Zephyr Scale test management enabling test case, test run, folder, and assignment operations via natural language.Last updated2MIT
Related MCP Connectors
MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.
Official MCP server for Qase — manage test cases, runs, suites, defects via AI tools.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/vilaabo/zephyr-scale-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server