Skip to main content
metabook-py

metabook-py

PR Matrix Release Python License: MIT

📚 X-ray any book's structure — chapters, paragraphs, sentences, clauses, words — as clean JSON. REST + MCP, Project Gutenberg search or your own EPUB. No book text ever leaves the API.

API docs · MCP server · Desktop example · Workflow

Metabook desktop example searching Pride and Prejudice and exploring its structural schema

Overview

Metabook is a Book Structure API: give it a title, an ISBN, a Gutenberg ID, or an EPUB file, and it returns the book's structural schema — what kind of book it is and how it's shaped — without ever returning the text itself.

Under the hood it locates the book via Gutendex (or walks your uploaded EPUB's spine), downloads and cleans the text, detects the structural schema, and counts everything at every level.

title / ISBN / Gutenberg ID ──► Gutendex ──► fetch + clean ──┐
                                                             ├──► detect schema ──► counts-only JSON
your .epub ──► Vercel Blob ──► package doc + spine XHTML ────┘

✨ Features

  • 🔍 Fuzzy search — find books by title or author via Gutendex, or go straight to an ISBN / Gutenberg ID
  • 🧬 Schema detection — classifies each book as scripture, sectioned_book, standard_book, essay_collection, or flat, with a confidence rating
  • 🔢 Counts, not content — chapters, paragraphs, sentences, clauses, and words per node; a word node is just its index. No book text is ever included in a response
  • 📤 Bring your own EPUBPOST /api/books/upload stores the file in Vercel Blob and analyses it with the same pipeline
  • 🔌 Two interfaces, one service layer — a FastAPI REST API and a FastMCP server share the same core
  • 🖥️ Native desktop client — a GPUI example app with an animated structure tree and a synced JSON code editor

Detail levels

The detail parameter controls how deep the returned tree nests beneath each paragraph:

detail Nested nodes
paragraph paragraphs only (counts for the rest)
sentence + sentence nodes
clause + clause nodes
word + word nodes (index + position only)

Token counts

Pass an optional tokenizer query parameter naming a Hugging Face tokenizer repository (e.g. bert-base-uncased) and every node in the tree carries a token count alongside its word count — special tokens excluded, so parent totals equal the sum of their children. The response metadata echoes the resolved tokenizer name and its vocabulary size. The tokenizer is fetched lazily on first use (cached on disk and in memory afterwards); an unknown name returns 422, a transient fetch failure on cold start returns 503. When the parameter is omitted, no token counts are computed and the response is unchanged.

curl "http://127.0.0.1:8000/api/books/structure?title=Pride+and+Prejudice&tokenizer=bert-base-uncased"

🚀 Quick start

make setup              # install dependencies (uv sync)
make dev                # run the API with auto-reload on :8000
make test               # run the test suite
make docker-up          # or run it via docker compose

Then open the interactive docs at http://127.0.0.1:8000/api/docs, or try:

curl "http://127.0.0.1:8000/api/books/structure?title=Pride+and+Prejudice&detail=sentence"

EPUB uploads

Uploads need a Vercel Blob read-write token in the environment (or .env / .env.local):

export BLOB_READ_WRITE_TOKEN=vercel_blob_rw_...

If the project is linked to Vercel, vercel env pull writes the token to .env.local (gitignored), which the app loads automatically — values there override .env.

Uploads collection (MongoDB, optional)

Every book a user uploads or selects from search results is persisted as a document in a MongoDB uploads collection: the book metadata, format (epub), the Vercel Blob link, and the scan state (scanned yet, last scanned, scope, schema, total token count). The structure tree itself is never stored. Set MONGODB_URI to enable (empty = disabled, no behavior change); re-selecting the same Gutenberg book updates its document instead of duplicating it:

export MONGODB_URI=mongodb://localhost:27017

Browse what's stored via GET /api/books/uploads.

🌐 REST API

Method Endpoint Purpose
GET /api/books/structure Analyse by title, isbn, or gutenberg_id (+ detail, tokenizer)
GET /api/books/structure/schemas List the supported structural schemas
POST /api/books/upload Upload an EPUB and analyse it
GET /api/books/uploads List persisted upload documents (needs MONGODB_URI)
GET /health Liveness + cache stats

Interactive OpenAPI docs live at /api/docs.

🤖 MCP server

A FastMCP server is mounted at /mcp, so agents can use the same service layer through three tools:

Tool Description
search_book_structure Analyse a book by title, ISBN, or Gutenberg ID
upload_book_epub Analyse an EPUB passed as base64 or a URL
list_supported_schemas Enumerate the structural schemas

🖥️ Desktop example (GPUI)

example/ is a native macOS client built with GPUI and gpui-component: a sidebar workspace whose Dashboard holds fuzzy search, EPUB drag-and-drop, and a cover grid of every book the API has scanned; selecting a book gives an animated lazily-materialised structure tree beside a read-only JSON code editor (tree-sitter highlighting, folding) that scrolls to and highlights whichever node you select. Light and dark themes, spring animations, collapsible sidebar.

Metabook desktop example — structure tree synced with the JSON schema editor
More screenshots
Search results Dark mode
Search matches Dark mode

Run it (API first, then the app):

make dev
cd example && cargo run

Or run both with one command (Ctrl-C stops both):

make serve

See example/README.md for the Metabook.app bundle (with app icon) and METABOOK_API configuration.

🌳 Branching and release

CI/release pipeline scaffolded from exegia/corpora-py: same branch model, GitHub Actions workflows, composite actions, and make-driven release automation.

See .github/WORKFLOW.md for the full branch model, versioning rules, and workflow reference. Quick summary:

<type>/<slug> --PR--> dev --(daily/manual)--> next --cut--> release/vX.Y.Z --draft PR--> main
                 (deleted on merge)         (preview)                       (deleted on release)

Common commands

make help                # list all targets
make ci                  # everything CI runs on a PR (lint + test)
make pack                # build the publishable wheel
make rulesets-diff       # rulesets GitHub currently has
make rulesets-apply      # push .github/rulesets/*.json

Bootstrap

There are no dev / next branches until the first wrapup. Run the Release workflow manually (Actions → Release → Run workflow), or locally:

make bootstrap-lanes

📄 License

MIT © Emmanuel De Freitas

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

metabook_py-3.0.0.tar.gz (2.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

metabook_py-3.0.0-py3-none-any.whl (43.9 kB view details)

Uploaded Python 3

File details

Details for the file metabook_py-3.0.0.tar.gz.

File metadata

  • Download URL: metabook_py-3.0.0.tar.gz
  • Upload date:
  • Size: 2.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for metabook_py-3.0.0.tar.gz
Algorithm Hash digest
SHA256 20cd3ea8dca09d54afe40a4f950ef9f18e46b760afe9b1ad9fae5ff66c83ef69
MD5 ce4c807b9cdbccf9488dc6b5c1ef5314
BLAKE2b-256 57d6b35cf2343b11e4efa886d6dd30f91eaf30f58b3c582e827f1f48ab02557e

See more details on using hashes here.

File details

Details for the file metabook_py-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: metabook_py-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 43.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for metabook_py-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 88c4e1db7915fa3f7359bb6a5c462c293ace6742df57b6d682d8223730d1d05a
MD5 a18a3f301851f8eda25863ea9f460d9a
BLAKE2b-256 84abd05366ace22a90ffe4121244dae70b417f0a77369af8bfd4db18b31ea3ee

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

3.0.0 This release

2 files

2.0.0

2 files

1.0.1

2 files

1.0.0

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page