Skip to main content
Glama
frogr
by frogr

gutenberg-mcp

An MCP server that lets Claude, ChatGPT, Cursor or any MCP client search, read and accurately quote public-domain books from Project Gutenberg, the free library of 75,000+ ebooks. MCP (Model Context Protocol) is the open standard that lets AI apps call outside tools.

It finds books through Gutendex (a JSON API over the Gutenberg catalog), downloads the plain text from a Project Gutenberg mirror, strips the license header and footer, detects the chapters, and gives the model stable line numbers to read and cite. Its most useful tool is quote_check: it tells the model whether a quotation is really in the book, how faithful the copy is, and what the book actually says. It runs locally over stdio (npx -y github:frogr/gutenberg-mcp) or as a remote server over Streamable HTTP with a web playground. No API key.

Playground: quote_check on a famous misquote

What you can ask

Is "Call me Ishmael" really the first line of Moby Dick? Which chapter?

Quote the opening sentence of Pride and Prejudice exactly, with the line number.

Does Sherlock Holmes ever say "Elementary, my dear Watson" in The Adventures of Sherlock Holmes?

Read me the first stave of A Christmas Carol.

Where does the white whale come up most in Moby Dick?

How long is Dracula, and which chapter is the longest?

Related MCP server: gutenberg-mcp

Why quote_check exists

Language models misquote. They smooth out punctuation, swap a word ("Lead on, Macduff" for "Lay on, Macduff"), merge two lines, or attach a film line to the book it was adapted from. The result reads right and is wrong, and it ends up in essays, slides and articles.

quote_check checks the quote against the real text at four levels, strictest first, and reports the first that matches:

match

Meaning

Example

exact

Same characters (only spacing and line breaks differ)

"Call me Ishmael." in Moby Dick

typography

Only quote marks, apostrophes, dash style or _italic_ markers differ

don't vs don’t, -- vs —

case

Same text, different capitals

"Marley was dead" vs "MARLEY was dead"

words

Same words in order, punctuation differs

Austen's opening line without its comma

none

Not in the book

"Elementary, my dear Watson"

Every hit comes back with its line numbers, chapter and the book's own lines, so the model can quote from the text instead of from memory. When the quote is not there, it returns the closest real passage (the window of the book that shares the most words with the quote, ranking content words above words like "the") and lists the words that are missing. Parts joined by ... are checked in order. A match can't start or end inside a word, so "all me Ishmael" does not match.

Install

Requires Node.js 20 or newer.

The package is not on npm yet. The commands below install it straight from GitHub with npx -y github:frogr/gutenberg-mcp: npm clones the repo, installs dependencies and builds it (a prepare script runs npm run build). The first start takes about 20 seconds while that happens, so run it once in a terminal before adding it to a client. If you'd rather not run a build through npx, use From source.

After the package is published to npm, npx -y gutenberg-mcp will do the same thing. Until then, don't run that name: nothing has been published under it by this project.

Claude Code

# local, over stdio
claude mcp add --transport stdio gutenberg -- npx -y github:frogr/gutenberg-mcp

# or a hosted copy, over HTTP
claude mcp add --transport http gutenberg https://YOUR-HOST/mcp

Claude Desktop

Add this to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop:

{
  "mcpServers": {
    "gutenberg": {
      "command": "npx",
      "args": ["-y", "github:frogr/gutenberg-mcp"]
    }
  }
}

For a hosted copy on a Pro, Max, Team or Enterprise plan: in Settings, open Connectors, choose Add custom connector, and paste https://YOUR-HOST/mcp.

Cursor

Add to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):

{
  "mcpServers": {
    "gutenberg": { "command": "npx", "args": ["-y", "github:frogr/gutenberg-mcp"] }
  }
}

For a hosted copy, use { "url": "https://YOUR-HOST/mcp" } instead.

Other clients

Any client that speaks MCP over stdio or Streamable HTTP works. To poke at the server by hand, run npx @modelcontextprotocol/inspector.

From source

