{
  "markdown": "# mcp-books\n\n[![npm](https://img.shields.io/npm/v/mcp-books.svg)](https://www.npmjs.com/package/mcp-books)\n[![CI](https://github.com/smeet666/mcp-books/actions/workflows/ci.yml/badge.svg)](https://github.com/smeet666/mcp-books/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/mcp-books.svg)](./LICENSE)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-6E56CF)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.smeet666/mcp-books)\n[![Glama](https://glama.ai/mcp/servers/smeet666/mcp-books/badges/score.svg)](https://glama.ai/mcp/servers/smeet666/mcp-books)\n[![M8ven](https://m8ven.ai/badge/mcp/smeet666-mcp-books-1kpajy?variant=verified)](https://m8ven.ai/mcp/smeet666-mcp-books-1kpajy)\n[![LobeHub](https://lobehub.com/badge/mcp/smeet666-mcp-books)](https://lobehub.com/mcp/smeet666-mcp-books)\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=books&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1ib29rcyJdfQ%3D%3D)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](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)\n\n<!-- m8ven-verify: 9550b67f15a2d999bf8a5859c9368aeb -->\n\nThree great archives hold the scanned record of what was published, and each\ndescribes it in its own words. The [Internet Archive](https://archive.org) keeps\nbooks, films, recordings and software deposited by anyone, and has run millions\nof them through optical character recognition. The\n[Library of Congress](https://www.loc.gov) publishes the national collections of\nthe United States, one catalogue per kind of material. [data.bnf.fr](https://data.bnf.fr)\npublishes the authority records of the Bibliothèque nationale de France, which\ndescribe works and the people who wrote them rather than copies.\n\nThis server reads all three with one question. You can search the words inside\nthe scanned documents, search the catalogues, and read one record in a single\nshape whichever archive holds it. It needs no API key and no account.\n\n_[Version française](#mcp-books-français)_\n\n---\n\n## Install\n\n**One-click install**\n\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=books&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1ib29rcyJdfQ%3D%3D)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](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)\n\n**Claude Code**\n\n```bash\nclaude mcp add books -- npx -y mcp-books\n```\n\n**Claude Desktop, Cursor, and any client using the standard config format**\n\n```json\n{\n  \"mcpServers\": {\n    \"books\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-books\"]\n    }\n  }\n}\n```\n\nNode 24 or later is required, and no environment variable has to be set.\n\n### With Docker\n\n```json\n{\n  \"mcpServers\": {\n    \"books\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-books:2.0.1\"]\n    }\n  }\n}\n```\n\n`-i` keeps stdin open, which is where the protocol travels, and `-t` is left out\nbecause a TTY rewrites the stream. The container needs outbound HTTPS to\n`archive.org`, `openlibrary.org`, `www.loc.gov` and `data.bnf.fr`, and nothing\nelse: no volume, no port, no credential.\n\n### Bundle, without npm\n\nDownload `mcp-books-2.0.1.mcpb` from\n[the latest release](https://github.com/smeet666/mcp-books/releases/latest) and\nopen it. A client that supports MCP bundles installs it on its own, with no npm\nand no configuration file to edit. The bundle carries its dependencies, so\nnothing is fetched at install time.\n\n## What you can ask\n\n- \"Which books mention the Beaumont light-house?\"\n- \"Find me anything on the 1906 San Francisco earthquake.\"\n- \"Read me that record and tell me who holds the original.\"\n- \"What does the BnF have on that author?\"\n- \"Search the photographs rather than the books.\"\n\nAn answer takes several seconds: three archives are asked, each at its own pace.\n\n## The three sources\n\n| Source    | Archive                              | What it describes                                |\n| --------- | ------------------------------------ | ------------------------------------------------ |\n| `archive` | the Internet Archive                 | deposited copies, of every kind                  |\n| `loc`     | the Library of Congress              | the national collections, one catalogue per kind |\n| `bnf`     | the Bibliothèque nationale de France | works and the people who wrote them              |\n\nA row's `id` names its archive, so an identifier read from one answer goes back\nto the right one. **Counts are never added across archives**, and an archive that\nfailed is reported as having failed rather than as having found nothing.\n\n## Tools\n\n| Tool            | What it does                                                       |\n| --------------- | ------------------------------------------------------------------ |\n| `search_inside` | Searches the words inside the scanned documents.                   |\n| `search_items`  | Searches the catalogues by title, creator, subject or plain words. |\n| `get_item`      | Reads one record in a single shape, whichever archive holds it.    |\n\n### `search_inside`\n\nSearches the text inside the scanned documents, which came off the page through\noptical character recognition.\n\n| Argument                 | Type                               | Required | What it does                                                      |\n| ------------------------ | ---------------------------------- | -------- | ----------------------------------------------------------------- |\n| `query`                  | string, 2 to 300 characters        | yes      | The phrase to look for inside the documents.                      |\n| `limit`                  | integer, 1 to 25, default `3`      | no       | Matches to keep from each archive.                                |\n| `page`                   | integer, 1 to 100, default `1`     | no       | Which page of matches.                                            |\n| `max_excerpt_chars`      | integer, 80 to 1200, default `300` | no       | How much of a passage to serve.                                   |\n| `max_excerpts_per_match` | integer, 1 to 10, default `2`      | no       | Passages served per matching document.                            |\n| `fan_out`                | boolean, default `true`            | no       | Ask every archive rather than stopping at the first that answers. |\n| `sources`                | array of source ids                | no       | Ask these archives alone.                                         |\n\n**In return:** `hits`, each carrying `id`, which `get_item` takes and which names\nits archive; `source` and `source_name`; the archive's own `identifier` without\nthe prefix; `title`, `creator` and `year`; `page_number` where the archive states\none; `excerpts`; and `excerpt_kind`.\n\n**`excerpt_kind` decides what an excerpt is worth.** A `passage` is the text\naround the words that matched. A `page_opening` is the start of the page, sent\nbecause the machine-read text the archive returned stops before those words\nappear: it does not carry the match, so quoting it quotes something else. All the\nexcerpts of one match are of one kind.\n\n### `search_items`\n\nSearches the catalogues.\n\n| Argument     | Type                                                            | Required | What it does                                   |\n| ------------ | --------------------------------------------------------------- | -------- | ---------------------------------------------- |\n| `query`      | string, 1 to 300 characters                                     | yes      | A title, a creator, a subject, or plain words. |\n| `media_type` | a kind one of the archives holds                                | no       | Which kind of material to search.              |\n| `year_from`  | integer, 1000 to 2100                                           | no       | Earliest year.                                 |\n| `year_to`    | integer, 1000 to 2100                                           | no       | Latest year.                                   |\n| `sort`       | `relevance`, `newest`, `oldest` or `title`, default `relevance` | no       | How the rows are ordered.                      |\n| `limit`      | integer, 1 to 25, default `5`                                   | no       | Rows to keep from each archive.                |\n| `page`       | integer, 1 to 100, default `1`                                  | no       | Which page of rows.                            |\n| `fan_out`    | boolean, default `true`                                         | no       | Ask every archive.                             |\n| `sources`    | array of source ids                                             | no       | Ask these archives alone.                      |\n\nThe three archives divide their material differently. The Internet Archive\nsearches every kind at once when none is named; the Library of Congress is one\nroute per kind, so a search naming none is told which one was read; and the BnF\nsearch reads works. A `media_type` one archive has no notion of leaves that\narchive out, and the answer says so.\n\n**In return:** rows in the shape a hit carries, with `per_source` giving one\nreport per archive: its `status`, the `count` it contributed, its\n`reported_total` and `reported_total_means`, which says what that number counts\nthere.\n\n### `get_item`\n\nReads one record in a single shape, whichever archive holds it.\n\n| Argument         | Type                                                                               | Required | What it does              |\n| ---------------- | ---------------------------------------------------------------------------------- | -------- | ------------------------- |\n| `identifier`     | string, 1 to 500 characters                                                        | yes      | The `id` a row carries.   |\n| `sections`       | array of `description`, `subjects`, `copies`, `context`, default `[\"description\"]` | no       | Which parts to return.    |\n| `max_copies`     | integer, 1 to 50, default `10`                                                     | no       | Copies to list.           |\n| `text_offset`    | integer, 0 to 1000000, default `0`                                                 | no       | Where to resume the text. |\n| `max_text_chars` | integer, 200 to 8000, default `1500`                                               | no       | How much text to serve.   |\n\n**In return:** the record with its `id`, `source` and `source_name`, the\narchive's own `identifier`, `title`, `creator`, `date` exactly as published, and\n`year` beside `year_means`, which says what that year is the year of, since the\nthree archives date a record differently. `attribution` is what that archive asks\nto be credited with, and `identifier_provisional` says when the identifier was\nbuilt rather than read, so a caller knows it may not resolve.\n\n## What an answer states about the archives\n\nEvery answer accounts for each archive separately. One that failed, one nobody\nasked, and one that answered with nothing are three different things, and they\nare reported as three. A total stays beside the archive that published it, with\nwhat that archive counts when it says it: one counts documents, another counts\nnewspaper leaves.\n\n## What scanned text is worth\n\nThe words inside a scanned document came off the page through optical character\nrecognition. An excerpt carries the misreadings of that process, and it is served\nas it was read rather than corrected. Quote it as scanned text, and link the\nrecord so a reader can look at the page.\n\n## Configuration\n\nEvery variable is optional. Set them in the `env` block of your client config.\n\n| Variable                  | Default                 | What it does                                                                                                                                                                        |\n| ------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `BOOKS_USER_AGENT`        | the project identity    | Names your application to the three archives, with an address where a person can be reached.                                                                                        |\n| `BOOKS_MIN_INTERVAL_MS`   | each archive's own pace | Widens the gap between two requests to one archive, from 500 to 60000. Left unset, every archive keeps the pace it publishes, and a figure set here applies only where it is wider. |\n| `BOOKS_TIMEOUT_MS`        | `45000`                 | Deadline for one request, from 1000 to 120000.                                                                                                                                      |\n| `BOOKS_MAX_RETRIES`       | `3`                     | Attempts after a transient failure, from 0 to 8.                                                                                                                                    |\n| `BOOKS_CACHE_TTL_MS`      | `900000`                | How long an answer stays in memory, from 0 to 86400000.                                                                                                                             |\n| `BOOKS_CACHE_MAX_ENTRIES` | `200`                   | Answers held in memory at once, from 1 to 5000.                                                                                                                                     |\n| `BOOKS_LOG_LEVEL`         | `error`                 | `silent`, `error`, `info` or `debug`, written to stderr.                                                                                                                            |\n\nA value outside its range falls back to the default, and the reason is written to\nstderr.\n\n## Errors\n\nEvery failure carries one of six codes, a message, and where it helps a hint\nnaming the next move.\n\n| Code            | What happened                                           | What to do                                                                      |\n| --------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |\n| `not_found`     | An archive answered, and holds no such record.          | Check the identifier with `search_items`.                                       |\n| `invalid_input` | The arguments were refused before any request went out. | Read the message, which names the argument.                                     |\n| `rate_limited`  | An archive asked this client to slow down.              | Wait, then call again with the same arguments. The record is still there.       |\n| `parse_failure` | An answer arrived in a shape this client cannot read.   | Report it at [the issue tracker](https://github.com/smeet666/mcp-books/issues). |\n| `network_error` | The request did not complete.                           | Try again shortly.                                                              |\n| `timeout`       | The request passed its deadline.                        | Raise `BOOKS_TIMEOUT_MS`, or ask for fewer rows.                                |\n\nAn archive that failed is reported per archive rather than failing the whole\nanswer, so one silent archive never hides the others.\n\n## As a library\n\nThe layer reading the three archives is published on its own, with its pacing,\nits cache and its errors, and with no protocol attached.\n\n```ts\nimport { BooksClient } from \"mcp-books/client\";\n\nconst client = new BooksClient();\nconst read = await client.searchItems({ query: \"beaumont light-house\", limit: 3 });\nconsole.log(read.data.rows.length);\n```\n\nEach read answers `{ data, cached }`, and throws an error carrying one of the six\ncodes. Each archive keeps its own pace, and its floor holds here as well.\n\n## Pacing and attribution\n\nEach archive is paced on its own, one request at a time, and the widest of its\nown floor and the configured interval governs: the Library of Congress publishes\nthe slowest, and asking all three at once therefore costs each of them one\nrequest rather than three. The `User-Agent` always ends with the project identity\nand an address where a person can be reached.\n\nEvery record carries the address of its page and the `attribution` its archive\nasks for. The Internet Archive items belong to their depositors, the Library of\nCongress records state their own rights, and the BnF asks that the source and the\ndate of retrieval be stated wherever its metadata are shown.\n\nThis MCP server is an unofficial project, with no affiliation to any of the\narchives it reads.\n\n## Privacy\n\nThis server collects nothing about you and sends nothing to its author. It runs\non your machine, contacts `archive.org`, `openlibrary.org`, `www.loc.gov` and\n`data.bnf.fr` and nothing else, holds its answers in memory while it runs, and\nwrites nothing to disk. [PRIVACY.md](PRIVACY.md) states what a request carries\nand which settings change any of it.\n\n## Development\n\n```bash\nnpm install\nnpm run build:fixtures\nnpm test\nnpm run check\n```\n\nTests run against generated fixtures and make no network request. The live suite,\n`npm run test:live`, makes one request per route and runs nightly against the\narchives themselves.\n\n## Contributing\n\nBugs, questions and ideas belong in\n[the issue tracker](https://github.com/smeet666/mcp-books/issues). Pull requests\nare welcome; opening an issue first helps agree on the shape of the change. See\n[CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT, see [LICENSE](LICENSE). The records belong to the archives that published\nthem and to their depositors.\n\n---\n\n<a name=\"mcp-books-français\"></a>\n\n# mcp-books (français)\n\n_[English version](#mcp-books)_\n\nTrois grandes archives conservent la trace numérisée de ce qui a été publié, et\nchacune la décrit dans ses propres mots. L'[Internet Archive](https://archive.org)\ngarde les livres, les films, les enregistrements et les logiciels que chacun y\ndépose, et en a passé des millions par la reconnaissance optique de caractères.\nLa [Library of Congress](https://www.loc.gov) publie les collections nationales\ndes États-Unis, un catalogue par type de document.\n[data.bnf.fr](https://data.bnf.fr) publie les notices d'autorité de la\nBibliothèque nationale de France, qui décrivent des œuvres et ceux qui les ont\nécrites plutôt que des exemplaires.\n\nCe serveur lit les trois avec une seule question. On peut chercher dans les mots\ncontenus dans les documents numérisés, chercher dans les catalogues, et lire une\nnotice sous une forme unique quelle que soit l'archive qui la détient. Aucune clé\nd'API, aucun compte.\n\n## Installation\n\n**Installation en un clic**\n\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=books&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1ib29rcyJdfQ%3D%3D)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](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)\n\n**Claude Code**\n\n```bash\nclaude mcp add books -- npx -y mcp-books\n```\n\n**Claude Desktop, Cursor, et tout client au format de configuration standard**\n\n```json\n{\n  \"mcpServers\": {\n    \"books\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-books\"]\n    }\n  }\n}\n```\n\nNode 24 ou plus récent est nécessaire, et aucune variable d'environnement n'est à\nrenseigner.\n\n### Avec Docker\n\n```json\n{\n  \"mcpServers\": {\n    \"books\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-books:2.0.1\"]\n    }\n  }\n}\n```\n\n`-i` garde l'entrée standard ouverte, qui est le canal du protocole, et `-t` est\nomis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS\nsortant vers `archive.org`, `openlibrary.org`, `www.loc.gov` et `data.bnf.fr`, et\nde rien d'autre : aucun volume, aucun port, aucun identifiant.\n\n### Bundle, sans npm\n\nTéléchargez `mcp-books-2.0.1.mcpb` depuis\n[la dernière publication](https://github.com/smeet666/mcp-books/releases/latest)\net ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm et\nsans fichier de configuration à modifier. Le bundle emporte ses dépendances, donc\nrien n'est téléchargé à l'installation.\n\n## Ce qu'on peut demander\n\n- « Quels livres mentionnent le phare de Beaumont ? »\n- « Trouve-moi ce qu'il y a sur le tremblement de terre de San Francisco en 1906. »\n- « Lis-moi cette notice et dis-moi qui conserve l'original. »\n- « Qu'est-ce que la BnF a sur cet auteur ? »\n- « Cherche dans les photographies plutôt que dans les livres. »\n\nUne réponse prend plusieurs secondes : trois archives sont interrogées, chacune à\nson rythme.\n\n## Les trois sources\n\n| Source    | Archive                             | Ce qu'elle décrit                                 |\n| --------- | ----------------------------------- | ------------------------------------------------- |\n| `archive` | l'Internet Archive                  | les exemplaires déposés, de tout type             |\n| `loc`     | la Library of Congress              | les collections nationales, un catalogue par type |\n| `bnf`     | la Bibliothèque nationale de France | les œuvres et ceux qui les ont écrites            |\n\nL'`id` d'une ligne nomme son archive, donc un identifiant lu dans une réponse\nretourne vers la bonne. **Les comptes ne sont jamais additionnés entre\narchives**, et une archive qui a échoué est rapportée comme ayant échoué plutôt\nque comme n'ayant rien trouvé.\n\n## Les outils\n\n| Outil           | Ce qu'il fait                                                         |\n| --------------- | --------------------------------------------------------------------- |\n| `search_inside` | Cherche dans les mots contenus dans les documents numérisés.          |\n| `search_items`  | Cherche dans les catalogues par titre, auteur, sujet ou mots simples. |\n| `get_item`      | Lit une notice sous une forme unique, quelle que soit l'archive.      |\n\n### `search_inside`\n\nCherche dans le texte contenu dans les documents numérisés, texte issu de la\nreconnaissance optique de caractères.\n\n| Argument                 | Type                             | Requis | Ce qu'il fait                                                            |\n| ------------------------ | -------------------------------- | ------ | ------------------------------------------------------------------------ |\n| `query`                  | chaîne, 2 à 300 caractères       | oui    | La phrase à chercher dans les documents.                                 |\n| `limit`                  | entier, 1 à 25, défaut `3`       | non    | Correspondances à garder de chaque archive.                              |\n| `page`                   | entier, 1 à 100, défaut `1`      | non    | Quelle page de correspondances.                                          |\n| `max_excerpt_chars`      | entier, 80 à 1200, défaut `300`  | non    | La longueur de passage à servir.                                         |\n| `max_excerpts_per_match` | entier, 1 à 10, défaut `2`       | non    | Passages servis par document correspondant.                              |\n| `fan_out`                | booléen, défaut `true`           | non    | Interroger chaque archive plutôt que s'arrêter à la première qui répond. |\n| `sources`                | tableau d'identifiants de source | non    | N'interroger que ces archives.                                           |\n\n**En retour :** `hits`, chacun portant `id`, que `get_item` reprend et qui nomme\nson archive ; `source` et `source_name` ; l'`identifier` propre à l'archive, sans\nle préfixe ; `title`, `creator` et `year` ; `page_number` là où l'archive en\nindique un ; `excerpts` ; et `excerpt_kind`.\n\n**`excerpt_kind` décide de ce que vaut un extrait.** Un `passage` est le texte\nautour des mots trouvés. Un `page_opening` est le début de la page, envoyé parce\nque le texte lu par machine que l'archive a rendu s'arrête avant que ces mots\napparaissent : il ne porte pas la correspondance, donc le citer cite autre chose.\nTous les extraits d'une correspondance sont d'un seul type.\n\n### `search_items`\n\nCherche dans les catalogues.\n\n| Argument     | Type                                                           | Requis | Ce qu'il fait                                       |\n| ------------ | -------------------------------------------------------------- | ------ | --------------------------------------------------- |\n| `query`      | chaîne, 1 à 300 caractères                                     | oui    | Un titre, un auteur, un sujet, ou des mots simples. |\n| `media_type` | un type que l'une des archives détient                         | non    | Le type de document à chercher.                     |\n| `year_from`  | entier, 1000 à 2100                                            | non    | Année la plus ancienne.                             |\n| `year_to`    | entier, 1000 à 2100                                            | non    | Année la plus récente.                              |\n| `sort`       | `relevance`, `newest`, `oldest` ou `title`, défaut `relevance` | non    | L'ordre des lignes.                                 |\n| `limit`      | entier, 1 à 25, défaut `5`                                     | non    | Lignes à garder de chaque archive.                  |\n| `page`       | entier, 1 à 100, défaut `1`                                    | non    | Quelle page de lignes.                              |\n| `fan_out`    | booléen, défaut `true`                                         | non    | Interroger chaque archive.                          |\n| `sources`    | tableau d'identifiants de source                               | non    | N'interroger que ces archives.                      |\n\nLes trois archives découpent leurs fonds différemment. L'Internet Archive cherche\ndans tous les types à la fois quand aucun n'est nommé ; la Library of Congress a\nune route par type, donc une recherche qui n'en nomme aucun se voit dire lequel a\nété lu ; et la recherche de la BnF lit des œuvres. Un `media_type` dont une\narchive n'a pas la notion l'écarte de la réponse, et la réponse le dit.\n\n**En retour :** des lignes dans la forme d'un `hit`, avec `per_source` qui donne\nun rapport par archive : son `status`, le `count` qu'elle a fourni, son\n`reported_total` et `reported_total_means`, qui dit ce que ce nombre compte\nlà-bas.\n\n### `get_item`\n\nLit une notice sous une forme unique, quelle que soit l'archive qui la détient.\n\n| Argument         | Type                                                                                | Requis | Ce qu'il fait                  |\n| ---------------- | ----------------------------------------------------------------------------------- | ------ | ------------------------------ |\n| `identifier`     | chaîne, 1 à 500 caractères                                                          | oui    | L'`id` que porte une ligne.    |\n| `sections`       | tableau de `description`, `subjects`, `copies`, `context`, défaut `[\"description\"]` | non    | Les parties à rendre.          |\n| `max_copies`     | entier, 1 à 50, défaut `10`                                                         | non    | Exemplaires à lister.          |\n| `text_offset`    | entier, 0 à 1000000, défaut `0`                                                     | non    | Où reprendre le texte.         |\n| `max_text_chars` | entier, 200 à 8000, défaut `1500`                                                   | non    | La longueur de texte à servir. |\n\n**En retour :** la notice avec son `id`, `source` et `source_name`,\nl'`identifier` propre à l'archive, `title`, `creator`, `date` exactement telle\nque publiée, et `year` accompagné de `year_means`, qui dit de quoi cette année\nest l'année, les trois archives datant une notice différemment. `attribution` est\nce que cette archive demande qu'on lui crédite, et `identifier_provisional` dit\nquand l'identifiant a été construit plutôt que lu, pour qu'un appelant sache\nqu'il peut ne pas résoudre.\n\n## Ce qu'une réponse dit des archives\n\nChaque réponse rend compte de chaque archive séparément. Une qui a échoué, une\nque personne n'a interrogée et une qui a répondu vide sont trois choses\ndifférentes, et elles sont rapportées comme trois. Un total reste à côté de\nl'archive qui l'a publié, avec ce que cette archive compte en le disant : l'une\ncompte des documents, une autre des feuillets de journaux.\n\n## Ce que vaut un texte numérisé\n\nLes mots contenus dans un document numérisé sont issus de la reconnaissance\noptique de caractères. Un extrait porte les erreurs de lecture de ce procédé, et\nil est servi tel qu'il a été lu plutôt que corrigé. Citez-le comme un texte\nnumérisé, et liez la notice pour qu'un lecteur puisse regarder la page.\n\n## Configuration\n\nChaque variable est facultative. Elles se posent dans le bloc `env` de la\nconfiguration du client.\n\n| Variable                  | Défaut                            | Ce qu'elle fait                                                                                                                                                                                           |\n| ------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `BOOKS_USER_AGENT`        | l'identité du projet              | Nomme votre application auprès des trois archives, avec une adresse où joindre une personne.                                                                                                              |\n| `BOOKS_MIN_INTERVAL_MS`   | le rythme propre à chaque archive | Élargit l'écart entre deux requêtes vers une même archive, de 500 à 60000. Non posée, chaque archive garde le rythme qu'elle publie, et une valeur posée ici ne s'applique que là où elle est plus large. |\n| `BOOKS_TIMEOUT_MS`        | `45000`                           | Délai d'une requête, de 1000 à 120000.                                                                                                                                                                    |\n| `BOOKS_MAX_RETRIES`       | `3`                               | Tentatives après un échec passager, de 0 à 8.                                                                                                                                                             |\n| `BOOKS_CACHE_TTL_MS`      | `900000`                          | Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000.                                                                                                                                     |\n| `BOOKS_CACHE_MAX_ENTRIES` | `200`                             | Réponses gardées en mémoire à la fois, de 1 à 5000.                                                                                                                                                       |\n| `BOOKS_LOG_LEVEL`         | `error`                           | `silent`, `error`, `info` ou `debug`, écrit sur la sortie d'erreur.                                                                                                                                       |\n\nUne valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la\nsortie d'erreur.\n\n## Erreurs\n\nChaque échec porte un des six codes, un message, et quand cela aide une\nindication du geste suivant.\n\n| Code            | Ce qui s'est passé                                    | Que faire                                                                             |\n| --------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------- |\n| `not_found`     | Une archive a répondu, et n'a pas cette notice.       | Vérifiez l'identifiant avec `search_items`.                                           |\n| `invalid_input` | Les arguments ont été refusés avant toute requête.    | Lisez le message, qui nomme l'argument.                                               |\n| `rate_limited`  | Une archive demande à ce client de ralentir.          | Attendez, puis rappelez avec les mêmes arguments. La notice est toujours là.          |\n| `parse_failure` | Une réponse est arrivée dans une forme illisible ici. | Signalez-le sur [le suivi d'incidents](https://github.com/smeet666/mcp-books/issues). |\n| `network_error` | La requête n'a pas abouti.                            | Réessayez sous peu.                                                                   |\n| `timeout`       | La requête a dépassé son délai.                       | Augmentez `BOOKS_TIMEOUT_MS`, ou demandez moins de lignes.                            |\n\nUne archive qui échoue est rapportée archive par archive plutôt que de faire\néchouer toute la réponse, donc une archive silencieuse n'en cache jamais\nd'autres.\n\n## Comme bibliothèque\n\nLa couche qui lit les trois archives est publiée seule, avec son rythme, son\ncache et ses erreurs, sans protocole attaché.\n\n```ts\nimport { BooksClient } from \"mcp-books/client\";\n\nconst client = new BooksClient();\nconst read = await client.searchItems({ query: \"beaumont light-house\", limit: 3 });\nconsole.log(read.data.rows.length);\n```\n\nChaque lecture répond `{ data, cached }`, et lève une erreur portant un des six\ncodes. Chaque archive garde son propre rythme, et son plancher tient également\nici.\n\n## Rythme et attribution\n\nChaque archive est cadencée pour elle-même, une requête à la fois, et c'est le\nplus large de son propre plancher et de l'intervalle configuré qui gouverne : la\nLibrary of Congress publie le plus lent, et interroger les trois à la fois coûte\ndonc à chacune une requête plutôt que trois. Le `User-Agent` se termine toujours\npar l'identité du projet et une adresse où joindre une personne.\n\nChaque notice porte l'adresse de sa page et l'`attribution` que son archive\ndemande. Les documents de l'Internet Archive appartiennent à ceux qui les ont\ndéposés, les notices de la Library of Congress énoncent leurs propres droits, et\nla BnF demande que la source et la date de récupération soient indiquées partout\noù ses métadonnées sont montrées.\n\nCe MCP est un projet non officiel, sans affiliation à aucune des archives qu'il\nlit.\n\n## Confidentialité\n\nCe serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur\nvotre machine, ne joint que `archive.org`, `openlibrary.org`, `www.loc.gov` et\n`data.bnf.fr`, garde ses réponses en mémoire le temps qu'il tourne, et n'écrit\nrien sur le disque. [PRIVACY.md](PRIVACY.md) dit ce qu'une requête emporte et\nquels réglages changent cela.\n\n## Développement\n\n```bash\nnpm install\nnpm run build:fixtures\nnpm test\nnpm run check\n```\n\nLes tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête.\nLa suite en direct, `npm run test:live`, émet une requête par route et tourne\nchaque nuit contre les archives elles-mêmes.\n\n## Contribuer\n\nLes anomalies, les questions et les idées ont leur place dans\n[le suivi d'incidents](https://github.com/smeet666/mcp-books/issues). Les\npropositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à\ns'accorder sur la forme du changement. Voir [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Licence\n\nMIT, voir [LICENSE](LICENSE). Les notices appartiennent aux archives qui les ont\npubliées et à ceux qui les y ont déposées.\n",
  "bytes": 36201,
  "sha": "bd8c384d639f3badff1c5a09232879869f9108e9d866e95911e48b36bf65e612",
  "repo_slug": "smeet666/mcp-books",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_smeet666_mcp_books_39e010be/readme"
}