mcp-databnf 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/PRIVACY.md +152 -0
- package/README.md +523 -301
- package/dist/bnf/client.d.ts +11 -1
- package/dist/bnf/client.js +53 -2
- package/dist/bnf/client.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/server.json +4 -4
package/README.md
CHANGED
|
@@ -9,33 +9,36 @@
|
|
|
9
9
|
[](https://cursor.com/en/install-mcp?name=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)
|
|
10
10
|
[](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)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
[data.bnf.fr](https://data.bnf.fr) is the open data service of the Bibliothèque
|
|
13
|
+
nationale de France. It publishes the authority records the national library
|
|
14
|
+
maintains: the people it catalogues, with their dates, their places, their
|
|
15
|
+
languages and their fields of activity; the works they wrote, with the editions
|
|
16
|
+
each work was published in; and the links to the copies digitised in Gallica. A
|
|
17
|
+
record states whether the library considers it established or still provisional.
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
This server connects a chat client to that service. You can search for an author
|
|
20
|
+
or a work by name, read a record in full, list what an author wrote, list the
|
|
21
|
+
editions of a work, and find the digitised copies attached to either. It needs no
|
|
22
|
+
API key and no account.
|
|
23
|
+
|
|
24
|
+
_[Version française](#mcp-databnf-français)_
|
|
18
25
|
|
|
19
26
|
---
|
|
20
27
|
|
|
21
|
-
##
|
|
28
|
+
## Install
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
data, and answers questions about them over SPARQL. That dataset knows things a
|
|
25
|
-
web search does not: which of two people bearing one name wrote a given book,
|
|
26
|
-
what the BnF recorded as somebody's date and place of death, which editions of a
|
|
27
|
-
work exist and who printed them, and which of those have been digitised.
|
|
30
|
+
**One-click install**
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
[](https://cursor.com/en/install-mcp?name=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)
|
|
33
|
+
[](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)
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
**Claude Code**
|
|
33
36
|
|
|
34
37
|
```bash
|
|
35
|
-
npx mcp-databnf
|
|
38
|
+
claude mcp add databnf -- npx -y mcp-databnf
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
**Claude Desktop, Cursor, and any client using the standard config format**
|
|
39
42
|
|
|
40
43
|
```json
|
|
41
44
|
{
|
|
@@ -48,6 +51,8 @@ npx mcp-databnf
|
|
|
48
51
|
}
|
|
49
52
|
```
|
|
50
53
|
|
|
54
|
+
Node 24 or later is required, and no environment variable has to be set.
|
|
55
|
+
|
|
51
56
|
### With Docker
|
|
52
57
|
|
|
53
58
|
```json
|
|
@@ -55,230 +60,309 @@ npx mcp-databnf
|
|
|
55
60
|
"mcpServers": {
|
|
56
61
|
"databnf": {
|
|
57
62
|
"command": "docker",
|
|
58
|
-
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-databnf:2.
|
|
63
|
+
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-databnf:2.1.0"]
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
```
|
|
63
68
|
|
|
64
|
-
`-i` keeps stdin open, which is where the protocol travels, and
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## The seven tools
|
|
69
|
-
|
|
70
|
-
| Tool | Answers |
|
|
71
|
-
| ---------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
-
| `search_authors` | Who does the BnF record under this name, and which record is which |
|
|
73
|
-
| `get_author` | Dates, places, occupation, language, country, Dewey class, and the same person in VIAF, IdRef, DBpedia, Wikidata and ISNI |
|
|
74
|
-
| `search_works` | Which works have these words in their title |
|
|
75
|
-
| `get_work` | Title, creators, date, language, form, subject, and whether the record is established or provisional |
|
|
76
|
-
| `list_works` | Which works the catalogue names a person the creator of, with the date and the form code it gives each |
|
|
77
|
-
| `list_editions` | Publisher, place, year, edition statement, extent, ISBN, catalogue link, and the Gallica link when there is one |
|
|
78
|
-
| `find_digitised` | Every digitised document the catalogue attaches to a person or a work, as links |
|
|
79
|
-
|
|
80
|
-
A typical exchange asks `search_authors` for a name, reads the rows, and passes
|
|
81
|
-
one identifier to `get_author`, to `list_works`, or on to `list_editions`.
|
|
82
|
-
|
|
83
|
-
## What it does not do, and why
|
|
84
|
-
|
|
85
|
-
**It never reads Gallica.** The BnF puts its metadata and its digitised contents
|
|
86
|
-
under two different regimes. The metadata this server reads may be reused freely
|
|
87
|
-
provided the source and the date of retrieval are stated. The contents on
|
|
88
|
-
gallica.bnf.fr are governed separately: their terms make use inside an
|
|
89
|
-
artificial-intelligence project subject to a paid licence outside academic
|
|
90
|
-
research, and the site refuses ClaudeBot and GPTBot at the server, then bans the
|
|
91
|
-
calling address after about fifteen requests whatever the pace.
|
|
92
|
-
|
|
93
|
-
So a Gallica address is treated here as what the catalogue says it is: a piece of
|
|
94
|
-
metadata, rendered as a link for a person to open. The server will tell you that
|
|
95
|
-
a 1873 Brussels printing of _Une saison en enfer_ has been digitised and give you
|
|
96
|
-
its address. It will not tell you what is on page four, whether the scan is
|
|
97
|
-
complete, or whether the document opens at all. A `bnf-onto:OCR` link names a
|
|
98
|
-
machine-read text of a document; the server reports that the text exists and
|
|
99
|
-
leaves it where it is. A test fails if any address on that host is ever built to
|
|
100
|
-
be called.
|
|
101
|
-
|
|
102
|
-
**It does not rank.** The BnF's full-text index answers whether a title or a name
|
|
103
|
-
carries the words asked for. It returns no measure of how well, so the rows come
|
|
104
|
-
back in the order the index holds them. Searching for `saison enfer` returns a
|
|
105
|
-
dozen studies of Rimbaud before Rimbaud, and every one of them is a correct
|
|
106
|
-
match. This server says so rather than inventing an order the catalogue does not
|
|
107
|
-
support, and it reports no total, because a total on a search that does not rank
|
|
108
|
-
reads as a measure of relevance.
|
|
109
|
-
|
|
110
|
-
**A name is matched letter for letter, and only among the people.** The index
|
|
111
|
-
compares the characters given against the characters a cataloguer entered, so
|
|
112
|
-
`Dostoïevski`, `Dostoievski` and `Dostoevskij` are three searches reaching three
|
|
113
|
-
different sets of records, and a handful of rows under one spelling is no
|
|
114
|
-
evidence about the others. `search_authors` says so on every answer, and it reads
|
|
115
|
-
the person records alone: an organisation or a conference is outside what it
|
|
116
|
-
looked at, so an answer holding no row is never a statement that the authority
|
|
117
|
-
file holds no such heading.
|
|
118
|
-
|
|
119
|
-
**A list of works is one link, not a bibliography.** `list_works` walks
|
|
120
|
-
`dcterms:creator`, the statement that ties a work to the person who made it.
|
|
121
|
-
That statement is real and it is partial. The catalogue credits a person on a
|
|
122
|
-
record in other ways, and the BnF holds printed editions whose work it has never
|
|
123
|
-
established as a record of its own, so a title missing from the list is not a
|
|
124
|
-
title the person did not write. Every answer says so, and none of them reports a
|
|
125
|
-
total: a count of what one link reaches would be read as a count of what somebody
|
|
126
|
-
wrote.
|
|
127
|
-
|
|
128
|
-
**A form code says what a work declares, and an empty one says nothing.** A work
|
|
129
|
-
record points at a term of the BnF's work-form vocabulary, and this dataset
|
|
130
|
-
publishes no label for those terms. So `roman`, `poesi` and `te` arrive as the
|
|
131
|
-
codes they are: some read as words and some do not. The catalogue also states no
|
|
132
|
-
form at all on a great many works, and that silence is a form unstated rather
|
|
133
|
-
than a genre denied. Keeping the rows that carry one code therefore finds the
|
|
134
|
-
works declaring it and never all the works of that form, which is why the codes
|
|
135
|
-
are reported and no filter is offered on them.
|
|
136
|
-
|
|
137
|
-
**It does not write biographies.** The field the BnF calls biographical
|
|
138
|
-
information is an occupation on most records: Rimbaud's says _Poète_, and that is
|
|
139
|
-
the whole of it. `get_author` returns that word and says what it is.
|
|
140
|
-
|
|
141
|
-
**It exposes no raw SPARQL tool.** An arbitrary query is an unbounded load on a
|
|
142
|
-
service a public institution pays for, and nothing here would control what the
|
|
143
|
-
caller wrote. Every query this server sends is one of ten written in advance.
|
|
144
|
-
|
|
145
|
-
## The licence, and what it asks of you
|
|
69
|
+
`-i` keeps stdin open, which is where the protocol travels, and `-t` is left out
|
|
70
|
+
because a TTY rewrites the stream. The container needs outbound HTTPS to
|
|
71
|
+
`data.bnf.fr`, and nothing else: no volume, no port, no credential.
|
|
146
72
|
|
|
147
|
-
|
|
73
|
+
### Bundle, without npm
|
|
148
74
|
|
|
149
|
-
|
|
150
|
-
|
|
75
|
+
Download `mcp-databnf-2.1.0.mcpb` from
|
|
76
|
+
[the latest release](https://github.com/smeet666/mcp-databnf/releases/latest) and
|
|
77
|
+
open it. A client that supports MCP bundles installs it on its own, with no npm
|
|
78
|
+
and no configuration file to edit. The bundle carries its dependencies, so
|
|
79
|
+
nothing is fetched at install time.
|
|
80
|
+
|
|
81
|
+
## What you can ask
|
|
82
|
+
|
|
83
|
+
- « Que dit la BnF de Colette ? »
|
|
84
|
+
- "List everything Marguerite Duras wrote."
|
|
85
|
+
- "Which editions of that work does the library hold?"
|
|
86
|
+
- "Are any of them digitised in Gallica?"
|
|
87
|
+
- "When was that record last established?"
|
|
88
|
+
|
|
89
|
+
The ordinary path runs from a search to a record: a row carries an `id`, and
|
|
90
|
+
`get_author` or `get_work` reads it.
|
|
91
|
+
|
|
92
|
+
## Tools
|
|
93
|
+
|
|
94
|
+
| Tool | What it does |
|
|
95
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
96
|
+
| `search_authors` | Finds people by name in the authority records. |
|
|
97
|
+
| `get_author` | Reads one person's record in full. |
|
|
98
|
+
| `search_works` | Finds works by title. |
|
|
99
|
+
| `get_work` | Reads one work's record in full. |
|
|
100
|
+
| `list_works` | Lists the works one person is credited with. |
|
|
101
|
+
| `list_editions` | Lists the editions of one work. |
|
|
102
|
+
| `find_digitised` | Finds the copies digitised in Gallica for a person or a work. |
|
|
103
|
+
|
|
104
|
+
### `search_authors`
|
|
105
|
+
|
|
106
|
+
Finds people by name in the authority records.
|
|
107
|
+
|
|
108
|
+
| Argument | Type | Required | What it does |
|
|
109
|
+
| -------- | ------------------------------ | -------- | --------------------- |
|
|
110
|
+
| `name` | string, 1 to 200 characters | yes | The name to look for. |
|
|
111
|
+
| `limit` | integer, 1 to 50, default `10` | no | Rows to serve. |
|
|
112
|
+
| `page` | integer, 1 to 100, default `1` | no | Which page of rows. |
|
|
113
|
+
|
|
114
|
+
**In return:** `authors`, each carrying `id`, which `get_author`, `list_works`
|
|
115
|
+
and `find_digitised` take; `name` as the service writes it; `label`, the
|
|
116
|
+
authority heading, usually with the dates; `birth_year` and `death_year`, `null`
|
|
117
|
+
where the record states none; `role`; and `source_url`. `words_searched` says
|
|
118
|
+
what was actually sent, `has_more` whether further pages exist, and
|
|
119
|
+
`index_window_full` that the index served everything it will serve for this
|
|
120
|
+
search.
|
|
121
|
+
|
|
122
|
+
### `get_author`
|
|
123
|
+
|
|
124
|
+
Reads one person's record in full.
|
|
125
|
+
|
|
126
|
+
| Argument | Type | Required | What it does |
|
|
127
|
+
| -------------------- | --------------------------- | -------- | --------------------------------------- |
|
|
128
|
+
| `author_id` | string, 1 to 200 characters | yes | The identifier a row carries. |
|
|
129
|
+
| `include_depictions` | boolean, default `false` | no | Add the portraits the record points to. |
|
|
130
|
+
|
|
131
|
+
**In return:** the person with `name`, `label`, `given_name`, `family_name`,
|
|
132
|
+
`other_names`, `birth_date` and `death_date` as published, `birth_year` and
|
|
133
|
+
`death_year` as numbers, `birth_place`, `death_place`,
|
|
134
|
+
`biographical_information`, `occupation`, `languages` as ISO 639-2 codes,
|
|
135
|
+
`countries` and `fields` in the words of the record. A field the record leaves
|
|
136
|
+
empty is `null`.
|
|
137
|
+
|
|
138
|
+
### `search_works`
|
|
139
|
+
|
|
140
|
+
Finds works by title.
|
|
141
|
+
|
|
142
|
+
| Argument | Type | Required | What it does |
|
|
143
|
+
| -------- | ------------------------------ | -------- | ----------------------------------- |
|
|
144
|
+
| `title` | string, 1 to 200 characters | yes | The words of the title to look for. |
|
|
145
|
+
| `limit` | integer, 1 to 50, default `10` | no | Rows to serve. |
|
|
146
|
+
| `page` | integer, 1 to 100, default `1` | no | Which page of rows. |
|
|
147
|
+
|
|
148
|
+
**In return:** `works`, each carrying `id`, which `get_work`, `list_editions` and
|
|
149
|
+
`find_digitised` take; `title`; `date`, the year the record gives the work, as
|
|
150
|
+
published; `creators`; `status`, reading `established` or `provisional`; and
|
|
151
|
+
`source_url`. The envelope carries the same `words_searched`, `has_more` and
|
|
152
|
+
`index_window_full` a search of people returns.
|
|
153
|
+
|
|
154
|
+
### `get_work`
|
|
155
|
+
|
|
156
|
+
Reads one work's record in full.
|
|
157
|
+
|
|
158
|
+
| Argument | Type | Required | What it does |
|
|
159
|
+
| -------------------- | --------------------------- | -------- | ------------------------------------------- |
|
|
160
|
+
| `work_id` | string, 1 to 200 characters | yes | The identifier a row carries. |
|
|
161
|
+
| `include_depictions` | boolean, default `false` | no | Add the illustrations the record points to. |
|
|
162
|
+
|
|
163
|
+
**In return:** the work with `title`, `label`, `date` as published, `first_year`,
|
|
164
|
+
`creators` as `{ id, name }`, `languages`, `forms`, `subjects` and
|
|
165
|
+
`dewey_classes` in the words of the record, `expression_count`, `same_as` for the
|
|
166
|
+
registers the BnF aligns it with, and `catalogue_url`. `status` reads
|
|
167
|
+
`established` or `provisional`, and `status_statement` says what the library
|
|
168
|
+
means by it: a provisional record is one the library has not finished checking.
|
|
169
|
+
|
|
170
|
+
### `list_works`
|
|
171
|
+
|
|
172
|
+
Lists the works one person is credited with.
|
|
151
173
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
wherever you show what you got.
|
|
174
|
+
| Argument | Type | Required | What it does |
|
|
175
|
+
| ----------- | ------------------------------ | -------- | ------------------------ |
|
|
176
|
+
| `author_id` | string, 1 to 200 characters | yes | The person's identifier. |
|
|
177
|
+
| `limit` | integer, 1 to 50, default `10` | no | Rows to serve. |
|
|
178
|
+
| `page` | integer, 1 to 100, default `1` | no | Which page of rows. |
|
|
158
179
|
|
|
159
|
-
|
|
180
|
+
**In return:** `works`, each carrying `id`, `title`, `date` as published, `year`
|
|
181
|
+
as a number where the record has one, `forms`, `status` and `source_url`, with
|
|
182
|
+
`has_more` to continue.
|
|
160
183
|
|
|
161
|
-
|
|
162
|
-
SPARQL query is a more expensive request than fetching a page.
|
|
184
|
+
### `list_editions`
|
|
163
185
|
|
|
164
|
-
|
|
165
|
-
- At least three seconds between two of them. Configuration can widen that and
|
|
166
|
-
cannot narrow it, including through the published client entry point.
|
|
167
|
-
- The `User-Agent` always carries the project identifier and an address where a
|
|
168
|
-
person can be reached, whatever a caller sets.
|
|
169
|
-
- Answers are cached in memory for fifteen minutes, so a conversation that walks
|
|
170
|
-
back over one author does not ask twice.
|
|
186
|
+
Lists the editions of one work.
|
|
171
187
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
188
|
+
| Argument | Type | Required | What it does |
|
|
189
|
+
| --------- | ------------------------------ | -------- | ---------------------- |
|
|
190
|
+
| `work_id` | string, 1 to 200 characters | yes | The work's identifier. |
|
|
191
|
+
| `limit` | integer, 1 to 50, default `10` | no | Rows to serve. |
|
|
192
|
+
| `page` | integer, 1 to 100, default `1` | no | Which page of rows. |
|
|
175
193
|
|
|
176
|
-
|
|
194
|
+
**In return:** `editions`, each carrying its own `id` in the BnF catalogue, the
|
|
195
|
+
`title` this edition bears, `date` and `year`, `publisher`, `place`,
|
|
196
|
+
`edition_statement`, `extent`, `isbn`, `note` as the cataloguer wrote it,
|
|
197
|
+
`catalogue_url`, `digitised` and `source_url`. A field the record leaves empty is
|
|
198
|
+
`null`.
|
|
177
199
|
|
|
178
|
-
|
|
200
|
+
### `find_digitised`
|
|
179
201
|
|
|
180
|
-
|
|
181
|
-
| ----------------------- | -------- | --------------------------------------------------------------------------------------------------- |
|
|
182
|
-
| `BNF_USER_AGENT` | none | Identify your own client. The project identifier is appended, so the BnF can always reach a person. |
|
|
183
|
-
| `BNF_MIN_INTERVAL_MS` | `3000` | Milliseconds between requests. The floor is 3000 and cannot be lowered. |
|
|
184
|
-
| `BNF_TIMEOUT_MS` | `60000` | Deadline for one query. |
|
|
185
|
-
| `BNF_MAX_RETRIES` | `3` | Attempts after a busy answer. |
|
|
186
|
-
| `BNF_CACHE_TTL_MS` | `900000` | How long an answer is kept. `0` turns the cache off. |
|
|
187
|
-
| `BNF_CACHE_MAX_ENTRIES` | `200` | How many answers are kept. |
|
|
188
|
-
| `BNF_LOG_LEVEL` | `error` | `silent`, `error`, `info` or `debug`. Logs go to stderr. |
|
|
202
|
+
Finds the copies digitised in Gallica attached to a person or a work.
|
|
189
203
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
204
|
+
| Argument | Type | Required | What it does |
|
|
205
|
+
| -------- | ------------------------------------------ | -------- | ---------------------------------------- |
|
|
206
|
+
| `id` | string, 1 to 200 characters | yes | The identifier of a person or of a work. |
|
|
207
|
+
| `kind` | `auto`, `person` or `work`, default `auto` | no | What the identifier stands for. |
|
|
208
|
+
| `limit` | integer, 1 to 200, default `40` | no | Links to serve. |
|
|
209
|
+
|
|
210
|
+
**In return:** `kind`, saying what the catalogue types the record as, and `links`,
|
|
211
|
+
each carrying the Gallica `ark`, its `url`, its `rendering` and the `role` the
|
|
212
|
+
person holds on it. `links_returned_by_role` counts them per role. This server
|
|
213
|
+
describes a digitised document and never opens one.
|
|
214
|
+
|
|
215
|
+
## Established and provisional records
|
|
216
|
+
|
|
217
|
+
A record carries a `status`. `established` means the library has checked it;
|
|
218
|
+
`provisional` means it has not finished, and `status_statement` says so in the
|
|
219
|
+
library's own words. Report the status alongside anything taken from a
|
|
220
|
+
provisional record.
|
|
221
|
+
|
|
222
|
+
## The licence, and what it asks
|
|
223
|
+
|
|
224
|
+
The BnF states one condition on these metadata:
|
|
225
|
+
|
|
226
|
+
> L'utilisation de ces métadonnées est libre et gratuite sous réserve du maintien
|
|
227
|
+
> de la mention de leur source et de l'indication de leur date de récupération.
|
|
228
|
+
|
|
229
|
+
Use is free of charge, provided the source is named and the date of retrieval is
|
|
230
|
+
stated. Every answer carries `retrieved_at` in its payload and ends its text with
|
|
231
|
+
the source and that date. A cached answer reports the moment it was originally
|
|
232
|
+
read, since that is when it was retrieved. Repeat both wherever what you got is
|
|
233
|
+
shown.
|
|
234
|
+
|
|
235
|
+
## Configuration
|
|
236
|
+
|
|
237
|
+
Every variable is optional. Set them in the `env` block of your client config.
|
|
238
|
+
|
|
239
|
+
| Variable | Default | What it does |
|
|
240
|
+
| ----------------------- | -------------------- | --------------------------------------------------------------------------------- |
|
|
241
|
+
| `BNF_USER_AGENT` | the project identity | Names your application to the BnF, with an address where a person can be reached. |
|
|
242
|
+
| `BNF_MIN_INTERVAL_MS` | `3000` | Gap between two requests, from 3000 to 120000. |
|
|
243
|
+
| `BNF_TIMEOUT_MS` | `60000` | Deadline for one request, from 1000 to 300000. |
|
|
244
|
+
| `BNF_MAX_RETRIES` | `3` | Attempts after a transient failure, from 0 to 8. |
|
|
245
|
+
| `BNF_CACHE_TTL_MS` | `900000` | How long an answer stays in memory, from 0 to 86400000. |
|
|
246
|
+
| `BNF_CACHE_MAX_ENTRIES` | `200` | Answers held in memory at once, from 1 to 5000. |
|
|
247
|
+
| `BNF_LOG_LEVEL` | `error` | `silent`, `error`, `info` or `debug`, written to stderr. |
|
|
248
|
+
|
|
249
|
+
A value outside its range falls back to the default, and the reason is written to
|
|
250
|
+
stderr.
|
|
193
251
|
|
|
194
252
|
## Errors
|
|
195
253
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
| `not_found` | The endpoint answered, and the BnF describes no such record |
|
|
199
|
-
| `invalid_input` | The request was refused rather than answered |
|
|
200
|
-
| `rate_limited` | The endpoint asked this client to slow down |
|
|
201
|
-
| `parse_failure` | The answer arrived in a shape this client cannot read |
|
|
202
|
-
| `network_error` | The request did not complete |
|
|
203
|
-
| `timeout` | The query exceeded its deadline, or the endpoint gave it up |
|
|
254
|
+
Every failure carries one of six codes, a message, and where it helps a hint
|
|
255
|
+
naming the next move.
|
|
204
256
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
257
|
+
| Code | What happened | What to do |
|
|
258
|
+
| --------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
259
|
+
| `not_found` | The service answered, and holds no such record. | Check the identifier with `search_authors` or `search_works`. |
|
|
260
|
+
| `invalid_input` | The arguments were refused before any request went out. | Read the message, which names the argument. |
|
|
261
|
+
| `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. |
|
|
262
|
+
| `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). |
|
|
263
|
+
| `network_error` | The request did not complete. | Try again shortly. |
|
|
264
|
+
| `timeout` | The request passed its deadline. | Raise `BNF_TIMEOUT_MS`, or ask for fewer rows. |
|
|
209
265
|
|
|
210
|
-
##
|
|
266
|
+
## As a library
|
|
211
267
|
|
|
212
|
-
The
|
|
213
|
-
|
|
268
|
+
The layer reading the service is published on its own, with its pacing, its cache
|
|
269
|
+
and its errors, and with no protocol attached.
|
|
214
270
|
|
|
215
271
|
```ts
|
|
216
272
|
import { BnfClient } from "mcp-databnf/client";
|
|
217
273
|
|
|
218
274
|
const client = new BnfClient();
|
|
219
|
-
const { data,
|
|
220
|
-
|
|
221
|
-
console.log("retrieved", retrievedAt);
|
|
275
|
+
const { data, cached } = await client.getAuthor("cb11907966z");
|
|
276
|
+
console.log(data.label, cached);
|
|
222
277
|
```
|
|
223
278
|
|
|
279
|
+
`getAuthor` and `getWork` each answer `{ data, cached }`, and throw an error
|
|
280
|
+
carrying one of the six codes. The three-second floor between two requests holds
|
|
281
|
+
here as well.
|
|
282
|
+
|
|
283
|
+
## Pacing and attribution
|
|
284
|
+
|
|
285
|
+
Requests go out one at a time with at least three seconds between them, and that
|
|
286
|
+
floor holds however the server is configured. Each question is answered by a
|
|
287
|
+
SPARQL query against a public endpoint the BnF runs at its own expense, which is
|
|
288
|
+
why the interval is wide and the deadline long. The `User-Agent` always ends with
|
|
289
|
+
the project identity and an address where a person can be reached.
|
|
290
|
+
|
|
291
|
+
Every answer carries the source and `retrieved_at`, which the licence asks to be
|
|
292
|
+
stated wherever the metadata are shown.
|
|
293
|
+
|
|
294
|
+
This MCP server is an unofficial project, with no affiliation to the
|
|
295
|
+
Bibliothèque nationale de France.
|
|
296
|
+
|
|
297
|
+
## Privacy
|
|
298
|
+
|
|
299
|
+
This server collects nothing about you and sends nothing to its author. It runs
|
|
300
|
+
on your machine, contacts `data.bnf.fr` and nothing else, holds its answers in memory
|
|
301
|
+
while it runs, and writes nothing to disk.
|
|
302
|
+
[PRIVACY.md](PRIVACY.md) states what a request carries and which settings change
|
|
303
|
+
any of it.
|
|
304
|
+
|
|
224
305
|
## Development
|
|
225
306
|
|
|
226
307
|
```bash
|
|
227
308
|
npm install
|
|
228
|
-
npm
|
|
229
|
-
npm
|
|
230
|
-
npm run
|
|
231
|
-
BNF_LIVE=1 npm run test:live # one real query per route
|
|
309
|
+
npm run build:fixtures
|
|
310
|
+
npm test
|
|
311
|
+
npm run check
|
|
232
312
|
```
|
|
233
313
|
|
|
234
|
-
|
|
235
|
-
`
|
|
236
|
-
|
|
237
|
-
canary, and it is the only thing that would notice the day the catalogue changes
|
|
238
|
-
shape.
|
|
314
|
+
Tests run against generated fixtures and make no network request. The live suite,
|
|
315
|
+
`npm run test:live`, makes one request per route and runs nightly against the
|
|
316
|
+
service itself.
|
|
239
317
|
|
|
240
318
|
## Contributing
|
|
241
319
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
320
|
+
Bugs, questions and ideas belong in
|
|
321
|
+
[the issue tracker](https://github.com/smeet666/mcp-databnf/issues). Pull
|
|
322
|
+
requests are welcome; opening an issue first helps agree on the shape of the
|
|
323
|
+
change. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
246
324
|
|
|
247
|
-
|
|
325
|
+
## License
|
|
248
326
|
|
|
249
|
-
The metadata belong to the Bibliothèque nationale de
|
|
250
|
-
|
|
251
|
-
retrieval.
|
|
327
|
+
MIT, see [LICENSE](LICENSE). The metadata belong to the Bibliothèque nationale de
|
|
328
|
+
France, free to use provided the source and the date of retrieval are stated.
|
|
252
329
|
|
|
253
330
|
---
|
|
254
331
|
|
|
332
|
+
<a name="mcp-databnf-français"></a>
|
|
333
|
+
|
|
255
334
|
# mcp-databnf (français)
|
|
256
335
|
|
|
257
|
-
|
|
258
|
-
Bibliothèque nationale de France. Chercher un auteur, trouver une œuvre, lister
|
|
259
|
-
les éditions que la BnF en conserve, lister ce qu'une personne a écrit, et
|
|
260
|
-
rassembler les liens vers ce qui a été numérisé.
|
|
336
|
+
_[English version](#mcp-databnf)_
|
|
261
337
|
|
|
262
|
-
|
|
338
|
+
[data.bnf.fr](https://data.bnf.fr) est le service de données ouvertes de la
|
|
339
|
+
Bibliothèque nationale de France. Il publie les notices d'autorité que la
|
|
340
|
+
bibliothèque nationale entretient : les personnes qu'elle catalogue, avec leurs
|
|
341
|
+
dates, leurs lieux, leurs langues et leurs domaines d'activité ; les œuvres
|
|
342
|
+
qu'elles ont écrites, avec les éditions dans lesquelles chaque œuvre a paru ; et
|
|
343
|
+
les liens vers les exemplaires numérisés dans Gallica. Une notice indique si la
|
|
344
|
+
bibliothèque la tient pour établie ou encore provisoire.
|
|
263
345
|
|
|
264
|
-
|
|
346
|
+
Ce serveur relie un client de conversation à ce service. On peut y chercher un
|
|
347
|
+
auteur ou une œuvre par son nom, lire une notice en entier, lister ce qu'un
|
|
348
|
+
auteur a écrit, lister les éditions d'une œuvre, et trouver les exemplaires
|
|
349
|
+
numérisés attachés à l'un ou l'autre. Aucune clé d'API, aucun compte.
|
|
265
350
|
|
|
266
|
-
|
|
267
|
-
liées, et répond aux questions qu'on lui pose en SPARQL. Ce jeu de données sait
|
|
268
|
-
des choses qu'une recherche sur le web ignore : lequel de deux homonymes a écrit
|
|
269
|
-
tel livre, ce que la BnF a enregistré comme date et lieu de mort de quelqu'un,
|
|
270
|
-
quelles éditions d'une œuvre existent et qui les a imprimées, et lesquelles ont
|
|
271
|
-
été numérisées.
|
|
351
|
+
## Installation
|
|
272
352
|
|
|
273
|
-
|
|
274
|
-
catalogue répond sans y ajouter.
|
|
353
|
+
**Installation en un clic**
|
|
275
354
|
|
|
276
|
-
|
|
355
|
+
[](https://cursor.com/en/install-mcp?name=databnf&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1kYXRhYm5mIl19)
|
|
356
|
+
[](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)
|
|
357
|
+
|
|
358
|
+
**Claude Code**
|
|
277
359
|
|
|
278
360
|
```bash
|
|
279
|
-
npx mcp-databnf
|
|
361
|
+
claude mcp add databnf -- npx -y mcp-databnf
|
|
280
362
|
```
|
|
281
363
|
|
|
364
|
+
**Claude Desktop, Cursor, et tout client au format de configuration standard**
|
|
365
|
+
|
|
282
366
|
```json
|
|
283
367
|
{
|
|
284
368
|
"mcpServers": {
|
|
@@ -290,6 +374,9 @@ npx mcp-databnf
|
|
|
290
374
|
}
|
|
291
375
|
```
|
|
292
376
|
|
|
377
|
+
Node 24 ou plus récent est nécessaire, et aucune variable d'environnement n'est à
|
|
378
|
+
renseigner.
|
|
379
|
+
|
|
293
380
|
### Avec Docker
|
|
294
381
|
|
|
295
382
|
```json
|
|
@@ -297,137 +384,272 @@ npx mcp-databnf
|
|
|
297
384
|
"mcpServers": {
|
|
298
385
|
"databnf": {
|
|
299
386
|
"command": "docker",
|
|
300
|
-
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-databnf:2.
|
|
387
|
+
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-databnf:2.1.0"]
|
|
301
388
|
}
|
|
302
389
|
}
|
|
303
390
|
}
|
|
304
391
|
```
|
|
305
392
|
|
|
306
|
-
`-i` garde l'entrée standard ouverte, qui est le canal du protocole, et
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
`
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
**
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
393
|
+
`-i` garde l'entrée standard ouverte, qui est le canal du protocole, et `-t` est
|
|
394
|
+
omis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS
|
|
395
|
+
sortant vers `data.bnf.fr`, et de rien d'autre : aucun volume, aucun port, aucun
|
|
396
|
+
identifiant.
|
|
397
|
+
|
|
398
|
+
### Bundle, sans npm
|
|
399
|
+
|
|
400
|
+
Téléchargez `mcp-databnf-2.1.0.mcpb` depuis
|
|
401
|
+
[la dernière publication](https://github.com/smeet666/mcp-databnf/releases/latest)
|
|
402
|
+
et ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm et
|
|
403
|
+
sans fichier de configuration à modifier. Le bundle emporte ses dépendances, donc
|
|
404
|
+
rien n'est téléchargé à l'installation.
|
|
405
|
+
|
|
406
|
+
## Ce qu'on peut demander
|
|
407
|
+
|
|
408
|
+
- « Que dit la BnF de Colette ? »
|
|
409
|
+
- « Liste tout ce qu'a écrit Marguerite Duras. »
|
|
410
|
+
- « Quelles éditions de cette œuvre la bibliothèque conserve-t-elle ? »
|
|
411
|
+
- « Y en a-t-il de numérisées dans Gallica ? »
|
|
412
|
+
- « Cette notice est-elle établie ou provisoire ? »
|
|
413
|
+
|
|
414
|
+
Le chemin ordinaire va d'une recherche à une notice : une ligne porte un `id`, et
|
|
415
|
+
`get_author` ou `get_work` la lit.
|
|
416
|
+
|
|
417
|
+
## Les outils
|
|
418
|
+
|
|
419
|
+
| Outil | Ce qu'il fait |
|
|
420
|
+
| ---------------- | ---------------------------------------------------------------------------- |
|
|
421
|
+
| `search_authors` | Trouve des personnes par leur nom dans les notices d'autorité. |
|
|
422
|
+
| `get_author` | Lit la notice d'une personne en entier. |
|
|
423
|
+
| `search_works` | Trouve des œuvres par leur titre. |
|
|
424
|
+
| `get_work` | Lit la notice d'une œuvre en entier. |
|
|
425
|
+
| `list_works` | Liste les œuvres attribuées à une personne. |
|
|
426
|
+
| `list_editions` | Liste les éditions d'une œuvre. |
|
|
427
|
+
| `find_digitised` | Trouve les exemplaires numérisés dans Gallica d'une personne ou d'une œuvre. |
|
|
428
|
+
|
|
429
|
+
### `search_authors`
|
|
430
|
+
|
|
431
|
+
Trouve des personnes par leur nom dans les notices d'autorité.
|
|
432
|
+
|
|
433
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
434
|
+
| -------- | --------------------------- | ------ | ---------------------- |
|
|
435
|
+
| `name` | chaîne, 1 à 200 caractères | oui | Le nom cherché. |
|
|
436
|
+
| `limit` | entier, 1 à 50, défaut `10` | non | Lignes à servir. |
|
|
437
|
+
| `page` | entier, 1 à 100, défaut `1` | non | Quelle page de lignes. |
|
|
438
|
+
|
|
439
|
+
**En retour :** `authors`, chacun portant `id`, que `get_author`, `list_works` et
|
|
440
|
+
`find_digitised` reprennent ; `name` tel que le service l'écrit ; `label`, la
|
|
441
|
+
vedette d'autorité, généralement avec les dates ; `birth_year` et `death_year`,
|
|
442
|
+
`null` là où la notice n'en indique pas ; `role` ; et `source_url`.
|
|
443
|
+
`words_searched` dit ce qui a réellement été envoyé, `has_more` s'il existe
|
|
444
|
+
d'autres pages, et `index_window_full` que l'index a servi tout ce qu'il servira
|
|
445
|
+
pour cette recherche.
|
|
446
|
+
|
|
447
|
+
### `get_author`
|
|
448
|
+
|
|
449
|
+
Lit la notice d'une personne en entier.
|
|
450
|
+
|
|
451
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
452
|
+
| -------------------- | -------------------------- | ------ | ---------------------------------------------------- |
|
|
453
|
+
| `author_id` | chaîne, 1 à 200 caractères | oui | L'identifiant que porte une ligne. |
|
|
454
|
+
| `include_depictions` | booléen, défaut `false` | non | Ajoute les portraits vers lesquels la notice pointe. |
|
|
455
|
+
|
|
456
|
+
**En retour :** la personne avec `name`, `label`, `given_name`, `family_name`,
|
|
457
|
+
`other_names`, `birth_date` et `death_date` tels que publiés, `birth_year` et
|
|
458
|
+
`death_year` en nombres, `birth_place`, `death_place`,
|
|
459
|
+
`biographical_information`, `occupation`, `languages` en codes ISO 639-2,
|
|
460
|
+
`countries` et `fields` dans les mots de la notice. Un champ que la notice laisse
|
|
461
|
+
vide vaut `null`.
|
|
462
|
+
|
|
463
|
+
### `search_works`
|
|
464
|
+
|
|
465
|
+
Trouve des œuvres par leur titre.
|
|
466
|
+
|
|
467
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
468
|
+
| -------- | --------------------------- | ------ | -------------------------- |
|
|
469
|
+
| `title` | chaîne, 1 à 200 caractères | oui | Les mots du titre cherché. |
|
|
470
|
+
| `limit` | entier, 1 à 50, défaut `10` | non | Lignes à servir. |
|
|
471
|
+
| `page` | entier, 1 à 100, défaut `1` | non | Quelle page de lignes. |
|
|
472
|
+
|
|
473
|
+
**En retour :** `works`, chacune portant `id`, que `get_work`, `list_editions` et
|
|
474
|
+
`find_digitised` reprennent ; `title` ; `date`, l'année que la notice donne à
|
|
475
|
+
l'œuvre, telle que publiée ; `creators` ; `status`, valant `established` ou
|
|
476
|
+
`provisional` ; et `source_url`. L'enveloppe porte les mêmes `words_searched`,
|
|
477
|
+
`has_more` et `index_window_full` qu'une recherche de personnes.
|
|
478
|
+
|
|
479
|
+
### `get_work`
|
|
480
|
+
|
|
481
|
+
Lit la notice d'une œuvre en entier.
|
|
482
|
+
|
|
483
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
484
|
+
| -------------------- | -------------------------- | ------ | ---------------------------------------------------------- |
|
|
485
|
+
| `work_id` | chaîne, 1 à 200 caractères | oui | L'identifiant que porte une ligne. |
|
|
486
|
+
| `include_depictions` | booléen, défaut `false` | non | Ajoute les illustrations vers lesquelles la notice pointe. |
|
|
487
|
+
|
|
488
|
+
**En retour :** l'œuvre avec `title`, `label`, `date` telle que publiée,
|
|
489
|
+
`first_year`, `creators` en `{ id, name }`, `languages`, `forms`, `subjects` et
|
|
490
|
+
`dewey_classes` dans les mots de la notice, `expression_count`, `same_as` pour
|
|
491
|
+
les registres auxquels la BnF l'aligne, et `catalogue_url`. `status` vaut
|
|
492
|
+
`established` ou `provisional`, et `status_statement` dit ce que la bibliothèque
|
|
493
|
+
entend par là : une notice provisoire est une notice qu'elle n'a pas fini de
|
|
494
|
+
vérifier.
|
|
495
|
+
|
|
496
|
+
### `list_works`
|
|
497
|
+
|
|
498
|
+
Liste les œuvres attribuées à une personne.
|
|
499
|
+
|
|
500
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
501
|
+
| ----------- | --------------------------- | ------ | ----------------------------- |
|
|
502
|
+
| `author_id` | chaîne, 1 à 200 caractères | oui | L'identifiant de la personne. |
|
|
503
|
+
| `limit` | entier, 1 à 50, défaut `10` | non | Lignes à servir. |
|
|
504
|
+
| `page` | entier, 1 à 100, défaut `1` | non | Quelle page de lignes. |
|
|
505
|
+
|
|
506
|
+
**En retour :** `works`, chacune portant `id`, `title`, `date` telle que publiée,
|
|
507
|
+
`year` en nombre quand la notice en a un, `forms`, `status` et `source_url`, avec
|
|
508
|
+
`has_more` pour poursuivre.
|
|
509
|
+
|
|
510
|
+
### `list_editions`
|
|
511
|
+
|
|
512
|
+
Liste les éditions d'une œuvre.
|
|
513
|
+
|
|
514
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
515
|
+
| --------- | --------------------------- | ------ | ------------------------- |
|
|
516
|
+
| `work_id` | chaîne, 1 à 200 caractères | oui | L'identifiant de l'œuvre. |
|
|
517
|
+
| `limit` | entier, 1 à 50, défaut `10` | non | Lignes à servir. |
|
|
518
|
+
| `page` | entier, 1 à 100, défaut `1` | non | Quelle page de lignes. |
|
|
519
|
+
|
|
520
|
+
**En retour :** `editions`, chacune portant son propre `id` au catalogue de la
|
|
521
|
+
BnF, le `title` que cette édition porte, `date` et `year`, `publisher`, `place`,
|
|
522
|
+
`edition_statement`, `extent`, `isbn`, `note` telle que le catalogueur l'a
|
|
523
|
+
écrite, `catalogue_url`, `digitised` et `source_url`. Un champ que la notice
|
|
524
|
+
laisse vide vaut `null`.
|
|
525
|
+
|
|
526
|
+
### `find_digitised`
|
|
527
|
+
|
|
528
|
+
Trouve les exemplaires numérisés dans Gallica attachés à une personne ou à une
|
|
529
|
+
œuvre.
|
|
530
|
+
|
|
531
|
+
| Argument | Type | Requis | Ce qu'il fait |
|
|
532
|
+
| -------- | ----------------------------------------- | ------ | -------------------------------------------- |
|
|
533
|
+
| `id` | chaîne, 1 à 200 caractères | oui | L'identifiant d'une personne ou d'une œuvre. |
|
|
534
|
+
| `kind` | `auto`, `person` ou `work`, défaut `auto` | non | Ce que l'identifiant désigne. |
|
|
535
|
+
| `limit` | entier, 1 à 200, défaut `40` | non | Liens à servir. |
|
|
536
|
+
|
|
537
|
+
**En retour :** `kind`, qui dit de quel type le catalogue tient la notice, et
|
|
538
|
+
`links`, chacun portant l'`ark` Gallica, son `url`, son `rendering` et le `role`
|
|
539
|
+
que la personne y tient. `links_returned_by_role` les compte par rôle. Ce serveur
|
|
540
|
+
décrit un document numérisé et n'en ouvre jamais aucun.
|
|
541
|
+
|
|
542
|
+
## Notices établies et provisoires
|
|
543
|
+
|
|
544
|
+
Une notice porte un `status`. `established` signifie que la bibliothèque l'a
|
|
545
|
+
vérifiée ; `provisional` qu'elle ne l'a pas terminée, et `status_statement` le
|
|
546
|
+
dit dans ses propres mots. Rapportez ce statut à côté de tout ce qui vient d'une
|
|
547
|
+
notice provisoire.
|
|
548
|
+
|
|
549
|
+
## La licence, et ce qu'elle demande
|
|
550
|
+
|
|
551
|
+
La BnF pose une condition sur ces métadonnées :
|
|
391
552
|
|
|
392
553
|
> L'utilisation de ces métadonnées est libre et gratuite sous réserve du maintien
|
|
393
554
|
> de la mention de leur source et de l'indication de leur date de récupération.
|
|
394
555
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
556
|
+
Chaque réponse porte `retrieved_at` dans sa charge utile et termine son texte par
|
|
557
|
+
la source et cette date. Une réponse servie depuis le cache rapporte le moment où
|
|
558
|
+
elle a été lue à l'origine, puisque c'est sa date de récupération. Redonnez les
|
|
559
|
+
deux partout où ce que vous avez obtenu est montré.
|
|
399
560
|
|
|
400
|
-
##
|
|
561
|
+
## Configuration
|
|
401
562
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
réduire, y compris par le point d'entrée `client` publié. Le `User-Agent` porte
|
|
405
|
-
toujours l'identifiant du projet et une adresse où joindre une personne. Les
|
|
406
|
-
réponses sont gardées quinze minutes en mémoire.
|
|
563
|
+
Chaque variable est facultative. Elles se posent dans le bloc `env` de la
|
|
564
|
+
configuration du client.
|
|
407
565
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
566
|
+
| Variable | Défaut | Ce qu'elle fait |
|
|
567
|
+
| ----------------------- | -------------------- | ----------------------------------------------------------------------------------- |
|
|
568
|
+
| `BNF_USER_AGENT` | l'identité du projet | Nomme votre application auprès de la BnF, avec une adresse où joindre une personne. |
|
|
569
|
+
| `BNF_MIN_INTERVAL_MS` | `3000` | Écart entre deux requêtes, de 3000 à 120000. |
|
|
570
|
+
| `BNF_TIMEOUT_MS` | `60000` | Délai d'une requête, de 1000 à 300000. |
|
|
571
|
+
| `BNF_MAX_RETRIES` | `3` | Tentatives après un échec passager, de 0 à 8. |
|
|
572
|
+
| `BNF_CACHE_TTL_MS` | `900000` | Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000. |
|
|
573
|
+
| `BNF_CACHE_MAX_ENTRIES` | `200` | Réponses gardées en mémoire à la fois, de 1 à 5000. |
|
|
574
|
+
| `BNF_LOG_LEVEL` | `error` | `silent`, `error`, `info` ou `debug`, écrit sur la sortie d'erreur. |
|
|
411
575
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
Tous facultatifs : `BNF_USER_AGENT`, `BNF_MIN_INTERVAL_MS` (3000, plancher
|
|
415
|
-
infranchissable), `BNF_TIMEOUT_MS` (60000), `BNF_MAX_RETRIES` (3),
|
|
416
|
-
`BNF_CACHE_TTL_MS` (900000), `BNF_CACHE_MAX_ENTRIES` (200), `BNF_LOG_LEVEL`
|
|
417
|
-
(`error`). Une valeur illisible est refusée, signalée sur stderr, et la valeur
|
|
418
|
-
par défaut s'applique.
|
|
576
|
+
Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la
|
|
577
|
+
sortie d'erreur.
|
|
419
578
|
|
|
420
579
|
## Erreurs
|
|
421
580
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
581
|
+
Chaque échec porte un des six codes, un message, et quand cela aide une
|
|
582
|
+
indication du geste suivant.
|
|
583
|
+
|
|
584
|
+
| Code | Ce qui s'est passé | Que faire |
|
|
585
|
+
| --------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
586
|
+
| `not_found` | Le service a répondu, et n'a pas cette notice. | Vérifiez l'identifiant avec `search_authors` ou `search_works`. |
|
|
587
|
+
| `invalid_input` | Les arguments ont été refusés avant toute requête. | Lisez le message, qui nomme l'argument. |
|
|
588
|
+
| `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à. |
|
|
589
|
+
| `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). |
|
|
590
|
+
| `network_error` | La requête n'a pas abouti. | Réessayez sous peu. |
|
|
591
|
+
| `timeout` | La requête a dépassé son délai. | Augmentez `BNF_TIMEOUT_MS`, ou demandez moins de lignes. |
|
|
592
|
+
|
|
593
|
+
## Comme bibliothèque
|
|
594
|
+
|
|
595
|
+
La couche qui lit le service est publiée seule, avec son rythme, son cache et ses
|
|
596
|
+
erreurs, sans protocole attaché.
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
import { BnfClient } from "mcp-databnf/client";
|
|
600
|
+
|
|
601
|
+
const client = new BnfClient();
|
|
602
|
+
const { data, cached } = await client.getAuthor("cb11907966z");
|
|
603
|
+
console.log(data.label, cached);
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
`getAuthor` et `getWork` répondent chacun `{ data, cached }`, et lèvent une
|
|
607
|
+
erreur portant un des six codes. Le plancher de trois secondes entre deux
|
|
608
|
+
requêtes tient également ici.
|
|
609
|
+
|
|
610
|
+
## Rythme et attribution
|
|
611
|
+
|
|
612
|
+
Les requêtes partent une à une avec au moins trois secondes entre elles, et ce
|
|
613
|
+
plancher tient quelle que soit la configuration. Chaque question se résout par
|
|
614
|
+
une requête SPARQL contre un point d'accès public que la BnF fait tourner à ses
|
|
615
|
+
frais, d'où un intervalle large et un délai long. Le `User-Agent` se termine
|
|
616
|
+
toujours par l'identité du projet et une adresse où joindre une personne.
|
|
617
|
+
|
|
618
|
+
Chaque réponse porte la source et `retrieved_at`, que la licence demande
|
|
619
|
+
d'indiquer partout où les métadonnées sont montrées.
|
|
620
|
+
|
|
621
|
+
Ce MCP est un projet non officiel, sans affiliation à la Bibliothèque nationale
|
|
622
|
+
de France.
|
|
623
|
+
|
|
624
|
+
## Confidentialité
|
|
625
|
+
|
|
626
|
+
Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur
|
|
627
|
+
votre machine, ne joint que `data.bnf.fr`, garde ses réponses en mémoire le temps qu'il
|
|
628
|
+
tourne, et n'écrit rien sur le disque. [PRIVACY.md](PRIVACY.md) dit ce qu'une
|
|
629
|
+
requête emporte et quels réglages changent cela.
|
|
630
|
+
|
|
631
|
+
## Développement
|
|
632
|
+
|
|
633
|
+
```bash
|
|
634
|
+
npm install
|
|
635
|
+
npm run build:fixtures
|
|
636
|
+
npm test
|
|
637
|
+
npm run check
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
Les tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête.
|
|
641
|
+
La suite en direct, `npm run test:live`, émet une requête par route et tourne
|
|
642
|
+
chaque nuit contre le service lui-même.
|
|
643
|
+
|
|
644
|
+
## Contribuer
|
|
645
|
+
|
|
646
|
+
Les anomalies, les questions et les idées ont leur place dans
|
|
647
|
+
[le suivi d'incidents](https://github.com/smeet666/mcp-databnf/issues). Les
|
|
648
|
+
propositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à
|
|
649
|
+
s'accorder sur la forme du changement. Voir [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
428
650
|
|
|
429
651
|
## Licence
|
|
430
652
|
|
|
431
|
-
MIT
|
|
432
|
-
France
|
|
433
|
-
|
|
653
|
+
MIT, voir [LICENSE](LICENSE). Les métadonnées appartiennent à la Bibliothèque
|
|
654
|
+
nationale de France, d'usage libre sous réserve d'indiquer la source et la date
|
|
655
|
+
de récupération.
|