Audiobookshelf MCP server
<center align="center" style="text-align: center;justify-content:center;">
<div align="center" style="text-align: center;justify-content:center;">
<h1 align="center" style="text-align: center;justify-content:center;">
Audiobookshelf MCP server
<img style="justify-content:center;text-align: center;width: 95px; height: auto;" width="793" height="411" alt="image" src="https://github.com/user-attachments/assets/abed1a04-d69b-4ab4-a490-d606064df72d" />
<img style="justify-content:center;text-align: center;width: 49px; height: auto;" alt="Audiobookshelf" src="public/logo.png" />
</h1>
   
</div>
</center>
<hr>
Run Audiobookshelf from Claude.ai and Claude Code. All 209 routes are tools. Not a curated subset: every endpoint the web interface can reach, this can reach.
<hr>
> [!WARNING]
> Using this server with a paid AI service costs money. Tool definitions and results are billed as input tokens, and an agent can call tools repeatedly on its own. You are responsible for every charge, so set spending limits with your provider. The author accepts no liability for any costs. See [DISCLAIMER.md](DISCLAIMER.md).
## Why not the other options
Audiobookshelf ships `docs/openapi.json`, but it documents 65 of the 209 routes its Express routers register, so anything generated from it covers under a third of the API. The routers are the complete list:
| Approach | Tools | Coverage |
| --- | --- | --- |
| Servers built on `docs/openapi.json` | up to 65 | 31 % |
| Hand-written subsets | a dozen or so | under 10 % |
| This one | **209** | **100 %** |
The published spec covers libraries, items and a few author and series routes. It leaves out playback sessions, progress, podcasts and their episode downloads, collections, playlists, users, backups, notifications, email and the whole settings surface.
## How it stays complete
`scripts/extract_spec.py` reads the routers and writes an OpenAPI document, borrowing summaries and parameters from the published docs wherever they exist. `scripts/generate_tools.py` then turns it into tools:
```bash
git clone --depth 1 https://github.com/advplyr/audiobookshelf.git /tmp/abs
python scripts/extract_spec.py /tmp/abs openapi.json
python scripts/generate_tools.py openapi.json src/audiobookshelf_mcp/tools.py
```
45 of the 209 operations carry the project's own descriptions; the rest are derived from the route.
A test compares every generated call against every operation in the extracted spec, in both directions. A route Audiobookshelf adds and this misses fails the build; so does a tool pointing at a route that does not exist.
## Tool names
Verb first, derived from the method and path, so the name says what it does:
| Pattern | Meaning | Example |
| --- | --- | --- |
| `list_*` | Read a collection | `list_api_libraries`, `list_api_me` |
| `get_*_by_id` | Read one record | `list_api_libraries_by_id` |
| `create_*` | POST | `create_api_libraries` |
| `update_*` | PATCH | `update_api_libraries_by_id` |
| `delete_*` | DELETE | `delete_api_libraries_by_id` |
209 tools is a lot to put in front of a model at once. If your client supports tool filtering, narrow it to the groups you use.
## What is covered
Every route the three routers register, across `/api`, `/public` and `/hls`: libraries and their items, books, podcasts and episode downloads, authors, series, collections, playlists, search, listening sessions and playback progress, `me`, users and API keys, notifications, email and ereader devices, RSS feeds and share links, the filesystem browser, caches, backups, logs, tools and the whole settings surface.
## Setup
```bash
git clone https://github.com/rollecode/audiobookshelf-mcp.git
cd audiobookshelf-mcp
uv venv && uv pip install -e .
```
```bash
export AUDIOBOOKSHELF_URL=http://127.0.0.1:13378
export AUDIOBOOKSHELF_TOKEN=... # Settings, Users, your user, API token
```
### Claude Code
```bash
claude mcp add audiobookshelf -- /path/to/audiobookshelf-mcp/.venv/bin/audiobookshelf-mcp
```
## Writing
Audiobookshelf patches rather than replaces, so `body` needs only the fields you are changing. Ids are strings throughout, not numbers.
## Hosting it
Running it over HTTP puts it in reach of Claude.ai as a custom connector, and of Claude Code on other machines. Three tiers, the same shape the other servers in this family use:
| Tier | Port | What it does |
| --- | --- | --- |
| `audiobookshelf-mcp` | 8570 | The server. No login of its own, never exposed |
| nginx | 8571 | Front door, behind a Cloudflare Tunnel |
| `auth-server.js` | 8572 | OAuth 2.1 sign-in, or a fixed bearer token |
```bash
npm install
node set-password.js 'a password for the sign-in page'
printf 'AUDIOBOOKSHELF_URL=...\n' > ~/.config/audiobookshelf-mcp/env
chmod 600 ~/.config/audiobookshelf-mcp/env
```
Copy `systemd/*.service` into `/etc/systemd/system/`, replacing `YOUR_USER` and the `ISSUER` hostname, then:
```bash
sudo systemctl enable --now audiobookshelf-mcp audiobookshelf-mcp-auth
```
Point `nginx/audiobookshelf-mcp.conf` at your own hostname and send the tunnel at `127.0.0.1:8571`.
Environment the server itself reads: `AUDIOBOOKSHELF_URL, AUDIOBOOKSHELF_TOKEN`. The sign-in page carries the Audiobookshelf mark and accent colour, set through `APP_NAME`, `APP_ACCENT` and `APP_BLURB` in the auth unit.
### Claude.ai
Settings, Connectors, Add custom connector, URL `https://audiobookshelf-mcp.your-domain/mcp`, client ID and secret blank. The sign-in page asks for the password set above. Connectors belong to the account, so adding it once covers mobile too.
## Development
```bash
uv pip install -e . pytest ruff
.venv/bin/python -m pytest tests
.venv/bin/ruff check .
```
TDQS
Scored across 212 tools
The toolset is mechanically derived from HTTP routes, so the verb often lies: 'create_items_batch_get', 'create_tags_rename', 'create_genres_rename', 'create_authorize', 'create_session_by_id_close' and 'create_watcher_update' are all reads or non-creates exposed under a 'create_' prefix. Several pairs sit adjacently with near-identical names ('get_me_progress_by_id_by_episode_id' vs 'get_me_progress_by_id_remove_from_continue_listening'), and multi-step batch endpoints (batch/scan, batch/update, batch/quickmatch) overlap heavily. An agent would frequently pick the wrong tool or need to consult the route string to disambiguate.
Names are uniformly snake_case and follow a recognizable verb_resource_by_id_path-param pattern, and the list_/get_ split for collections vs. singles is coherent. However the verb is chosen from the HTTP method rather than the action, so 'create_X' covers gets, renames, applies and deletes, and side-effecting GETs like 'get_backups_by_id_apply' read as pure reads. The convention is readable but semantically unreliable.
212 tools is far beyond any reasonable agent-facing surface and is essentially a 1:1 dump of the REST API, including trivial variants (cover, download, track, ffprobe, ebook/status). Most of these would be composed by a handful of higher-level tools, and the sheer count makes selection and context management impractical.
Coverage of the Audiobookshelf domain is broad — items, libraries, collections, playlists, podcasts/episodes, series, authors, users, sessions, backups, notifications, feeds, search, stats and tools — with CRUD on most resources. The main gap is that nearly every description tells the agent to 'read the matching GET or the /schema endpoint' but no schema tool is exposed, leaving payload shapes undiscoverable; a handful of mutations are oddly modeled as GETs.