MCP server that searches inside several archives at once, browses their catalogues and reads records. No API key.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
claude mcp add mcp-books -- npx -y mcp-books{
"mcpServers": {
"mcp-books": {
"command": "npx",
"args": ["-y", "mcp-books"]
}
}
}MCP Servers overview
# mcp-books [](https://www.npmjs.com/package/mcp-books) [](https://github.com/smeet666/mcp-books/actions/workflows/ci.yml) [](./LICENSE) [](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.smeet666/mcp-books) [](https://glama.ai/mcp/servers/smeet666/mcp-books) [](https://m8ven.ai/mcp/smeet666-mcp-books-1kpajy) [](https://cursor.com/en/install-mcp?name=books&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1ib29rcyJdfQ%3D%3D) [](https://insiders.vscode.dev/redirect/mcp/install?name=books&config=%7B%22name%22%3A%22books%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-books%22%5D%7D) <!-- m8ven-verify: 9550b67f15a2d999bf8a5859c9368aeb --> One question, several archives. An MCP server that asks every archive it reads at the same time, inside the scanned text and across the catalogues, and merges what comes back without flattening what makes the two answers different. Today it reads three: the **Internet Archive**, holding the machine-read text of digitised books, periodicals and documents; the **Library of Congress**, holding the text of American newspaper pages and one catalogue per kind of material; and **data.bnf.fr**, the open catalogue of the Bibliothèque nationale de France, which describes works as entities and holds no text of its own. No API key. No account. Read-only. --- ## What it does These archives answer different questions with the same gesture. One reads the text inside digitised books; another reads the text printed on newspaper pages; another describes works a national library has catalogued, and carries no text at all. Searching for a phrase asks where that phrase was ever printed, in books and in the press at once, and the archive that holds no text is named as absent from that question rather than quietly left out. The merge is therefore **additive**. It is what each archive holds, put together. Nothing is set side by side, because archives holding different things have nothing to compare. This server: - **searches the machine-read text of every archive at once** and returns one list of matches, each naming the archive it came from; - **searches every catalogue at once**, each in that archive's own vocabulary; - **reads one record**, routed by the archive its identifier names. ### What makes the answers usable Merging two archives is easy if you are willing to lose what tells them apart. This one keeps every difference visible: | The difference | What a flattened answer would do | What happens here | | ----------------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | One index holds a page number, the other holds none | Invent a page, or drop a true one | `page_number` is a real leaf on one archive and `null` on the other, and the answer says which | | One returns the matched passage, the other the opening of the page | Present both under one field name | `excerpt_kind` travels with every match, the note counts how many are openings, and an opening is placed after the matches that carry the words | | The archives count different things | Add the counts into a total | Each count is reported in that archive's own terms, and none is added to another | | A year means an edition's date in one place and a catalogue date in the other | Sort the merged list by year | No date order spans the archives; a sort is applied inside each, and what that order can and cannot express is said | | One record states terms of reuse, another states none | Summarise the answer as reusable | Terms are stated per record, and a record stating none has granted nothing | | One archive searches a whole record, another searches titles alone | Present one query as one question | `searches_on` says which fields each archive read, and the notes say the same words were not the same question | | One archive applies a year range and an order, another applies neither | Report the filter as applied | A narrowing an archive cannot apply is never sent to it, and `filters_dropped` names the archive and the reason | | One row is a copy held somewhere, another is a work as an entity | Call them all the same thing | `row_describes` says what a row is on each archive, and `identifier_provisional` marks an identifier its archive can still replace | ### One query, several questions The archives do not read the same fields. An index over a whole record answers a person's name with the books that person wrote; an index over titles alone answers the same name with the books written **about** them. Sending one query to several archives therefore asks several questions, and the answer says which: `searches_on` in `per_source` names the fields each archive matched against, and a note says so in the block a text-only client renders. The narrowings work the same way. `year_from`, `year_to` and `sort` are applied by the archives whose catalogues carry them. An archive whose catalogue carries neither is **never sent them**, and `filters_dropped` names it with the reason, because a merged list that honoured a criterion on two of its halves and dropped it in silence on the third would claim a filter one of its halves never received. A row from such an archive that happens to satisfy the range does so by chance. A row is not one kind of thing either. It is a copy an archive holds on one, a catalogue record that may name something on a shelf on another, and a work as an entity on a third, whose editions and whose author are records of their own. `row_describes` says which, `media_type` carries each archive's own word for it, and `identifier_provisional` marks a row whose identifier the archive itself calls provisional and can replace once a cataloguer settles the record. ### Excerpts, and what they are worth Every excerpt is what optical recognition read off a scanned page. The words can be wrong, so they are quoted as scanned text and the page is linked. Beyond that, an excerpt is one of two objects, and the difference is the whole reason the field carries a kind: - **`passage`** is the text around the words that matched. - **`page_opening`** is the start of the page. It arrives when the machine-read text that came back with a row stops before the searched words appear, so it does not carry the match at all. Quoting one as the archive's answer puts words in front of a reader that the excerpt does not hold. Every answer counts how many of its excerpts are openings. Matches whose excerpt carries the searched words are also placed **before** the matches whose excerpt does not. Whether an excerpt holds those words is a property each row states about itself, so ordering on it compares no score across archives and invents no relevance. Nothing is dropped for it: a page opening still names a page where the words were found, and it stays in the answer behind the matches that show them. The one-from-each-archive order holds inside each of the two groups. An answer whose matches are all of one kind was placed by nothing, and keeps quiet about an order it did not perform. ### One question, several wordings The archives do not read a query the same way, and `per_source` says which each one does. An index that answers only where every word given appears comes back empty on a question written as a sentence, even for a work it holds several copies of, and that emptiness reads as an archive holding nothing. An index that scores the words instead answers the same question with whatever it ranks highest, so a row of its can carry only some of the words given. Both searches answer it by deriving further wordings from the query and asking each archive for the **union** of what they return. The derivations are made from the words themselves, with no corpus statistics and no language model, so every wording sent is one a reader can retype: - the words as asked, always first; - a quoted phrase without its quotation marks, which an index requiring those words adjacent can then match apart; - the words a question writes with a capital letter inside the sentence, kept in the order they were written and with a run of them kept whole: a capital there is the writing's own mark on a name, a name is what a catalogue files a record under, and reading the mark needs no lexicon and no list of words to ignore; - failing any such mark, the longest words of a long question, which is all the letters can say once nothing in the question names anything; - the same words with their diacritics removed, and two words run together, because a name is filed under more than one spelling. Three derivations
What people ask about mcp-books
What is smeet666/mcp-books?
+
smeet666/mcp-books is mcp servers for the Claude AI ecosystem. MCP server that searches inside several archives at once, browses their catalogues and reads records. No API key. It has 0 GitHub stars and its last recorded update is dated 2026-08-27.
How do I install mcp-books?
+
You can install mcp-books by cloning the repository (https://github.com/smeet666/mcp-books) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is smeet666/mcp-books safe to use?
+
Our security agent has analyzed smeet666/mcp-books and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains smeet666/mcp-books?
+
smeet666/mcp-books is maintained by smeet666. The last recorded GitHub activity is dated 2026-08-27, with 3 open issues.
Are there alternatives to mcp-books?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy mcp-books to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/smeet666-mcp-books)<a href="https://claudewave.com/repo/smeet666-mcp-books"><img src="https://claudewave.com/api/badge/smeet666-mcp-books" alt="Featured on ClaudeWave: smeet666/mcp-books" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!