Skip to main content
Glama
README.md
# bookbind

bookbind is a small local bridge to Epublys, a hosted
service that works on EPUB and PDF ebooks: merging and
splitting books, compressing them, converting between
formats, editing metadata, checking a file for spec
problems, and generating cover art. This package does
none of that work itself. It stands in front of the
service's remote MCP endpoint, presents the upstream
tool list locally exactly as captured, and passes each
call through, returning whatever the upstream returns.

That split matters in practice. The conversions,
metadata edits and validation verdicts all come from
Epublys' own machinery, so a result you get through
bookbind is the service's result, not a local
approximation. The bridge adds no processing of its
own and rewrites nothing on the way back. Most tools
take base64-encoded file content (`file`, or `files`
for the multi-file tools) and return base64-encoded
output; the upstream's own free-tier and Pro limits,
as described in each tool's description, apply
upstream.

## Tools

This build serves a **labelled subset** of the
captured surface: 12 of the 13 tools seen in the live
capture. The omitted tool is `upgrade_to_pro`, which
returns a checkout link so the user can upgrade their
account to a paid tier; a payment funnel is out of
scope for this program, so the tool is deliberately
absent, and a test asserts that absence. The remaining
tools are document operations, served verbatim —
including `epub_to_pdf`, whose captured description
carries the upstream's own Pro-tier language. This
rebuild adds no payment or gating machinery of its
own.

- `merge_epub` — merge two or more EPUB files
  (`files`, required) into one ebook with a table of
  contents and chapter dividers; optional `names`,
  `title`, `author` and `dividers`.
- `split_epub` — split one EPUB (`file`, required).
  With a chapter range (`chapterStart` /
  `chapterEnd`) the result is a single EPUB of exactly
  those chapters; without one it is a ZIP holding one
  EPUB per chapter.
- `compress_epub` — shrink an EPUB (`file`,
  required), with a compression `level` from 1 to 9
  and an option to strip unused assets.
- `read_epub_metadata` — read an EPUB's metadata
  (`file`, required): title, author, language,
  publisher, description, series, cover status and
  more, returned as JSON.
- `edit_epub_metadata` — edit metadata fields in an
  EPUB (`file`, required): title, author(s), language,
  publisher, description, series, subjects, ISBN,
  date, even a new cover image; returns the modified
  EPUB.
- `epub_to_pdf` — convert an EPUB (`file`, required)
  to PDF, with page size, margins, font and page
  number options.
- `pdf_to_epub` — convert a PDF (`file`, required) to
  an EPUB, with automatic chapter detection, chapter
  grouping modes and optional image extraction.
- `markdown_to_epub` — build an EPUB3 ebook from
  Markdown files (`files`, required), one file per
  chapter in array order; understands YAML frontmatter
  and Obsidian wikilinks.
- `docx_to_epub` — convert a Word document (`file`,
  required) to an EPUB3 ebook, splitting chapters on
  headings or page breaks and keeping formatting,
  lists, tables, images and footnotes.
- `epub_to_markdown` — convert an EPUB (`file`,
  required) to Markdown: a ZIP with one file per
  chapter, an index, and the referenced images.
- `validate_epub` — validate an EPUB (`file`,
  required) for errors, compatibility issues and spec
  compliance; returns JSON check results, with an
  optional deep scan and auto-fix.
- `generate_cover` — generate an AI book cover image
  from a creative `description` and a `genre`, with
  optional `title`, `author` and `seed`. No argument
  is required by the captured schema, though the
  upstream expects a description or a title.

## Configuration

- `EPUBLYS_MCP_URL` (optional) — override the
  upstream endpoint. Defaults to
  `https://epublys.com/mcp`. (The override hook is
  this rebuild's own labelled reconstruction.)
- `EPUBLYS_API_KEY` (optional) — when set, every
  upstream request carries
  `Authorization: Bearer <key>`. When it is not set,
  no auth header is sent, matching the keyless
  capture this rebuild is based on. (The header
  behaviour is a labelled reconstruction; the
  registry record declares an optional Authorization
  header for the remote, but the capture was taken
  without one.) Account-scoped behaviour is served
  upstream under the caller's own credential.

### Forwarding mechanics

On the first tool call the client opens a
streamable HTTP session upstream: a JSON-RPC
`initialize` request (protocolVersion `2025-03-26`,
clientInfo name `bookbind`), then a
`notifications/initialized` notification, then the
`tools/call` request carrying the caller's
arguments unchanged. When the upstream answers
`initialize` with an `Mcp-Session-Id` header, that
value rides on every later request, and the session
is reused for the life of the process. Replies may
arrive as plain JSON or as server-sent events; both
are read, and the message with the matching id wins.

Successful upstream results pass through verbatim,
including any `isError` flag the upstream sets and
any extra fields it adds. Failures — a JSON-RPC
error, a non-2xx status, an unreadable response, or
a request that cannot be completed — come back as
an `isError` result whose text starts with
`bookbind error:` (this rendering is this
rebuild's own labelled reconstruction).

## CLI

Each tool is also a subcommand taking one JSON
argument string (omit it for tools that take none):

```bash
npx @reneturcios/bookbind read_epub_metadata '{"file":"<base64-epub>"}'
npx @reneturcios/bookbind generate_cover '{"description":"a lighthouse at dusk","genre":"literary"}'
npx @reneturcios/bookbind validate_epub '{"file":"<base64-epub>","deepScan":true}'
npx @reneturcios/bookbind --version
```

Exit codes: `0` on success, `1` on an `isError`
result, `2` on a usage error.

## MCP server

```bash
npx -y @reneturcios/bookbind mcp
```

MCP client config:

```json
{
  "mcpServers": {
    "bookbind": {
      "command": "npx",
      "args": ["-y", "@reneturcios/bookbind", "mcp"]
    }
  }
}
```

## Docker

```bash
docker run -i ghcr.io/cloudcorprecords/bookbind
docker run --rm ghcr.io/cloudcorprecords/bookbind --version
```

The container's default command is `mcp`, so the first
form is a stdio MCP server; any other arguments reach
the CLI normally.

## Development

```bash
npm install
npm run build
npm test
npm run dev
```

The test suite runs entirely against a stubbed
JSON-RPC upstream — no live network calls.

## License

MIT — see `LICENSE`.