Skip to main content
Glama
madhawar
by madhawar
README.md
# 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).