Kavita MCP Connector
by si-essence
README.md
# kavita-mcp (Kavita MCP connector)
MCP connector for a self-hosted [Kavita](https://github.com/Kareadita/Kavita) server (v0.9.1.x). It speaks the HTTP API over stdio and over stateless Streamable HTTP on localhost.
Kavita is GPL-3.0 software. This connector does not copy that code. It only calls the HTTP API on the server you configure. It is not affiliated with Kavita or Kavitareader. Bring your own Auth Key from User Settings on your server.
The spec file `kavita.openapi.json` has 517 operations across 46 tags. This connector covers 453 of them in 43 tools. It leaves out 64 endpoints that return files, feeds, or client-sync protocols. `scripts/gen-operations.mjs` writes `src/operations.ts` from the spec. Do not edit that file by hand.
Self-hosted servers only. There is no default base URL. `KAVITA_URL` is required. Hosts on `kavitareader.com` and its subdomains are refused. That domain is the Kavita+ license and cloud service.
## Setup
```bash
npm install
npm run ci
npm start
npm run start:http
```
`npm start` speaks stdio. `npm run start:http` serves Streamable HTTP at `http://127.0.0.1:3000/mcp` and `GET /health`. HTTP mode has no authentication of its own. Keep it on localhost.
```json
{
"mcpServers": {
"kavita": {
"command": "node",
"args": ["/workspace/connectors/kavita/dist/index.js"],
"env": {
"KAVITA_URL": "http://127.0.0.1:5000",
"KAVITA_API_KEY": "...",
"KAVITA_ALLOW_WRITES": "false",
"KAVITA_TOOLSETS": "server,library,series,collection,readinglist,search"
}
}
}
}
```
Regenerate the registry after an OpenAPI bump.
```bash
npm run gen:operations
```
`scripts/live-check.mjs` talks to a real server over stdio. It needs `KAVITA_URL` and `KAVITA_API_KEY`, sets `KAVITA_TOOLSETS=all` and `KAVITA_ALLOW_WRITES=true`, and prints pass or fail lines only. The parent runs it. This workspace does not start Kavita.
## Config
| Variable | Meaning |
| --- | --- |
| `KAVITA_URL` | Required. Self-hosted origin, `http` or `https`, no userinfo, query, or hash. `kavitareader.com` is refused. |
| `KAVITA_API_KEY` | Auth Key from User Settings. Sent as the `x-api-key` header. |
| `KAVITA_USERNAME` | Optional login. Set together with `KAVITA_PASSWORD` when no Auth Key is set. |
| `KAVITA_PASSWORD` | Password for that login. The connector posts `/api/Account/login` once and refreshes the JWT once after a 401. |
| `KAVITA_ALLOW_WRITES` | Must be the literal `true` before a confirmed write is sent. |
| `KAVITA_TOOLSETS` | Comma list of toolsets, or `all`. Default is the read-focused set below. |
| `KAVITA_PER_MINUTE` | Local request budget. Default 30. Cache hits do not spend it. |
| `KAVITA_TIMEOUT_MS` | Upstream timeout. Default 20000. |
| `KAVITA_CACHE_TTL_SEC` | Read cache TTL. Default 60. Writes clear the cache. |
| `KAVITA_CONTACT` | Contact token in the User-Agent. Must not contain the key or password. |
| `MCP_TRANSPORT` | `stdio` or `http`. `--http` overrides. |
| `PORT` | HTTP port. Default 3000. |
## Safety
GET is a read. POST, PUT, and DELETE are writes, except a reviewed list of POST queries in `READ_POST_PATHS` (series filters, search-style lookups, stats-like reads). A few GETs that start logins or update checks are writes (`GET_SIDE_EFFECT_PATHS`). Anything not on the read list stays a write.
A write needs `confirm: true` as a boolean and `KAVITA_ALLOW_WRITES=true`. The string `"true"` is rejected. Otherwise the tool returns a dry-run preview of method, path, query, and redacted body, and it sends nothing. Destructive, credential, and exposure operations add a warning line on the tool and on the preview. That set covers deletes, scans, cache clears, user invites and role changes, Auth Key create and revoke, password reset, settings, license, scrobbling tokens, OAuth and OIDC, and email.
Auth Key create and rotate return the key once, with a shown-only-once note. Later list and get calls redact it. Account `apiKey` and `email` are redacted. Library folder paths stay in successful responses. Error text drops stack traces and filesystem paths.
HTTP 401 is unauthorized. HTTP 403 is forbidden. HTTP 404 is not found. HTTP 400 and 422 are invalid input. HTTP 429 includes Retry-After. Other failures are server, network, or timeout. Response bodies are capped.
## Tools
Default `KAVITA_TOOLSETS` publishes 12 tools (186 operations). `KAVITA_TOOLSETS=all` publishes 43 tools (453 operations, 236 reads and 217 writes). Each tool takes `action` plus optional `params`, `query`, `body`, and `confirm`.
`action` `help` with optional `target` returns the path, query, and body fields for one action. Descriptions list action names only, so the tool list stays small.
| Toolset | Tool | Operations | Default |
| --- | --- | --- | --- |
| server | `kavita_server` | 17 | yes |
| library | `kavita_library` | 23 | yes |
| series | `kavita_series` | 33 | yes |
| collection | `kavita_collection` | 12 | yes |
| readinglist | `kavita_readinglist` | 27 | yes |
| search | `kavita_search` | 4 | yes |
| metadata | `kavita_metadata` | 14 | yes |
| person | `kavita_person` | 10 | yes |
| chapter | `kavita_chapter` | 5 | yes |
| volume | `kavita_volume` | 4 | yes |
| stats | `kavita_stats` | 33 | yes |
| wanttoread | `kavita_wanttoread` | 4 | yes |
| account | `kavita_account` | 28 | no |
| activity | `kavita_activity` | 1 | no |
| admin | `kavita_admin` | 1 | no |
| annotation | `kavita_annotation` | 12 | no |
| book | `kavita_book` | 2 | no |
| cbl | `kavita_cbl` | 13 | no |
| color_scape | `kavita_color_scape` | 3 | no |
| device | `kavita_device` | 10 | no |
| email | `kavita_email` | 1 | no |
| filter | `kavita_filter` | 12 | no |
| font | `kavita_font` | 3 | no |
| health | `kavita_health` | 1 | no |
| image | `kavita_image` | 3 | no |
| kavita_plus_audit | `kavita_kavita_plus_audit` | 6 | no |
| license | `kavita_license` | 13 | no |
| locale | `kavita_locale` | 1 | no |
| manage | `kavita_manage` | 2 | no |
| oauth | `kavita_oauth` | 2 | no |
| oidc | `kavita_oidc` | 2 | no |
| panels | `kavita_panels` | 2 | no |
| plugin | `kavita_plugin` | 5 | no |
| rating | `kavita_rating` | 4 | no |
| reader | `kavita_reader` | 35 | no |
| reading_profile | `kavita_reading_profile` | 16 | no |
| review | `kavita_review` | 5 | no |
| scrobbling | `kavita_scrobbling` | 19 | no |
| settings | `kavita_settings` | 20 | no |
| stream | `kavita_stream` | 17 | no |
| theme | `kavita_theme` | 6 | no |
| upload | `kavita_upload` | 12 | no |
| users | `kavita_users` | 10 | no |
Example. List libraries, then preview a scan.
```json
{ "action": "get_libraries" }
```
```json
{ "action": "post_scan", "query": { "libraryId": "1", "force": "false" } }
```
Add `"confirm": true` only after `KAVITA_ALLOW_WRITES=true`.
## Exclusions
64 operations are in `EXCLUSIONS`, each with a reason. The coverage test checks that the spec equals the registry plus that list, in both directions.
- Download. Zip archives and the size helpers for those archives.
- Opds. XML catalogues, and the Auth Key sits in the path.
- Koreader and Tachiyomi. Client sync protocols, not management APIs.
- Image cover and page bytes, Reader image, pdf, and thumbnail bytes, font file bytes, epub page HTML and resource bytes, the server log zip, and the stats file-extension CSV.
- Multipart uploads on Cbl, Font, Theme, and Upload. The tool sends JSON and cannot attach a file part.
JSON image lookups and the rest of Upload stay in the registry.
## What this is not
This is not a Kavita+ client and it will not call `kavitareader.com`. It does not download archives, serve OPDS, stream pages, or speak KOReader or Tachiyomi sync. It does not copy Kavita source. HTTP mode is an unauthenticated localhost transport for your own process.
Live check result: 43 checks passed, failed=0, against a real local Kavita 0.9.1.4 (about 22 of 453 ops live). See LIVE-CHECK.md for exact coverage.
## License
MIT, see [LICENSE](LICENSE). This is an independent, unofficial connector and is not endorsed by the Kavita project or its owners.
The upstream kavita.openapi.json comes from a GPL-3.0 project, so it is not shipped here. `src/operations.ts` was generated from it, and tests fall back to a route-only fixture in `test/fixtures/`. To regenerate, download the spec from the upstream project into the repo root (it is gitignored) and run `node scripts/gen-operations.mjs`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues