Skip to main content
Glama
cyanheads

gutenberg-mcp-server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

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


Related MCP server: books-catalog

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, and copyright ("true", "false", "null"; false means public domain in the USA). Live fallback rejects queries over four words

  • sort is popular (default) or ascending/descending by Gutenberg ID. Up to 32 books per page; use totalCount and hasMore to page

  • Each result carries is_readable (readable by gutenberg_get_text) and has_plain_text. Fails with query_requires_mirror, page_out_of_range, or catalog_unavailable


gutenberg_get_book tool

  • Returns the full formats map (MIME type → download URL) and authors, translators, and editors with birth/death years

  • Also carries is_readable, has_plain_text, summary, source_notes, and download_count (downloads in the last 30 days, not lifetime)

  • Fails with not_found or catalog_unavailable


gutenberg_get_text tool

  • Reads a book in offset/limit chunks (default limit 20,000, capped at 50,000), with the Gutenberg license header and footer stripped. requestedLimit and appliedLimit report both

  • Prefers UTF-8 plain text and falls back to HTML converted to text; sourceFormat says which. Returns totalChars, length, remainingChars, hasMore, and provenance (ID, title, license URL). Use length, not limit, to compute the next offset

  • 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, or catalog_unavailable


  • Returns up to 32 titles (limit, default 20), most downloaded in the last 30 days first. requestedLimit and appliedLimit report the cap

  • Optional languages, topic, mime_type, and copyright filters work as in search. totalInCatalog gives the full count

  • Output reports truncation and carries a continuation pointing at gutenberg_search_books. Empty results succeed with a notice; fails with catalog_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_readable on every search and browse result flags editions gutenberg_get_text can read

  • offset, length, totalChars, remainingChars, and hasMore support reliable sequential reads

  • provenance and sourceFormat on 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

  1. Clone the repository:

git clone https://github.com/cyanheads/gutenberg-mcp-server.git
  1. Navigate into the directory:

cd gutenberg-mcp-server
  1. Install dependencies:

bun install
  1. 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/catch in tool logic

  • Use ctx.log for request-scoped logging, ctx.state for 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.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A well-documented MCP server that exposes a local SQLite catalog of public-domain books through tools like search, get, filter by genre, top-rated, and catalog stats.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables search and reading of Project Gutenberg books with tools for searching by title/author/subject and fetching word-range slices of book text.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    This MCP server enables AI agents to search and retrieve exact, cited passages from a large corpus of public-domain books, including full-text search, book metadata, chapters, quotes, and 'ask book' Q&A. Payments are handled via x402 micropayments on Base.
    8
    53 npm
    MIT