Skip to content

feat: add update_book and update_chapter tools - #20

Merged
ttpears merged 2 commits into
ttpears:mainfrom
strausmann:feat/update-book-chapter-tools
Aug 27, 2026
Merged

feat: add update_book and update_chapter tools#20
ttpears merged 2 commits into
ttpears:mainfrom
strausmann:feat/update-book-chapter-tools

Conversation

@strausmann

Copy link
Copy Markdown
Contributor

Summary

Books and chapters could be created and deleted, but not renamed or moved,
via the MCP layer — the only way to rename one was to drop to the raw
BookStack REST API. update_chapter closes most of the gap tracked in #12
(thanks @scocchiarella for the API research there — the field list below
matches your proposal).

  • update_book(id, {name?, description?, tags?})
  • update_chapter(id, {name?, description?, book_id?, priority?, tags?})
    book_id moves the chapter to another book, priority reorders it
    within its book.

Scope notes:

  • Not included: Feature: update_chapter tool and priority support for content ordering #12 also proposed adding priority to update_page. Left
    out to keep this focused — happy to follow up.
  • update_book intentionally exposes only name/description/tags,
    matching update_shelf's scope. image_id (multipart upload, not a
    JSON PUT field) and default_template_id were left out deliberately;
    easy to add later if wanted.
  • Both mirror the existing update_page/update_shelf pattern exactly:
    same write-gate guard, same enhance*Response wrapping, same Zod schema
    style. No new patterns, no new permission logic.

Testing

type-check / build / test all pass unchanged (the existing 4-test
suite covers only the concurrency limiter).

Heads-up on the test setup — I did NOT use a throwaway instance as
CONTRIBUTING.md recommends.
I verified end-to-end against an existing,
live BookStack instance with the built server (BOOKSTACK_ENABLE_WRITE=true):
renamed a book, renamed + reordered a chapter, and moved a chapter to a
different book — all via the new tools, independently confirmed via a
second untouched MCP session against the same instance. All test objects
were clearly marked (PRTEST-…), created and then permanently deleted as
part of the run; recycle bin verified empty afterward. Nothing left behind.

No new automated tests were added: the project has no coverage of actual
BookStack API calls anywhere (per CONTRIBUTING.md), and introducing an
API-mocking harness felt like a separate decision for you rather than
something to bundle here. Not re-tested explicitly: the ENABLE_WRITE=false
path and invalid-id / non-existent-target-book error paths — both go
through the exact same shared code as update_page/update_shelf.

Version

Left package.json untouched — say the word for a bump (5.3.0 → 5.4.0)
since that triggers your tag/release flow.

Books and chapters could only be created and deleted, not renamed or
moved, via the MCP layer — the only way to rename one was to drop down
to the raw BookStack REST API. update_chapter also closes the gap
tracked in ttpears#12 (rename/move a chapter without reaching for curl).

Both tools mirror the existing update_page/update_shelf pattern
exactly: same write-gate guard, same enhance*Response wrapping, same
Zod schema style. update_chapter additionally accepts book_id (move to
a different book, matching update_page's book_id semantics) and
priority (reorder within its book).

Verified against a live BookStack instance: type-check/build/tests
pass unchanged, and both tools were exercised end-to-end (rename,
priority change, and a cross-book move) via the built server, with the
result independently confirmed by an untouched second MCP session.
Test objects were created and permanently removed as part of the
verification. No new tests were added — this repo's existing suite
only covers the concurrency limiter, and introducing an API-mocking
harness for it felt like a separate decision to leave to the
maintainer rather than bundle in here.
Copilot AI lite review requested due to automatic review settings August 6, 2026 08:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds missing BookStack “update” capabilities for books and chapters to the MCP server’s write-tool surface area, aligning these operations with existing update_page / update_shelf patterns so users can rename/move/reorder without dropping to raw REST calls.

Changes:

  • Register new write tools: update_book and update_chapter (with book_id move + priority reorder support).
  • Implement corresponding BookStackClient methods: updateBook() and updateChapter() using PUT endpoints.
  • Update README feature/tool listing to reflect the added tools and updated write-tool count.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/index.ts Registers update_book and update_chapter write tools with Zod input schemas and tool handlers.
src/bookstack-client.ts Adds updateBook and updateChapter client methods that call BookStack PUT endpoints and return enhanced responses.
README.md Updates tool counts and write-tool table to include the new update tools.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/index.ts
priority is an integer sort order; the schema previously accepted floats
and negatives via z.coerce.number(), which BookStack would reject or sort
unexpectedly. Constrain it at the tool boundary to a non-negative integer.
@strausmann

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot note on priority: it now validates as a non-negative integer at the tool boundary (z.coerce.number().int().min(0)), so floats and negatives are rejected up front rather than surfacing as a BookStack error or unexpected ordering (fa51cb9). type-check/build/tests still pass unchanged.

Ashton210z added a commit to Ashton210z/bookstack-mcp that referenced this pull request Aug 25, 2026
update_page already supports moving content between books; update_chapter
was missing the equivalent. book_id moves the chapter to a different book,
priority reorders it within its book (matches upstream PR ttpears#20's proposal).

@ttpears ttpears left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build is green, and a trial merge onto main passes type-check/build/test locally (9/9).

docker-preview failing is not this PR — fork PRs get a read-only GITHUB_TOKEN, so the GHCR push returns denied: installation not allowed to Write organization package. Only build is required. Gating that job on same-repo PRs is a separate fix.

Test setup is fine as described — a PUT passthrough doesn't need a throwaway instance.

re: version — leave package.json alone, I'll cut the release.

update_page priority from #12 stays open as the follow-up.

@ttpears
ttpears merged commit bf679bf into ttpears:main Aug 27, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants