tram-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tram_mcp-0.1.0/.github/workflows/publish.yml +40 -0
- tram_mcp-0.1.0/.github/workflows/tag-release.yml +92 -0
- tram_mcp-0.1.0/.github/workflows/tests.yml +37 -0
- tram_mcp-0.1.0/.gitignore +18 -0
- tram_mcp-0.1.0/.python-version +1 -0
- tram_mcp-0.1.0/CLAUDE.md +74 -0
- tram_mcp-0.1.0/LICENSE +21 -0
- tram_mcp-0.1.0/PKG-INFO +163 -0
- tram_mcp-0.1.0/README.md +138 -0
- tram_mcp-0.1.0/main.py +4 -0
- tram_mcp-0.1.0/pyproject.toml +44 -0
- tram_mcp-0.1.0/tests/__init__.py +0 -0
- tram_mcp-0.1.0/tests/conftest.py +23 -0
- tram_mcp-0.1.0/tests/test_catalog.py +113 -0
- tram_mcp-0.1.0/tests/test_client.py +65 -0
- tram_mcp-0.1.0/tests/test_execute.py +81 -0
- tram_mcp-0.1.0/tests/test_get_method_info.py +45 -0
- tram_mcp-0.1.0/tests/test_list_categories.py +28 -0
- tram_mcp-0.1.0/tram_mcp/__init__.py +5 -0
- tram_mcp-0.1.0/tram_mcp/server.py +251 -0
- tram_mcp-0.1.0/uv.lock +1403 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish Package (manual)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
name: Build and publish to PyPI
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
uses: actions/checkout@v6
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v7
|
|
19
|
+
with:
|
|
20
|
+
version: "latest"
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v6
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.13"
|
|
26
|
+
|
|
27
|
+
- name: Install build dependencies
|
|
28
|
+
run: uv pip install --system --upgrade build twine
|
|
29
|
+
|
|
30
|
+
- name: Clean previous builds
|
|
31
|
+
run: rm -rf dist/ build/ *.egg-info
|
|
32
|
+
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: uv build
|
|
35
|
+
|
|
36
|
+
- name: Publish to PyPI
|
|
37
|
+
env:
|
|
38
|
+
TWINE_USERNAME: __token__
|
|
39
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
40
|
+
run: twine upload dist/*
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
name: Tag and release on merge to main
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [closed]
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: "release"
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
tag:
|
|
17
|
+
name: Create version tag
|
|
18
|
+
if: github.event.pull_request.merged == true
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v6
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v7
|
|
29
|
+
with:
|
|
30
|
+
version: "latest"
|
|
31
|
+
|
|
32
|
+
- name: Get version
|
|
33
|
+
id: version
|
|
34
|
+
run: echo "version=$(uv version --short)" >> "$GITHUB_OUTPUT"
|
|
35
|
+
|
|
36
|
+
- name: Check if tag already exists
|
|
37
|
+
id: tag_check
|
|
38
|
+
run: |
|
|
39
|
+
if git rev-parse "v${{ steps.version.outputs.version }}" \
|
|
40
|
+
>/dev/null 2>&1; then
|
|
41
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
42
|
+
else
|
|
43
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
- name: Create and push tag
|
|
47
|
+
if: steps.tag_check.outputs.exists == 'false'
|
|
48
|
+
run: |
|
|
49
|
+
git config user.name "github-actions[bot]"
|
|
50
|
+
git config user.email \
|
|
51
|
+
"github-actions[bot]@users.noreply.github.com"
|
|
52
|
+
git tag "v${{ steps.version.outputs.version }}"
|
|
53
|
+
git push origin "v${{ steps.version.outputs.version }}"
|
|
54
|
+
|
|
55
|
+
outputs:
|
|
56
|
+
version: ${{ steps.version.outputs.version }}
|
|
57
|
+
tag_exists: ${{ steps.tag_check.outputs.exists }}
|
|
58
|
+
|
|
59
|
+
publish:
|
|
60
|
+
name: Build and publish to PyPI
|
|
61
|
+
needs: tag
|
|
62
|
+
if: needs.tag.outputs.tag_exists == 'false'
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout code
|
|
67
|
+
uses: actions/checkout@v6
|
|
68
|
+
|
|
69
|
+
- name: Install uv
|
|
70
|
+
uses: astral-sh/setup-uv@v7
|
|
71
|
+
with:
|
|
72
|
+
version: "latest"
|
|
73
|
+
|
|
74
|
+
- name: Set up Python
|
|
75
|
+
uses: actions/setup-python@v6
|
|
76
|
+
with:
|
|
77
|
+
python-version: "3.13"
|
|
78
|
+
|
|
79
|
+
- name: Install build dependencies
|
|
80
|
+
run: uv pip install --system --upgrade build twine
|
|
81
|
+
|
|
82
|
+
- name: Clean previous builds
|
|
83
|
+
run: rm -rf dist/ build/ *.egg-info
|
|
84
|
+
|
|
85
|
+
- name: Build package
|
|
86
|
+
run: uv build
|
|
87
|
+
|
|
88
|
+
- name: Publish to PyPI
|
|
89
|
+
env:
|
|
90
|
+
TWINE_USERNAME: __token__
|
|
91
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
92
|
+
run: twine upload dist/*
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout code
|
|
21
|
+
uses: actions/checkout@v6
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v7
|
|
25
|
+
with:
|
|
26
|
+
version: "latest"
|
|
27
|
+
|
|
28
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
29
|
+
uses: actions/setup-python@v6
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
|
|
33
|
+
- name: Install dependencies
|
|
34
|
+
run: uv sync
|
|
35
|
+
|
|
36
|
+
- name: Run tests
|
|
37
|
+
run: uv run pytest
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
tram_mcp-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is an MCP (Model Context Protocol) server that wraps the `testrail_api_module` PyPI package, exposing TestRail API endpoints as MCP tools. Built with FastMCP.
|
|
8
|
+
|
|
9
|
+
**Key design principle:** Tools should be discovered dynamically from the `testrail_api_module` rather than hardcoded, to avoid overwhelming LLMs with too many tools and to automatically support new endpoints as the underlying package updates.
|
|
10
|
+
|
|
11
|
+
## Tech Stack
|
|
12
|
+
|
|
13
|
+
- Python 3.13, managed with `uv`
|
|
14
|
+
- FastMCP (`fastmcp>=2.12.4`) for MCP server framework
|
|
15
|
+
- `testrail_api_module` as the underlying TestRail API client (needs to be added as dependency)
|
|
16
|
+
|
|
17
|
+
## Common Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Install dependencies
|
|
21
|
+
uv sync
|
|
22
|
+
|
|
23
|
+
# Add a new dependency
|
|
24
|
+
uv add <package>
|
|
25
|
+
|
|
26
|
+
# Run the MCP server
|
|
27
|
+
uv run python main.py
|
|
28
|
+
|
|
29
|
+
# Run all tests
|
|
30
|
+
uv run pytest
|
|
31
|
+
|
|
32
|
+
# Run a single test
|
|
33
|
+
uv run pytest test_testing/test_browse.py::test_apple_page_title -v
|
|
34
|
+
|
|
35
|
+
# Run tests with output
|
|
36
|
+
uv run pytest -s
|
|
37
|
+
|
|
38
|
+
# Install packages (not dependencies - dependencies use `uv add`)
|
|
39
|
+
uv pip install <package>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Authentication & Secrets
|
|
43
|
+
|
|
44
|
+
- Credentials are managed by **1Password** via an ephemeral `.env` file at the project root.
|
|
45
|
+
- The `.env` file is **not** a normal file — it requires `cat .env` to trigger the 1Password listener and materialize the contents. Python's `open()` and shell `source`/`.` **do not** trigger it.
|
|
46
|
+
- The server uses `_load_env_from_cat()` in `tram_mcp/server.py` to run `cat .env` via subprocess at startup and parse the results into `os.environ`.
|
|
47
|
+
- **Do NOT hardcode credentials** in `.mcp.json` — the `env` block there won't stay in sync. Let the server read from `.env` at startup.
|
|
48
|
+
- Supported env vars: `TESTRAIL_URL`, `TESTRAIL_USERNAME`, `TESTRAIL_API_KEY`, `TESTRAIL_PASSWORD`. Either `TESTRAIL_API_KEY` or `TESTRAIL_PASSWORD` must be set.
|
|
49
|
+
- If auth fails repeatedly, check for **account lockout** — TestRail locks accounts after too many failed attempts (~10 min cooldown).
|
|
50
|
+
|
|
51
|
+
## Architecture Goals
|
|
52
|
+
|
|
53
|
+
The MCP server should:
|
|
54
|
+
1. **Introspect `testrail_api_module`** at startup to discover available API modules (projects, cases, runs, results, etc.) and their methods
|
|
55
|
+
2. **Dynamically register MCP tools** based on discovered endpoints rather than manually defining each one
|
|
56
|
+
3. **Provide a category/discovery pattern** — e.g., a `list_categories` tool that returns available API modules, and a way to invoke specific endpoints — so the LLM can explore capabilities without being flooded with hundreds of tools upfront
|
|
57
|
+
4. **Pass through** to `TestRailAPI` client methods, handling authentication via environment variables or MCP configuration
|
|
58
|
+
|
|
59
|
+
## TestRail Instance Notes
|
|
60
|
+
|
|
61
|
+
- **URL:** `https://vermontsystems.testrail.io`
|
|
62
|
+
- **Templates:** Template 1 = "Test Case (Text)" uses `custom_steps`/`custom_expected` fields. Template 2 = "Test Case (Steps)" uses `custom_steps_separated` (array of `{content, expected}`). To use separated steps, set `template_id: 2`.
|
|
63
|
+
- When updating cases from Text to Steps template, you must change `template_id` in the same call.
|
|
64
|
+
|
|
65
|
+
## Git Rules
|
|
66
|
+
|
|
67
|
+
- **Never** add `Co-Authored-By` lines to commit messages.
|
|
68
|
+
|
|
69
|
+
## TestRail API Module Reference
|
|
70
|
+
|
|
71
|
+
The `testrail_api_module` package (`TestRailAPI` class) organizes endpoints into submodules accessed as attributes: `api.projects.get_projects()`, `api.cases.add_case(...)`, `api.results.add_result(...)`, etc. Key modules include: projects, cases, runs, results, attachments, bdd, configurations, labels, sections, users, statuses, plans, datasets, milestones, suites, priorities.
|
|
72
|
+
|
|
73
|
+
Docs: https://trtmn.github.io/testrail_api_module/
|
|
74
|
+
Source: https://github.com/trtmn/testrail_api_module
|
tram_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matt Troutman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tram_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tram-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server exposing TestRail API endpoints as tools for LLMs
|
|
5
|
+
Project-URL: Homepage, https://github.com/trtmn/tram-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/trtmn/tram-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/trtmn/tram-mcp/issues
|
|
8
|
+
Author-email: Matt Troutman <git@trtmn.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api,llm,mcp,model-context-protocol,testing,testrail
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: fastmcp>=2.12.4
|
|
22
|
+
Requires-Dist: python-dotenv>=1.1.1
|
|
23
|
+
Requires-Dist: testrail-api-module==0.7.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# TestRail MCP Server
|
|
27
|
+
|
|
28
|
+
[](https://github.com/trtmn/tram-mcp/actions/workflows/tests.yml)
|
|
29
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
30
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
31
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
32
|
+
[](https://opensource.org/licenses/MIT)
|
|
33
|
+
|
|
34
|
+
Connect your AI coding assistant to [TestRail](https://www.testrail.com/) — manage test cases, runs, results, and more directly from VS Code, Cursor, Claude Desktop, or Claude Code. Built on the [Model Context Protocol](https://modelcontextprotocol.io/) and powered by [`testrail_api_module`](https://github.com/trtmn/testrail_api_module).
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Dynamic tool discovery** — endpoints are introspected from `testrail_api_module` at startup, so new API coverage is picked up automatically
|
|
39
|
+
- **LLM-friendly** — instead of registering hundreds of tools, provides a category-based discovery pattern so models can explore available operations without being overwhelmed
|
|
40
|
+
|
|
41
|
+
## Requirements
|
|
42
|
+
|
|
43
|
+
- Python 3.11+
|
|
44
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
45
|
+
|
|
46
|
+
## Quick Install
|
|
47
|
+
|
|
48
|
+
<a href="vscode:mcp/install?%7B%22name%22%3A%22testrail%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22tram-mcp%22%5D%2C%22env%22%3A%7B%22TESTRAIL_URL%22%3A%22%22%2C%22TESTRAIL_USERNAME%22%3A%22%22%2C%22TESTRAIL_API_KEY%22%3A%22%22%7D%7D"><img src="https://img.shields.io/badge/VS_Code-Install_Server-0078d7?style=flat-square&logo=visual-studio-code" alt="Install in VS Code"></a>
|
|
49
|
+
<a href="vscode-insiders:mcp/install?%7B%22name%22%3A%22testrail%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22tram-mcp%22%5D%2C%22env%22%3A%7B%22TESTRAIL_URL%22%3A%22%22%2C%22TESTRAIL_USERNAME%22%3A%22%22%2C%22TESTRAIL_API_KEY%22%3A%22%22%7D%7D"><img src="https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visual-studio-code" alt="Install in VS Code Insiders"></a>
|
|
50
|
+
<a href="cursor://anysphere.cursor-deeplink/mcp/install?name=testrail&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyJ0cmFtLW1jcCJdLCJlbnYiOnsiVEVTVFJBSUxfVVJMIjoiIiwiVEVTVFJBSUxfVVNFUk5BTUUiOiIiLCJURVNUUkFJTF9BUElfS0VZIjoiIn19"><img src="https://img.shields.io/badge/Cursor-Install_Server-purple?style=flat-square&logo=cursor" alt="Install in Cursor"></a>
|
|
51
|
+
|
|
52
|
+
After installing, you will be prompted to fill in your TestRail credentials. See [Configuration](#configuration) below.
|
|
53
|
+
|
|
54
|
+
## Manual Installation
|
|
55
|
+
|
|
56
|
+
### Claude Desktop
|
|
57
|
+
|
|
58
|
+
Add to your Claude Desktop config file:
|
|
59
|
+
|
|
60
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
61
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"testrail": {
|
|
67
|
+
"command": "uvx",
|
|
68
|
+
"args": ["tram-mcp"],
|
|
69
|
+
"env": {
|
|
70
|
+
"TESTRAIL_URL": "https://yourinstance.testrail.io",
|
|
71
|
+
"TESTRAIL_USERNAME": "your-email@example.com",
|
|
72
|
+
"TESTRAIL_API_KEY": "your-api-key"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Claude Code
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
claude mcp add testrail \
|
|
83
|
+
-e TESTRAIL_URL=https://yourinstance.testrail.io \
|
|
84
|
+
-e TESTRAIL_USERNAME=your-email@example.com \
|
|
85
|
+
-e TESTRAIL_API_KEY=your-api-key \
|
|
86
|
+
-- uvx tram-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### VS Code / VS Code Insiders
|
|
90
|
+
|
|
91
|
+
Create `.vscode/mcp.json` in your project (or add to your User Settings):
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"servers": {
|
|
96
|
+
"testrail": {
|
|
97
|
+
"type": "stdio",
|
|
98
|
+
"command": "uvx",
|
|
99
|
+
"args": ["tram-mcp"],
|
|
100
|
+
"env": {
|
|
101
|
+
"TESTRAIL_URL": "",
|
|
102
|
+
"TESTRAIL_USERNAME": "",
|
|
103
|
+
"TESTRAIL_API_KEY": ""
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
VS Code supports `${input:variableName}` placeholders to prompt for values at startup.
|
|
111
|
+
|
|
112
|
+
### Cursor
|
|
113
|
+
|
|
114
|
+
Create `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"testrail": {
|
|
120
|
+
"command": "uvx",
|
|
121
|
+
"args": ["tram-mcp"],
|
|
122
|
+
"env": {
|
|
123
|
+
"TESTRAIL_URL": "https://yourinstance.testrail.io",
|
|
124
|
+
"TESTRAIL_USERNAME": "your-email@example.com",
|
|
125
|
+
"TESTRAIL_API_KEY": "your-api-key"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Configuration
|
|
133
|
+
|
|
134
|
+
The server requires TestRail credentials via environment variables:
|
|
135
|
+
|
|
136
|
+
| Variable | Required | Description |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `TESTRAIL_URL` | Yes | Your TestRail instance URL (e.g. `https://example.testrail.io`) |
|
|
139
|
+
| `TESTRAIL_USERNAME` | Yes | TestRail username or email |
|
|
140
|
+
| `TESTRAIL_API_KEY` | Yes* | TestRail API key |
|
|
141
|
+
| `TESTRAIL_PASSWORD` | Yes* | TestRail password (alternative to API key) |
|
|
142
|
+
|
|
143
|
+
*Either `TESTRAIL_API_KEY` or `TESTRAIL_PASSWORD` must be set. API key is recommended.
|
|
144
|
+
|
|
145
|
+
## Development
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Install dependencies
|
|
149
|
+
uv sync
|
|
150
|
+
|
|
151
|
+
# Run the server locally
|
|
152
|
+
uv run tram_mcp
|
|
153
|
+
|
|
154
|
+
# Run tests
|
|
155
|
+
uv run pytest
|
|
156
|
+
|
|
157
|
+
# Run a single test
|
|
158
|
+
uv run pytest path/to/test.py::test_name -v
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
tram_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# TestRail MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://github.com/trtmn/tram-mcp/actions/workflows/tests.yml)
|
|
4
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
5
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
6
|
+
[](https://pypi.org/project/tram-mcp/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
Connect your AI coding assistant to [TestRail](https://www.testrail.com/) — manage test cases, runs, results, and more directly from VS Code, Cursor, Claude Desktop, or Claude Code. Built on the [Model Context Protocol](https://modelcontextprotocol.io/) and powered by [`testrail_api_module`](https://github.com/trtmn/testrail_api_module).
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Dynamic tool discovery** — endpoints are introspected from `testrail_api_module` at startup, so new API coverage is picked up automatically
|
|
14
|
+
- **LLM-friendly** — instead of registering hundreds of tools, provides a category-based discovery pattern so models can explore available operations without being overwhelmed
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
- Python 3.11+
|
|
19
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
20
|
+
|
|
21
|
+
## Quick Install
|
|
22
|
+
|
|
23
|
+
<a href="vscode:mcp/install?%7B%22name%22%3A%22testrail%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22tram-mcp%22%5D%2C%22env%22%3A%7B%22TESTRAIL_URL%22%3A%22%22%2C%22TESTRAIL_USERNAME%22%3A%22%22%2C%22TESTRAIL_API_KEY%22%3A%22%22%7D%7D"><img src="https://img.shields.io/badge/VS_Code-Install_Server-0078d7?style=flat-square&logo=visual-studio-code" alt="Install in VS Code"></a>
|
|
24
|
+
<a href="vscode-insiders:mcp/install?%7B%22name%22%3A%22testrail%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22tram-mcp%22%5D%2C%22env%22%3A%7B%22TESTRAIL_URL%22%3A%22%22%2C%22TESTRAIL_USERNAME%22%3A%22%22%2C%22TESTRAIL_API_KEY%22%3A%22%22%7D%7D"><img src="https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visual-studio-code" alt="Install in VS Code Insiders"></a>
|
|
25
|
+
<a href="cursor://anysphere.cursor-deeplink/mcp/install?name=testrail&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyJ0cmFtLW1jcCJdLCJlbnYiOnsiVEVTVFJBSUxfVVJMIjoiIiwiVEVTVFJBSUxfVVNFUk5BTUUiOiIiLCJURVNUUkFJTF9BUElfS0VZIjoiIn19"><img src="https://img.shields.io/badge/Cursor-Install_Server-purple?style=flat-square&logo=cursor" alt="Install in Cursor"></a>
|
|
26
|
+
|
|
27
|
+
After installing, you will be prompted to fill in your TestRail credentials. See [Configuration](#configuration) below.
|
|
28
|
+
|
|
29
|
+
## Manual Installation
|
|
30
|
+
|
|
31
|
+
### Claude Desktop
|
|
32
|
+
|
|
33
|
+
Add to your Claude Desktop config file:
|
|
34
|
+
|
|
35
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
36
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"testrail": {
|
|
42
|
+
"command": "uvx",
|
|
43
|
+
"args": ["tram-mcp"],
|
|
44
|
+
"env": {
|
|
45
|
+
"TESTRAIL_URL": "https://yourinstance.testrail.io",
|
|
46
|
+
"TESTRAIL_USERNAME": "your-email@example.com",
|
|
47
|
+
"TESTRAIL_API_KEY": "your-api-key"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Claude Code
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
claude mcp add testrail \
|
|
58
|
+
-e TESTRAIL_URL=https://yourinstance.testrail.io \
|
|
59
|
+
-e TESTRAIL_USERNAME=your-email@example.com \
|
|
60
|
+
-e TESTRAIL_API_KEY=your-api-key \
|
|
61
|
+
-- uvx tram-mcp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### VS Code / VS Code Insiders
|
|
65
|
+
|
|
66
|
+
Create `.vscode/mcp.json` in your project (or add to your User Settings):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"servers": {
|
|
71
|
+
"testrail": {
|
|
72
|
+
"type": "stdio",
|
|
73
|
+
"command": "uvx",
|
|
74
|
+
"args": ["tram-mcp"],
|
|
75
|
+
"env": {
|
|
76
|
+
"TESTRAIL_URL": "",
|
|
77
|
+
"TESTRAIL_USERNAME": "",
|
|
78
|
+
"TESTRAIL_API_KEY": ""
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
VS Code supports `${input:variableName}` placeholders to prompt for values at startup.
|
|
86
|
+
|
|
87
|
+
### Cursor
|
|
88
|
+
|
|
89
|
+
Create `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"testrail": {
|
|
95
|
+
"command": "uvx",
|
|
96
|
+
"args": ["tram-mcp"],
|
|
97
|
+
"env": {
|
|
98
|
+
"TESTRAIL_URL": "https://yourinstance.testrail.io",
|
|
99
|
+
"TESTRAIL_USERNAME": "your-email@example.com",
|
|
100
|
+
"TESTRAIL_API_KEY": "your-api-key"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Configuration
|
|
108
|
+
|
|
109
|
+
The server requires TestRail credentials via environment variables:
|
|
110
|
+
|
|
111
|
+
| Variable | Required | Description |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `TESTRAIL_URL` | Yes | Your TestRail instance URL (e.g. `https://example.testrail.io`) |
|
|
114
|
+
| `TESTRAIL_USERNAME` | Yes | TestRail username or email |
|
|
115
|
+
| `TESTRAIL_API_KEY` | Yes* | TestRail API key |
|
|
116
|
+
| `TESTRAIL_PASSWORD` | Yes* | TestRail password (alternative to API key) |
|
|
117
|
+
|
|
118
|
+
*Either `TESTRAIL_API_KEY` or `TESTRAIL_PASSWORD` must be set. API key is recommended.
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Install dependencies
|
|
124
|
+
uv sync
|
|
125
|
+
|
|
126
|
+
# Run the server locally
|
|
127
|
+
uv run tram_mcp
|
|
128
|
+
|
|
129
|
+
# Run tests
|
|
130
|
+
uv run pytest
|
|
131
|
+
|
|
132
|
+
# Run a single test
|
|
133
|
+
uv run pytest path/to/test.py::test_name -v
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
tram_mcp-0.1.0/main.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tram-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server exposing TestRail API endpoints as tools for LLMs"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Matt Troutman", email = "git@trtmn.com" },
|
|
10
|
+
]
|
|
11
|
+
keywords = ["mcp", "testrail", "testing", "api", "llm", "model-context-protocol"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Software Development :: Testing",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"fastmcp>=2.12.4",
|
|
24
|
+
"python-dotenv>=1.1.1",
|
|
25
|
+
"testrail-api-module==0.7.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/trtmn/tram-mcp"
|
|
30
|
+
Repository = "https://github.com/trtmn/tram-mcp"
|
|
31
|
+
Issues = "https://github.com/trtmn/tram-mcp/issues"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = ["pytest"]
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["hatchling"]
|
|
38
|
+
build-backend = "hatchling.build"
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
tram_mcp = "tram_mcp:main"
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import MagicMock
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import tram_mcp.server as server
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture(autouse=True)
|
|
11
|
+
def _reset_client():
|
|
12
|
+
"""Reset the global _client before and after every test."""
|
|
13
|
+
server._client = None
|
|
14
|
+
yield
|
|
15
|
+
server._client = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def mock_client():
|
|
20
|
+
"""Provide a MagicMock wired into server._client with chained attr access."""
|
|
21
|
+
client = MagicMock()
|
|
22
|
+
server._client = client
|
|
23
|
+
return client
|