torrent-mcp
# torrent-mcp
A personal movie/series torrent-queue pipeline — IMDb list scraping, OMDb
title lookups, Jackett search, and qBittorrent RSS queue management — as a
tested Python library, a CLI, and an [MCP](https://modelcontextprotocol.io)
server so a natural-language client (a Telegram bot, Claude Desktop, etc.)
can drive the whole thing in plain English.
This replaces a folder of ad hoc scripts (`B6_imdb-torrents/`) that each
hardcoded one person's Jackett API key, OMDb key, LAN IP, and `/home/b/...`
paths directly in source. All of that is now environment configuration —
see `.env.sample` — so the code itself has nothing sensitive in it.
## What it does
| Area | CLI command(s) | MCP tool(s) |
|---|---|---|
| Find candidate titles from an IMDb list page | `find-candidates` | `find_imdb_candidates` |
| Check IMDb ids against what's already queued (and, optionally, a Plex export) | `check-candidates` | `check_candidates` |
| Add/remove/list a queue's `feeds.json` entries | `add-to-queue`, `remove-from-queue`, `list-queue` | `add_to_queue`, `remove_from_queue`, `list_queue` |
| Repoint a queue at a different Jackett indexer | `switch-indexer` | `switch_indexer` |
| Jackett indexer discovery & search | `list-indexers`, `check-imdb-support`, `search`, `find-largest` | `list_indexers`, `check_imdb_search_support`, `search_torrents`, `find_largest_torrent` |
| OMDb title lookups | `lookup`, `search-title`, `identify-file` | `lookup_title`, `search_title`, `identify_title` |
| Library maintenance | `find-duplicates`, `diff-urls`, `archive-downloads`, `backup-queue` | `find_duplicate_filenames`, `diff_missing_urls`, `archive_downloads`, `backup_queue` |
`list_profiles` (MCP only) reports which queue profiles are configured.
## Install
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e .
```
Copy `.env.sample` to `.env` and fill in your own `OMDB_API_KEY`,
`JACKETT_URL`/`JACKETT_API_KEY`, and `TORRENT_MCP_PROFILES` (one entry per
qBittorrent+Jackett RSS queue — movies, series, upgrades, ...). See the
comments in `.env.sample` for every setting.
## CLI
```bash
torrent-mcp find-candidates "https://www.imdb.com/list/ls0123456789/"
torrent-mcp check-candidates movies tt1375666 tt0111161
torrent-mcp add-to-queue movies tt1375666 --indexer yts
torrent-mcp list-queue movies --resolve-titles
torrent-mcp switch-indexer movies yts torrentgalaxy
torrent-mcp lookup tt1375666
torrent-mcp --help # full command list
```
## MCP server
```bash
torrent-mcp-server
```
Runs over stdio, ready for any MCP client (Claude Desktop, the MCP
Inspector, a custom client) to spawn as a subprocess. Example
`claude_desktop_config.json` entry:
```json
{
"mcpServers": {
"torrent-mcp": {
"command": "/absolute/path/to/.venv/bin/torrent-mcp-server",
"env": { "OMDB_API_KEY": "...", "JACKETT_API_KEY": "...", "...": "..." }
}
}
}
```
### Integration with ocabra_telegram
[ocabra_telegram](https://github.com/luisriverag/ocabra_telegram) drives
this server the same way it already drives
[homebox_mcp](https://github.com/luisriverag/homebox_mcp) — over stdio via
a small JSON-RPC client (`homebox_tools.McpStdioClient`, reused as-is by
its `torrent_tools.py`) and `bot.py`'s `call_ocabra_with_tools` tool-calling
loop, which now runs over whichever backends (Homebox, torrent-mcp, both)
are active for the current user. See that repo's README, "Torrent Queue
Integration", for the `TORRENT_MCP_*` env vars to set there. Once wired,
Telegram messages like *"what's queued for movies?"* or *"add tt1375666 to
the movies queue"* drive this project directly — this project only owns
the MCP server side; the client-side wiring lives in `ocabra_telegram`.
## Development
```bash
pip install -e ".[dev]"
pytest
```
Tests mock all external HTTP (OMDb, Jackett, IMDb) with
[`respx`](https://github.com/lundberg/respx) and use `tmp_path` for
filesystem operations — nothing touches the network or a real queue.
## Notes on the original scripts
- `manage_queue/queue_get-titles.py` used `imdbpy` to scrape IMDb directly
for titles; this project uses OMDb everywhere instead (already needed
for other lookups), so there's one metadata dependency, not two.
- The ten near-identical `switchindexer_*.sh` scripts (one hardcoded
path + container per direction) are now one `switch-indexer` command
parameterized by profile and indexer names.
- `trackers/check_imdbsearch.py` logged into Jackett's dashboard with an
admin password before calling its API; the API calls it made only ever
needed the API key, so that login step (and the password) is gone.
- Nothing here runs `sudo` or shells out to `docker` unless
`DOCKER_RESTART_ENABLED=true`, and then only for a container name from
your own `TORRENT_MCP_PROFILES` config — never a name supplied through a
tool call.
TDQS
Scored across 18 tools
Most tools are clearly separated by object (profiles, queue entries, indexers, titles, files), and descriptions specify exact inputs and outputs. The main potential confusion is between lookup_title/search_title/identify_title and search_torrents/find_largest_torrent, but their boundary conditions are stated clearly enough.
Every tool uses a consistent snake_case, imperative verb-first naming pattern such as list, add, remove, search, find, or check. Even longer names like check_imdb_search_support and find_duplicate_filenames follow the same convention, making the set predictable.
At 18 tools, this is slightly above the typical sweet spot, but the server spans queue management, indexer operations, metadata resolution, and media-file housekeeping. Each tool maps to a distinct operation, so the count feels broad rather than redundant.
The core pipeline—finding IMDb candidates, checking them against the queue/Plex, adding and removing queue entries, searching indexers, and archiving downloads—is well covered. Minor gaps such as profile creation/deletion and directly adding a found torrent to qBittorrent exist but can be worked around with the available tools.