gutenberg-mcp-server
An MCP server that provides tools to search the Project Gutenberg catalog, fetch complete book metadata, and retrieve plain-text content with chunking capabilities. It supports filtering by title, author, topic, language, and copyright status, enabling agents to access over 78,000 public-domain ebooks.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://gutenberg.caseyjhand.com/mcpWhat its tools do
4 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.
Checks and signals
Each line is separate evidence, not a trust score.
- Passed Endpoint answered the live check ·
- Availability 1 of 1 checks passed in 30 days
What you can do with it
- Search the Project Gutenberg catalog by title, author, or topic
- Fetch complete metadata for a specific book by ID
- Retrieve plain-text content of books with offset/limit chunking
- Browse popular books filtered by language or subject
Source and maintenance
- Maintenance checked
Protocol and capabilities
- Server
- gutenberg-mcp-server 0.3.2
- MCP protocol negotiated in check
- 2025-11-25
- Tools
- 4 advertised
- Resources
- 1 advertised
- Resource templates
- 1 advertised
- Prompts
- 0 advertised
{
"tools": {
"listChanged": true
},
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"extensions": {
"io.modelcontextprotocol/skills": {
"directoryRead": true
}
}
}Server-provided instructions
Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.
Tools
4 advertised
gutenberg_search_books — Search Gutenberg Books
Search the Project Gutenberg catalog of 78,000+ books. Every query word matches a title or author substring; filter by topic, language, translator, author lifespan, IDs, MIME prefix or copyright status. More than four query words, and the translator filter, require the local mirror. Empty matches succeed with criteria and a notice. Default popularity uses downloads in the last 30 days at the source snapshot. Returns IDs, titles, authors, languages, subjects, counts, and is_readable — use gutenberg_get_book for full metadata.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"description": "Narrow results to these Gutenberg IDs, intersected with other filters. An empty list selects nothing; omit for unrestricted IDs. Use gutenberg_get_book for full single-ID metadata."
},
"page": {
"type": "integer",
"default": 1,
"maximum": 9007199254740991,
"description": "Page number for paginated results (1-indexed). Each page returns up to 32 books. Use totalCount to determine total pages.",
"exclusiveMinimum": 0
},
"sort": {
"enum": [
"popular",
"ascending",
"descending"
],
"type": "string",
"default": "popular",
"description": "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."
},
"query": {
"type": "string",
"description": "Every nonblank whitespace-separated word must match title or author name as a literal substring. The local mirror ignores case and accents; live fallback may require accents and rejects more than four words. Example: \"dickens expectations\" matches Great Expectations."
},
"topic": {
"type": "string",
"description": "Phrase to match against subjects and bookshelves, ignoring case and, on the local mirror, accents. Example: \"detective\" matches the \"Detective Fiction\" bookshelf and \"Detective and mystery stories\" subject. Separate from query — topic searches categorization metadata, not title/author."
},
"copyright": {
"type": "array",
"items": {
"enum": [
"true",
"false",
"null"
],
"type": "string"
},
"description": "Any selected source copyright status: \"true\" copyrighted, \"false\" public domain in the USA, \"null\" unknown. Empty means all statuses; this is not worldwide legal clearance."
},
"languages": {
"type": "array",
"items": {
"type": "string",
"maxLength": 3,
"minLength": 2
},
"description": "Filter to books in any of these catalog language codes, exactly as results report them (\"en\", not \"eng\"). Example: [\"en\"] for English, [\"fr\", \"de\"] for French or German, [\"enm\"] for Middle English."
},
"mime_type": {
"type": "string",
"description": "Literal prefix of a format MIME key, such as \"text/plain\" or \"application/pdf\". Type and subtype casing is normalized; parameter suffixes retain literal case. Blank means unset."
},
"translator": {
"type": "string",
"description": "Every nonblank whitespace-separated word must match a translator name as a literal substring, ignoring case and accents; words can land on different translators of one book. Requires the local mirror. Example: \"maude\" finds the Aylmer and Louise Maude translations. Result rows omit translators; gutenberg_get_book reports them."
},
"author_year_end": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Include only books with an author who has a known birth or death year on or before this year. With author_year_start, one author must meet both bounds. Example: author_year_start=1800 with author_year_end=1899 returns books with 19th-century authors."
},
"author_year_start": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Include only books with an author who has a known birth or death year on or after this year (positive = CE, negative = BCE). With author_year_end, one author must meet both bounds."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"books",
"totalCount",
"page",
"hasMore",
"effectiveCriteria"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "number",
"description": "Current page number."
},
"books": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title",
"authors",
"languages",
"subjects",
"download_count",
"has_plain_text",
"is_readable"
],
"properties": {
"id": {
"type": "number",
"description": "Gutenberg ID — pass to gutenberg_get_book for the full record or gutenberg_get_text to read the book."
},
"title": {
"type": "string",
"description": "Book title."
},
"authors": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"birth_year",
"death_year"
],
"properties": {
"name": {
"type": "string",
"description": "Author name in \"Last, First\" format."
},
"birth_year": {
"type": [
"number",
"null"
],
"description": "Author birth year, or null if unknown."
},
"death_year": {
"type": [
"number",
"null"
],
"description": "Author death year, or null if unknown or still living."
}
},
"description": "Author entry.",
"additionalProperties": false
},
"description": "Author(s) of the work."
},
"subjects": {
"type": "array",
"items": {
"type": "string"
},
"description": "Library of Congress subject headings."
},
"languages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Catalog language codes for this edition."
},
"is_readable": {
"type": "boolean",
"description": "Eligible Text record with UTF-8 plain text, or HTML without audio formats. Does not guarantee the mirror file exists."
},
"download_count": {
"type": "number",
"description": "Downloads in the last 30 days at the source snapshot."
},
"has_plain_text": {
"type": "boolean",
"description": "True for Text records with UTF-8 plain text; HTML-only editions can still have is_readable=true."
}
},
"description": "Book entry.",
"additionalProperties": false
},
"description": "Matching books, ordered by the sort parameter."
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"translator_requires_mirror",
"query_requires_mirror",
"page_out_of_range",
"catalog_unavailable"
],
"description": "Machine-readable failure mode. Declared by this tool: `translator_requires_mirror`: A translator filter was supplied while the local mirror could not answer. `query_requires_mirror`: More than four query words were supplied while the local mirror could not answer. `page_out_of_range`: The requested page number is past the last page of results for this query. `catalog_unavailable`: The Project Gutenberg catalog did not answer within the time this server allows for one search. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"notice": {
"type": "string",
"description": "Actionable guidance for an empty selection, or a caveat that the live catalog checked author_year_start and author_year_end separately. The caveat can accompany results."
},
"hasMore": {
"type": "boolean",
"description": "True if there are additional pages of results."
},
"totalCount": {
"type": "number",
"description": "Total number of books matching the query across all pages."
},
"effectiveCriteria": {
"type": "object",
"required": [
"sort",
"page"
],
"properties": {
"ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"description": "Restrict to these Gutenberg IDs, intersected with other filters. An empty list selects nothing; omit for unrestricted IDs."
},
"page": {
"type": "integer",
"default": 1,
"maximum": 9007199254740991,
"description": "One-indexed page of at most 32 matches. Pages beyond the result range are errors.",
"exclusiveMinimum": 0
},
"sort": {
"enum": [
"popular",
"ascending",
"descending"
],
"type": "string",
"default": "popular",
"description": "Popular orders by source-snapshot downloads in the last 30 days, with ID tie-breaks locally; ascending and descending order by Gutenberg ID."
},
"query": {
"type": "string",
"description": "Every nonblank word must occur in the title or an author name as a literal substring. The local mirror ignores case and accents; live matching is upstream-defined. More than four words require the local mirror. Whitespace separates words."
},
"topic": {
"type": "string",
"description": "Phrase in a subject or bookshelf, ignoring case and, on the local mirror, accents; blank means unset."
},
"copyright": {
"type": "array",
"items": {
"enum": [
"true",
"false",
"null"
],
"type": "string"
},
"description": "Any selected source copyright status: \"true\" copyrighted, \"false\" public domain in the USA, \"null\" unknown. Empty means all statuses; this is not worldwide legal clearance."
},
"languages": {
"type": "array",
"items": {
"type": "string",
"maxLength": 3,
"minLength": 2
},
"description": "Any listed two- or three-letter catalog language code; empty means all languages."
},
"mime_type": {
"type": "string",
"description": "Literal prefix of a format MIME key, such as \"text/plain\" or \"application/pdf\". Type and subtype casing is normalized; parameter suffixes retain literal case. Blank means unset."
},
"translator": {
"type": "string",
"description": "Every nonblank word must occur in a translator name as a literal substring, ignoring case and accents. Requires the local mirror. Whitespace separates words."
},
"author_year_end": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or before this year (CE positive, BCE negative). With author_year_start, one author must meet both bounds."
},
"author_year_start": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or after this year (CE positive, BCE negative). With author_year_end, one author must meet both bounds."
}
},
"description": "Normalized search criteria, including sort and page defaults.",
"additionalProperties": false
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": true,
"idempotentHint": true
}gutenberg_get_book — Get Gutenberg Book
Fetch complete metadata for a Project Gutenberg book by ID — title, authors (with birth/death years), translators, editors, source bibliographic notes, subjects, bookshelves, languages, copyright status, and the full formats map with download URLs (plain text, HTML, EPUB, cover image, etc.). Use is_readable before gutenberg_get_text; source_notes may identify specific editions.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Project Gutenberg book ID. Visible in Gutenberg URLs (e.g., gutenberg.org/ebooks/1342) and returned by gutenberg_search_books and gutenberg_browse_popular. Example: 1342 for Pride and Prejudice, 2600 for War and Peace.",
"exclusiveMinimum": 0
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"id",
"title",
"authors",
"translators",
"editors",
"subjects",
"bookshelves",
"languages",
"copyright",
"media_type",
"download_count",
"source_notes",
"is_readable",
"summary",
"summaries",
"formats",
"has_plain_text"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"id": {
"type": "number",
"description": "Gutenberg ID."
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"not_found",
"catalog_unavailable"
],
"description": "Machine-readable failure mode. Declared by this tool: `not_found`: No book exists with the given ID. `catalog_unavailable`: The Project Gutenberg catalog did not answer within the time this server allows for one lookup. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"title": {
"type": "string",
"description": "Book title."
},
"authors": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"birth_year",
"death_year"
],
"properties": {
"name": {
"type": "string",
"description": "Author name in \"Last, First\" format."
},
"birth_year": {
"type": [
"number",
"null"
],
"description": "Birth year, or null if unknown."
},
"death_year": {
"type": [
"number",
"null"
],
"description": "Death year, or null if unknown or still living."
}
},
"description": "Author entry.",
"additionalProperties": false
},
"description": "Primary author(s)."
},
"editors": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"birth_year",
"death_year"
],
"properties": {
"name": {
"type": "string",
"description": "Editor name."
},
"birth_year": {
"type": [
"number",
"null"
],
"description": "Birth year, or null if unknown."
},
"death_year": {
"type": [
"number",
"null"
],
"description": "Death year, or null if unknown."
}
},
"description": "Editor entry.",
"additionalProperties": false
},
"description": "Editors, if any."
},
"formats": {
"type": "object",
"description": "Map of MIME type to download URL. Key types: \"text/plain; charset=utf-8\" (preferred for gutenberg_get_text), \"text/html\", \"application/epub+zip\", \"image/jpeg\" (cover). Not every format is present for every book.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
},
"summary": {
"type": [
"string",
"null"
],
"description": "First entry of summaries, not necessarily primary, or null when the source has none."
},
"subjects": {
"type": "array",
"items": {
"type": "string"
},
"description": "Library of Congress subject headings."
},
"copyright": {
"type": [
"boolean",
"null"
],
"description": "Copyright status: false = public domain in the USA, true = under copyright, null = unknown."
},
"languages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Catalog language codes for this edition."
},
"summaries": {
"type": "array",
"items": {
"type": "string"
},
"description": "Every source-provided summary: sorted on the RDF mirror, upstream order on live fallback. Empty when there are none."
},
"media_type": {
"type": "string",
"description": "Source media type, such as \"Text\" or \"Sound\" (audio). Use is_readable to check reader support."
},
"bookshelves": {
"type": "array",
"items": {
"type": "string"
},
"description": "Project Gutenberg bookshelf categories (e.g., \"Best Books Ever Listings\", \"Category: Classics of Literature\")."
},
"is_readable": {
"type": "boolean",
"description": "Eligible Text record with UTF-8 plain text, or HTML without audio formats. Does not guarantee the mirror file exists."
},
"translators": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"birth_year",
"death_year"
],
"properties": {
"name": {
"type": "string",
"description": "Translator name."
},
"birth_year": {
"type": [
"number",
"null"
],
"description": "Birth year, or null if unknown."
},
"death_year": {
"type": [
"number",
"null"
],
"description": "Death year, or null if unknown."
}
},
"description": "Translator entry.",
"additionalProperties": false
},
"description": "Translators, if this is a translated work."
},
"source_notes": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
],
"description": "Source-provided RDF bibliographic notes in document order, including explicit edition references. [] means inspected with no notes; null means unavailable from this source."
},
"download_count": {
"type": "number",
"description": "Downloads in the last 30 days at the source snapshot, used for popularity ranking."
},
"has_plain_text": {
"type": "boolean",
"description": "True if media_type is \"Text\" and \"text/plain; charset=utf-8\" is present. HTML-only editions can still have is_readable=true."
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": true,
"idempotentHint": true
}gutenberg_get_text — Get Gutenberg Book Text
Retrieve the plain-text content of a Project Gutenberg book, stripped of the standard license header and footer. Front matter such as producer credits, the title page, contents, and prefaces stays in the text. For long works — novels routinely run 500KB–2MB — use offset and limit to read in chunks rather than fetching the whole book at once, or pass find to jump to a known passage without paging. The response reports totalChars and remainingChars for reliable pagination. Prefers UTF-8 plain text; falls back to an HTML edition converted to text; refuses audio books (media_type "Sound") with a clear error.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Project Gutenberg book ID. Use gutenberg_search_books or gutenberg_get_book to find IDs. Example: 1342 for Pride and Prejudice, 2600 for War and Peace, 84 for Frankenstein.",
"exclusiveMinimum": 0
},
"find": {
"type": "string",
"description": "A passage to locate instead of paging to it: the response starts at the first occurrence at or after offset and adds match, and an absent passage fails with passage_not_found rather than returning other text. Matching ignores letter case and whitespace around find. Any run of spaces, tabs, or line breaks matches any other such run, so a hard-wrapped line still matches. Straight and curly quotes match each other. Accents count: \"cafe\" does not match \"café\". Everything else is literal, with no wildcards or patterns, so an italic word stored as _word_ needs its underscores. A blank find is an ordinary read."
},
"limit": {
"type": "integer",
"default": 20000,
"maximum": 9007199254740991,
"minimum": 1,
"description": "Requested maximum characters. Default 20,000; requests above 50,000 are capped locally at 50,000. Paragraph-boundary trimming may return less than the applied limit — use length for continuation. Trimming never cuts before a find match ends."
},
"offset": {
"type": "integer",
"default": 0,
"maximum": 9007199254740991,
"minimum": 0,
"description": "Character offset into the stripped literary text at which to start reading. 0 returns the beginning of the work. To read subsequent chunks, use offset = prior_offset + prior_length (the length field from the previous response — NOT offset + limit, because the actual returned length may be slightly less than limit due to paragraph-boundary trimming). With find, the search starts here and the returned chunk starts at the match."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"id",
"title",
"text",
"offset",
"length",
"requestedLimit",
"appliedLimit",
"totalChars",
"remainingChars",
"hasMore",
"provenance",
"sourceFormat"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"id": {
"type": "number",
"description": "Gutenberg book ID."
},
"text": {
"type": "string",
"description": "The requested chunk of literary text, stripped of Gutenberg license boilerplate. Encoding: UTF-8. Line endings: normalized to LF."
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"text_file_not_found",
"text_fetch_rejected",
"invalid_text_response",
"not_found",
"audio_book",
"no_text_format",
"offset_out_of_range",
"passage_not_found",
"text_fetch_failed",
"catalog_unavailable"
],
"description": "Machine-readable failure mode. Declared by this tool: `text_file_not_found`: The catalog entry exists but its mirror text file returned HTTP 404. `text_fetch_rejected`: The mirror permanently rejected this text request. `invalid_text_response`: The mirror returned an empty document, HTML on a plain-text path, or recognizable server failure document. `not_found`: No book exists with the given ID. `audio_book`: The book is an audio recording (media_type \"Sound\"), not a text book — no literary plain text is available. `no_text_format`: The book has no UTF-8 plain-text or HTML edition available to read (for example an ASCII-only or PDF/TeX-only entry). `offset_out_of_range`: The offset is greater than or equal to totalChars (past the end of the book). `passage_not_found`: find has no occurrence at or after offset. `text_fetch_failed`: The Gutenberg mirror had a transient failure or the download did not finish within the remaining upstream allowance. `catalog_unavailable`: The catalog lookup that precedes reading a book did not answer within the time this server allows. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"match": {
"type": "object",
"required": [
"offset",
"length",
"laterMatches"
],
"properties": {
"length": {
"type": "number",
"description": "Characters the match spans in the stored text. Can differ from the length of find, since a whitespace run matches a run of any length."
},
"offset": {
"type": "number",
"description": "Start of the match, in the same coordinates as offset and totalChars."
},
"laterMatches": {
"type": "number",
"description": "Non-overlapping occurrences after this one. While above 0, repeat the same find with offset = match.offset + match.length for the next."
}
},
"description": "Where find matched. Absent on a read without find.",
"additionalProperties": false
},
"title": {
"type": "string",
"description": "Book title, from the catalog record."
},
"length": {
"type": "number",
"description": "Number of characters in this chunk."
},
"offset": {
"type": "number",
"description": "Character offset where this chunk begins: the match start when find matched."
},
"hasMore": {
"type": "boolean",
"description": "True if there is more text after this chunk. When true, call again with offset = offset + length and no find."
},
"provenance": {
"type": "string",
"description": "One-line source note with Project Gutenberg ID, title, and license URL."
},
"totalChars": {
"type": "number",
"description": "Total characters in the stripped literary text. Use with offset and length to determine progress and plan subsequent calls."
},
"appliedLimit": {
"type": "number",
"description": "Character limit applied to this chunk, at most 50,000."
},
"sourceFormat": {
"enum": [
"text/plain; charset=utf-8",
"text/plain; charset=us-ascii",
"text/html"
],
"type": "string",
"description": "The format that was fetched. \"text/html\" indicates HTML-to-text conversion was applied because no plain-text format was available."
},
"remainingChars": {
"type": "number",
"description": "Characters remaining after this chunk (totalChars - offset - length). 0 means this chunk includes the end of the book."
},
"requestedLimit": {
"type": "number",
"description": "Positive integral character limit requested by the caller, before capping."
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": true,
"idempotentHint": true
}gutenberg_browse_popular — Browse Popular Gutenberg Books
Browse Project Gutenberg books ordered by downloads in the last 30 days at the source snapshot. Returns up to 32 titles with IDs, authors, languages, download counts, and is_readable. Filter by language, topic, MIME prefix or copyright status. Empty matches succeed with criteria and a notice; truncated results include executable search continuation. Use this for discovery — "what are the most popular classics in French?".
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"limit": {
"type": "integer",
"default": 20,
"maximum": 9007199254740991,
"minimum": 1,
"description": "Requested number of books. Default 20; requests above 32 are capped locally at 32."
},
"topic": {
"type": "string",
"description": "Filter by a subject or bookshelf keyword (case-insensitive phrase match). Example: \"science fiction\", \"adventure\", \"detective\". Applies on top of the language filter."
},
"copyright": {
"type": "array",
"items": {
"enum": [
"true",
"false",
"null"
],
"type": "string"
},
"description": "Any selected source copyright status: \"true\" copyrighted, \"false\" public domain in the USA, \"null\" unknown. Empty means all statuses; this is not worldwide legal clearance."
},
"languages": {
"type": "array",
"items": {
"type": "string",
"maxLength": 3,
"minLength": 2
},
"description": "Restrict to books in these catalog language codes, exactly as results report them (\"en\", not \"eng\"). Example: [\"en\"] for English only, [\"de\", \"fr\"] for German or French, [\"ang\"] for Old English. Omit for all languages."
},
"mime_type": {
"type": "string",
"description": "Literal prefix of a format MIME key, such as \"text/plain\" or \"application/pdf\". Type and subtype casing is normalized; parameter suffixes retain literal case. Blank means unset."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"requestedLimit",
"appliedLimit",
"books",
"totalInCatalog",
"effectiveCriteria",
"truncated",
"shown",
"cap"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cap": {
"type": "number",
"description": "The limit that was applied."
},
"books": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title",
"authors",
"languages",
"download_count",
"has_plain_text",
"is_readable"
],
"properties": {
"id": {
"type": "number",
"description": "Gutenberg ID."
},
"title": {
"type": "string",
"description": "Book title."
},
"authors": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"birth_year",
"death_year"
],
"properties": {
"name": {
"type": "string",
"description": "Author name in \"Last, First\" format."
},
"birth_year": {
"type": [
"number",
"null"
],
"description": "Birth year, or null if unknown."
},
"death_year": {
"type": [
"number",
"null"
],
"description": "Death year, or null if unknown or still living."
}
},
"description": "Author entry.",
"additionalProperties": false
},
"description": "Author(s)."
},
"languages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Language codes."
},
"is_readable": {
"type": "boolean",
"description": "Eligible Text record with UTF-8 plain text, or HTML without audio formats. Does not guarantee the mirror file exists."
},
"download_count": {
"type": "number",
"description": "Downloads in the last 30 days at the source snapshot — the popularity ranking basis."
},
"has_plain_text": {
"type": "boolean",
"description": "True for Text records with UTF-8 plain text; HTML-only editions can still have is_readable=true."
}
},
"description": "Book entry.",
"additionalProperties": false
},
"description": "Top books by downloads in the last 30 days at the source snapshot, most popular first."
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"catalog_unavailable"
],
"description": "Machine-readable failure mode. Declared by this tool: `catalog_unavailable`: The Project Gutenberg catalog did not answer within the time this server allows for one browse. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"shown": {
"type": "number",
"description": "Number of books returned in this response."
},
"notice": {
"type": "string",
"description": "Guidance for empty or capped results."
},
"truncated": {
"type": "boolean",
"description": "True when the catalog held more matches than were returned."
},
"appliedLimit": {
"type": "number",
"description": "Book limit applied locally, at most 32."
},
"continuation": {
"type": "object",
"required": [
"tool",
"arguments"
],
"properties": {
"tool": {
"type": "string",
"const": "gutenberg_search_books",
"description": "Tool to call for the remaining matching books."
},
"arguments": {
"type": "object",
"required": [
"sort",
"page"
],
"properties": {
"ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"description": "Restrict to these Gutenberg IDs, intersected with other filters. An empty list selects nothing; omit for unrestricted IDs."
},
"page": {
"type": "integer",
"default": 1,
"maximum": 9007199254740991,
"description": "One-indexed page of at most 32 matches. Pages beyond the result range are errors.",
"exclusiveMinimum": 0
},
"sort": {
"enum": [
"popular",
"ascending",
"descending"
],
"type": "string",
"default": "popular",
"description": "Popular orders by source-snapshot downloads in the last 30 days, with ID tie-breaks locally; ascending and descending order by Gutenberg ID."
},
"query": {
"type": "string",
"description": "Every nonblank word must occur in the title or an author name as a literal substring. The local mirror ignores case and accents; live matching is upstream-defined. More than four words require the local mirror. Whitespace separates words."
},
"topic": {
"type": "string",
"description": "Phrase in a subject or bookshelf, ignoring case and, on the local mirror, accents; blank means unset."
},
"copyright": {
"type": "array",
"items": {
"enum": [
"true",
"false",
"null"
],
"type": "string"
},
"description": "Any selected source copyright status: \"true\" copyrighted, \"false\" public domain in the USA, \"null\" unknown. Empty means all statuses; this is not worldwide legal clearance."
},
"languages": {
"type": "array",
"items": {
"type": "string",
"maxLength": 3,
"minLength": 2
},
"description": "Any listed two- or three-letter catalog language code; empty means all languages."
},
"mime_type": {
"type": "string",
"description": "Literal prefix of a format MIME key, such as \"text/plain\" or \"application/pdf\". Type and subtype casing is normalized; parameter suffixes retain literal case. Blank means unset."
},
"translator": {
"type": "string",
"description": "Every nonblank word must occur in a translator name as a literal substring, ignoring case and accents. Requires the local mirror. Whitespace separates words."
},
"author_year_end": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or before this year (CE positive, BCE negative). With author_year_start, one author must meet both bounds."
},
"author_year_start": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or after this year (CE positive, BCE negative). With author_year_end, one author must meet both bounds."
}
},
"description": "Executable search arguments preserving all filters. Page 1 may repeat already shown books when the browse cap cuts a page.",
"additionalProperties": false
}
},
"description": "Present only when more matching books exist.",
"additionalProperties": false
},
"requestedLimit": {
"type": "number",
"description": "Positive integral book limit requested before capping."
},
"totalInCatalog": {
"type": "number",
"description": "Total books matching the filter in the full catalog (useful for context — \"top 20 of 60,000\")."
},
"effectiveCriteria": {
"type": "object",
"required": [
"sort",
"page"
],
"properties": {
"ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"description": "Restrict to these Gutenberg IDs, intersected with other filters. An empty list selects nothing; omit for unrestricted IDs."
},
"page": {
"type": "integer",
"default": 1,
"maximum": 9007199254740991,
"description": "One-indexed page of at most 32 matches. Pages beyond the result range are errors.",
"exclusiveMinimum": 0
},
"sort": {
"enum": [
"popular",
"ascending",
"descending"
],
"type": "string",
"default": "popular",
"description": "Popular orders by source-snapshot downloads in the last 30 days, with ID tie-breaks locally; ascending and descending order by Gutenberg ID."
},
"query": {
"type": "string",
"description": "Every nonblank word must occur in the title or an author name as a literal substring. The local mirror ignores case and accents; live matching is upstream-defined. More than four words require the local mirror. Whitespace separates words."
},
"topic": {
"type": "string",
"description": "Phrase in a subject or bookshelf, ignoring case and, on the local mirror, accents; blank means unset."
},
"copyright": {
"type": "array",
"items": {
"enum": [
"true",
"false",
"null"
],
"type": "string"
},
"description": "Any selected source copyright status: \"true\" copyrighted, \"false\" public domain in the USA, \"null\" unknown. Empty means all statuses; this is not worldwide legal clearance."
},
"languages": {
"type": "array",
"items": {
"type": "string",
"maxLength": 3,
"minLength": 2
},
"description": "Any listed two- or three-letter catalog language code; empty means all languages."
},
"mime_type": {
"type": "string",
"description": "Literal prefix of a format MIME key, such as \"text/plain\" or \"application/pdf\". Type and subtype casing is normalized; parameter suffixes retain literal case. Blank means unset."
},
"translator": {
"type": "string",
"description": "Every nonblank word must occur in a translator name as a literal substring, ignoring case and accents. Requires the local mirror. Whitespace separates words."
},
"author_year_end": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or before this year (CE positive, BCE negative). With author_year_start, one author must meet both bounds."
},
"author_year_start": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "An author has a known birth or death year on or after this year (CE positive, BCE negative). With author_year_end, one author must meet both bounds."
}
},
"description": "Normalized browse criteria, including popular sort and first page.",
"additionalProperties": false
},
"truncationCeiling": {
"type": "number",
"description": "Downloads in the last 30 days at the source snapshot for the least-popular book shown; omitted books have at most this count."
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": true,
"idempotentHint": true
}Prompts
0 advertised
Resources
1 advertised
gutenberg-guide
Gates and workflows for the gutenberg_* tools over Project Gutenberg. Covers deciding whether a book can be read, why a title, accent, or translator search comes back empty, finding a novel's opening or a chapter inside a book, jumping to a known passage or paging long works, ranking reading lists by downloads, and comparing editions and translations. Use when finding, reading, quoting, or recommending books from Project Gutenberg.
skill://gutenberg-guide/SKILL.mdio.modelcontextprotocol/skills
skill://{+path}90-day uptime
A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.
- 2026-11-07: 1 of 1 checks answered
30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 725 ms
- 95th percentile latency
- 725 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 725 ms · metadata changed · 4 tool(s), 1 resource(s), 1 resource template(s), 0 prompt(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http gutenberg-mcp-server https://gutenberg.caseyjhand.com/mcpCodex
codex mcp add gutenberg-mcp-server --url https://gutenberg.caseyjhand.com/mcpCursor
{
"mcpServers": {
"gutenberg-mcp-server": {
"url": "https://gutenberg.caseyjhand.com/mcp"
}
}
}Cline
{
"mcpServers": {
"gutenberg-mcp-server": {
"type": "streamableHttp",
"url": "https://gutenberg.caseyjhand.com/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"gutenberg-mcp-server": {
"type": "http",
"url": "https://gutenberg.caseyjhand.com/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http gutenberg-mcp-server https://gutenberg.caseyjhand.com/mcpClaude Desktop
https://gutenberg.caseyjhand.com/mcpWindsurf
{
"mcpServers": {
"gutenberg-mcp-server": {
"serverUrl": "https://gutenberg.caseyjhand.com/mcp"
}
}
}Let your agent find its tools
Find servers like gutenberg-mcp-server from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.