# xray-cloud-mcp An [MCP](https://modelcontextprotocol.io) server for **Xray Cloud** (test management for Jira). It lets an MCP client (Claude Code, Claude Desktop, etc.) import automation results and manage Xray test entities — Tests, Test Executions, and Test Sets — directly. ## Tools | Tool | API | Read/Write | Purpose | |------|-----|-----------|---------| | `import_execution_junit` | REST | write | Import JUnit XML results into a Test Execution | | `import_execution_xray` | REST | write | Import native Xray-JSON execution results | | `get_tests` | GraphQL | read | Query Test issues by JQL | | `create_test` | GraphQL | write | Create a Manual/Cucumber/Generic Test (with steps) | | `update_test` | GraphQL | write | Change a Test's type and/or append steps | | `get_test_executions` | GraphQL | read | Query Test Executions by JQL | | `create_test_execution` | GraphQL | write | Create a Test Execution, optionally seeded with tests | | `add_tests_to_execution` | GraphQL | write | Add tests to an existing execution | | `add_tests_to_test_set` | GraphQL | write | Add tests to an existing Test Set | The write tools mutate shared Jira/Xray state — review the target before running them. ## Credentials Create an Xray **API Key** in Jira → **Xray → Global Settings → API Keys** (for a service user). This yields a `client_id` + `client_secret`. The server resolves them at startup, **never from a file on disk**, in this order: 1. **Direct env vars** `XRAY_CLIENT_ID` + `XRAY_CLIENT_SECRET`, if both are set — simplest for local use and CI. 2. **Azure Key Vault** — read from the vault at `XRAY_KEY_VAULT_URL` via [`DefaultAzureCredential`](https://learn.microsoft.com/azure/developer/javascript/sdk/authentication/overview) (`az login` locally, managed identity in Azure). Useful when you don't want secrets in env. ### Configuration | Var | Required | Default | Purpose | |-----|----------|---------|---------| | `XRAY_CLIENT_ID` / `XRAY_CLIENT_SECRET` | one of the two methods | — | Direct credentials | | `XRAY_KEY_VAULT_URL` | (if not using direct vars) | — | Azure Key Vault to read secrets from | | `XRAY_CLIENT_ID_SECRET_NAME` | no | `xray-client-id` | Key Vault secret name for the client id | | `XRAY_CLIENT_SECRET_SECRET_NAME` | no | `xray-client-secret` | Key Vault secret name for the client secret | | `XRAY_BASE_URL` | no | `https://xray.cloud.getxray.app` | Xray Cloud endpoint | > If you only need direct env-var auth, the `@azure/*` dependencies are still installed but never > invoked. Remove them and the Key Vault branch in `src/config.ts` if you want a leaner build. ## Build ```bash npm install npm run build # -> dist/ npm run auth-check # resolves credentials + obtains a token (prints no secret) ``` ## Use with an MCP client Add to your MCP client config (e.g. Claude Code's `.mcp.json` or Claude Desktop's config), pointing at the built entrypoint: ```json { "mcpServers": { "xray": { "command": "node", "args": ["/absolute/path/to/xray-cloud-mcp/dist/index.js"], "env": { "XRAY_CLIENT_ID": "your-client-id", "XRAY_CLIENT_SECRET": "your-client-secret" } } } } ``` Or, with Azure Key Vault instead of inline secrets: ```json "env": { "XRAY_KEY_VAULT_URL": "https://your-vault.vault.azure.net" } ``` ## Notes - **Description on create:** some Jira projects make the Description field mandatory; `create_test` defaults it to the summary so creation never fails for lack of one. - **Importing results:** point `import_execution_junit` at the JUnit XML your test runner produces (Playwright, Jest, JUnit, etc.). Use `import_execution_xray` for the richer native Xray JSON. - **stdio only:** the server speaks MCP over stdio; diagnostics go to stderr (stdout is the protocol channel). ## License MIT — see [LICENSE](LICENSE).