Skip to main content
Glama
adakh3
by adakh3
README.md
# testrails-mcp

An MCP (Model Context Protocol) server that exposes TestRail CRUD operations to
agentic coding tools like Claude Code and Codex CLI, plus a bundled agent skill
for turning Jira tickets into TestRail cases.

## What it does

`testrails-mcp` is a thin, async wrapper around the TestRail API v2. Once
registered with your agent, it lets the model:

- **Navigate** your TestRail instance — list projects, suites, and sections.
- **Manage test cases** — list, read, create, update, and (soft-)delete cases.
- **Manage runs** — list, read, create, and close test runs; list the tests
  inside a run.
- **Record results** — add and read results for cases within a run.

It speaks **stdio** (the standard MCP transport for local tools), authenticates
with TestRail via HTTP Basic auth using your email and API key, and reads
credentials from environment variables or a local `.env` file.

The repo also ships a portable agent **skill** (`skills/jira-to-testrail/`) that
auto-triggers when a user asks to convert a Jira ticket into TestRail cases.
The skill orchestrates a Jira MCP (any vendor) + this MCP to produce one case
per acceptance criterion, with a confirmation gate before anything is created.

## Requirements

- Python 3.11+
- A TestRail account with API access enabled (admin → Site Settings → API)
- A TestRail API key — generate one at *My Settings → API Keys → Add Key*
- An agent runtime that speaks MCP — Claude Code, Codex CLI, Claude Desktop,
  or any other MCP-compatible client

## Setup

```bash
git clone <this-repo> testrails-mcp
cd testrails-mcp

uv venv
uv pip install -e .

cp .env.example .env
# then edit .env with your TestRail URL, email, and API key
```

`.env` shape:

```
TESTRAIL_URL=https://yourcompany.testrail.io
TESTRAIL_USER=you@example.com
TESTRAIL_API_KEY=...
```

Verify it launches:

```bash
.venv/bin/testrails-mcp
# (should sit silently waiting on stdin; Ctrl+C to exit)
```

Confirm the protocol surface:

```bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | .venv/bin/testrails-mcp
```

For an interactive smoke test with form inputs for every tool:

```bash
npx @modelcontextprotocol/inspector .venv/bin/testrails-mcp
```

## Register with your agent

### Claude Code

```bash
claude mcp add testrails -- /absolute/path/to/.venv/bin/testrails-mcp
```

Or add to `~/.claude.json` (user-scope) or `.mcp.json` (project-scope):

```json
{
  "mcpServers": {
    "testrails": {
      "command": "/absolute/path/to/.venv/bin/testrails-mcp"
    }
  }
}
```

