bookstack-mcp exposes a BookStack wiki to an AI assistant (Claude Code, Cowork,
or any MCP-compatible client) as a set of callable tools — searching pages,
reading content, and optionally creating/editing pages and books. It's how an
AI session answers questions out of a BookStack instance, and how it can make
edits there if write mode is enabled.
Don't point this at a production BookStack instance while developing. Stand
up a throwaway local copy first and point everything at that. A minimal
docker-compose.yml for a disposable BookStack + database:
services:
bookstack-db:
image: mariadb:11.4
environment:
MARIADB_ROOT_PASSWORD: local-dev-only
MARIADB_DATABASE: bookstack
MARIADB_USER: bookstack
MARIADB_PASSWORD: local-dev-only
volumes: [bookstack-db:/var/lib/mysql]
bookstack:
image: lscr.io/linuxserver/bookstack:latest
environment:
APP_URL: http://localhost:6875
APP_KEY: base64:SVGvKZ8b6l0Y1n4kZ0pQ2xW7mJ3rT5uH8cA1dE9fG2s=
DB_HOST: bookstack-db
DB_USERNAME: bookstack # not DB_USER — see Gotchas
DB_PASSWORD: local-dev-only
DB_DATABASE: bookstack
ports: ["6875:80"]
depends_on: [bookstack-db]
volumes:
bookstack-db:docker compose up -dRequires Node 22 specifically — the test runner needs glob support that only landed in Node 21+, and older versions fail with a confusing "Could not find" error rather than anything indicating a version problem.
A few things that weren't obvious the first time through:
- BookStack's container env vars must be
DB_USERNAME/DB_PASSWORD, not the older LSIO-styleDB_USER/DB_PASS— get the name wrong and you get a silent 500 with no hint why. First container start also takes about a minute for DB migrations; a 500 during that window just means it's not ready yet. - The API token BookStack gives you (Edit Profile → API Tokens) is actually
two separate values — a Token ID and a Token Secret, both shown once on
the creation screen.
.envwants both (BOOKSTACK_TOKEN_ID/BOOKSTACK_TOKEN_SECRET); copying only one string will leave you stuck. - If you're developing over SSH and viewing BookStack from your local
browser,
localhost:6875refers to your machine, not the remote host — use an SSH local port-forward tunnel to reach it. npm run devdoes not load.envat all — see Gotchas below for why, and what to run instead.
npm install
cp .env.example .env
# fill in BOOKSTACK_BASE_URL, BOOKSTACK_TOKEN_ID, BOOKSTACK_TOKEN_SECRET
# BOOKSTACK_ENABLE_WRITE=true is safe against a local throwaway instance
node --env-file=.env --import tsx src/index.tsnpm testThis runs Node's built-in test runner (node --test) against src/**/*.test.ts.
Passing looks like:
✔ constructor rejects max < 1
✔ allows up to `max` holders concurrently and queues the rest
✔ run() releases the permit even when fn throws
✔ bounds real concurrency under a burst
ℹ tests 4
ℹ pass 4
ℹ fail 0
Worth knowing going in: this is currently 4 tests, all covering the
concurrency limiter (BOOKSTACK_MAX_CONCURRENCY) — there's no coverage yet of
the actual BookStack API calls, error handling, or caching behavior. Coverage
here is thin; don't treat it as representative of this project's other repos
(mediawiki-mcp, content-mcp), which are considerably better covered.
git switch main && git pull
git switch -c fix/short-description # or feat/, ci/, docs/
# ...make your change...
git add -A && git commit
git push -u origin fix/short-description
gh pr create --fillCommit messages explain why, not what — the diff already shows what
changed. No AI attribution lines or emoji in commits. Never commit .env,
tokens, or secrets. The maintainer reviews and approves PRs; merging is safe
and reversible once approved.
Merging a change that bumps the version in package.json cuts a git tag,
which kicks off the release workflow — but that workflow pauses and waits
for maintainer approval before anything actually publishes to npm. A merge
never ships anything on its own.
npm run dev(tsx src/index.ts) does not load.env. There's nodotenvimport and no--env-fileflag anywhere in the repo, andBOOKSTACK_BASE_URLis read directly fromprocess.envviagetRequiredEnvVar. So filling in.envper the setup steps silently does nothing if you run the documentednpm run dev. Usenode --env-file=.env --import tsx src/index.tsinstead. The same gap exists inmediawiki-mcp, so the real fix is likely one shared change (either thedevscript or adotenvimport) rather than two separate patches — a known issue, not yet fixed as of this PR.- Needs Node 22 specifically for the test runner's glob support — anything older fails with a misleading error.
- Test coverage is thin — 4 tests, all about the concurrency limiter, and it wasn't running in CI until recently.
npm installreports a double-digit number of audit vulnerabilities on a fresh install. Worth a look eventually, not a blocker for local dev.- Once running, the server sits in stdio mode waiting for an MCP client to talk to it — that's expected behavior, not a hang.