Qbt Kit
qBittorrent WebUI API: all 123 endpoints, with confirmation required on destructive operations and a read-only mode that holds through the raw call.
ماذا يمكنك أن تفعل مع Qbt Kit؟
- All 123 endpoints of qBittorrent 5.2.3, each one a spec entry that
- A verifiable coverage claim. The endpoint list is extracted from the
- An MCP server with 15 tools — 13 task-shaped, plus
qbt_calland - Compatibility measured, not assumed — tested against real 4.6, 5.0, 5.1
- Typed throughout, no runtime dependency beyond
httpxandtyper.
التثبيت
خطوات التثبيت موجودة في التوثيق أدناه. التوثيق
التوثيق
مأخوذ من ملف README للمشروع على GitHub ويُحدَّث أسبوعيًا. تفتح الروابط على GitHub.
المحتويات
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%
The ledger is generated from qBittorrent's own source, and CI fails if it slips.
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.
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` extra
Both 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 server
As 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-kit
The 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 123
Scope 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 |
|---|---|
QBT_URL | base URL, default http://127.0.0.1:8080 |
QBT_API_KEY | API key (qBittorrent 5.2+); preferred when present |
QBT_USERNAME | WebUI username, for cookie login on any version |
QBT_PASSWORD | WebUI password |
QBT_READ_ONLY | 1/true/yes to refuse everything that changes state |
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 Keychain
Safety
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
docs/TRACEABILITY.md | how the coverage claim is built and gated |
docs/TESTING.md | the container harness, and behaviours that cost real time to learn |
docs/PLAN.md | the design and the reasoning behind it |
docs/ROADMAP.md | what is done and what is not |
docs/REVIEW-1.md | an independent review of the plan, with every finding dispositioned |
docs/dependencies.md | every dependency, and why it is justified |
SECURITY.md | 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.
الأسئلة الشائعة
ما هو Qbt Kit؟
qBittorrent WebUI API: all 123 endpoints, with confirmation required on destructive operations and a read-only mode that holds through the raw call.
كيف أثبّت Qbt Kit؟
اتبع خطوات التثبيت في توثيقه المعروض في هذه الصفحة وفي مستودعه.
هل Qbt Kit مفتوح المصدر؟
نعم. شيفرته متاحة على GitHub بترخيص MIT.
من يصون Qbt Kit؟
ينشره manueltarouca. يدرجه AI.tn لكنه لا يصونه ولا يوصي به.
من القوائم المجتمعية awesome-mcp-servers ومستودع المشروع على GitHub. الإدراج ليس توصية: راجع شيفرة الخادم وصلاحياته قبل منحه الوصول إلى بياناتك.