komga-mcp
by pierrec18
README.md
# komga-mcp
A small, **read-only** [Model Context Protocol](https://modelcontextprotocol.io)
(MCP) server that exposes your [Komga](https://komga.org) reading data to any
MCP-compatible client over **Streamable HTTP**.
It is intentionally minimal and safe: it can only *read* from Komga. There is no
tool that writes progress, edits metadata, deletes, downloads, scans, or issues
arbitrary API calls.
## Tools
The server advertises **exactly four** tools:
| Tool | Description |
|------|-------------|
| `search_comics` | Search a series or a book by title. |
| `get_unread_series` | List series that contain unread books. |
| `get_reading_progress` | List books in progress with page/percentage. |
| `continue_reading` | Books in progress first, then on-deck (next unread), separated. |
Every response is a normalized JSON payload — never a raw Komga dump, never file
paths or device identifiers.
## HTTP endpoints
| Path | Method | Auth | Purpose |
|------|--------|------|---------|
| `/mcp` | POST | Bearer | MCP Streamable HTTP endpoint |
| `/health` | GET | none | Liveness (does not call Komga) |
| `/ready` | GET | Bearer | Readiness (checks Komga connectivity) |
Inbound requests to `/mcp` and `/ready` require
`Authorization: Bearer <MCP_BEARER_TOKEN>`.
## Configuration
Set via environment variables (see [`.env.example`](./.env.example)):
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PORT` | no | `8000` | Listen port |
| `KOMGA_URL` | yes | — | Base URL of Komga (e.g. `http://komga:25600`) |
| `KOMGA_API_KEY` | yes | — | Sent to Komga as `X-API-Key` |
| `MCP_BEARER_TOKEN` | yes | — | Required bearer for inbound MCP clients |
| `KOMGA_REQUEST_TIMEOUT_MS` | no | `10000` | Per-request timeout (1000..60000) |
| `LOG_LEVEL` | no | `info` | `error` / `warn` / `info` / `debug` |
Generate a strong bearer token, for example: `openssl rand -hex 32`.
## Run with Docker
```bash
cp .env.example .env # then edit .env with real values
docker run --rm --env-file .env -p 8101:8000 ghcr.io/pierrec18/komga-mcp:0.1.0
```
Or with Compose — see [`compose.example.yaml`](./compose.example.yaml). The image
runs as a non-root user and is compatible with a read-only root filesystem.
## Run from source
```bash
npm ci
npm run build
KOMGA_URL=http://localhost:25600 \
KOMGA_API_KEY=... \
MCP_BEARER_TOKEN=... \
npm start
```
## Connecting an MCP client
Point any MCP client at the Streamable HTTP endpoint and pass the bearer token.
Example with the official TypeScript SDK:
```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:8101/mcp"),
{ requestInit: { headers: { Authorization: `Bearer ${process.env.MCP_BEARER_TOKEN}` } } },
);
const client = new Client({ name: "my-client", version: "1.0.0" });
await client.connect(transport);
console.log(await client.listTools());
```
This server is **not** tied to any particular client or agent framework.
## Development
```bash
npm ci
npm run lint # ESLint
npm run typecheck # tsc --noEmit
npm test # vitest (runs against a fake Komga; never your real instance)
npm run build # emit dist/
```
## Security
See [SECURITY.md](./SECURITY.md). In short: read-only by design, bearer-protected,
secrets never logged, upstream errors sanitized, timeouts and bounded limits on
everything.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues