testrails-mcp
# 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
Scored across 15 tools
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.
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.
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.
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.