{
  "markdown": "# QTM4J MCP Server\n\n[![npm](https://img.shields.io/npm/v/qtm4j-mcp-server.svg)](https://www.npmjs.com/package/qtm4j-mcp-server)\n[![npm downloads](https://img.shields.io/npm/dm/qtm4j-mcp-server.svg)](https://www.npmjs.com/package/qtm4j-mcp-server)\n[![Node](https://img.shields.io/node/v/qtm4j-mcp-server.svg)](https://www.npmjs.com/package/qtm4j-mcp-server)\n[![License](https://img.shields.io/npm/l/qtm4j-mcp-server.svg)](LICENSE)\n\nAn [MCP](https://modelcontextprotocol.io) server with **87 tools** for [QMetry Test Management for Jira (QTM4J)](https://www.qmetry.com/qmetry-test-management-jira). Search and manage test cases, cycles, executions, plans, folders, comments, defects, automation rules, and project metadata from Claude Desktop, Claude Code, VS Code Copilot, Cursor, or any MCP-compatible client.\n\n**Distribution**:\n- npm: [`qtm4j-mcp-server`](https://www.npmjs.com/package/qtm4j-mcp-server)\n- MCP Registry: `io.github.salehrifai42/qtm4j-mcp-server`\n- GitHub: [`salehrifai42/qmetrymcp`](https://github.com/salehrifai42/qmetrymcp)\n\n## Quick start (no clone required)\n\nYou need a QMetry API key (QMetry → *API Keys*) and Node.js 18+.\n\n### Claude Desktop\n\nEdit your config file and restart Claude:\n- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n- Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n- Linux: `~/.config/Claude/claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"qtm4j\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"qtm4j-mcp-server@^0.1\"],\n      \"env\": {\n        \"QTM4J_API_KEY\": \"your-api-key-here\",\n        \"QTM4J_REGION\": \"US\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code (CLI)\n\n```bash\nclaude mcp add qtm4j -e QTM4J_API_KEY=your-api-key-here -e QTM4J_REGION=US -- npx -y qtm4j-mcp-server@^0.1\n```\n\n### VS Code (GitHub Copilot Agent mode)\n\nCreate `.vscode/mcp.json` in your workspace:\n\n```json\n{\n  \"servers\": {\n    \"qtm4j\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"qtm4j-mcp-server@^0.1\"],\n      \"env\": {\n        \"QTM4J_API_KEY\": \"${env:QTM4J_API_KEY}\",\n        \"QTM4J_REGION\": \"US\"\n      }\n    }\n  }\n}\n```\n\nSwitch Copilot Chat to **Agent** mode and the `qtm4j_*` tools appear automatically.\n\n### Cursor\n\nAdd to `~/.cursor/mcp.json` (or `<project>/.cursor/mcp.json` for project-level):\n\n```json\n{\n  \"mcpServers\": {\n    \"qtm4j\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"qtm4j-mcp-server@^0.1\"],\n      \"env\": { \"QTM4J_API_KEY\": \"your-api-key-here\" }\n    }\n  }\n}\n```\n\n> The example configs above pin the package to `^0.1` so a future breaking release won't auto-upgrade you. Drop the `@^0.1` suffix if you'd rather always run the latest.\n\n### Global install (faster startup)\n\n`npx` re-resolves the package on every launch, which adds a few seconds of startup latency. If you use the server frequently, install it globally and point your client at the binary directly:\n\n```bash\nnpm install -g qtm4j-mcp-server\n```\n\nThen in your client config, replace the `npx` command:\n\n```json\n{\n  \"mcpServers\": {\n    \"qtm4j\": {\n      \"command\": \"qtm4j-mcp-server\",\n      \"env\": {\n        \"QTM4J_API_KEY\": \"your-api-key-here\",\n        \"QTM4J_REGION\": \"US\"\n      }\n    }\n  }\n}\n```\n\nTradeoff: instant startup and works offline, but you'll need to run `npm update -g qtm4j-mcp-server` to get new versions.\n\n## Configuration\n\n| Variable | Required | Default | Description |\n| --- | --- | --- | --- |\n| `QTM4J_API_KEY` | yes | — | QMetry API key, sent on every request as the `apiKey` header |\n| `QTM4J_REGION` | no | `US` | `US` → `https://qtmcloud.qmetry.com`, `AU` → `https://syd-qtmcloud.qmetry.com` |\n\n> 💡 Set `QTM4J_REGION=AU` if your QMetry instance is on the Sydney cluster.\n\n## Tools\n\nAll tools are prefixed with `qtm4j_` to avoid collisions with other MCP servers.\n\n| Area | Tools |\n| --- | --- |\n| **Test Cases** | `qtm4j_create_test_case`, `qtm4j_get_test_case`, `qtm4j_search_test_cases`, `qtm4j_update_test_case`, `qtm4j_delete_test_case`, `qtm4j_archive_test_case`, `qtm4j_unarchive_test_case`, `qtm4j_clone_test_cases`, `qtm4j_create_test_steps`, `qtm4j_update_test_steps` |\n| **Test Cycles** | `qtm4j_create_test_cycle`, `qtm4j_get_test_cycle`, `qtm4j_search_test_cycles`, `qtm4j_update_test_cycle`, `qtm4j_delete_test_cycle`, `qtm4j_archive_test_cycle`, `qtm4j_unarchive_test_cycle` |\n| **Test Executions** | `qtm4j_get_test_cycle_executions`, `qtm4j_get_test_execution`, `qtm4j_update_test_execution`, `qtm4j_update_test_step_execution`, `qtm4j_bulk_update_test_executions`, `qtm4j_get_execution_teststeps`, `qtm4j_update_execution_custom_fields`, `qtm4j_upload_execution_attachment`, `qtm4j_list_execution_attachments`, `qtm4j_delete_execution_attachment` |\n| **Test Plans** | `qtm4j_create_test_plan`, `qtm4j_get_test_plan`, `qtm4j_search_test_plans`, `qtm4j_update_test_plan`, `qtm4j_delete_test_plan`, `qtm4j_archive_test_plan`, `qtm4j_unarchive_test_plan`, `qtm4j_link_test_cycles_to_plan`, `qtm4j_get_linked_test_cycles`, `qtm4j_unlink_test_cycles_from_plan` |\n| **Comments** | `qtm4j_get_test_case_comments`, `qtm4j_add_test_case_comment`, `qtm4j_update_test_case_comment`, `qtm4j_delete_test_case_comment`, `qtm4j_get_test_cycle_comments`, `qtm4j_add_test_cycle_comment`, `qtm4j_update_test_cycle_comment`, `qtm4j_delete_test_cycle_comment`, `qtm4j_get_test_plan_comments`, `qtm4j_add_test_plan_comment`, `qtm4j_update_test_plan_comment`, `qtm4j_delete_test_plan_comment` |\n| **Defects** | `qtm4j_get_execution_defects`, `qtm4j_link_execution_defects`, `qtm4j_unlink_execution_defects`, `qtm4j_get_step_execution_defects`, `qtm4j_link_step_execution_defects`, `qtm4j_unlink_step_execution_defects`, `qtm4j_search_cycle_defects`, `qtm4j_get_cycle_defect_summary` |\n| **Folders** | `qtm4j_list_folders`, `qtm4j_create_folder` |\n| **Automation** | `qtm4j_link_automation_rule`, `qtm4j_unlink_automation_rule`, `qtm4j_run_automation_rules` |\n| **Metadata** (read-only) | `qtm4j_get_projects`, `qtm4j_get_priorities`, `qtm4j_get_priority_icons`, `qtm4j_get_statuses`, `qtm4j_get_environments`, `qtm4j_get_builds`, `qtm4j_get_labels`, `qtm4j_get_components`, `qtm4j_get_execution_results`, `qtm4j_get_custom_fields`, `qtm4j_get_parameters`, `qtm4j_get_user_permissions` |\n\nSee [`docs/TOOLS.md`](docs/TOOLS.md) for the full reference and [`docs/COOKBOOK.md`](docs/COOKBOOK.md) for example prompts colleagues can paste into any MCP client.\n\nEvery tool ships with annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so clients can decide whether to ask for confirmation. Read tools accept a `response_format` parameter (`json` default, or `markdown` for human-readable output). Large responses are automatically truncated at 25k characters with a hint to narrow the query.\n\nAll tools validate inputs with Zod, paginate via `startAt`/`maxResults`, and automatically retry rate-limited (HTTP 429) responses with exponential back-off (up to 3 attempts).\n\n## Trying it out\n\nOnce connected, ask your assistant something like:\n\n> *Search QMetry project `<your project ID>` for test cases with status \"To Do\" and show me the first 5.*\n\nThe client will call `qtm4j_search_test_cases` and render the response.\n\n> *Get all executions in test cycle `<KEY>-TR-747` and mark any unexecuted ones as Pass.*\n\n## Example tool calls\n\n> Replace `<projectId>` and `<KEY>` with your tenant's numeric Jira project ID and project key. Find them in the project URL: `…?projectId=<projectId>&projectKey=<KEY>`. Use `qtm4j_get_execution_results` to discover your tenant's `executionResultId` values.\n\n```jsonc\n// Search test cases\n{\n  \"name\": \"qtm4j_search_test_cases\",\n  \"arguments\": {\n    \"projectId\": \"<projectId>\",\n    \"status\": [\"Approved\"],\n    \"maxResults\": 20,\n    \"response_format\": \"markdown\"\n  }\n}\n\n// Update an execution result\n{\n  \"name\": \"qtm4j_update_test_execution\",\n  \"arguments\": {\n    \"cycleId\": \"<internal-cycle-id>\",\n    \"testCaseExecutionId\": \"<internal-tc-execution-id>\",\n    \"executionResultId\": \"<pass-id>\",\n    \"comment\": \"Verified on staging\"\n  }\n}\n```\n\n## Troubleshooting\n\n- **Tools don't appear in my client.** Restart the client after editing config. Check `claude mcp list` (Claude Code) or VS Code's MCP panel for connection status. On first run, `npx -y qtm4j-mcp-server` may take a few seconds to download the package.\n- **401 Unauthorized.** Your `QTM4J_API_KEY` is invalid or expired. Generate a new one in QMetry → *API Keys*.\n- **404 on execution or search endpoints.** Many endpoints want the **internal numeric `id`**, not the human key like `<KEY>-TR-747`. Call `qtm4j_get_test_cycle` first to translate the key into the internal id.\n- **Empty or oversized folder response.** Pass `folderId` to `qtm4j_list_folders` to scope to a subtree — full project trees on large projects can exceed the response size limit.\n- **`projectId` rejected.** Use the **numeric** Jira project ID, not the project key string. You can find it in the Jira project URL: `…?projectId=<numeric-id>&projectKey=<KEY>`.\n\n## Notes\n\n- Search endpoints use `POST /…/search` — filters go in the body under `filter`, pagination/sort on the query string. Tool handlers wrap this for you.\n- `204 No Content` responses resolve as `{ message: \"…\" }`.\n- The Swagger spec does not currently document a framework-style automation import-result endpoint (e.g. JUnit/TestNG/Cucumber ingestion); the automation tools cover the rules-run and rule-link flows exposed in the spec.\n\n## Development\n\nLocal setup if you want to modify the server:\n\n```bash\ngit clone https://github.com/salehrifai42/qmetrymcp.git\ncd qmetrymcp\nnpm install\nnpm run build\nQTM4J_API_KEY=your-key npm start\n```\n\nTest changes with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nQTM4J_API_KEY=your-key npx @modelcontextprotocol/inspector node dist/index.js\n```\n\nRun the unit tests (no API key or network needed — the HTTP client's transport is faked in-memory):\n\n```bash\nnpm test\n```\n\n## Replicating the bulk xlsx import workflow\n\nThe repo ships a Claude Code skill (`.claude/skills/xlsx-to-qmetry/`) and a Python importer (`scripts/import-xlsx-to-qmetry.py`) for pushing folders of Excel test cases into QMetry. Tenant-specific IDs (project, parent folder, status, custom-field IDs, components) are kept out of git — you supply them in your own `config.json`.\n\nFirst-run after cloning:\n\n```bash\ncp config.template.json config.json\n# Edit config.json — fill in:\n#   connection.apiKey         (QMetry → avatar → API Keys → Generate)\n#   connection.projectId      (numeric Jira project ID)\n#   xlsxImport.parentFolderId (target folder for new test cases)\n#   xlsxImport.statusId       (e.g. Draft / Approved)\n#   xlsxImport.apiTestFieldId (custom field ID for \"API Test\" toggle, if used)\n#   xlsxImport.options        (Yes/No option IDs for that custom field)\n#   xlsxImport.componentIds   (default components to attach; can be [])\n\ncp .claude/commands/qtm4j.template.md .claude/commands/qtm4j.md\n# Optional: populate qtm4j.md with your tenant's IDs using the GET endpoints listed inside.\n```\n\nDiscover the IDs you need with the running MCP server (`qtm4j_get_projects`, `qtm4j_get_statuses`, `qtm4j_get_components`, `qtm4j_get_custom_fields`, `qtm4j_list_folders`) or with `node scripts/refresh-field-reference.mjs` to dump everything to `field_reference.json`.\n\nThen launch Claude Code from the repo root and the `xlsx-to-qmetry` skill auto-loads. Drop your workbooks under `Input/<batch-name>/` and ask Claude to import them — see [`docs/EXCEL-IMPORT-GUIDE.md`](docs/EXCEL-IMPORT-GUIDE.md) for the full workflow.\n\n## Bugs and contributions\n\nFound a bug or want to suggest a feature? Open an issue at <https://github.com/salehrifai42/qmetrymcp/issues>. PRs welcome.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 11701,
  "sha": "3c1a92c0e4eb97264f42132969a0fc737d950d88a038b07d0f7232ef3e3a5a99",
  "repo_slug": "salehrifai42/qmetrymcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_salehrifai42_qtm4j_mcp_server_37ae7c34/readme"
}