git clone https://github.com/frogr/gutenberg-mcp && cd gutenberg-mcp
npm ci   # also builds dist/ through the prepare script
# stdio: "command": "node", "args": ["/absolute/path/to/gutenberg-mcp/dist/index.js"]
# HTTP:  npm start  (playground at http://localhost:3000, MCP at /mcp)

Tools

Tool

What it does

Key inputs

Returns

search_books

Search the catalog by title and author words

query, author, language (two-letter codes), topic, page

Book ids, titles, authors with life years, subjects, 30-day downloads, whether a plain-text edition exists

get_book

Metadata plus the table of contents

id

Title, authors, subjects, summary, line count, and every detected chapter/letter/stave/act/scene with start and end lines

read_passage

Read by chapter or line

id, chapter or start_line, max_lines ≤ 200

Numbered lines, the chapter they belong to, next_start_line for paging

find_in_book

Find a word or phrase

id, query, whole_word, max_results ≤ 20, context_lines ≤ 5

Total count, counts per chapter, first matches with numbered context

quote_check

Verify a quotation

id, quote (≤ 2,000 chars), case_sensitive

found, match level, verdict, every location with the real lines, or the closest passage and the missing words

book_stats

Count things

id, top_n

Words, unique words, sentences, average sentence and word length, reading time, top content words, longest and shortest chapter

Every tool is read-only (readOnlyHint: true), validates its input with zod, and declares an outputSchema. Results come back as JSON text, which every client can read, and as structuredContent for clients that use it. Every result that contains book text carries an attribution line naming the book and linking its gutenberg.org page (see Attribution).

How it works

