bookstack-mcp
by jmhooper
README.md
This is an HTTP MCP server that allows your agents to communicated with Bookstack.
I built this MCP server because I use bookstack pretty heavily. I could not find a good solution for letting my LLM read and update books using an HTTP powered MCP server.
## Getting started
I built this with the intention that it would run alongside bookstack using docker compose.
### Configuration
The server is configured with environment variables (a local `.env` file is also
loaded — see [`.env.example`](.env.example)):
| Variable | Required | Default | Description |
| -------------------- | -------- | ------- | ----------------------------------------------------------------------------- |
| `BOOKSTACK_BASE_URL` | yes | — | Root URL of the BookStack instance to talk to (e.g. `http://bookstack:6875`). |
| `PORT` | no | `3000` | Port the MCP HTTP server listens on. |
| `LOG_LEVEL` | no | `info` | Winston log level: `error`, `warn`, `info`, or `debug`. |
Note the **BookStack API token is not configured on the server**. Each request carries the token and the server forwards it to BookStack, so a single instance can serve multiple users/tokens — see [Authentication](#authentication) below.
### Example docker compose
The server is meant to run on the same Docker network as BookStack so it can reach it by service name. Point `BOOKSTACK_BASE_URL` at the `bookstack` service (over the internal network) rather than a public/localhost URL:
```yaml
services:
bookstack:
image: lscr.io/linuxserver/bookstack:latest
environment:
APP_URL: http://localhost:6875
# BookStack also needs a database service and its DB_* settings.
# See https://www.bookstackapp.com/docs/admin/installation/ for a
# complete BookStack + MySQL compose setup.
ports:
- "6875:6875"
bookstack-mcp:
build: .
environment:
BOOKSTACK_BASE_URL: http://bookstack:6875
PORT: "6045"
LOG_LEVEL: info
ports:
- "6045:6045"
depends_on:
- bookstack
```
Then point your MCP client at `http://<host>:6045/mcp`. A `GET /health` endpoint is available for container health checks.
### Authentication
Create an API token in BookStack (**Edit Profile → API Tokens → Create Token**), which gives you a Token ID and a Token Secret. Send them on every request in the `Authorization` header, joined with a colon:
```
Authorization: Token <token_id>:<token_secret>
```
The `Token ` / `Bearer ` scheme prefix is optional (a raw `<id>:<secret>` value is also accepted). Requests without a token are rejected with `401`. The server forwards the token to BookStack, so it inherits exactly the permissions of that token's user.
## Available tools
The server exposes four tools over the MCP endpoint (`POST /mcp`).
### `bookstack_search`
Search across all BookStack content (shelves, books, chapters, and pages).
This tool is Read-only.
| Argument | Required | Description |
| -------- | -------- | ------------------------------------------------------------------------- |
| `query` | yes | Search text, using BookStack search syntax (e.g. `cats {created_by:me}`). |
| `page` | no | 1-based page number. |
| `count` | no | Results per page (max 100). |
### `bookstack_crud`
Create, read, update, delete, or list BookStack entities. Works across four entity types: `book`, `chapter`, `page`, and `shelf`.
| Argument | Required | Description |
| ----------- | ---------------------------- | --------------------------------------------------------------------------------------------------- |
| `entity` | yes | `book`, `chapter`, `page`, or `shelf`. |
| `operation` | yes | `create`, `read`, `update`, `delete`, or `list`. |
| `id` | for `read`/`update`/`delete` | Numeric ID of the target entity. |
| `data` | for `create`/`update` | Entity fields (see below). Validated per entity before sending. |
| `params` | optional, for `list` | `{ count (max 500), offset, sort, filter }` — e.g. `sort: "-created_at"`, `filter: { book_id: 3 }`. |
`data` fields by entity (`*` = required on create; all optional on update):
| Entity | Fields |
| --------- | ------------------------------------------------------------------------------------------------- |
| `book` | `name*`, `description`, `description_html`, `tags` `[{name,value}]`, `default_template_id` |
| `chapter` | `book_id*`, `name*`, `description`, `description_html`, `tags`, `priority`, `default_template_id` |
| `page` | `name*`, `book_id` **or** `chapter_id*`, `html` **or** `markdown*`, `tags`, `priority` |
| `shelf` | `name*`, `description`, `description_html`, `books` `[bookId, ...]`, `tags` |
### `bookstack_read_page`
Read a page's content as markdown. Returns the page body as raw markdown text
(not HTML or JSON), via BookStack's markdown export endpoint.
This tool is read-only.
| Argument | Required | Description |
| -------- | -------- | ------------------------------- |
| `id` | yes | Numeric ID of the page to read. |
### `bookstack_write_page`
Overwrite an existing page's content with markdown. This is **update-only** — to
create a new page, use `bookstack_crud`. Returns a confirmation with the page's
id, name, and slug.
| Argument | Required | Description |
| ---------- | -------- | --------------------------------------------- |
| `id` | yes | Numeric ID of the page to overwrite. |
| `markdown` | yes | New page body, as markdown. Replaces content. |
The `bookstack_search` and `bookstack_crud` tools return the BookStack API response as JSON. Errors (validation failures or BookStack API errors) come back as tool errors with a descriptive message.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues