About gutenberg-mcp-server
gutenberg-mcp-server lets readers and research workflows search and read Project Gutenberg's public-domain catalog. It provides book metadata and retrieves supported text in chunks, with catalog search backed by a local mirror and Gutendex fallback.
Key features
- 01Search books by title, author, or topic
- 02Filter by language and other fields
- 03Retrieve book metadata and formats
- 04Read text in offset-based chunks
- 05Browse popular books
Use cases
- 01Find books by author, topic, or language
- 02Retrieve metadata for a selected edition
- 03Read long books in sequential chunks
- 04Browse popular titles by topic
MCP support
Exposes Project Gutenberg catalog search, metadata, text retrieval, and popular-book browsing to MCP clients through four tools. Available over STDIO or Streamable HTTP.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://gutenberg.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-gutenberg https://gutenberg.caseyjhand.com/mcp{"mcpServers":{"cyanheads-gutenberg":{"type":"http","url":"https://gutenberg.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-gutenberg":{"type":"http","url":"https://gutenberg.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-gutenberg":{"type":"http","url":"https://gutenberg.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-gutenberg":{"serverUrl":"https://gutenberg.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
4| Parameter | Type | Required | Description |
|---|---|---|---|
| ids | array | No | Narrow results to specific Gutenberg ID numbers. Other filters still apply. Useful for batch pre-fetching known IDs; use gutenberg_get_book for single-ID lookups. |
| page | integer | No | Page number for paginated results (1-indexed). Each page returns up to 32 books. Use totalCount to determine total pages. |
| sort | enum | No | Result ordering. "popular" (default) sorts by downloads in the last 30 days at the source snapshot, descending. "ascending" and "descending" sort by Gutenberg ID number.popular | ascending | descending |
| query | string | No | Words to match against book titles and author names (case-insensitive, space-separated). Example: "dickens expectations" matches Great Expectations by Charles Dickens. |
| topic | string | No | Case-insensitive phrase to match against subjects and bookshelves. Example: "detective" returns books on the "Detective and Mystery Stories" bookshelf. Separate from query — topic searches categorization metadata, not title/author. |
| languages | array | No | Filter to books in any of these two-character ISO 639-1 language codes. Example: ["en"] for English, ["fr", "de"] for French or German. |
| author_year_end | integer | No | Include only books with at least one author alive on or before this year. Example: author_year_start=1800 with author_year_end=1899 returns books with 19th-century authors. |
| author_year_start | integer | No | Include only books with at least one author alive on or after this year (positive = CE, negative = BCE). Combine with author_year_end for a range. |
Details
From the project README@cyanheads/gutenberg-mcp-server
Search, browse, and read 78,000+ public-domain books from Project Gutenberg with full plain-text retrieval and offset/limit chunking via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://gutenberg.caseyjhand.com/mcp
Overview
Project Gutenberg's library of 78,000+ public-domain books. Search by title, author, topic, or language, fetch full book metadata, and read supported UTF-8 plain-text and HTML editions in manageable chunks.
Tools
| Tool | Description |
|---|---|
gutenberg_search_books | Search the catalog by title, author, topic, language, or author lifespan, with pagination and popularity sorting |
gutenberg_get_book | Fetch complete metadata for a book by ID — authors, translators, editors, full formats map, subjects, copyright status |
gutenberg_get_text | Retrieve a book's plain-text content stripped of license boilerplate, with offset/limit chunking |
gutenberg_browse_popular | Browse the most-downloaded books, optionally filtered by language or topic |
Capability reference
gutenberg_search_books tool
- Filters:
query(title/author words),topic,languages(ISO 639-1),author_year_start/author_year_end,ids,mime_type, andcopyright("true","false","null"; false means public domain in the USA). Live fallback rejects queries over four words sortispopular(default) orascending/descendingby Gutenberg ID. Up to 32 books per page; usetotalCountandhasMoreto page- Each result carries
is_readable(readable bygutenberg_get_text) andhas_plain_text. Fails withquery_requires_mirror,page_out_of_range, orcatalog_unavailable
gutenberg_get_book tool
- Returns the full
formatsmap (MIME type → download URL) and authors, translators, and editors with birth/death years - Also carries
is_readable,has_plain_text,summary,source_notes, anddownload_count(downloads in the last 30 days, not lifetime) - Fails with
not_foundorcatalog_unavailable
gutenberg_get_text tool
- Reads a book in
offset/limitchunks (defaultlimit20,000, capped at 50,000), with the Gutenberg license header and footer stripped.requestedLimitandappliedLimitreport both - Prefers UTF-8 plain text and falls back to HTML converted to text;
sourceFormatsays which. ReturnstotalChars,length,remainingChars,hasMore, andprovenance(ID, title, license URL). Uselength, notlimit, to compute the nextoffset - Fails with
not_found,audio_book(media_type "Sound"),no_text_format,offset_out_of_range,text_file_not_found,text_fetch_rejected,invalid_text_response,text_fetch_failed, orcatalog_unavailable
gutenberg_browse_popular tool
- Returns up to 32 titles (
limit, default 20), most downloaded in the last 30 days first.requestedLimitandappliedLimitreport the cap - Optional
languages,topic,mime_type, andcopyrightfilters work as in search.totalInCataloggives the full count - Output reports truncation and carries a
continuationpointing atgutenberg_search_books. Empty results succeed with a notice; fails withcatalog_unavailable
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Gutenberg-specific:
- Searches and lookups read a local SQLite+FTS5 catalog mirror, falling back to Gutendex when the mirror is cold or missing a record
- Full plain-text retrieval from a Project Gutenberg content mirror, with UTF-8/HTML fallback
- Book text is cached per tenant, so later chunk reads skip the fetch
- No API key required
Agent-friendly output:
is_readableon every search and browse result flags editionsgutenberg_get_textcan readoffset,length,totalChars,remainingChars, andhasMoresupport reliable sequential readsprovenanceandsourceFormaton every text response cover attribution and fidelity
Getting started
Public Hosted Instance
A public instance is available at https://gutenberg.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"gutenberg-mcp-server": {
"type": "streamable-http",
"url": "https://gutenberg.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
No API key required. Add the following to your MCP client configuration file:
{
"mcpServers": {
"gutenberg-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/gutenberg-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"gutenberg-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/gutenberg-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"gutenberg-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/gutenberg-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key required — Project Gutenberg data is freely available.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/gutenberg-mcp-server.git
- Navigate into the directory:
cd gutenberg-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env if you need to override any defaults
Configuration
| Variable | Description | Default |
|---|---|---|
GUTENDEX_BASE_URL | Gutendex catalog API base URL. | https://gutendex.com/books/ |
GUTENBERG_TEXT_BASE_URL | Content mirror serving the /cache/epub file tree. | https://gutenberg.pglaf.org |
GUTENBERG_MIRROR_PATH | SQLite catalog path; use a persistent volume in containers. | ./.mirror/gutenberg-catalog.sqlite |
GUTENBERG_MIRROR_REFRESH_CRON | Cron schedule for in-process catalog refresh. | Unset |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_SESSION_MODE | HTTP session mode: auto, stateful, or stateless. Overrides the stateless posture the server declares in createApp(). | stateless |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
Build the local catalog with bun run mirror:init and check it with bun run mirror:verify. The server never harvests on startup, and uses Gutendex until the first harvest completes. Keep the catalog up to date with bun run mirror:refresh on a host scheduler, or set GUTENBERG_MIRROR_REFRESH_CRON.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t gutenberg-mcp-server .
docker run --rm -p 3010:3010 gutenberg-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/gutenberg-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits services. |
src/config/server-config.ts | Server-specific environment variable parsing (Gutendex and file-server URL overrides). |
src/mcp-server/tools/definitions/ | Tool definitions (*.tool.ts). |
src/services/gutendex/ | Gutendex catalog API client — search and book metadata. |
src/services/catalog-mirror/ | Local SQLite+FTS5 catalog mirror — RDF ingestion and read helpers. |
src/services/gutenberg-text/ | Full plain-text retrieval, boilerplate stripping, tenant-scoped caching, and chunking. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md / AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools via the entry arrays in
src/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Data attribution
Data from Project Gutenberg is in the public domain. Catalog metadata sourced from Gutendex (MIT license).
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.