Skip to main content
Glama
jmhooper
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.