Skip to main content
Glama
revelri

lutris-source-mcp

by revelri
README.md
# lutris-source-mcp

Source pipeline MCP for [`lutris-mcp`](https://github.com/revelri/lutris-mcp).
Closes the *find -> download -> install* loop: searches Prowlarr, hands off
to qBittorrent, polls until done, classifies the resulting tree, returns a
path that lutris-mcp's `install_from_yaml` or `install_from_directory`
consumes directly.

## Tools

| Tool | What it does |
| --- | --- |
| `prepare_install_source(query, ...)` | The composite. Search → grab → poll → classify → return path. mutates: true |
| `cancel_pipeline(infohash)` | Abort an in-flight grab. mutates: true |
| `stop_seeding(infohash)` | Remove from qBittorrent without deleting on-disk files. mutates: true |
| `pipeline_health()` | Verify Prowlarr + qBittorrent reachable; surface configured indexers. mutates: false |
| `setup(...)` | Write `~/.config/lutris-source-mcp/config.toml` (first-run). mutates: true |

## Multi-tracker ranking

Prowlarr aggregates public (1337x, TPB, etc.) and private (Gazelle: RED, OPS,
GGn) trackers in one search. The composite ranks across them with this key:

```
(indexer_priority,                          # 1 = highest, 50 = lowest
 freeleech_first if freeleech_only else 0,
 -seeders,
 size_bytes)                                # smaller wins as tiebreak
```

`indexer_priority` comes from the Prowlarr indexer's `priority` field — set
it in Prowlarr's UI per tracker (e.g. private = 1, public = 25). The MCP
respects it rather than inventing a separate trust ranking.

### Gazelle hygiene

Pass `freeleech_only=True` (or set `policy.freeleech_only = true` in TOML)
to drop non-freeleech results from Gazelle indexers before ranking. Public
results pass through unchanged (freeleech is meaningless there). Auth
itself stays in Prowlarr's UI; the MCP never sees Gazelle credentials.

## Stall detection

Each poll prints a stdout heartbeat:

```
[prepare_install_source] deadbeef dl=12345/100000 (12.3%) peers=8 rate=215.4KiB/s elapsed=14s
```

If `downloaded` doesn't increase for `stall_timeout_seconds` (default 5min),
the tool returns `{ok: false, reason: "stalled"}` so the agent can pick
another candidate.

## Config

`~/.config/lutris-source-mcp/config.toml`:

```toml
[prowlarr]
base_url = "http://localhost:9696"
api_key  = "..."

[qbittorrent]
base_url     = "http://localhost:8080"
username     = "admin"
password     = "..."
download_dir = "/mnt/games/Downloads"

[policy]
blocklist      = ["fitgirl"]
allow_indexers = []
max_size_gb    = 50
freeleech_only = false
min_seeders    = 1
```

Every key has a `LUTRIS_SOURCE_MCP_<SECTION>_<KEY>` env override
(e.g. `LUTRIS_SOURCE_MCP_PROWLARR_API_KEY`, `LUTRIS_SOURCE_MCP_POLICY_FREELEECH_ONLY`).

## Companions

For read-only Prowlarr/qBittorrent inspection, install
[`jmagar/prowlarr-mcp`](https://github.com/jmagar/prowlarr-mcp) and
[`pickpppcc/qbittorrent-mcp`](https://github.com/pickpppcc/qbittorrent-mcp)
alongside. Three small focused servers, no overlap.

## License

MIT.

TDQS

B3.4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: cancel_pipeline stops a torrent, pipeline_health checks connectivity, prepare_install_source handles full search and download, setup writes config, and stop_seeding stops seeding without deletion. No ambiguity between them.

Naming Consistency4/5

Tools use snake_case and mostly follow a verb_noun pattern (e.g., cancel_pipeline, prepare_install_source). However, 'setup' is a single verb and 'pipeline_health' is noun_noun, introducing minor inconsistency.

Tool Count5/5

With 5 tools, the set is well-scoped for a source management server. Each tool covers an essential operation without bloat or deficiency.

Completeness4/5

The tool surface covers core workflows: setup, health check, download/prepare, cancellation, and seeding control. Minor gaps like listing pipelines or updating config exist but are not critical for the intended use.