qbt-kit
Provides tools for interacting with the qBittorrent WebUI API, enabling agents to manage torrents, categories, RSS feeds, search, transfers, application settings, logs, and sync data. Includes safety controls such as confirmation for destructive actions, read-only mode, and guarded raw endpoint access.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
qbt-kit
A complete, typed Python client for the qBittorrent WebUI API — with a CLI that covers every endpoint one-to-one, and an MCP server so coding agents can drive it without deleting your data.
$ qbt coverage
qbt-kit coverage — target release-5.2.3
scope n spec progress
torrents 61 61 ████████████████████ 61/61
app 16 16 ████████████████████ 16/16
rss 14 14 ████████████████████ 14/14
search 11 11 ████████████████████ 11/11
transfer 9 9 ████████████████████ 9/9
torrentcreator 4 4 ████████████████████ 4/4
auth 2 2 ████████████████████ 2/2
clientdata 2 2 ████████████████████ 2/2
log 2 2 ████████████████████ 2/2
sync 2 2 ████████████████████ 2/2
----
TOTAL 123 123 ████████████████████ 100.0%Highlights
All 123 endpoints of qBittorrent 5.2.3, each one a spec entry that generates the client method, the CLI command and the docs together.
A verifiable coverage claim. The endpoint list is extracted from the qBittorrent C++ source per release tag and committed, so CI fails both when the spec misses an endpoint and when it invents one.
An MCP server with 15 tools — 13 task-shaped, plus
qbt_callandlist_endpoints— and safety gates that hold even through the escape hatch.Compatibility measured, not assumed — tested against real 4.6, 5.0, 5.1 and 5.2 containers, with a rename table so
torrents/stopresolves topauseon servers that predate the rename.Typed throughout, no runtime dependency beyond
httpxandtyper.
That coverage claim is worth a sentence of context. The wiki page most clients
are written against documents 78 endpoints. qBittorrent 5.2.3 ships
123, and two whole scopes — torrentcreator and clientdata — appear in
no wiki page at all.
Related MCP server: qBittorrent MCP Server
Installation
PyPI's qbt name belongs to an unrelated package, so the CLI is run via
--from:
uvx --from qbt-kit qbt doctor
uvx --from "qbt-kit[mcp]" qbt-mcp --help # the server lives in the `mcp` extraBoth run via --from because the qbt name on PyPI belongs to an unrelated
package, and qbt-mcp is a script inside this one rather than a package of its
own — uvx qbt-mcp resolves to nothing.
Or add it to a project:
uv add qbt-kit # library and CLI
uv add "qbt-kit[mcp]" # with the MCP serverAs a Claude Code plugin
This repository is also a plugin marketplace, so one line installs the MCP server and the skill together:
/plugin install qbt-kit --marketplace manueltarouca/qbt-kitThe bundled MCP server runs from the plugin's own checkout, so it needs uv
but not a published package, and it always matches the version you installed.
Point it at your server with QBT_URL, and see Configuration
for credentials.
Quickstart
qbt doctor # version, auth mode, endpoint availability
qbt torrents info --category tv # the API calls this `info`, not `list`
qbt torrents add --urls <magnet> --category tv --auto-tmm
qbt health # swarm health across the queue
qbt coverage # the endpoint coverage ledger
qbt call torrents/pieceStates -p hash=<h> # raw, reaches all 123Scope commands mirror the API exactly — torrents info, not a friendlier
list — so anything you read in qBittorrent's own docs translates directly.
--json works everywhere, so every command composes with jq.
qbt ready is also there, but it inspects the local filesystem to decide
whether a download has really settled, so it only means anything when the CLI
runs on the same machine as qBittorrent.
MCP server
{
"mcpServers": {
"qbittorrent": {
"command": "uvx",
"args": ["--from", "qbt-kit[mcp]", "qbt-mcp", "--url", "http://127.0.0.1:8080"]
}
}
}Fifteen tools rather than 123 — a tool list that long costs context
on every turn and measurably worsens which tool a model picks. qbt_call keeps
every endpoint reachable and list_endpoints lets a model discover them, so the
small surface stays complete.
Configuration
Flags first, then the environment, then the macOS Keychain:
variable | meaning |
| base URL, default |
| API key (qBittorrent 5.2+); preferred when present |
| WebUI username, for cookie login on any version |
| WebUI password |
|
|
Keychain fallback uses service qbittorrent, account api-key for a key and
webui for the password:
security add-generic-password -s qbittorrent -a api-key -w '<key>'qBittorrent has no OAuth, so there is no token flow to delegate and the
secret is long-lived. The reference MCP servers put credentials straight into
the client's env block — GITHUB_PERSONAL_ACCESS_TOKEN is the canonical
example — but that file is plaintext and frequently committed. Prefer the
Keychain, and if you do use env, reference a variable instead of pasting the
secret:
"env": {
"QBT_URL": "${QBT_URL:-http://127.0.0.1:8080}",
"QBT_API_KEY": "${QBT_API_KEY:-}" // empty falls through to the Keychain
}The :- default matters. Claude Code passes an unset ${VAR} through as the
literal text ${VAR} rather than as empty, which otherwise surfaces as a
confusing 401 much later — so qbt-mcp detects that case at startup and says
so plainly instead of starting.
On startup it reports, on stderr, where the credentials came from and never what they are:
qbt-mcp: http://127.0.0.1:8080 · WebAPI 2.15.1 · auth=bearer via macOS KeychainSafety
An agent driving a torrent client can destroy data that took weeks to collect, so the gates are code rather than guidance:
Destructive endpoints require
confirm;delete_filesis never implied.--read-only(orQBT_READ_ONLY=1) blocks mutations, including viaqbt_call.app/setPreferencesrefuses the WebUI, auth and network keys that would sever the connection or weaken security. There is no override.Refusals return a structured cause and remedy, so an agent can correct itself instead of seeing an opaque tool error.
qbt-mcp speaks stdio by default, which keeps it a child process with nothing
listening. The sse and streamable-http transports expose an
unauthenticated control surface holding your qBittorrent credentials — bound
to loopback, but do not forward those ports. See SECURITY.md.
Documentation
how the coverage claim is built and gated | |
the container harness, and behaviours that cost real time to learn | |
the design and the reasoning behind it | |
what is done and what is not | |
an independent review of the plan, with every finding dispositioned | |
every dependency, and why it is justified | |
threat model, credential handling, how to report a vulnerability |
A Claude skill ships in skills/qbt-kit/ covering CLI usage
and the swarm-health rule.
Field notes
Things that cost us time, documented so they cost you none.
Login success cannot be read from the status code. qBittorrent ≤5.1 answers a failed login with HTTP 200 and the body
Fails.; 5.2 returns an empty 204. The only rule that holds across versions is whether a session cookie was issued.app/webapiVersionrequires authentication. Onlyauth/loginis public, so you cannot read the version to decide how to authenticate. Probe instead.The session cookie is not always
SID. On 5.2 it isQBT_SID_<port>; on 5.0/5.1 it is user-configurable. Never match on the name.A bare 401 is often Host-header validation, not bad credentials. It is on by default and rejects any request whose
Hostport differs from the port qBittorrent listens on — which is what happens behind mapped container ports, SSH tunnels and most reverse proxies.API keys exist only from qBittorrent 5.2.0. Sending
Authorization: Bearerto 5.0/5.1 gets a 403 that looks like a credentials problem.pause/resumewere removed in 5.0, not aliased; they 404 there.progress: 1.0does not mean every file is on disk. Progress is computed over the selected files, so a torrent with files at priority 0 reports 100% having never fetched them.size < total_sizeis the cheap flag, from the same listing call.A category alone does not place a torrent. qBittorrent only applies a category's save path under automatic torrent management, so
torrents/addwith a category but withoutautoTMMfiles it in the global save path.A stalled torrent is usually not slow but stuck.
availabilityis how many complete copies exist across reachable peers; when it does not exceedprogress, no peer has the missing pieces. But a queued torrent reports availability 0 simply for not being connected — judging those as dead is how you delete healthy downloads.
Contributing
See CONTRIBUTING.md. The short version: endpoints are added
to the spec under src/qbtkit/spec/, never by hand to the CLI or MCP, and
tools/build_coverage.py --strict has to stay green.
Acknowledgements
qBittorrent — and specifically its
src/webui/api/*controller.cpp, which is the only complete and accurate description of this API that exists.qbittorrent-apiis the mature, well-maintained Python library for this API, and if a library is all you need, use it. qbt-kit exists for the CLI, the MCP server and the verifiable coverage claim, not because anything is wrong with it.
Licence
MIT — see LICENSE.
Available Tools
15 toolsadd_torrentC
Add a torrent by magnet or URL, or several at once.
Inputs: urls (required), stopped, auto_tmm, category, +1 more. Returns: result
categoriesC
List, create, edit or remove categories.
Inputs: name, action, confirm, save_path. Returns: result
control_torrentsA
Start, stop, recheck or reannounce torrents. Note that force_start makes a torrent ignore share limits, so a stop-on-complete rule stops applying to it.
Inputs: action (required), hashes. Returns: result
delete_torrentsA
Remove torrents. delete_files is never implied: without it the data stays on disk. Requires confirm=True because it cannot be undone.
Inputs: hashes (required), confirm, delete_files. Returns: result
list_endpointsA
List every endpoint qbt_call can reach, with its shape.
Inputs: scope, mutating_only. Returns: result
list_torrentsC
List torrents, with the fields that usually matter.
Inputs: tag, full, sort, limit, +2 more. Returns: result
move_torrentsA
Move a torrent's data to a new location. qBittorrent performs the move and the torrent stays valid; the call returns before the move finishes. A recheck afterwards is optional because it rehashes everything.
Inputs: hashes (required), location (required), recheck. Returns: result
preferencesA
Read preferences, or write a subset. Keys that would sever this connection or weaken the server's security (WebUI port, password, host-header validation and similar) are refused outright, with no override.
Inputs: keys, action, values. Returns: result
qbt_callA
Call any qBittorrent endpoint directly as scope/name, for anything the tools above do not cover. Parameters are validated against the endpoint spec, and the same safety gates apply: destructive endpoints need confirm, and read-only mode refuses anything that mutates state.
Inputs: path (required), params, confirm. Returns: result
searchA
Run a plugin search: start it, poll until it settles, return the results. Requires qBittorrent to have search plugins installed.
Inputs: pattern (required), limit, plugins, category, +1 more. Returns: result
server_infoB
Server version, auth mode and endpoint availability.
Inputs: no named parameters. Returns: result
swarm_healthA
Judge whether each torrent can actually finish. availability is how many complete copies exist across reachable peers; when it does not exceed progress, no peer holds the missing pieces and the download can never complete however long it waits. Queued torrents are excluded because they report availability 0 simply for not being connected yet. progress is relative to the selected files, so partial_selection marks torrents that are 100% yet never fetched their deselected files.
Inputs: include_complete. Returns: result
tagsC
List, create, delete, add or remove tags.
Inputs: names, action, hashes, confirm. Returns: result
torrent_detailB
Properties, trackers and files for one torrent.
Inputs: hash (required). Returns: result
transfer_statusB
Global transfer rates, limits and connection status.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
TDQS
Scored across 15 tools
Each tool targets a distinct resource or concern (list vs detail vs swarm health vs control vs move vs delete), and the status/config tools are clearly separated. The main soft overlap is qbt_call acting as an escape hatch for anything the others cover, but it is explicitly framed as a fallback, so the boundaries stay readable.
There is a mix of verb_noun tools (list_torrents, add_torrent, delete_torrents, move_torrents, control_torrents), noun-phrase tools (torrent_detail, transfer_status, server_info, swarm_health), and bare-noun names (categories, tags, preferences, search). Plural bulk nouns versus a singular add_torrent and the multi-action bundle names break a uniform pattern.
15 tools sits at the top of the well-scoped range and each maps to a real qBittorrent capability. Multi-action tools (categories, tags, control_torrents, preferences) sensibly bundle related operations instead of exploding the count.
Core lifecycle is covered: list, detail, add, control, move, delete, plus transfer/server status, categories, tags, preferences, and search. Gaps exist for RSS feed/automation-rule management and per-torrent file/peer priority, though qbt_call provides a raw fallback for those.
Maintenance
Related MCP Connectors
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
Jikan MCP — wraps the Jikan v4 API (anime/manga data, free, no auth)
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Related MCP Servers
- AlicenseBqualityDmaintenancePython wrapper & MCP server for the rqbit API810 PyPI3MIT
- FlicenseAqualityDmaintenanceEnables interaction with qBittorrent through its Web API to search for torrents using search plugins and manage downloads. Supports torrent searching, downloading via URLs/magnet links, and torrent management operations like pause, resume, and delete.73-
- AlicenseBqualityCmaintenanceMCP server that exposes qui's JSON REST API as tools for monitoring and managing qBittorrent instances, torrents, automations, cross-seeding, RSS, backups, and related services.12MIT
- AlicenseAqualityCmaintenanceMCP server exposing qBittorrent's WebUI API v2 as tools, enabling LLMs to manage torrents, categories, tags, RSS feeds, search plugins, and application settings.903MIT