Skip to content

Feature: image gallery tools (create_image, list_images, delete_image) #11

Description

@scocchiarella

Summary

Add tools for BookStack's /api/image-gallery endpoint: upload, list, and delete images in the gallery. We've implemented this in our fork and it's working well — happy to contribute a PR if there's interest.

Why this matters for MCP

MCP's tool interface is text-based JSON — there's no binary streaming primitive. This creates a fundamental problem for image uploads:

Without an upload tool, the only way to get images into BookStack pages is to embed them as base64 data URIs in the html or markdown argument of create_page/update_page. This means:

  • The model must generate the base64 string as output tokens — slow, expensive, and error-prone for large images
  • The full base64 payload transits through the model's context window, consuming tokens that could be used for actual reasoning
  • A 200 KB JPEG becomes ~270 KB of base64 text — multiplied across a page with several figures, this can easily blow past context limits
  • Base64 data URIs aren't real hosted assets — they bloat the page HTML permanently and can't be reused, thumbnailed, or managed in BookStack's gallery

With a create_image tool, the model passes a file path or URL (a few bytes of text), and the MCP server reads/fetches the image bytes directly and uploads them to BookStack. Zero image bytes transit the model. BookStack hosts the image and returns a URL that the model can embed in page content via a normal update_page call. This is the correct MCP pattern for binary content: let the server handle I/O, keep the model interface lightweight.

Proposed tools

create_image (write)

Upload an image to the BookStack gallery from a local file path or URL.

Inputs:
  file_path: string (optional) — absolute path readable by the MCP server
  url: string (optional) — HTTP(S) URL to fetch (exactly one of file_path/url required)
  name: string (optional) — gallery display name (defaults to filename)
  uploaded_to: number — page ID (BookStack requires a page association)

Returns:
  id, name, url, thumbs, plus ready-to-paste html and markdown snippets

list_images (read)

List images in the gallery, optionally filtered by page.

Inputs:
  uploaded_to: number (optional) — filter by page ID
  offset, count, sort — standard pagination

delete_image (write)

Delete an image from the gallery by ID.

Implementation notes from our fork

  • Must use native fetch, not axios, for the multipart upload. The axios instance in BookStackClient sets a default Content-Type: application/json header which clobbers the multipart/form-data boundary. This causes BookStack to fail parsing the body entirely (422 on every request, regardless of inputs). Native fetch sets the boundary automatically from FormData.
  • The createImage client method should surface BookStack's response body in errors — a bare Request failed with status code 422 without the validation details makes debugging very difficult.
  • We store authToken as an instance property on BookStackClient so the fetch call can use it without extracting it from axios internals.
  • Gated behind enableWrite like the other write tools.
  • 50 MB sanity check on upload size (matches typical BookStack/PHP limits).
  • Supports common web formats: PNG, JPEG, GIF, WebP, SVG.

Real-world usage

We use this to let Claude build richly illustrated wiki pages autonomously: it takes screenshots or receives image file paths, uploads them to BookStack's gallery via create_image, gets back hosted URLs, then embeds them in page content via update_page. The entire workflow stays within MCP tool calls — no manual image uploading or copy-pasting URLs.

Happy to open a PR with our implementation if you'd like to include this upstream.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions