{
  "markdown": "# mcp-databnf\n\n[![npm](https://img.shields.io/npm/v/mcp-databnf.svg)](https://www.npmjs.com/package/mcp-databnf)\n[![CI](https://github.com/smeet666/mcp-databnf/actions/workflows/ci.yml/badge.svg)](https://github.com/smeet666/mcp-databnf/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/mcp-databnf.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-databnf)\n[![Glama](https://glama.ai/mcp/servers/smeet666/mcp-databnf/badges/score.svg)](https://glama.ai/mcp/servers/smeet666/mcp-databnf)\n[![M8ven](https://m8ven.ai/badge/mcp/smeet666-mcp-databnf-abxqfo?variant=verified)](https://m8ven.ai/mcp/smeet666-mcp-databnf-abxqfo)\n[![LobeHub](https://lobehub.com/badge/mcp/smeet666-mcp-databnf)](https://lobehub.com/mcp/smeet666-mcp-databnf)\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)\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=databnf&config=%7B%22name%22%3A%22databnf%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-databnf%22%5D%7D)\n\n[data.bnf.fr](https://data.bnf.fr) is the open data service of the Bibliothèque\nnationale de France. It publishes the authority records the national library\nmaintains: the people it catalogues, with their dates, their places, their\nlanguages and their fields of activity; the works they wrote, with the editions\neach work was published in; and the links to the copies digitised in Gallica. A\nrecord states whether the library considers it established or still provisional.\n\nThis server connects a chat client to that service. You can search for an author\nor a work by name, read a record in full, list what an author wrote, list the\neditions of a work, and find the digitised copies attached to either. It needs no\nAPI key and no account.\n\n_[Version française](#mcp-databnf-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=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)\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=databnf&config=%7B%22name%22%3A%22databnf%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-databnf%22%5D%7D)\n\n**Claude Code**\n\n```bash\nclaude mcp add databnf -- npx -y mcp-databnf\n```\n\n**Claude Desktop, Cursor, and any client using the standard config format**\n\n```json\n{\n  \"mcpServers\": {\n    \"databnf\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-databnf\"]\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    \"databnf\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-databnf:2.1.2\"]\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`data.bnf.fr`, and nothing else: no volume, no port, no credential.\n\n### Bundle, without npm\n\nDownload `mcp-databnf-2.1.2.mcpb` from\n[the latest release](https://github.com/smeet666/mcp-databnf/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- « Que dit la BnF de Colette ? »\n- \"List everything Marguerite Duras wrote.\"\n- \"Which editions of that work does the library hold?\"\n- \"Are any of them digitised in Gallica?\"\n- \"When was that record last established?\"\n\nThe ordinary path runs from a search to a record: a row carries an `id`, and\n`get_author` or `get_work` reads it.\n\n## Tools\n\n| Tool             | What it does                                                  |\n| ---------------- | ------------------------------------------------------------- |\n| `search_authors` | Finds people by name in the authority records.                |\n| `get_author`     | Reads one person's record in full.                            |\n| `search_works`   | Finds works by title.                                         |\n| `get_work`       | Reads one work's record in full.                              |\n| `list_works`     | Lists the works one person is credited with.                  |\n| `list_editions`  | Lists the editions of one work.                               |\n| `find_digitised` | Finds the copies digitised in Gallica for a person or a work. |\n\n### `search_authors`\n\nFinds people by name in the authority records.\n\n| Argument | Type                           | Required | What it does          |\n| -------- | ------------------------------ | -------- | --------------------- |\n| `name`   | string, 1 to 200 characters    | yes      | The name to look for. |\n| `limit`  | integer, 1 to 50, default `10` | no       | Rows to serve.        |\n| `page`   | integer, 1 to 100, default `1` | no       | Which page of rows.   |\n\n**In return:** `authors`, each carrying `id`, which `get_author`, `list_works`\nand `find_digitised` take; `name` as the service writes it; `label`, the\nauthority heading, usually with the dates; `birth_year` and `death_year`, `null`\nwhere the record states none; `role`; and `source_url`. `words_searched` says\nwhat was actually sent, `has_more` whether further pages exist, and\n`index_window_full` that the index served everything it will serve for this\nsearch.\n\n### `get_author`\n\nReads one person's record in full.\n\n| Argument             | Type                        | Required | What it does                            |\n| -------------------- | --------------------------- | -------- | --------------------------------------- |\n| `author_id`          | string, 1 to 200 characters | yes      | The identifier a row carries.           |\n| `include_depictions` | boolean, default `false`    | no       | Add the portraits the record points to. |\n\n**In return:** the person with `name`, `label`, `given_name`, `family_name`,\n`other_names`, `birth_date` and `death_date` as published, `birth_year` and\n`death_year` as numbers, `birth_place`, `death_place`,\n`biographical_information`, `occupation`, `languages` as ISO 639-2 codes,\n`countries` and `fields` in the words of the record. A field the record leaves\nempty is `null`.\n\n### `search_works`\n\nFinds works by title.\n\n| Argument | Type                           | Required | What it does                        |\n| -------- | ------------------------------ | -------- | ----------------------------------- |\n| `title`  | string, 1 to 200 characters    | yes      | The words of the title to look for. |\n| `limit`  | integer, 1 to 50, default `10` | no       | Rows to serve.                      |\n| `page`   | integer, 1 to 100, default `1` | no       | Which page of rows.                 |\n\n**In return:** `works`, each carrying `id`, which `get_work`, `list_editions` and\n`find_digitised` take; `title`; `date`, the year the record gives the work, as\npublished; `creators`; `status`, reading `established` or `provisional`; and\n`source_url`. The envelope carries the same `words_searched`, `has_more` and\n`index_window_full` a search of people returns.\n\n### `get_work`\n\nReads one work's record in full.\n\n| Argument             | Type                        | Required | What it does                                |\n| -------------------- | --------------------------- | -------- | ------------------------------------------- |\n| `work_id`            | string, 1 to 200 characters | yes      | The identifier a row carries.               |\n| `include_depictions` | boolean, default `false`    | no       | Add the illustrations the record points to. |\n\n**In return:** the work with `title`, `label`, `date` as published, `first_year`,\n`creators` as `{ id, name }`, `languages`, `forms`, `subjects` and\n`dewey_classes` in the words of the record, `expression_count`, `same_as` for the\nregisters the BnF aligns it with, and `catalogue_url`. `status` reads\n`established` or `provisional`, and `status_statement` says what the library\nmeans by it: a provisional record is one the library has not finished checking.\n\n### `list_works`\n\nLists the works one person is credited with.\n\n| Argument    | Type                           | Required | What it does             |\n| ----------- | ------------------------------ | -------- | ------------------------ |\n| `author_id` | string, 1 to 200 characters    | yes      | The person's identifier. |\n| `limit`     | integer, 1 to 50, default `10` | no       | Rows to serve.           |\n| `page`      | integer, 1 to 100, default `1` | no       | Which page of rows.      |\n\n**In return:** `works`, each carrying `id`, `title`, `date` as published, `year`\nas a number where the record has one, `forms`, `status` and `source_url`, with\n`has_more` to continue.\n\n### `list_editions`\n\nLists the editions of one work.\n\n| Argument  | Type                           | Required | What it does           |\n| --------- | ------------------------------ | -------- | ---------------------- |\n| `work_id` | string, 1 to 200 characters    | yes      | The work's identifier. |\n| `limit`   | integer, 1 to 50, default `10` | no       | Rows to serve.         |\n| `page`    | integer, 1 to 100, default `1` | no       | Which page of rows.    |\n\n**In return:** `editions`, each carrying its own `id` in the BnF catalogue, the\n`title` this edition bears, `date` and `year`, `publisher`, `place`,\n`edition_statement`, `extent`, `isbn`, `note` as the cataloguer wrote it,\n`catalogue_url`, `digitised` and `source_url`. A field the record leaves empty is\n`null`.\n\n### `find_digitised`\n\nFinds the copies digitised in Gallica attached to a person or a work.\n\n| Argument | Type                                       | Required | What it does                             |\n| -------- | ------------------------------------------ | -------- | ---------------------------------------- |\n| `id`     | string, 1 to 200 characters                | yes      | The identifier of a person or of a work. |\n| `kind`   | `auto`, `person` or `work`, default `auto` | no       | What the identifier stands for.          |\n| `limit`  | integer, 1 to 200, default `40`            | no       | Links to serve.                          |\n\n**In return:** `kind`, saying what the catalogue types the record as, and `links`,\neach carrying the Gallica `ark`, its `url`, its `rendering` and the `role` the\nperson holds on it. `links_returned_by_role` counts them per role. This server\ndescribes a digitised document and never opens one.\n\n## Established and provisional records\n\nA record carries a `status`. `established` means the library has checked it;\n`provisional` means it has not finished, and `status_statement` says so in the\nlibrary's own words. Report the status alongside anything taken from a\nprovisional record.\n\n## The licence, and what it asks\n\nThe BnF states one condition on these metadata:\n\n> L'utilisation de ces métadonnées est libre et gratuite sous réserve du maintien\n> de la mention de leur source et de l'indication de leur date de récupération.\n\nUse is free of charge, provided the source is named and the date of retrieval is\nstated. Every answer carries `retrieved_at` in its payload and ends its text with\nthe source and that date. A cached answer reports the moment it was originally\nread, since that is when it was retrieved. Repeat both wherever what you got is\nshown.\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| `BNF_USER_AGENT`        | the project identity | Names your application to the BnF, with an address where a person can be reached. |\n| `BNF_MIN_INTERVAL_MS`   | `3000`               | Gap between two requests, from 3000 to 120000.                                    |\n| `BNF_TIMEOUT_MS`        | `60000`              | Deadline for one request, from 1000 to 300000.                                    |\n| `BNF_MAX_RETRIES`       | `3`                  | Attempts after a transient failure, from 0 to 8.                                  |\n| `BNF_CACHE_TTL_MS`      | `900000`             | How long an answer stays in memory, from 0 to 86400000.                           |\n| `BNF_CACHE_MAX_ENTRIES` | `200`                | Answers held in memory at once, from 1 to 5000.                                   |\n| `BNF_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`     | The service answered, and holds no such record.         | Check the identifier with `search_authors` or `search_works`.                                                |\n| `invalid_input` | The arguments were refused before any request went out. | Read the message, which names the argument.                                                                  |\n| `rate_limited`  | The service asked this client to slow down.             | Wait the number of seconds the hint names and call again with the same arguments. The record is still there. |\n| `parse_failure` | The answer arrived in a shape this client cannot read.  | Report it at [the issue tracker](https://github.com/smeet666/mcp-databnf/issues).                            |\n| `network_error` | The request did not complete.                           | Try again shortly.                                                                                           |\n| `timeout`       | The request passed its deadline.                        | Raise `BNF_TIMEOUT_MS`, or ask for fewer rows.                                                               |\n\n## As a library\n\nThe layer reading the service is published on its own, with its pacing, its cache\nand its errors, and with no protocol attached.\n\n```ts\nimport { BnfClient } from \"mcp-databnf/client\";\n\nconst client = new BnfClient();\nconst { data, cached } = await client.getAuthor(\"cb11907966z\");\nconsole.log(data.label, cached);\n```\n\n`getAuthor` and `getWork` each answer `{ data, cached }`, and throw an error\ncarrying one of the six codes. The three-second floor between two requests holds\nhere as well.\n\n## Pacing and attribution\n\nRequests go out one at a time with at least three seconds between them, and that\nfloor holds however the server is configured. Each question is answered by a\nSPARQL query against a public endpoint the BnF runs at its own expense, which is\nwhy the interval is wide and the deadline long. The `User-Agent` always ends with\nthe project identity and an address where a person can be reached.\n\nEvery answer carries the source and `retrieved_at`, which the licence asks to be\nstated wherever the metadata are shown.\n\nThis MCP server is an unofficial project, with no affiliation to the\nBibliothèque nationale de France.\n\n## Privacy\n\nThis server collects nothing about you and sends nothing to its author. It runs\non your machine, contacts `data.bnf.fr` and nothing else, holds its answers in memory\nwhile it runs, and writes nothing to disk.\n[PRIVACY.md](PRIVACY.md) states what a request carries and which settings change\nany 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\nservice itself.\n\n## Contributing\n\nBugs, questions and ideas belong in\n[the issue tracker](https://github.com/smeet666/mcp-databnf/issues). Pull\nrequests are welcome; opening an issue first helps agree on the shape of the\nchange. See [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT, see [LICENSE](LICENSE). The metadata belong to the Bibliothèque nationale de\nFrance, free to use provided the source and the date of retrieval are stated.\n\n---\n\n<a name=\"mcp-databnf-français\"></a>\n\n# mcp-databnf (français)\n\n_[English version](#mcp-databnf)_\n\n[data.bnf.fr](https://data.bnf.fr) est le service de données ouvertes de la\nBibliothèque nationale de France. Il publie les notices d'autorité que la\nbibliothèque nationale entretient : les personnes qu'elle catalogue, avec leurs\ndates, leurs lieux, leurs langues et leurs domaines d'activité ; les œuvres\nqu'elles ont écrites, avec les éditions dans lesquelles chaque œuvre a paru ; et\nles liens vers les exemplaires numérisés dans Gallica. Une notice indique si la\nbibliothèque la tient pour établie ou encore provisoire.\n\nCe serveur relie un client de conversation à ce service. On peut y chercher un\nauteur ou une œuvre par son nom, lire une notice en entier, lister ce qu'un\nauteur a écrit, lister les éditions d'une œuvre, et trouver les exemplaires\nnumérisés attachés à l'un ou l'autre. Aucune clé d'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=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)\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=databnf&config=%7B%22name%22%3A%22databnf%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-databnf%22%5D%7D)\n\n**Claude Code**\n\n```bash\nclaude mcp add databnf -- npx -y mcp-databnf\n```\n\n**Claude Desktop, Cursor, et tout client au format de configuration standard**\n\n```json\n{\n  \"mcpServers\": {\n    \"databnf\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-databnf\"]\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    \"databnf\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-databnf:2.1.2\"]\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 `data.bnf.fr`, et de rien d'autre : aucun volume, aucun port, aucun\nidentifiant.\n\n### Bundle, sans npm\n\nTéléchargez `mcp-databnf-2.1.2.mcpb` depuis\n[la dernière publication](https://github.com/smeet666/mcp-databnf/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- « Que dit la BnF de Colette ? »\n- « Liste tout ce qu'a écrit Marguerite Duras. »\n- « Quelles éditions de cette œuvre la bibliothèque conserve-t-elle ? »\n- « Y en a-t-il de numérisées dans Gallica ? »\n- « Cette notice est-elle établie ou provisoire ? »\n\nLe chemin ordinaire va d'une recherche à une notice : une ligne porte un `id`, et\n`get_author` ou `get_work` la lit.\n\n## Les outils\n\n| Outil            | Ce qu'il fait                                                                |\n| ---------------- | ---------------------------------------------------------------------------- |\n| `search_authors` | Trouve des personnes par leur nom dans les notices d'autorité.               |\n| `get_author`     | Lit la notice d'une personne en entier.                                      |\n| `search_works`   | Trouve des œuvres par leur titre.                                            |\n| `get_work`       | Lit la notice d'une œuvre en entier.                                         |\n| `list_works`     | Liste les œuvres attribuées à une personne.                                  |\n| `list_editions`  | Liste les éditions d'une œuvre.                                              |\n| `find_digitised` | Trouve les exemplaires numérisés dans Gallica d'une personne ou d'une œuvre. |\n\n### `search_authors`\n\nTrouve des personnes par leur nom dans les notices d'autorité.\n\n| Argument | Type                        | Requis | Ce qu'il fait          |\n| -------- | --------------------------- | ------ | ---------------------- |\n| `name`   | chaîne, 1 à 200 caractères  | oui    | Le nom cherché.        |\n| `limit`  | entier, 1 à 50, défaut `10` | non    | Lignes à servir.       |\n| `page`   | entier, 1 à 100, défaut `1` | non    | Quelle page de lignes. |\n\n**En retour :** `authors`, chacun portant `id`, que `get_author`, `list_works` et\n`find_digitised` reprennent ; `name` tel que le service l'écrit ; `label`, la\nvedette d'autorité, généralement avec les dates ; `birth_year` et `death_year`,\n`null` là où la notice n'en indique pas ; `role` ; et `source_url`.\n`words_searched` dit ce qui a réellement été envoyé, `has_more` s'il existe\nd'autres pages, et `index_window_full` que l'index a servi tout ce qu'il servira\npour cette recherche.\n\n### `get_author`\n\nLit la notice d'une personne en entier.\n\n| Argument             | Type                       | Requis | Ce qu'il fait                                        |\n| -------------------- | -------------------------- | ------ | ---------------------------------------------------- |\n| `author_id`          | chaîne, 1 à 200 caractères | oui    | L'identifiant que porte une ligne.                   |\n| `include_depictions` | booléen, défaut `false`    | non    | Ajoute les portraits vers lesquels la notice pointe. |\n\n**En retour :** la personne avec `name`, `label`, `given_name`, `family_name`,\n`other_names`, `birth_date` et `death_date` tels que publiés, `birth_year` et\n`death_year` en nombres, `birth_place`, `death_place`,\n`biographical_information`, `occupation`, `languages` en codes ISO 639-2,\n`countries` et `fields` dans les mots de la notice. Un champ que la notice laisse\nvide vaut `null`.\n\n### `search_works`\n\nTrouve des œuvres par leur titre.\n\n| Argument | Type                        | Requis | Ce qu'il fait              |\n| -------- | --------------------------- | ------ | -------------------------- |\n| `title`  | chaîne, 1 à 200 caractères  | oui    | Les mots du titre cherché. |\n| `limit`  | entier, 1 à 50, défaut `10` | non    | Lignes à servir.           |\n| `page`   | entier, 1 à 100, défaut `1` | non    | Quelle page de lignes.     |\n\n**En retour :** `works`, chacune portant `id`, que `get_work`, `list_editions` et\n`find_digitised` reprennent ; `title` ; `date`, l'année que la notice donne à\nl'œuvre, telle que publiée ; `creators` ; `status`, valant `established` ou\n`provisional` ; et `source_url`. L'enveloppe porte les mêmes `words_searched`,\n`has_more` et `index_window_full` qu'une recherche de personnes.\n\n### `get_work`\n\nLit la notice d'une œuvre en entier.\n\n| Argument             | Type                       | Requis | Ce qu'il fait                                              |\n| -------------------- | -------------------------- | ------ | ---------------------------------------------------------- |\n| `work_id`            | chaîne, 1 à 200 caractères | oui    | L'identifiant que porte une ligne.                         |\n| `include_depictions` | booléen, défaut `false`    | non    | Ajoute les illustrations vers lesquelles la notice pointe. |\n\n**En retour :** l'œuvre avec `title`, `label`, `date` telle que publiée,\n`first_year`, `creators` en `{ id, name }`, `languages`, `forms`, `subjects` et\n`dewey_classes` dans les mots de la notice, `expression_count`, `same_as` pour\nles registres auxquels la BnF l'aligne, et `catalogue_url`. `status` vaut\n`established` ou `provisional`, et `status_statement` dit ce que la bibliothèque\nentend par là : une notice provisoire est une notice qu'elle n'a pas fini de\nvérifier.\n\n### `list_works`\n\nListe les œuvres attribuées à une personne.\n\n| Argument    | Type                        | Requis | Ce qu'il fait                 |\n| ----------- | --------------------------- | ------ | ----------------------------- |\n| `author_id` | chaîne, 1 à 200 caractères  | oui    | L'identifiant de la personne. |\n| `limit`     | entier, 1 à 50, défaut `10` | non    | Lignes à servir.              |\n| `page`      | entier, 1 à 100, défaut `1` | non    | Quelle page de lignes.        |\n\n**En retour :** `works`, chacune portant `id`, `title`, `date` telle que publiée,\n`year` en nombre quand la notice en a un, `forms`, `status` et `source_url`, avec\n`has_more` pour poursuivre.\n\n### `list_editions`\n\nListe les éditions d'une œuvre.\n\n| Argument  | Type                        | Requis | Ce qu'il fait             |\n| --------- | --------------------------- | ------ | ------------------------- |\n| `work_id` | chaîne, 1 à 200 caractères  | oui    | L'identifiant de l'œuvre. |\n| `limit`   | entier, 1 à 50, défaut `10` | non    | Lignes à servir.          |\n| `page`    | entier, 1 à 100, défaut `1` | non    | Quelle page de lignes.    |\n\n**En retour :** `editions`, chacune portant son propre `id` au catalogue de la\nBnF, le `title` que cette édition porte, `date` et `year`, `publisher`, `place`,\n`edition_statement`, `extent`, `isbn`, `note` telle que le catalogueur l'a\nécrite, `catalogue_url`, `digitised` et `source_url`. Un champ que la notice\nlaisse vide vaut `null`.\n\n### `find_digitised`\n\nTrouve les exemplaires numérisés dans Gallica attachés à une personne ou à une\nœuvre.\n\n| Argument | Type                                      | Requis | Ce qu'il fait                                |\n| -------- | ----------------------------------------- | ------ | -------------------------------------------- |\n| `id`     | chaîne, 1 à 200 caractères                | oui    | L'identifiant d'une personne ou d'une œuvre. |\n| `kind`   | `auto`, `person` ou `work`, défaut `auto` | non    | Ce que l'identifiant désigne.                |\n| `limit`  | entier, 1 à 200, défaut `40`              | non    | Liens à servir.                              |\n\n**En retour :** `kind`, qui dit de quel type le catalogue tient la notice, et\n`links`, chacun portant l'`ark` Gallica, son `url`, son `rendering` et le `role`\nque la personne y tient. `links_returned_by_role` les compte par rôle. Ce serveur\ndécrit un document numérisé et n'en ouvre jamais aucun.\n\n## Notices établies et provisoires\n\nUne notice porte un `status`. `established` signifie que la bibliothèque l'a\nvérifiée ; `provisional` qu'elle ne l'a pas terminée, et `status_statement` le\ndit dans ses propres mots. Rapportez ce statut à côté de tout ce qui vient d'une\nnotice provisoire.\n\n## La licence, et ce qu'elle demande\n\nLa BnF pose une condition sur ces métadonnées :\n\n> L'utilisation de ces métadonnées est libre et gratuite sous réserve du maintien\n> de la mention de leur source et de l'indication de leur date de récupération.\n\nChaque réponse porte `retrieved_at` dans sa charge utile et termine son texte par\nla source et cette date. Une réponse servie depuis le cache rapporte le moment où\nelle a été lue à l'origine, puisque c'est sa date de récupération. Redonnez les\ndeux partout où ce que vous avez obtenu est montré.\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| `BNF_USER_AGENT`        | l'identité du projet | Nomme votre application auprès de la BnF, avec une adresse où joindre une personne. |\n| `BNF_MIN_INTERVAL_MS`   | `3000`               | Écart entre deux requêtes, de 3000 à 120000.                                        |\n| `BNF_TIMEOUT_MS`        | `60000`              | Délai d'une requête, de 1000 à 300000.                                              |\n| `BNF_MAX_RETRIES`       | `3`                  | Tentatives après un échec passager, de 0 à 8.                                       |\n| `BNF_CACHE_TTL_MS`      | `900000`             | Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000.               |\n| `BNF_CACHE_MAX_ENTRIES` | `200`                | Réponses gardées en mémoire à la fois, de 1 à 5000.                                 |\n| `BNF_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`     | Le service a répondu, et n'a pas cette notice.       | Vérifiez l'identifiant avec `search_authors` ou `search_works`.                                  |\n| `invalid_input` | Les arguments ont été refusés avant toute requête.   | Lisez le message, qui nomme l'argument.                                                          |\n| `rate_limited`  | Le service demande à ce client de ralentir.          | Attendez les secondes indiquées et rappelez avec les mêmes arguments. La notice est toujours là. |\n| `parse_failure` | La réponse est arrivée dans une forme illisible ici. | Signalez-le sur [le suivi d'incidents](https://github.com/smeet666/mcp-databnf/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 `BNF_TIMEOUT_MS`, ou demandez moins de lignes.                                         |\n\n## Comme bibliothèque\n\nLa couche qui lit le service est publiée seule, avec son rythme, son cache et ses\nerreurs, sans protocole attaché.\n\n```ts\nimport { BnfClient } from \"mcp-databnf/client\";\n\nconst client = new BnfClient();\nconst { data, cached } = await client.getAuthor(\"cb11907966z\");\nconsole.log(data.label, cached);\n```\n\n`getAuthor` et `getWork` répondent chacun `{ data, cached }`, et lèvent une\nerreur portant un des six codes. Le plancher de trois secondes entre deux\nrequêtes tient également ici.\n\n## Rythme et attribution\n\nLes requêtes partent une à une avec au moins trois secondes entre elles, et ce\nplancher tient quelle que soit la configuration. Chaque question se résout par\nune requête SPARQL contre un point d'accès public que la BnF fait tourner à ses\nfrais, d'où un intervalle large et un délai long. Le `User-Agent` se termine\ntoujours par l'identité du projet et une adresse où joindre une personne.\n\nChaque réponse porte la source et `retrieved_at`, que la licence demande\nd'indiquer partout où les métadonnées sont montrées.\n\nCe MCP est un projet non officiel, sans affiliation à la Bibliothèque nationale\nde France.\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 `data.bnf.fr`, garde ses réponses en mémoire le temps qu'il\ntourne, et n'écrit rien sur le disque. [PRIVACY.md](PRIVACY.md) dit ce qu'une\nrequête emporte et quels 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 le service lui-même.\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-databnf/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 métadonnées appartiennent à la Bibliothèque\nnationale de France, d'usage libre sous réserve d'indiquer la source et la date\nde récupération.\n",
  "bytes": 33229,
  "sha": "15bf5a7f228584a97a1feb4b830e88e718047acf1020e0998eb1f9f0a1cdd582",
  "repo_slug": "smeet666/mcp-databnf",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_smeet666_mcp_databnf_ff61ca2e/readme"
}