Skip to content

Commit 884eebe

Browse files
committed
v3.3.1: strip raw_html in get_page to honor pagination
Large pages were blowing past MCP token caps because BookStack returns raw_html alongside html/markdown/text and we weren't stripping it, bypassing the limit/offset pagination on the content field. Also reorganize README to lead with the plugin marketplace install.
1 parent 09a3fb1 commit 884eebe

6 files changed

Lines changed: 58 additions & 24 deletions

File tree

.claude/settings.local.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,17 @@
1414
"WebFetch(domain:spec.modelcontextprotocol.io)",
1515
"WebFetch(domain:modelcontextprotocol.io)",
1616
"Bash(find:*)",
17-
"Bash(grep:*)"
17+
"Bash(grep:*)",
18+
"WebFetch(domain:www.librechat.ai)",
19+
"Bash(gh api *)",
20+
"Bash(python3 -m json.tool)",
21+
"mcp__plugin_context7_context7__resolve-library-id",
22+
"mcp__plugin_context7_context7__query-docs",
23+
"Bash(gh repo *)",
24+
"WebFetch(domain:bookstack.bassopaolo.com)"
1825
],
1926
"deny": [],
2027
"ask": [],
2128
"defaultMode": "acceptEdits"
2229
}
23-
}
30+
}

CLAUDE.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
BookStack MCP Server v2.1 — A TypeScript MCP server providing BookStack wiki integration for AI assistants. Published to npm as `bookstack-mcp`. Uses McpServer API with `registerTool()` and Zod schemas with `z.coerce.number()` for broad MCP client compatibility.
7+
BookStack MCP Server — A TypeScript MCP server providing BookStack wiki integration for AI assistants. Published to npm as `bookstack-mcp`. Uses McpServer API with `registerTool()` and Zod schemas with `z.coerce.number()` for broad MCP client compatibility. Current version is tracked in `package.json`.
88

99
## Build & Development Commands
1010