Text comes from a mirror, not www.gutenberg.org. Project Gutenberg's robot policy says the main site is for human visitors, that automated access can get an IP blocked, and points programs to mirrors. So book files are downloaded from https://gutenberg.pglaf.org/cache/epub/{id}/pg{id}.txt by default. That host is the high-speed mirror Project Gutenberg runs itself (it is in their mirror list), and it serves the same files at the same paths: Pride and Prejudice (pg1342.txt) had the same checksum on both hosts when this was checked. Set GUTENBERG_MIRROR to use another mirror that serves cache/epub/, or your own rsync copy. Reading a book does not wait for the catalog. If the file is missing, the server asks Gutendex for the book's formats, takes the best text/plain one (UTF-8 first) and maps it to the same file on the mirror (ebooks/{id}.txt.utf-8 becomes cache/epub/{id}/pg{id}.txt; files/1342/1342-0.txt becomes 1/3/4/1342/1342-0.txt, the mirror's directory layout). URLs that aren't Project Gutenberg files are refused. Files over 16 MB are refused while streaming, before they are held in memory.

License header and footer. Everything before *** START OF THE PROJECT GUTENBERG EBOOK ... *** and after the matching END line is removed, including older variants (THIS PROJECT GUTENBERG EBOOK, E-BOOK, End of the Project Gutenberg EBook of ...). The title, author, language and release date are read from the header first, so get_book can still answer if the catalog is down. A short attribution line replaces the license (see Attribution).

Line numbers. Line 1 is the first line after the header. All tools use the same numbering, so a line from find_in_book can go straight into read_passage or a citation.

Chapters. A heading is a short line after a blank line that is either a keyword plus a number (CHAPTER XII., Chapter 3: The Ball, BOOK THE FIRST, STAVE III, Letter 4, SCENE II. A Street.), a Roman numeral with an all-caps title (IV. THE BOSCOMBE VALLEY MYSTERY) or a title on the next line, or a section word (PREFACE, ETYMOLOGY, EPILOGUE). Then:

  • a run of three or more headings with no text between them is a printed contents page and is dropped;

  • book, part, volume and act headings group what follows, so CHAPTER I of Book Two is not a duplicate of CHAPTER I of Book One;

  • a heading printed twice keeps the later copy, and borrows the earlier copy's title if it has none;

  • a bare word like PROLOGUE. with a speech right under it is a character in a play, not a heading;

  • if nothing else is found, a bare I, II, III sequence is used (short works like Heart of Darkness).

scripts/eval.mjs checks this against 21 books (see PROOF.md).

Search. find_in_book and quote_check search a normalized copy of the book (line breaks become spaces; curly quotes, dashes and _italics_ markers are unified; case folded) and map each hit back to its source lines with a binary search over per-line offsets. That index costs one integer per line, not per character.

Caching. Parsed books live in an in-memory LRU bounded by an estimated byte budget (BOOK_CACHE_MB, default 160) and 24 entries. Two tools asking for the same book at once share one download. Catalog responses (Gutendex, and the gutenberg.org search feed below) are cached for an hour, so a repeated search doesn't reach either service again.

Gutendex is sometimes slow. Popular searches come back in under a second, but uncached ones took 40 to 60 seconds or timed out when tested (see PROOF.md). So search_books waits 8 seconds for Gutendex and then answers from gutenberg.org's own OPDS search feed (the catalog feed that e-reader apps use; ids, titles and authors only, no filters), saying so in source and note. This is the only request that goes to www.gutenberg.org. It happens only when Gutendex is slow, is cached for an hour, and counts against the server's per-IP and daily limits. The Gutendex request keeps running and is cached for next time. get_book waits up to 3 seconds for the catalog after the text arrives, then falls back to the title and author in the file header.

Errors. Upstream failures become tool errors (isError: true) that say what happened and what to try next:

No Project Gutenberg book has id 424242. (HTTP 404)
Hint: Use search_books to find the right id.

Unexpected errors are logged on the server and reach the client only as a generic message.

Remote server

npm start (or node dist/http.js) serves:

Route

Purpose

POST /mcp

MCP over Streamable HTTP, stateless, JSON responses (official @modelcontextprotocol/sdk transport)

GET /health

Status, version, cached book count, the text mirror, limits. Never calls upstream.

GET /

Web playground: run every tool from a form, rendered results, raw JSON toggle, client config snippets

Limits, all set by env var: 30 requests per minute per IP on /mcp (token bucket, RATE_LIMIT_PER_MINUTE), 5,000 requests per UTC day across everyone (DAILY_REQUEST_LIMIT), 64 KB request bodies (MAX_BODY_BYTES, enforced while streaming), 30 seconds per request (REQUEST_TIMEOUT_MS), slow-header protection, and CORS (CORS_ORIGINS, default *). Rate-limited responses carry Retry-After. Behind a proxy, set TRUST_PROXY to the number of proxies so the real client IP is used and a spoofed X-Forwarded-For is ignored. The playground page is served with a strict Content-Security-Policy and builds all book text into the page as text nodes, never HTML.

Configuration

Env var

Default

Purpose

GUTENDEX_URL

https://gutendex.com

Catalog API. Gutendex is open source; point this at your own copy if you need speed.

GUTENBERG_MIRROR

https://gutenberg.pglaf.org

Where book texts are downloaded from. Any Project Gutenberg mirror that serves cache/epub/.

GUTENDEX_TIMEOUT_MS

20000

Timeout for one catalog request

TEXT_TIMEOUT_MS

30000

Timeout for one book download

MAX_BOOK_MB

16

Largest book file accepted

BOOK_CACHE_MB

160

Memory budget for parsed books (estimated)

PORT, HOST

3000, 0.0.0.0

HTTP only

RATE_LIMIT_PER_MINUTE

30

HTTP only, per IP

DAILY_REQUEST_LIMIT

5000

HTTP only, global

MAX_BODY_BYTES

65536

HTTP only

REQUEST_TIMEOUT_MS

30000

HTTP only

CORS_ORIGINS

*

HTTP only, * or a comma-separated allow list

TRUST_PROXY

0

HTTP only, number of reverse proxies in front

.env.example lists them all.

Deploy

Render (free plan)

  1. Push this repo to GitHub.

  2. In Render: New > Blueprint, pick the repo. render.yaml sets up a free web service with npm ci && npm run build, npm start, a /health check, TRUST_PROXY=1 and BOOK_CACHE_MB=150 (the free plan has 512 MB of RAM).

  3. When it is live, open the URL for the playground. The MCP endpoint is https://<your-service>.onrender.com/mcp.

Free Render services sleep when idle, so the first request after a while takes longer, and the book cache starts empty after each sleep.

Docker

docker build -t gutenberg-mcp .
docker run -p 3000:3000 gutenberg-mcp

Development

npm install
npm test                         # vitest, recorded fixtures only, no network
npm run typecheck
npm run build
node scripts/smoke.mjs           # stdio: initialize + tools/list (add --live for a real call)
node scripts/smoke-http.mjs      # HTTP: /health, CORS, initialize, tools/list, playground (add --live)
node scripts/call.mjs quote_check '{"id":2701,"quote":"Call me Ishmael."}'   # one live tool call
node scripts/eval.mjs            # live accuracy check: 22 quotes, 21 books
node scripts/screenshots.mjs     # Playwright screenshots of the playground into docs/screenshots

Tests run against two recorded book excerpts (Moby Dick and Pride and Prejudice, with their real license header and footer), recorded Gutendex and gutenberg.org search responses, and a mocked fetch that throws on any request it does not expect. test/server.test.ts runs the full MCP protocol in memory; test/http.test.ts runs the SDK client against a real local socket.

src/
  index.ts            stdio entrypoint (the package bin)
  http.ts, app.ts     remote server: Node adapter, routes, limits
  server.ts           tool registration
  gutenberg.ts        Gutendex + mirror client: timeouts, retries, caches, errors
  book.ts             a parsed book: lines, chapters, lazy search indexes and stats
  text/               header stripping, chapter detection, normalization, stats, LRU
  tools/              one file per tool: zod input/output schemas + handler
public/index.html     playground (no build step, no dependencies)
eval/                 hand-labeled quotes and book structures for scripts/eval.mjs

Attribution

Every result with book text carries a line like this:

"Pride and Prejudice" by Jane Austen. Public domain text (USA), eBook #1342: https://www.gutenberg.org/ebooks/1342

It doesn't say "Project Gutenberg" on purpose. The server strips the Project Gutenberg license header and footer from each book. Project Gutenberg's license says that once you strip the license and all references to Project Gutenberg, you can do anything you want with the text, and that the name is a trademark reserved for copies that keep the license. Their permissions page also says crediting them as a source, with a link to the book's landing page, needs no permission, and the license lists links in acknowledgements as not using the trademark. So the line names the book, says it's public domain in the USA, and links the landing page, without presenting the stripped text as a Project Gutenberg eBook. Outside the USA, check your own country's copyright rules.

License

MIT © Austin French. Book texts are public domain in the USA and come from Project Gutenberg's collection; this project is not affiliated with Project Gutenberg or Gutendex.


Need an MCP server for your own data? austn.net

Available Tools

6 tools
book_statsBook statisticsA
Read-onlyIdempotent

Compute statistics for a Project Gutenberg book: word count, unique words, average sentence and word length, reading time, most frequent content words, and the longest and shortest chapters. Deterministic counting, no model involved.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesProject Gutenberg book id, e.g. 2701 (Moby Dick) or 1342 (Pride and Prejudice). Find ids with search_books.
top_nNoHow many most-frequent words to list (5-50, default 20).

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
noteNo
titleNo
top_wordsYesMost frequent words, excluding English function words, Mr/Mrs and numbers.
line_countYes
word_countYes
attributionYesCredit line to keep with any quoted text.
unique_wordsYesDistinct lowercased word forms.
chapter_countYes
sentence_countYesApproximate: ends of sentences found by punctuation, skipping common abbreviations like Mr.
longest_chapterNo
shortest_chapterNo
type_token_ratioYesunique_words / word_count. Falls naturally as books get longer, so compare books of similar length.
reading_time_minutesYesAt 238 words per minute.
avg_word_length_charsYes
avg_sentence_length_wordsYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=true, so safety is covered. The description adds a meaningful behavioral trait beyond them: results come from deterministic counting rather than a model, so outputs are reproducible and non-hallucinated. It does not, however, note failure modes (e.g., network fetch errors for openWorld access) or performance characteristics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the verb and resource, and the metric list is justified because it tells the agent what the tool returns without opening the output schema. Slightly dense but no wasted sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema, rich annotations, and 100% parameter coverage, the description only needs to convey what is computed and that it is deterministic — which it does. Minor remaining gap: no note that fetching book text may depend on external availability despite openWorldHint.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents id (with examples and a pointer to search_books) and top_n (range and default). The description adds no additional parameter semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Compute) and resource (statistics for a Project Gutenberg book), then enumerates the exact metrics produced (word count, unique words, sentence/word length, reading time, frequent words, chapter extremes). This clearly separates it from metadata-oriented siblings like get_book or search_books.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the enumerated metrics, but there is no explicit when-to-use/when-not statement or named alternative among siblings (get_book, read_passage, find_in_book). The 'deterministic counting, no model involved' note hints at reliability rather than routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_in_bookFind in bookA
Read-onlyIdempotent

