miqa-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.
@@ -0,0 +1,9 @@
1
+ # python build + env artifacts (this dir is intentionally not a git repo yet,
2
+ # but keeping this here means a later `git init` stays clean).
3
+ .venv/
4
+ *.egg-info/
5
+ __pycache__/
6
+ *.pyc
7
+ dist/
8
+ build/
9
+ .pytest_cache/
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: miqa-mcp
3
+ Version: 0.1.0
4
+ Summary: MIQA MCP Server
5
+ Author: MIQA / Magna Labs
6
+ License: MIT
7
+ Keywords: claude,fastmcp,mcp,miqa
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: fastmcp>=2.0
10
+ Requires-Dist: miqatools>=2.0.0rc0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=8.0; extra == 'dev'
13
+ Description-Content-Type: text/markdown
14
+
15
+ # MIQA MCP
16
+
17
+ A read-only MCP server built with FastMCP. It exposes MIQA test-reporting data to
18
+ Claude Code (and any MCP client) over stdio. It is a thin MCP surface on top of the
19
+ [`miqatools`](../magna-cli) library: the tools call `miqatools`' read-only reporting
20
+ wrappers, which resolve credentials and talk to the MIQA v2 REST API.
21
+
22
+ The packaging shape — a console script that runs a stdio `main()`, configured via
23
+ environment variables — is what makes it registerable with `claude mcp add`.
24
+
25
+ Tools exposed (all READ-ONLY; none mutate MIQA state):
26
+
27
+ - `find_runs_by_version(version_name: str, limit: int = 100) -> list` — find Test
28
+ Chain Runs for a version name (newest-first; empty list if none match).
29
+ - `get_test_run(run_id: int, sample_ds_id: int | None = None) -> dict` — JSON details
30
+ for a single Test Chain Run (optionally narrowed to one sample).
31
+ - `get_test_run_results(run_id: int, sample_ds_id: int | None = None)` — the
32
+ assertion/result summary table (JSON or CSV depending on the server).
33
+ - `get_test_run_report(run_id: int, sample_ds_id: int | None = None, format="json")` —
34
+ the sample-centric structured report (feature-flag gated on the server).
35
+
36
+ Built on the standalone `fastmcp` package (jlowin). Requires Python >= 3.10.
37
+
38
+ ## Configuration
39
+
40
+ The server reads its MIQA credentials from environment variables (resolved by the
41
+ `miqatools` client):
42
+
43
+ - `MIQA_SERVER_URL` — MIQA server hostname (e.g. `yourco.miqa.io`).
44
+ - `MIQA_API_KEY` — MIQA API key.
45
+
46
+ Claude Code injects these into the server subprocess via the `--env` block (see
47
+ "Register with Claude Code" below).
48
+
49
+ ## Prerequisite: install miqatools first (not yet on PyPI)
50
+
51
+ This server depends on `miqatools>=2.0.0rc0`, which is **not yet published to PyPI**.
52
+ Until it is, install `miqatools` from its local checkout first (editable), then install
53
+ this server:
54
+
55
+ ```
56
+ pip install -e ../magna-cli # the miqatools library
57
+ pip install -e . # this server
58
+ ```
59
+
60
+ Once `miqatools` is published, `pip install .` (or `uvx miqa-mcp`) will resolve it from
61
+ PyPI automatically and this extra step goes away.
62
+
63
+ ---
64
+
65
+ ## 1. Install options
66
+
67
+ Because `miqatools` is not yet on PyPI (see "Prerequisite" above), install it locally
68
+ first, then install this server. A plain virtualenv with editable installs is best while
69
+ `miqatools` is unpublished:
70
+
71
+ ```
72
+ python -m venv .venv
73
+ .venv/bin/pip install -e ../magna-cli # miqatools (the library dependency)
74
+ .venv/bin/pip install -e . # this server
75
+ ```
76
+
77
+ The console script then lives at `.venv/bin/miqa-mcp`. It starts and waits silently on
78
+ stdin — that is correct: it is a stdio MCP server waiting for a client to speak the
79
+ protocol. Press Ctrl-C to stop; you normally let Claude Code launch it rather than running
80
+ it by hand.
81
+
82
+ ### Eventual published form
83
+
84
+ Once both `miqatools` and this server are published to PyPI, the local-editable dance
85
+ collapses to a normal install (dependencies resolve automatically):
86
+
87
+ ```
88
+ uvx miqa-mcp # ephemeral
89
+ pipx install miqa-mcp
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 2. Register with Claude Code
95
+
96
+ `claude mcp add <name> [flags] -- <command> [args...]` registers a stdio server. Claude
97
+ Code launches `<command>` as a subprocess and speaks MCP over its stdin/stdout. The `--`
98
+ separates Claude's own flags from the subprocess command line.
99
+
100
+ Since `miqatools` is unpublished, install into a venv (see above) so `miqa-mcp` is on the
101
+ venv's PATH, then register that console script — passing MIQA credentials via `--env`:
102
+
103
+ ```
104
+ claude mcp add miqa-mcp \
105
+ --env MIQA_SERVER_URL=yourco.miqa.io \
106
+ --env MIQA_API_KEY=your-key-here \
107
+ -- /absolute/path/to/.venv/bin/miqa-mcp
108
+ ```
109
+
110
+ If `miqa-mcp` is already on your PATH (activated venv or pipx install), the command is just
111
+ the script name:
112
+
113
+ ```
114
+ claude mcp add miqa-mcp --env MIQA_SERVER_URL=yourco.miqa.io --env MIQA_API_KEY=your-key-here -- miqa-mcp
115
+ ```
116
+
117
+ ### Passing configuration via env
118
+
119
+ A stdio server cannot receive HTTP headers, so its configuration is passed as environment
120
+ variables, which Claude Code injects into the subprocess. Use `--env KEY=value` (short form
121
+ `-e KEY=value`), and put it before the `--` so it is read as one of Claude's own flags.
122
+
123
+ This server reads `MIQA_SERVER_URL` and `MIQA_API_KEY` from its environment (the
124
+ `miqatools` client resolves them), so both must be passed via `--env`:
125
+
126
+ ```
127
+ claude mcp add miqa-mcp --env MIQA_SERVER_URL=yourco.miqa.io --env MIQA_API_KEY=your-key-here -- /absolute/path/to/.venv/bin/miqa-mcp
128
+ ```
129
+
130
+ Repeat `--env` for each variable. This env-block mechanism is the stdio equivalent of the
131
+ `--header` flag that HTTP-transport servers use; stdio servers get their config through env,
132
+ not headers.
133
+
134
+ By default the server is registered at `local` scope (this project only). Add
135
+ `--scope user` to make it available across all your projects.
136
+
137
+ ---
138
+
139
+ ## 3. Verify
140
+
141
+ List registered servers — `miqa-mcp` should appear, and Claude Code will have started it
142
+ and confirmed the connection:
143
+
144
+ ```
145
+ claude mcp list
146
+ ```
147
+
148
+ You can also inspect just this one:
149
+
150
+ ```
151
+ claude mcp get miqa-mcp
152
+ ```
153
+
154
+ Inside a Claude Code session, the tools surface as `find_runs_by_version`, `get_test_run`,
155
+ `get_test_run_results`, and `get_test_run_report`. With valid `MIQA_SERVER_URL` /
156
+ `MIQA_API_KEY` in the env, ask the session to find runs for a version name and it will call
157
+ the MIQA API through the server.
158
+
159
+ ---
160
+
161
+ ## 4. Remove
162
+
163
+ ```
164
+ claude mcp remove miqa-mcp
165
+ ```
166
+
167
+ If you installed with pipx and want to uninstall the package too:
168
+
169
+ ```
170
+ pipx uninstall miqa-mcp
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 5. Run the tests
176
+
177
+ The test suite asserts the four tools register on the FastMCP instance and that each
178
+ delegates to the corresponding `miqatools` wrapper (the wrappers are mocked, so no network
179
+ is touched). Install `miqatools` first, then this package with its dev extra:
180
+
181
+ ```
182
+ .venv/bin/pip install -e ../magna-cli
183
+ .venv/bin/pip install -e '.[dev]'
184
+ .venv/bin/pytest
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 6. How this fits together
190
+
191
+ This server is a thin, read-only MCP surface; all MIQA client logic lives in the
192
+ `miqatools` library. The reporting wrappers (`find_tcrs_by_version`, `get_tcr_summary`,
193
+ `get_tcr_report`) and the existing `get_tcr_info_json` helper stay in `miqatools` as client
194
+ code; this repo only adds the FastMCP tools and the stdio entry point. The packaging shape —
195
+ console script -> stdio `main()` -> env-based config (`MIQA_SERVER_URL`, `MIQA_API_KEY`) — is
196
+ what `claude mcp add` launches.
@@ -0,0 +1,182 @@
1
+ # MIQA MCP
2
+
3
+ A read-only MCP server built with FastMCP. It exposes MIQA test-reporting data to
4
+ Claude Code (and any MCP client) over stdio. It is a thin MCP surface on top of the
5
+ [`miqatools`](../magna-cli) library: the tools call `miqatools`' read-only reporting
6
+ wrappers, which resolve credentials and talk to the MIQA v2 REST API.
7
+
8
+ The packaging shape — a console script that runs a stdio `main()`, configured via
9
+ environment variables — is what makes it registerable with `claude mcp add`.
10
+
11
+ Tools exposed (all READ-ONLY; none mutate MIQA state):
12
+
13
+ - `find_runs_by_version(version_name: str, limit: int = 100) -> list` — find Test
14
+ Chain Runs for a version name (newest-first; empty list if none match).
15
+ - `get_test_run(run_id: int, sample_ds_id: int | None = None) -> dict` — JSON details
16
+ for a single Test Chain Run (optionally narrowed to one sample).
17
+ - `get_test_run_results(run_id: int, sample_ds_id: int | None = None)` — the
18
+ assertion/result summary table (JSON or CSV depending on the server).
19
+ - `get_test_run_report(run_id: int, sample_ds_id: int | None = None, format="json")` —
20
+ the sample-centric structured report (feature-flag gated on the server).
21
+
22
+ Built on the standalone `fastmcp` package (jlowin). Requires Python >= 3.10.
23
+
24
+ ## Configuration
25
+
26
+ The server reads its MIQA credentials from environment variables (resolved by the
27
+ `miqatools` client):
28
+
29
+ - `MIQA_SERVER_URL` — MIQA server hostname (e.g. `yourco.miqa.io`).
30
+ - `MIQA_API_KEY` — MIQA API key.
31
+
32
+ Claude Code injects these into the server subprocess via the `--env` block (see
33
+ "Register with Claude Code" below).
34
+
35
+ ## Prerequisite: install miqatools first (not yet on PyPI)
36
+
37
+ This server depends on `miqatools>=2.0.0rc0`, which is **not yet published to PyPI**.
38
+ Until it is, install `miqatools` from its local checkout first (editable), then install
39
+ this server:
40
+
41
+ ```
42
+ pip install -e ../magna-cli # the miqatools library
43
+ pip install -e . # this server
44
+ ```
45
+
46
+ Once `miqatools` is published, `pip install .` (or `uvx miqa-mcp`) will resolve it from
47
+ PyPI automatically and this extra step goes away.
48
+
49
+ ---
50
+
51
+ ## 1. Install options
52
+
53
+ Because `miqatools` is not yet on PyPI (see "Prerequisite" above), install it locally
54
+ first, then install this server. A plain virtualenv with editable installs is best while
55
+ `miqatools` is unpublished:
56
+
57
+ ```
58
+ python -m venv .venv
59
+ .venv/bin/pip install -e ../magna-cli # miqatools (the library dependency)
60
+ .venv/bin/pip install -e . # this server
61
+ ```
62
+
63
+ The console script then lives at `.venv/bin/miqa-mcp`. It starts and waits silently on
64
+ stdin — that is correct: it is a stdio MCP server waiting for a client to speak the
65
+ protocol. Press Ctrl-C to stop; you normally let Claude Code launch it rather than running
66
+ it by hand.
67
+
68
+ ### Eventual published form
69
+
70
+ Once both `miqatools` and this server are published to PyPI, the local-editable dance
71
+ collapses to a normal install (dependencies resolve automatically):
72
+
73
+ ```
74
+ uvx miqa-mcp # ephemeral
75
+ pipx install miqa-mcp
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 2. Register with Claude Code
81
+
82
+ `claude mcp add <name> [flags] -- <command> [args...]` registers a stdio server. Claude
83
+ Code launches `<command>` as a subprocess and speaks MCP over its stdin/stdout. The `--`
84
+ separates Claude's own flags from the subprocess command line.
85
+
86
+ Since `miqatools` is unpublished, install into a venv (see above) so `miqa-mcp` is on the
87
+ venv's PATH, then register that console script — passing MIQA credentials via `--env`:
88
+
89
+ ```
90
+ claude mcp add miqa-mcp \
91
+ --env MIQA_SERVER_URL=yourco.miqa.io \
92
+ --env MIQA_API_KEY=your-key-here \
93
+ -- /absolute/path/to/.venv/bin/miqa-mcp
94
+ ```
95
+
96
+ If `miqa-mcp` is already on your PATH (activated venv or pipx install), the command is just
97
+ the script name:
98
+
99
+ ```
100
+ claude mcp add miqa-mcp --env MIQA_SERVER_URL=yourco.miqa.io --env MIQA_API_KEY=your-key-here -- miqa-mcp
101
+ ```
102
+
103
+ ### Passing configuration via env
104
+
105
+ A stdio server cannot receive HTTP headers, so its configuration is passed as environment
106
+ variables, which Claude Code injects into the subprocess. Use `--env KEY=value` (short form
107
+ `-e KEY=value`), and put it before the `--` so it is read as one of Claude's own flags.
108
+
109
+ This server reads `MIQA_SERVER_URL` and `MIQA_API_KEY` from its environment (the
110
+ `miqatools` client resolves them), so both must be passed via `--env`:
111
+
112
+ ```
113
+ claude mcp add miqa-mcp --env MIQA_SERVER_URL=yourco.miqa.io --env MIQA_API_KEY=your-key-here -- /absolute/path/to/.venv/bin/miqa-mcp
114
+ ```
115
+
116
+ Repeat `--env` for each variable. This env-block mechanism is the stdio equivalent of the
117
+ `--header` flag that HTTP-transport servers use; stdio servers get their config through env,
118
+ not headers.
119
+
120
+ By default the server is registered at `local` scope (this project only). Add
121
+ `--scope user` to make it available across all your projects.
122
+
123
+ ---
124
+
125
+ ## 3. Verify
126
+
127
+ List registered servers — `miqa-mcp` should appear, and Claude Code will have started it
128
+ and confirmed the connection:
129
+
130
+ ```
131
+ claude mcp list
132
+ ```
133
+
134
+ You can also inspect just this one:
135
+
136
+ ```
137
+ claude mcp get miqa-mcp
138
+ ```
139
+
140
+ Inside a Claude Code session, the tools surface as `find_runs_by_version`, `get_test_run`,
141
+ `get_test_run_results`, and `get_test_run_report`. With valid `MIQA_SERVER_URL` /
142
+ `MIQA_API_KEY` in the env, ask the session to find runs for a version name and it will call
143
+ the MIQA API through the server.
144
+
145
+ ---
146
+
147
+ ## 4. Remove
148
+
149
+ ```
150
+ claude mcp remove miqa-mcp
151
+ ```
152
+
153
+ If you installed with pipx and want to uninstall the package too:
154
+
155
+ ```
156
+ pipx uninstall miqa-mcp
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 5. Run the tests
162
+
163
+ The test suite asserts the four tools register on the FastMCP instance and that each
164
+ delegates to the corresponding `miqatools` wrapper (the wrappers are mocked, so no network
165
+ is touched). Install `miqatools` first, then this package with its dev extra:
166
+
167
+ ```
168
+ .venv/bin/pip install -e ../magna-cli
169
+ .venv/bin/pip install -e '.[dev]'
170
+ .venv/bin/pytest
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 6. How this fits together
176
+
177
+ This server is a thin, read-only MCP surface; all MIQA client logic lives in the
178
+ `miqatools` library. The reporting wrappers (`find_tcrs_by_version`, `get_tcr_summary`,
179
+ `get_tcr_report`) and the existing `get_tcr_info_json` helper stay in `miqatools` as client
180
+ code; this repo only adds the FastMCP tools and the stdio entry point. The packaging shape —
181
+ console script -> stdio `main()` -> env-based config (`MIQA_SERVER_URL`, `MIQA_API_KEY`) — is
182
+ what `claude mcp add` launches.
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "miqa-mcp"
7
+ version = "0.1.0"
8
+ description = "MIQA MCP Server"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "MIQA / Magna Labs" }]
13
+ keywords = ["mcp", "fastmcp", "claude", "miqa"]
14
+ dependencies = [
15
+ "fastmcp>=2.0",
16
+ "miqatools>=2.0.0rc0",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ dev = [
21
+ "pytest>=8.0",
22
+ ]
23
+
24
+ [project.scripts]
25
+ miqa-mcp = "miqa_mcp.server:main"
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["src/miqa_mcp"]
@@ -0,0 +1,11 @@
1
+ """MIQA MCP — a read-only FastMCP server over the miqatools client."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("miqa-mcp")
7
+ except PackageNotFoundError:
8
+ # running from a source checkout that was never installed.
9
+ __version__ = "0.0.0+source"
10
+
11
+ __all__ = ["__version__"]
@@ -0,0 +1,92 @@
1
+ """MIQA MCP server - a FastMCP surface over the miqatools client"""
2
+
3
+ from typing import Optional
4
+
5
+ from fastmcp import FastMCP
6
+
7
+ from miqatools.reporting import (
8
+ find_tcrs_by_version,
9
+ get_tcr_report,
10
+ get_tcr_summary,
11
+ )
12
+ from miqatools.remoteexecution.triggertest_helpers import get_tcr_info_json
13
+
14
+ mcp = FastMCP("miqa-mcp")
15
+
16
+
17
+ @mcp.tool
18
+ def find_runs_by_version(version_name: str, limit: int = 100) -> list:
19
+ """Find Miqa Test Chain Runs for a given version name.
20
+
21
+ Results are newest-first. Returns an empty list when nothing matches.
22
+
23
+ Args:
24
+ version_name: The version identifier to search for (e.g. "bcftools:1.4.1").
25
+ limit: Maximum number of runs to return (default 100).
26
+
27
+ Returns:
28
+ A list of run summary dicts, each including id, testchain_id,
29
+ testchain_name, status, outcome, version_name, start and end.
30
+ """
31
+ return find_tcrs_by_version(version_name=version_name, limit=limit)
32
+
33
+
34
+ @mcp.tool
35
+ def get_test_run(run_id: int, sample_ds_id: Optional[int] = None) -> dict:
36
+ """Get JSON details describing a single Miqa Test Chain Run.
37
+
38
+ Args:
39
+ run_id: The Miqa Test Chain Run ID.
40
+ sample_ds_id: Optional Datasource (sample) ID to narrow the details to
41
+ a single sample within the run.
42
+
43
+ Returns:
44
+ A dict describing the Test Chain Run.
45
+ """
46
+ return get_tcr_info_json(run_id, ds_id=sample_ds_id)
47
+
48
+
49
+ @mcp.tool
50
+ def get_test_run_results(run_id: int, sample_ds_id: Optional[int] = None):
51
+ """Get the assertion/result summary table for a Miqa Test Chain Run.
52
+
53
+ The response may be JSON (dict/list) or CSV/plain text depending on the
54
+ server configuration.
55
+
56
+ Args:
57
+ run_id: The Miqa Test Chain Run ID.
58
+ sample_ds_id: Optional Datasource (sample) ID to narrow the summary to
59
+ a single sample.
60
+
61
+ Returns:
62
+ Parsed JSON when the server returns JSON, otherwise the raw text body
63
+ (e.g. CSV).
64
+ """
65
+ return get_tcr_summary(run_id, ds_id=sample_ds_id)
66
+
67
+
68
+ @mcp.tool
69
+ def get_test_run_report(run_id: int, sample_ds_id: Optional[int] = None, format: str = "json"):
70
+ """Get the sample-centric structured report for a Miqa Test Chain Run.
71
+
72
+ This report is gated by a server feature flag; if it is disabled the call
73
+ raises an error and the caller should fall back to get_test_run_results.
74
+
75
+ Args:
76
+ run_id: The Miqa Test Chain Run ID.
77
+ sample_ds_id: Optional Datasource (sample) ID to narrow the report to a
78
+ single sample.
79
+ format: Report mode; "json" (default) returns structured JSON.
80
+
81
+ Returns:
82
+ The structured report (JSON) as returned by the server.
83
+ """
84
+ return get_tcr_report(run_id, mode=format, ds_id=sample_ds_id)
85
+
86
+
87
+ def main() -> None:
88
+ mcp.run()
89
+
90
+
91
+ if __name__ == "__main__":
92
+ main()
@@ -0,0 +1,68 @@
1
+ import pytest
2
+
3
+ # The server depends on fastmcp (and miqatools); skip if fastmcp is absent.
4
+ pytest.importorskip("fastmcp")
5
+
6
+ from miqa_mcp import server # noqa: E402
7
+
8
+
9
+ EXPECTED_TOOLS = {
10
+ "find_runs_by_version",
11
+ "get_test_run",
12
+ "get_test_run_results",
13
+ "get_test_run_report",
14
+ }
15
+
16
+
17
+ def _registered_tool_names():
18
+ """Return the set of registered tool names across fastmcp versions.
19
+
20
+ FastMCP exposes registered tools via an (async) ``list_tools()`` /
21
+ ``get_tools()`` API; handle both coroutine and sync return values.
22
+ """
23
+ import asyncio
24
+ import inspect
25
+
26
+ mcp = server.mcp
27
+ lister = getattr(mcp, "list_tools", None) or getattr(mcp, "get_tools", None)
28
+ assert lister is not None, "Could not introspect registered FastMCP tools"
29
+
30
+ tools = lister()
31
+ if inspect.iscoroutine(tools):
32
+ tools = asyncio.run(tools)
33
+
34
+ if isinstance(tools, dict):
35
+ return set(tools.keys())
36
+ return {t.name for t in tools}
37
+
38
+
39
+ def test_exactly_four_read_tools_registered():
40
+ names = _registered_tool_names()
41
+ # Exactly the four read tools — no mutating tools, no leftover demo tools.
42
+ assert names == EXPECTED_TOOLS
43
+
44
+
45
+ def test_main_calls_run(monkeypatch):
46
+ called = {}
47
+ monkeypatch.setattr(server.mcp, "run", lambda *a, **k: called.setdefault("ran", True))
48
+ server.main()
49
+ assert called.get("ran") is True
50
+
51
+
52
+ def test_tools_delegate_to_miqatools_wrappers(monkeypatch):
53
+ """Each tool delegates to the corresponding miqatools wrapper (no network)."""
54
+ monkeypatch.setattr(server, "find_tcrs_by_version", lambda version_name, limit=100: ["run"])
55
+ monkeypatch.setattr(server, "get_tcr_info_json", lambda run_id, ds_id=None: {"id": run_id})
56
+ monkeypatch.setattr(server, "get_tcr_summary", lambda run_id, ds_id=None: "summary")
57
+ monkeypatch.setattr(
58
+ server, "get_tcr_report", lambda run_id, mode="json", ds_id=None: {"mode": mode}
59
+ )
60
+
61
+ # FastMCP may wrap the function; unwrap via .fn when present.
62
+ def _fn(tool_obj):
63
+ return getattr(tool_obj, "fn", tool_obj)
64
+
65
+ assert _fn(server.find_runs_by_version)("bcftools:1.4.1") == ["run"]
66
+ assert _fn(server.get_test_run)(1386) == {"id": 1386}
67
+ assert _fn(server.get_test_run_results)(1386) == "summary"
68
+ assert _fn(server.get_test_run_report)(1386) == {"mode": "json"}