### Codex CLI

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.testrails]
command = "/absolute/path/to/.venv/bin/testrails-mcp"
```

### Other clients (Claude Desktop, etc.)

Use the standard MCP server entry: command =
`/absolute/path/to/.venv/bin/testrails-mcp`, no args.

## Tools

**Navigation**
- `list_projects()`
- `list_suites(project_id)`
- `list_sections(project_id, suite_id?)`

**Cases (CRUD)**
- `list_cases(project_id, suite_id?, section_id?, limit?, offset?)`
- `get_case(case_id)`
- `add_case(section_id, title, type_id?, priority_id?, estimate?, refs?, custom_fields?)`
- `update_case(case_id, title?, type_id?, priority_id?, estimate?, refs?, custom_fields?)`
- `delete_case(case_id, soft=True)` — `soft=True` previews; pass `soft=False` to actually delete

**Runs**
- `list_runs(project_id)`
- `get_run(run_id)`
- `add_run(project_id, name, suite_id?, description?, case_ids?, include_all?)`
- `close_run(run_id)`
- `list_tests(run_id)`

**Results**
- `add_result_for_case(run_id, case_id, status_id, comment?, version?, elapsed?, defects?)`
- `get_results_for_case(run_id, case_id)`

TestRail default status IDs: **1=Passed, 2=Blocked, 3=Untested, 4=Retest, 5=Failed**.

`custom_fields` on `add_case` / `update_case` accepts any TestRail custom field
the instance has configured — commonly `custom_steps`, `custom_preconds`,
`custom_expected`, or `custom_steps_separated`.

## Skills

This repo ships one bundled skill — a portable `SKILL.md` that works in both
Claude Code and Codex CLI. Skills are auto-loaded by the agent based on their
description and activate when the user's prompt matches.

### `jira-to-testrail`

Converts a Jira ticket into TestRail test cases. Triggers on phrases like:

- *"Turn PROJ-1234 into test cases"*
- *"Create TestRail cases from this ticket"*
- *"Generate QA coverage for <ticket>"*

What it does:

1. Verifies both a Jira MCP and this TestRail MCP are connected.
2. Reads the ticket, extracts acceptance criteria (refuses to invent any).
3. Auto-discovers the instance's custom-field shape by sampling an existing
   case in the target section.
4. Drafts one case per AC with behavior-focused titles and mapped priority.
5. **Shows you the plan and waits for confirmation** before creating.
6. Creates the cases and reports IDs + URLs as a table.
7. On partial failure, asks how to proceed rather than auto-retrying.

Requires a Jira MCP to also be installed (e.g. Atlassian's official MCP, or
`mcp-atlassian`) — the skill is vendor-agnostic about which one.

### Installing the skill

Skills live in a directory the agent watches. Symlink the bundled skill into
your agent's skills location so `git pull` keeps it up to date:

**Claude Code**

```bash
mkdir -p ~/.claude/skills
ln -s "$(pwd)/skills/jira-to-testrail" ~/.claude/skills/jira-to-testrail
```

**Codex CLI**

```bash
mkdir -p ~/.agents/skills
ln -s "$(pwd)/skills/jira-to-testrail" ~/.agents/skills/jira-to-testrail
```

**Project-scoped (Codex only)**

If you'd rather scope the skill to a single repo, drop a copy into that repo's
`.agents/skills/` directory — Codex walks up from the cwd to find skills.

**Prefer a copy over a symlink:**

```bash
cp -r skills/jira-to-testrail ~/.claude/skills/   # or ~/.agents/skills/
```

### Verifying the skill loaded

- **Claude Code:** run `/skills` and look for `jira-to-testrail` in the list.
- **Codex CLI:** start a new session and ask *"what skills do you have?"* — it
  should mention `jira-to-testrail` (Codex loads skill names/descriptions at
  session start).

If it doesn't show up, double-check:

1. The symlink target exists (`ls -la ~/.claude/skills/jira-to-testrail`).
2. `SKILL.md` is directly inside that folder, not nested further.
3. The frontmatter (`name`, `description`) is present and valid YAML.

## Project layout

```
testrails_mcp/
├── pyproject.toml
├── README.md
├── .env.example
├── .gitignore
├── src/testrails_mcp/
│   ├── __init__.py
│   ├── client.py          # async httpx client (Basic auth)
│   └── server.py          # FastMCP tools, stdio entrypoint
└── skills/
    └── jira-to-testrail/
        └── SKILL.md       # portable Claude/Codex skill
```

## Troubleshooting

- **`Missing TestRail credentials` on startup** — `.env` not found or missing a
  key. The server reads `.env` from the cwd it's launched in; if your agent
  spawns it from a different directory, set the vars in your shell profile or
  agent config instead.
- **`TestRail API 401`** — wrong email or API key. Confirm the key in *My
  Settings → API Keys* and that the user has API access on the instance.
- **`TestRail API 403` on create/update/delete** — the user lacks write
  permission on the project, suite, or section.
- **`delete_case` returns a preview** — that's the default (`soft=True`). Pass
  `soft=False` to actually delete.
- **Skill doesn't trigger** — descriptions are matched fuzzily, but very short
  prompts may miss. Try a phrase closer to the examples in the skill's
  description. As a fallback you can invoke it explicitly (`/skill
  jira-to-testrail` in Codex; mention the skill name directly in Claude Code).

## Roadmap

Phase 1 (current): Cases, Runs, Results, plus the Jira → TestRail skill.

Likely next:

- Sections CRUD (so the skill can create new sections if needed).
- Milestones and Plans.
- A `bulk_add_result_for_cases` tool (TestRail has a native batch endpoint).
- A second skill for *bug report → regression case* flows.

## License

MIT.

TDQS

A3.5/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct TestRail entity or action (project, suite, section, case, run, result, test) with clear boundaries, e.g., add_case vs update_case, list_cases vs get_case, add_result_for_case vs get_results_for_case. No two tools have overlapping purposes.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern using snake_case (e.g., add_case, get_run, list_sections). Verbs are imperative (add, get, list, delete, close, update) and nouns are singular entity names. Minor prepositions like 'for_case' are uniform.

Tool Count5/5

Fifteen tools is well-scoped for a TestRail MCP covering core entities: projects, suites, sections, cases, runs, results, and tests. Each tool serves a clear purpose without unnecessary bloat or missing essentials.

Completeness4/5

The tool set provides full CRUD for test cases and runs, plus read and list operations for most entities. However, missing create/update/delete for sections and suites are notable gaps that agents would need to work around, though core test workflow is covered.

Maintenance

ActivityInactive
ResponsivenessNo issues