Find every occurrence of a word or phrase in a Project Gutenberg book. Returns the total count, per-chapter counts, and the first matches with line numbers and surrounding lines. Ignores case, quote style, dash style and line breaks.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesProject Gutenberg book id, e.g. 2701 (Moby Dick) or 1342 (Pride and Prejudice). Find ids with search_books.
queryYesWord or phrase to find, e.g. "white whale". Case, curly vs straight quotes, dash style and line breaks are ignored.
whole_wordNoOnly match whole words ("whale" will not match "whales"). Default false.
max_resultsNoMatches to return with context (1-20, default 10). total_matches always counts all of them.
context_linesNoLines of context before and after each match (0-5, default 1).

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
noteNo
queryYes
matchesYes
returnedYes
by_chapterYesMatch counts per chapter, in book order (chapters with no matches left out).
attributionYesCredit line to keep with any quoted text.
total_matchesYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, open world), and the description layers on matching semantics (case, quote style, dash style and line breaks ignored) and truncation behavior (only 'the first matches' are returned while counts are complete). That is real added context, though the normalization claim largely duplicates the query parameter description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: purpose first, then what is returned, then matching behavior. Nothing is padding, and the most decision-relevant information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need only frame the operation, and it does so along with a quick summary of the return payload and matching rules. Nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter including whole_word, max_results and context_lines is already fully documented in the schema. The description adds no parameter-level detail beyond the schema, which is the expected baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find every occurrence of a word or phrase in a Project Gutenberg book') plus the result shape, which cleanly separates it from search_books (finds books), get_book/read_passage (retrieves text) and book_stats (aggregates). An agent can tell what this does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the purpose — you call it to locate occurrences inside a known book — but the description never states when to use this versus search_books or quote_check, which also operate on book text. No exclusions or conditions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_bookBook details and chaptersA
Read-onlyIdempotent

