qBittorrent MCP has 10 tools with basic schemas and descriptions, but significant gaps limit production readiness. All tools have descriptions (10 - 200 chars, mostly adequate) and input schemas with types. However, descriptions lack actionable context for LLM selection (e.g., when to use qbt_list_torrents vs qbt_torrent_info). Parameters use free-form strings where enums would prevent hallucination (filter, sort, category). Output is unstructured text rather than JSON, forcing LLMs to parse and extract fields. Error handling is absent, no guidance on retries, user-fixable errors, or recovery paths. No tool annotations (readOnlyHint, destructiveHint) despite clear risk levels. Destructive tools (qbt_delete_torrents) lack confirmation patterns. Parameter relationships undocumented (e.g., hashes format 'pipe-separated' is mentioned but not validated). Overall: functional but below production baseline.
Add one or more torrents to qBittorrent. Args: urls: Magnet or HTTP URLs, separated by newlines torrent_files: Local file paths to .torrent files, separated by newlines savepath: Download save path (overrides default) category: Category to assign tags: Comma-separated tags paused: Add in paused state skip_checking: Skip hash checking
Add trackers to one or more torrents. Args: hashes: Torrent hash(es), pipe-separated urls: Tracker URLs, one per line
Delete one or more torrents. Args: hashes: Torrent hash(es), pipe-separated (use 'all' for all torrents) delete_files: Also delete downloaded files
List torrents in qBittorrent. Args: filter: Filter by state - all, downloading, completed, paused, active, inactive, resumed, stalled, stalled_uploading, stalled_downloading category: Filter by category name sort: Sort by field (e.g. name, added_on, size, progress, dlspeed, upspeed, ratio) reverse: Reverse sort order search: Filter by torrent name
Pause one or more torrents. Args: hashes: Torrent hash(es), pipe-separated (use 'all' for all torrents)
No enum constraints on filter, sort, category parameters. Free-form strings invite hallucinated values (e.g., 'filter: invalid_state'). qbt_list_torrents accepts filter values like 'downloading|completed|paused' but does not declare them as an enum.
Output is unstructured plain text (e.g., 'Found 5 torrent(s):\n name | state | progress...') instead of JSON. LLMs must parse text to extract fields, wasting tokens and risking extraction errors. No documented output schema.
Destructive tool qbt_delete_torrents lacks confirmation or dry-run pattern. No guidance on recovery if agent makes a mistake. Descriptions do not warn of irreversibility.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 53 | 2026-07-28+ | v2 |
Resume one or more torrents. Args: hashes: Torrent hash(es), pipe-separated (use 'all' for all torrents)
Set category for one or more torrents. Args: hashes: Torrent hash(es), pipe-separated category: Category name
List files within a torrent. Args: hash: Torrent hash
Get detailed info for a specific torrent. Args: hash: Torrent hash
List trackers for a torrent. Args: hash: Torrent hash
No error handling or recovery guidance. Tools return raw API responses (e.g., 'Ok.' or HTTP status) without context. LLMs cannot determine if a failure is retryable, user-fixable, or fatal.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Risk levels are documented in the rubric but not exposed to the MCP client, limiting safety guardrails.