mcp-databnf 1.0.0 → 1.0.1
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 +17 -0
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/dist/bnf/client.d.ts +0 -0
- package/dist/bnf/client.js +1 -1
- package/dist/bnf/client.js.map +1 -1
- package/dist/index.d.ts +0 -0
- package/dist/index.js +61 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
|
|
9
9
|
// src/version.ts
|
|
10
|
-
var PKG_VERSION = "1.0.
|
|
10
|
+
var PKG_VERSION = "1.0.1";
|
|
11
11
|
var REPO_URL = "https://github.com/smeet666/mcp-databnf";
|
|
12
12
|
|
|
13
13
|
// src/config.ts
|
|
@@ -1395,6 +1395,14 @@ function truncate(text2, maxChars) {
|
|
|
1395
1395
|
return `${text2.slice(0, Math.max(0, maxChars - 1)).trimEnd()}\u2026`;
|
|
1396
1396
|
}
|
|
1397
1397
|
var NO_RANKING = "The full-text index answers whether a record matches, and it does not score how well. These rows are in the order the index returned them, so the row a person would call the obvious answer can sit anywhere in the list, or on a later page.";
|
|
1398
|
+
async function classifyEmptyPage(page2, firstPageHasRow) {
|
|
1399
|
+
if (page2 === 1) return "absent";
|
|
1400
|
+
try {
|
|
1401
|
+
return await firstPageHasRow() ? "past_the_end" : "absent";
|
|
1402
|
+
} catch {
|
|
1403
|
+
return "undetermined";
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1398
1406
|
var GALLICA_CAVEAT = "These are links for a person to open. This server reads the BnF catalogue and never requests gallica.bnf.fr, so it cannot say whether a document opens, what it contains, or on what terms it may be reused.";
|
|
1399
1407
|
var PROVISIONAL_CAVEAT = "A provisional record is one the BnF created to hold a title it has catalogued and not yet established as a work of its own. Its identifier can change, and it can be merged into an established record.";
|
|
1400
1408
|
|
|
@@ -1946,6 +1954,25 @@ function lifespan(birthYear, deathYear) {
|
|
|
1946
1954
|
if (deathYear !== null) return ` (died ${deathYear})`;
|
|
1947
1955
|
return "";
|
|
1948
1956
|
}
|
|
1957
|
+
function emptyPageNote(emptiness, page2, words) {
|
|
1958
|
+
const quoted = words.map((word) => `"${word}"`).join(", ");
|
|
1959
|
+
if (emptiness === "past_the_end") {
|
|
1960
|
+
return `Page ${page2} holds no row because it sits past the last row of this search. Records do carry ${quoted} in a name, and they are on earlier pages: call again with page=1, or with a lower page number, to read them.`;
|
|
1961
|
+
}
|
|
1962
|
+
if (emptiness === "undetermined") {
|
|
1963
|
+
return `Page ${page2} holds no row, and reading the first page of the same search to find out why did not answer. This is either a name carrying ${quoted} matching no record, or a page sitting past the last row of a search that does match. Call again with page=1: rows there mean the second.`;
|
|
1964
|
+
}
|
|
1965
|
+
return `No record in the BnF authority file carries every one of these words in a name: ${quoted}. A search here reads names, so a person known by a pen name is found under that name rather than their own.`;
|
|
1966
|
+
}
|
|
1967
|
+
function emptyPageBody(emptiness, page2, name) {
|
|
1968
|
+
if (emptiness === "past_the_end") {
|
|
1969
|
+
return `Page ${page2} of the search for "${name}" holds no row: it sits past the last row. Call again with page=1.`;
|
|
1970
|
+
}
|
|
1971
|
+
if (emptiness === "undetermined") {
|
|
1972
|
+
return `Page ${page2} of the search for "${name}" holds no row, and whether the rows stop before it could not be read. Call again with page=1.`;
|
|
1973
|
+
}
|
|
1974
|
+
return `No person in the BnF authority file matches "${name}".`;
|
|
1975
|
+
}
|
|
1949
1976
|
async function runSearchAuthors(client, args) {
|
|
1950
1977
|
try {
|
|
1951
1978
|
const words = client.words(args.name);
|
|
@@ -1995,17 +2022,20 @@ async function runSearchAuthors(client, args) {
|
|
|
1995
2022
|
`More matches exist beyond this page. Ask for page ${args.page + 1}, or narrow the name. This server reports no total, because counting every match means asking the endpoint to walk the whole index a second time.`
|
|
1996
2023
|
);
|
|
1997
2024
|
}
|
|
2025
|
+
let emptiness = "absent";
|
|
1998
2026
|
if (authors.length === 0) {
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2027
|
+
emptiness = await classifyEmptyPage(args.page, async () => {
|
|
2028
|
+
const first = await client.searchAuthors(args.name, 1, 0);
|
|
2029
|
+
return first.data.rows.length > 0;
|
|
2030
|
+
});
|
|
2031
|
+
notes.push(emptyPageNote(emptiness, args.page, words));
|
|
2002
2032
|
}
|
|
2003
2033
|
if (words.length < args.name.trim().split(/\s+/).length) {
|
|
2004
2034
|
notes.push(
|
|
2005
2035
|
`The index was asked for ${words.map((word) => `"${word}"`).join(", ")}; anything in the name that was not a word was set aside.`
|
|
2006
2036
|
);
|
|
2007
2037
|
}
|
|
2008
|
-
const body = authors.length === 0 ?
|
|
2038
|
+
const body = authors.length === 0 ? emptyPageBody(emptiness, args.page, args.name) : `${authors.length} record(s) for "${args.name}":
|
|
2009
2039
|
${authors.map((author, index) => {
|
|
2010
2040
|
const life = lifespan(author.birth_year, author.death_year);
|
|
2011
2041
|
const role = author.role ? ` \xB7 ${author.role}` : "";
|
|
@@ -2063,6 +2093,25 @@ var searchWorksOutput = z8.object({
|
|
|
2063
2093
|
retrieved_at: retrievedAtSchema,
|
|
2064
2094
|
notes: z8.array(z8.string())
|
|
2065
2095
|
});
|
|
2096
|
+
function emptyPageNote2(emptiness, page2, words) {
|
|
2097
|
+
const quoted = words.map((word) => `"${word}"`).join(", ");
|
|
2098
|
+
if (emptiness === "past_the_end") {
|
|
2099
|
+
return `Page ${page2} holds no row because it sits past the last row of this search. Works do carry ${quoted} in their title, and they are on earlier pages: call again with page=1, or with a lower page number, to read them.`;
|
|
2100
|
+
}
|
|
2101
|
+
if (emptiness === "undetermined") {
|
|
2102
|
+
return `Page ${page2} holds no row, and reading the first page of the same search to find out why did not answer. This is either a title carrying ${quoted} matching no record, or a page sitting past the last row of a search that does match. Call again with page=1: rows there mean the second.`;
|
|
2103
|
+
}
|
|
2104
|
+
return `No work in the BnF catalogue has a title carrying every one of these words: ${quoted}. Every word given has to appear, so dropping one widens the search.`;
|
|
2105
|
+
}
|
|
2106
|
+
function emptyPageBody2(emptiness, page2, title) {
|
|
2107
|
+
if (emptiness === "past_the_end") {
|
|
2108
|
+
return `Page ${page2} of the search for "${title}" holds no row: it sits past the last row. Call again with page=1.`;
|
|
2109
|
+
}
|
|
2110
|
+
if (emptiness === "undetermined") {
|
|
2111
|
+
return `Page ${page2} of the search for "${title}" holds no row, and whether the rows stop before it could not be read. Call again with page=1.`;
|
|
2112
|
+
}
|
|
2113
|
+
return `No work in the BnF catalogue matches "${title}".`;
|
|
2114
|
+
}
|
|
2066
2115
|
async function runSearchWorks(client, args) {
|
|
2067
2116
|
try {
|
|
2068
2117
|
const words = client.words(args.title);
|
|
@@ -2111,12 +2160,15 @@ async function runSearchWorks(client, args) {
|
|
|
2111
2160
|
`More matches exist beyond this page. Ask for page ${args.page + 1}, or add a word to the title. This server reports no total: a count would read as a measure of the search, and this search has none.`
|
|
2112
2161
|
);
|
|
2113
2162
|
}
|
|
2163
|
+
let emptiness = "absent";
|
|
2114
2164
|
if (works.length === 0) {
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2165
|
+
emptiness = await classifyEmptyPage(args.page, async () => {
|
|
2166
|
+
const first = await client.searchWorks(args.title, 1, 0);
|
|
2167
|
+
return first.data.rows.length > 0;
|
|
2168
|
+
});
|
|
2169
|
+
notes.push(emptyPageNote2(emptiness, args.page, words));
|
|
2118
2170
|
}
|
|
2119
|
-
const body = works.length === 0 ?
|
|
2171
|
+
const body = works.length === 0 ? emptyPageBody2(emptiness, args.page, args.title) : `${works.length} work(s) whose title carries ${words.map((word) => `"${word}"`).join(" and ")}:
|
|
2120
2172
|
${works.map((work, index) => {
|
|
2121
2173
|
const by = work.creators.length > 0 ? ` \xB7 ${work.creators.map((creator) => creator.name ?? creator.id).join(", ")}` : "";
|
|
2122
2174
|
const when = work.date ? ` (${work.date})` : "";
|