Get one Project Gutenberg book's metadata (title, authors, languages, subjects, summary) and its table of contents: every detected chapter, letter, stave, act or scene with start and end line numbers. Call this before read_passage to pick a chapter.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesProject Gutenberg book id, e.g. 2701 (Moby Dick) or 1342 (Pride and Prejudice). Find ids with search_books.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
urlYes
noteNo
titleYes
authorsYes
summaryNo
chaptersYesDetected table of contents with line offsets. Empty when the book has no recognizable headings.
subjectsYes
languagesYes
line_countYesLines in the book text after the license header and footer are removed. All line numbers refer to this text.
attributionYesCredit line to keep with any quoted text.
bookshelvesYes
release_dateNoProject Gutenberg release date, from the file header.
chapter_countYes
download_countNo
metadata_sourceYestext_header means the catalog was unavailable and title/author come from the book file.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so safety is covered. The description adds useful behavioral context beyond that: the return payload includes metadata fields and a per-unit table of contents with line ranges, which tells the agent what granularity of chapter boundaries to expect.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The payload description comes first and the workflow guidance ('call before read_passage') is front-loaded at the end where it is easiest to act on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not enumerate return values, and it correctly focuses on scope, contents, and call ordering. Annotations cover safety, the sole parameter is fully documented in the schema, and the relationship to read_passage is stated — nothing needed to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'id' parameter is already documented with range and examples in the schema itself. The description adds no id syntax, format, or lookup detail beyond what the schema supplies, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get one Project Gutenberg book's metadata... and its table of contents') and enumerates exactly what the TOC contains (chapters, letters, staves, acts, scenes with start/end line numbers). It is clearly distinguishable from siblings like search_books and read_passage by naming the latter directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit sequencing guidance: 'Call this before read_passage to pick a chapter,' which tells the agent when this tool is the right entry point. It stops short of a full when-not/alternative matrix (e.g., when to prefer book_stats or find_in_book instead), but the primary workflow is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