@@ -42,6 +42,7 @@ BOOKSTACK_BASE_URL=https://your-bookstack.com # Required
4242
BOOKSTACK_TOKEN_ID=your-token-id # Required
4343
BOOKSTACK_TOKEN_SECRET=your-token-secret # Required
4444
BOOKSTACK_ENABLE_WRITE=false # Optional
45+
BOOKSTACK_INSECURE_SKIP_TLS_VERIFY=false # Optional, for self-signed BookStack
4546
```
4647

4748
### TypeScript Configuration
@@ -57,7 +58,24 @@ Published as `bookstack-mcp`. Key package.json fields:
5758
- `prepare`: runs build (triggers on install from git and before publish)
5859
- `engines`: `>=18`
5960

60-
To publish: `npm publish` (package is unscoped, no `--access public` needed)
61+
## Release Process
62+
63+
Releases are fully automated by GitHub Actions — **never run `npm publish` locally**.
64+
65+
1. Bump `version` in `package.json` (semver) in the same PR/commit as the changes you want to ship.
66+
2. Merge to `main`.
67+
3. `.github/workflows/ci.yml` runs:
68+
- `build` job: `npm ci` + `npm run build` on every push and PR.
69+
- `tag` job (main only): if `package.json` version doesn't already have a matching `v${version}` git tag, it creates and pushes one using `RELEASE_PAT` (a PAT is required because the default `GITHUB_TOKEN` cannot trigger downstream workflows).
70+
4. The pushed tag triggers `.github/workflows/release.yml`, which:
71+
- Builds, then upgrades npm to the latest (Node 20 ships npm 10.x; trusted publishing needs ≥ 11.5.1).
72+
- Publishes via npm **trusted publishing (OIDC)** with `--provenance` — no `NPM_TOKEN`. The npm CLI exchanges the Actions OIDC token (`id-token: write`) for a short-lived registry token at publish time. This requires the npm package to have a trusted publisher configured pointing at this repo's `release.yml`.
73+
- Creates a GitHub Release for the tag with auto-generated notes (`gh release create --generate-notes`).
74+
75+
Notes:
76+
- Don't tag manually — let the `tag` job do it from the version bump. Manually pushed tags will still trigger `release.yml`, but you bypass the version-changed gate.
77+
- If `RELEASE_PAT` is missing/expired, the tag never gets pushed and the release silently doesn't happen. Symptom: CI green on main, no new tag, no npm release.
78+
- Don't add an `NPM_TOKEN` secret — trusted publishing replaces it. Adding one weakens the threat model.
6179

6280
## Key Implementation Details
6381

README.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,24 @@ Restart LibreChat after config changes.
137137

138138
### Claude Code (CLI)
139139

140-
Add the server with `claude mcp add`. Repeat `--env` for each variable, and put all flags **before** the server name; the `--` separator marks the start of the command Claude Code will spawn:
140+
The recommended path is the `ttpears/claude-plugins` marketplace, which ships this repo's plugin manifest (`.claude-plugin/plugin.json`):
141+
142+
```
143+
/plugin marketplace add ttpears/claude-plugins
144+
/plugin install bookstack-mcp@ttpears-plugins
145+
```
146+
147+
Then set the `BOOKSTACK_*` environment variables in your shell so the plugin's MCP server can authenticate:
148+
149+
```bash
150+
export BOOKSTACK_BASE_URL=https://your-bookstack.com
151+
export BOOKSTACK_TOKEN_ID=your-token-id
152+
export BOOKSTACK_TOKEN_SECRET=your-token-secret
153+
```
154+
155+
#### Manual install (alternative)
156+
157+
If you'd rather not use the marketplace, register the server directly with `claude mcp add`. Repeat `--env` for each variable, put all flags **before** the server name, and use `--` to mark the start of the command Claude Code will spawn:
141158

142159
```bash
143160
claude mcp add bookstack \
@@ -178,17 +195,6 @@ The resulting config entry looks like this (in `.mcp.json` for project scope, or
178195

179196
> **Tip for committed `.mcp.json`:** Claude Code expands `${VAR}` and `${VAR:-default}` references in `.mcp.json` from the surrounding shell. Use that to keep secrets out of git: set `"BOOKSTACK_TOKEN_SECRET": "${BOOKSTACK_TOKEN_SECRET}"` in the file and have each developer export the variable in their shell.
180197

181-
### Claude Code (plugin marketplace)
182-
183-
This repo also ships a Claude Code plugin manifest (`.claude-plugin/plugin.json`). Add the marketplace and install:
184-
185-
```
186-
/plugin marketplace add ttpears/claude-plugins
187-
/plugin install bookstack-mcp@ttpears-plugins
188-
```
189-
190-
Then set the `BOOKSTACK_*` environment variables in your shell so the plugin's MCP server can authenticate.
191-
192198
## MCP Resources
193199

194200
Books and pages are also exposed as MCP resources, so clients that browse resources (Claude Desktop, MCP Inspector, etc.) can `@`-mention them directly:

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bookstack-mcp",
3-
"version": "3.3.0",
3+
"version": "3.3.1",
44
"description": "MCP server for BookStack wiki — search, read, create, and manage documentation via AI assistants",
55
"type": "module",
66
"bin": {

src/bookstack-client.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,11 @@ export class BookStackClient {
207207
const nextOffset = offset + slice.length;
208208
const truncated = nextOffset < totalChars;
209209

210-
// Strip duplicate large fields from the base page object
211-
const { html: _h, markdown: _m, text: _t, ...pageMeta } = page;
210+
// Strip duplicate large fields from the base page object. raw_html is the
211+
// unprocessed editor source BookStack returns alongside html/markdown/text;
212+
// leaving it in would bypass the limit/offset pagination and can blow past
213+
// MCP token caps for large pages.
214+
const { html: _h, markdown: _m, text: _t, raw_html: _r, ...pageMeta } = page as any;
212215

213216
return {
214217
...pageMeta,
@@ -424,9 +427,9 @@ export class BookStackClient {
424427
? `${page.text.substring(0, 200)}${page.text.length > 200 ? '...' : ''}`
425428
: 'No content preview available';
426429

427-
// List responses from BookStack don't include html/markdown/text, but strip defensively
428-
// and never embed full content here — use get_page for that.
429-
const { html: _h, markdown: _m, text: _t, ...pageMeta } = page as any;
430+
// List responses from BookStack don't include html/markdown/text/raw_html, but strip
431+
// defensively and never embed full content here — use get_page for that.
432+
const { html: _h, markdown: _m, text: _t, raw_html: _r, ...pageMeta } = page as any;
430433

431434
return {
432435
...pageMeta,

0 commit comments

Comments
 (0)