quote_checkVerify a quotationA
Read-onlyIdempotent

Check whether a quotation really appears in a Project Gutenberg book, and how exactly. Reports the strictest match (exact, typography-only differences, case, or punctuation), every location with the book's actual lines, and, when the quote is not there, the closest real passage. Use it before quoting a public-domain book.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesProject Gutenberg book id, e.g. 2701 (Moby Dick) or 1342 (Pride and Prejudice). Find ids with search_books.
quoteYesThe quotation to verify, e.g. "Call me Ishmael." Surrounding quote marks are ignored. Use "..." for omitted words.
case_sensitiveNoRequire matching capitalization. Default false.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
foundYes
matchYesStrictest level that matched: exact > typography (quote/dash style) > case > words (punctuation differs) > none.
quoteYes
closestNoWhen not found: the passage sharing the most words with the quote (at least half), to show what the text really says.
verdictYesOne sentence explaining the result.
locationsYes
attributionYesCredit line to keep with any quoted text.
occurrencesYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a read-only, idempotent, non-destructive, open-world call, so the safety profile is covered. The description adds genuine behavioral context beyond that: it reports the strictest match tier, returns every location with the book's actual lines, and falls back to the closest real passage when no match exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense sentence carries the capability and return tiers, and a short second sentence gives the call-to-action. Everything is front-loaded and each clause (match tiers, locations, closest-passage fallback) earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, annotations covering safety, and full schema coverage on parameters, the description needs only to convey purpose, usage context, and match-report behavior — all of which it does. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so id, quote, and case_sensitive are already documented in the schema; baseline is 3. The description's mention of "typography-only differences, case, or punctuation" loosely echoes the case_sensitive behavior but adds no new parameter syntax or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: check whether a quotation appears in a Project Gutenberg book, including the match-strictness tiers it reports. This functionally separates it from a plain full-text search like find_in_book, but no sibling is named, so differentiation is implied rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use it before quoting a public-domain book" gives a clear when-to-use context. It stops short of excluding cases (e.g. use find_in_book for raw occurrences, read_passage to fetch surrounding text) or naming alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_passageRead a passageA
Read-onlyIdempotent

Read a Project Gutenberg book by chapter or by line number, up to 200 lines per call. Lines come back numbered so you can cite them, with next_start_line for paging. The license header and footer are already removed.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesProject Gutenberg book id, e.g. 2701 (Moby Dick) or 1342 (Pride and Prejudice). Find ids with search_books.
chapterNoChapter index from get_book's chapter list. Reading starts at its heading. Use this or start_line, not both.
max_linesNoLines to return (1-200, default 80). Blank lines count. When a chapter is given, reading stops at its end.
start_lineNo1-based line to start at (line numbers from get_book, find_in_book or a previous read_passage). Default 1.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
textYesThe passage, one book line per row, each prefixed with its line number (" 813 CHAPTER 1. Loomings.").
titleNo
chapterNoChapter containing start_line.
end_lineYes
start_lineYes
attributionYesCredit line to keep with any quoted text.
total_linesYes
next_start_lineYesPass as start_line to keep reading; null at the end of the book.
chapter_end_lineNoLast line of the current chapter.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive, open-world behavior, so the safety profile is covered. The description adds genuinely new operational context: a 200-line ceiling, numbered output for citation, a next_start_line cursor for paging, and removal of Gutenberg license header/footer.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences with no filler: the core action and addressing modes come first, then the output/paging contract, then the header-footer cleanup. Every clause carries information the agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value detail is not strictly required, yet the description still explains numbering and the paging cursor. Nothing critical is missing for correct invocation, though a pointer to when to choose this over its siblings would make it fully sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so id, chapter, start_line and max_lines are already fully documented, including the chapter/start_line exclusivity. The description restates the chapter-or-line choice and the line cap but adds no format or syntax detail beyond the schema, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb (read) and resource (a Project Gutenberg book) plus the two addressing modes (chapter or line number) and a hard size cap. It clearly distinguishes a reading operation from the search/list siblings, though it never names an alternative tool to route away from.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'read by chapter or by line number' tells the agent which parameter style to pick, and the schema clarifies not to combine them. There is no explicit statement of when to prefer this over get_book or find_in_book, and no prerequisites or exclusions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_booksSearch Project GutenbergA
Read-onlyIdempotent

Search the Project Gutenberg catalog (more than 75,000 public-domain books) by title and author words, optionally filtered by language and topic. Returns book ids, titles, authors with life years, subjects and popularity. Use the id with get_book and the reading tools.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoResults page (32 books per page, most downloaded first).
queryYesWords from the title and/or author name, e.g. "moby dick", "austen pride", "frankenstein".
topicNoOptional subject or bookshelf keyword, e.g. "gothic", "detective", "poetry", "children".
authorNoOptional author name or part of it, e.g. "Dickens". Added to the search words.
languageNoOptional two-letter language code(s), comma-separated, e.g. "en" or "fr,de".

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
pageYes
booksYes
totalYesTotal matching books (null when the source does not report it).
sourceYesgutenberg.org means Gutendex was too slow and the simpler gutenberg.org search answered: ids, titles and authors only, no filters.
next_pageYesPass as page for more results; null on the last page.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=true and destructiveHint=false, so the safety profile is fully covered. The description adds a brief note about what is returned (ids, titles, authors with life years, subjects, popularity), but nothing about ranking or result limits beyond what the page parameter schema already says.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with zero filler; the capability statement comes first and the follow-up routing hint second, both earning their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a filtered search tool with a full output schema and complete parameter documentation, the description covers purpose, filters and next steps adequately. It omits nothing an agent needs to invoke it, though it could note result ordering or when the catalog search is preferable to a per-book sibling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (query, author, topic, language, page) is already documented with examples in the schema. The description's 'by title and author words, optionally filtered by language and topic' largely restates that mapping without adding syntax or format detail — baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and resource (Project Gutenberg catalog) with scope (75,000+ public-domain books) and the searchable fields. The final sentence routes the agent to get_book and the reading tools, so it is distinguishable from siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly describes the search context and explicitly hands off to get_book / reading tools after finding an id, which is genuine routing guidance. It does not state when to prefer this over siblings like book_stats, but no exclusions are needed for a catalog search entry point.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedbook_stats
    • First observedfind_in_book
    • First observedget_book
    • First observedquote_check
    • First observedread_passage
    • First observedsearch_books

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct operation: catalog search vs. book metadata/TOC retrieval vs. reading passages vs. in-book word lookup vs. quotation verification vs. statistical analysis. The only potential overlap is between find_in_book and quote_check, but their descriptions clearly differentiate occurrence lookup from strict quote validation, so an agent can reliably select the right tool.

Naming Consistency4/5

Most names follow a consistent verb_noun pattern (search_books, get_book, read_passage, find_in_book, quote_check), which is easy to parse. The one deviation is book_stats, a noun_noun compound that breaks the verb-first convention, but it is still readable and predictable in context.

Tool Count5/5

Six tools is well-scoped for a Project Gutenberg reading and research server. Each tool covers a distinct stage of the workflow—discovery, inspection, reading, lookup, verification, and analysis—and none feels redundant or missing.

Completeness5/5

The surface fully covers the read-only domain: finding books, retrieving metadata and table of contents, reading passages with paging, locating words, verifying quotations, and computing statistics. No obvious lifecycle gaps exist for a public-domain reading and citation server, and the reading tools handle full-book traversal through pagination.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to read and navigate EPUB files through 13 specialized tools for pagination, full-text search, metadata access, and footnote resolution. Supports session-based reading with table of contents navigation and chapter summaries.
    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
    Not graded
    quality
    A
    maintenance
    Search, browse, and read 75,000+ public-domain books from Project Gutenberg with full plain-text retrieval and offset/limit chunking via MCP.
    567 npm
    4
    Apache 2.0