mcp-libraryofcongress
This server offers read-only access to the Library of Congress digital collections without an API key.
Search scanned newspaper pages: Find phrases in OCR text of digitised American newspapers, filterable by location, publication, and date range. Returns match details and direct links to scanned pages.
Search the catalogue: Query items by media type (books, photos, maps, audio, films, manuscripts, notated-music, newspapers) with filters for subject, location, language, collection, year, and online availability. Returns item details and links.
Retrieve records: Get full metadata, citations, resources, and paginated descriptions for a specific item using its identifier (including newspaper identifiers).
List digital collections: Browse curated collections with descriptions, item counts, and filter codes to use in catalogue searches.
All operations are read-only, respect rate limits through pacing, and employ caching for repeated queries.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-libraryofcongressSearch newspapers for 'Lincoln assassination' in 1865."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-libraryofcongress
The Library of Congress is the national library of the United States, and it publishes a large part of its holdings online: books, photographs, maps, sound recordings, manuscripts, and the pages of American newspapers going back to the eighteenth century. The newspaper pages have been scanned and run through optical character recognition, so the words printed on them can be searched. Curators also gather material into digital collections, each described and published as a body of its own.
This server connects a chat client to that library. You can search the words printed inside the newspapers, search the catalogue by title, creator, subject, place or language, read one record with its rights statement and where the original is held, and list the digital collections. It needs no API key and no account.
Install
One-click install
Claude Code
claude mcp add libraryofcongress -- npx -y mcp-libraryofcongressClaude Desktop, Cursor, and any client using the standard config format
{
"mcpServers": {
"libraryofcongress": {
"command": "npx",
"args": ["-y", "mcp-libraryofcongress"]
}
}
}Node 24 or later is required, and no environment variable has to be set.
With Docker
{
"mcpServers": {
"libraryofcongress": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-libraryofcongress:3.0.1"]
}
}
}-i keeps stdin open, which is where the protocol travels, and -t is left out
because a TTY rewrites the stream. The container needs outbound HTTPS to
www.loc.gov and chroniclingamerica.loc.gov, and nothing else: no volume, no
port, no credential.
Bundle, without npm
Download mcp-libraryofcongress-3.0.1.mcpb from
the latest release
and open it. A client that supports MCP bundles installs it on its own, with no
npm and no configuration file to edit. The bundle carries its dependencies, so
nothing is fetched at install time.
Related MCP server: ANNO MCP Server
What you can ask
"What did Oklahoma newspapers write about the 1907 statehood vote?"
"Find me photographs of Chicago tenements before 1920."
"Read that record and tell me who holds the original."
"What digital collections are there on the Civil War?"
"Can I reuse that photograph?"
The ordinary path runs from a search to a record: a row carries an identifier,
and get_item reads it.
Tools
Tool | What it does |
| Searches the words printed inside scanned newspaper pages. |
| Searches the catalogue by title, creator, subject, place or language. |
| Reads one record, its rights and where the original is held. |
| Lists the digital collections curators published. |
search_newspapers
Searches the text of scanned newspaper pages, which came off the page through optical character recognition.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The words to look for on the pages. |
| string, up to 120 characters | no | A place the paper was published in. |
| string, up to 200 characters | no | One newspaper. |
| integer, 1000 to 9999 | no | Earliest year, inclusive. |
| integer, 1000 to 9999 | no | Latest year, inclusive. |
| integer, 1 to 25, default | no | Matches to serve. |
| integer, 1 to 100, default | no | Which page of matches. |
| integer, 80 to 1200, default | no | How much of a passage to serve. |
| integer, 1 to 10, default | no | Passages served per matching page. |
In return: hits, each carrying identifier, which get_item takes;
title; creator, which is the library that contributed the scan; year;
page_number, the leaf within the issue; published_on; publication with the
years the paper ran; state; excerpts; and excerpt_kind.
excerpt_kind decides what an excerpt is worth. A passage is the text
around the words that matched, centred on them. A page_opening is the start of
the leaf, sent because the text the Library returned with the row stops before
those words appear: it does not carry the match, so quoting it quotes something
else, and source_url opens the leaf with the query applied. total counts
newspaper leaves, and it pages: it is never a count of how many times the words
occur.
search_items
Searches the catalogue, one kind of thing at a time.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | Words to look for. |
|
| no | The catalogue to read. |
| integer, 1000 to 9999 | no | Earliest year, inclusive. |
| integer, 1000 to 9999 | no | Latest year, inclusive. |
| string, up to 120 characters | no | A subject heading. |
| string, up to 120 characters | no | A place. |
| string, up to 120 characters | no | A language, written in English. |
| string, up to 160 characters | no | One collection, as |
| boolean, default | no | Keep the records available online. |
|
| no | How the rows are ordered. |
| integer, 1 to 50, default | no | Rows to serve. |
| integer, 1 to 100, default | no | Which page of rows. |
In return: items, each carrying identifier, title, creator, year,
date as published, which is often a range, is_collection and source_url.
The Library keeps one catalogue per kind of thing, so a search without
media_type reads the general one, and total counts the records matching
there.
get_item
Reads one record. The heavier parts are asked for rather than served by default, and a long description paginates.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The identifier a row carries. |
| array of | no | Which parts to return. |
| integer, 0 or more, default | no | Where to resume the description. |
| integer, 200 to 20000, default | no | How much of the description to serve. |
In return: the record with its title, creator, year, date, format
and source_url, plus description, subjects, location, language,
part_of for the collections and divisions it sits in, repository naming where
the original is held, call_number and rights. A field the record leaves empty
is null. next_offset continues a long description and is null at the end.
An identifier can carry slashes: a single newspaper issue is named by its paper,
its date and its edition together.
list_collections
Lists the digital collections, bodies of material a curator chose, described and published together.
Argument | Type | Required | What it does |
| integer, 1 to 50, default | no | Collections to serve. |
| integer, 1 to 100, default | no | Which page of collections. |
| boolean, default | no | Keep the collections a search can be narrowed to. |
| integer, 80 to 2000, default | no | How much of each description to serve. |
In return: collections, each carrying identifier, the slug it is
addressed by; title; collection_filter, the wording search_items takes;
searchable_media_types; description; item_count; subjects; formats for
the kinds of thing it holds; and source_url. total counts the collections the
Library publishes, which is more than the number returned.
What scanned text is worth
The words inside a newspaper page came off the page through optical character recognition, so an excerpt carries the misreadings of that process. It is served as it was read rather than corrected. Quote it as scanned text, and link the page so a reader can look at the leaf itself.
Rights
A record states its own rights in rights, and the Library's terms differ from
one deposit to the next. Read that statement before reusing anything, and repeat
it beside whatever is shown.
Configuration
Every variable is optional. Set them in the env block of your client config.
Variable | Default | What it does |
| the project identity | Names your application to the Library, with an address where a person can be reached. |
|
| Gap between two requests, from 3000 to 60000. |
|
| Deadline for one request, from 1000 to 120000. |
|
| Deadline for a newspaper search, from 1000 to 300000. |
|
| Attempts after a transient failure, from 0 to 8. |
|
| How long an answer stays in memory, from 0 to 86400000. |
|
| Answers held in memory at once, from 1 to 5000. |
|
|
|
A value outside its range falls back to the default, and the reason is written to stderr.
Errors
Every failure carries one of six codes, a message, and where it helps a hint naming the next move.
Code | What happened | What to do |
| The Library answered, and holds no such record. | Check the identifier with |
| The arguments were refused before any request went out. | Read the message, which names the argument. |
| The Library 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. |
| The answer arrived in a shape this client cannot read. | Report it at the issue tracker. |
| The request did not complete. | Try again shortly. |
| The request passed its deadline. | Raise |
As a library
The layer reading the Library is published on its own, with its pacing, its cache and its errors, and with no protocol attached.
import { LocClient } from "mcp-libraryofcongress/client";
const client = new LocClient();
const { data, cached } = await client.searchItems({ query: "tenement", mediaType: "photos" });
console.log(data.total, cached);Each read answers { data, cached }, and throws an error carrying one of the six
codes. The floor between two requests holds here as well.
Pacing and attribution
The Library publishes a limit of 20 requests a minute for its API and 10 for the
site as a whole, and the lower of the two governs: requests go out one at a time
with at least six seconds between them, and the floor of three seconds holds
however the server is configured. The User-Agent always ends with the project
identity and an address where a person can be reached.
Every result carries the address of the page it was read from. The Library of Congress is a public institution, and its records state their own rights.
This MCP server is an unofficial project, with no affiliation to the Library of Congress.
Privacy
This server collects nothing about you and sends nothing to its author. It runs
on your machine, contacts www.loc.gov and chroniclingamerica.loc.gov and nothing else, holds its answers in memory
while it runs, and writes nothing to disk.
PRIVACY.md states what a request carries and which settings change
any of it.
Development
npm install
npm run build:fixtures
npm test
npm run checkTests run against generated fixtures and make no network request. The live suite,
npm run test:live, makes one request per route and runs nightly against the
Library itself.
Contributing
Bugs, questions and ideas belong in the issue tracker. Pull requests are welcome; opening an issue first helps agree on the shape of the change. See CONTRIBUTING.md.
License
MIT, see LICENSE. The records belong to the Library of Congress and to the depositors it names, under the rights each record states.
mcp-libraryofcongress (français)
La Library of Congress est la bibliothèque nationale des États-Unis, et elle publie en ligne une large part de ses fonds : livres, photographies, cartes, enregistrements sonores, manuscrits, et les pages des journaux américains depuis le dix-huitième siècle. Ces pages de journaux ont été numérisées puis passées par la reconnaissance optique de caractères, si bien que les mots qui y sont imprimés sont cherchables. Des conservateurs rassemblent aussi des documents en collections numériques, chacune décrite et publiée comme un ensemble à part entière.
Ce serveur relie un client de conversation à cette bibliothèque. On peut chercher dans les mots imprimés à l'intérieur des journaux, chercher au catalogue par titre, auteur, sujet, lieu ou langue, lire une notice avec ses conditions de droits et le lieu où l'original est conservé, et lister les collections numériques. Aucune clé d'API, aucun compte.
Installation
Installation en un clic
Claude Code
claude mcp add libraryofcongress -- npx -y mcp-libraryofcongressClaude Desktop, Cursor, et tout client au format de configuration standard
{
"mcpServers": {
"libraryofcongress": {
"command": "npx",
"args": ["-y", "mcp-libraryofcongress"]
}
}
}Node 24 ou plus récent est nécessaire, et aucune variable d'environnement n'est à renseigner.
Avec Docker
{
"mcpServers": {
"libraryofcongress": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-libraryofcongress:3.0.1"]
}
}
}-i garde l'entrée standard ouverte, qui est le canal du protocole, et -t est
omis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS
sortant vers www.loc.gov et chroniclingamerica.loc.gov, et de rien d'autre :
aucun volume, aucun port, aucun identifiant.
Bundle, sans npm
Téléchargez mcp-libraryofcongress-3.0.1.mcpb depuis
la dernière publication
et ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm et
sans fichier de configuration à modifier. Le bundle emporte ses dépendances, donc
rien n'est téléchargé à l'installation.
Ce qu'on peut demander
« Qu'ont écrit les journaux de l'Oklahoma sur le vote d'accession de 1907 ? »
« Trouve-moi des photographies d'immeubles de rapport à Chicago avant 1920. »
« Lis cette notice et dis-moi qui conserve l'original. »
« Quelles collections numériques existent sur la guerre de Sécession ? »
« Puis-je réutiliser cette photographie ? »
Le chemin ordinaire va d'une recherche à une notice : une ligne porte un
identifier, et get_item la lit.
Les outils
Outil | Ce qu'il fait |
| Cherche dans les mots imprimés des pages de journaux numérisées. |
| Cherche au catalogue par titre, auteur, sujet, lieu ou langue. |
| Lit une notice, ses droits et le lieu de conservation de l'original. |
| Liste les collections numériques publiées par les conservateurs. |
search_newspapers
Cherche dans le texte des pages de journaux numérisées, texte issu de la reconnaissance optique de caractères.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | Les mots à chercher sur les pages. |
| chaîne, jusqu'à 120 caractères | non | Un lieu de publication du journal. |
| chaîne, jusqu'à 200 caractères | non | Un journal en particulier. |
| entier, 1000 à 9999 | non | Année la plus ancienne, incluse. |
| entier, 1000 à 9999 | non | Année la plus récente, incluse. |
| entier, 1 à 25, défaut | non | Correspondances à servir. |
| entier, 1 à 100, défaut | non | Quelle page de correspondances. |
| entier, 80 à 1200, défaut | non | La longueur de passage à servir. |
| entier, 1 à 10, défaut | non | Passages servis par page correspondante. |
En retour : hits, chacun portant identifier, que get_item reprend ;
title ; creator, qui est la bibliothèque ayant fourni la numérisation ;
year ; page_number, le feuillet dans le numéro ; published_on ;
publication avec les années de parution du journal ; state ; excerpts ; et
excerpt_kind.
excerpt_kind décide de ce que vaut un extrait. Un passage est le texte
autour des mots trouvés, centré sur eux. Un page_opening est le début du
feuillet, envoyé parce que le texte rendu par la bibliothèque avec la ligne
s'arrête avant que ces mots apparaissent : il ne porte pas la correspondance,
donc le citer cite autre chose, et source_url ouvre le feuillet avec la requête
appliquée. total compte des feuillets de journaux, et il pagine : ce n'est
jamais un compte du nombre de fois où les mots apparaissent.
search_items
Cherche au catalogue, un type de chose à la fois.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | Les mots à chercher. |
|
| non | Le catalogue à lire. |
| entier, 1000 à 9999 | non | Année la plus ancienne, incluse. |
| entier, 1000 à 9999 | non | Année la plus récente, incluse. |
| chaîne, jusqu'à 120 caractères | non | Une vedette-matière. |
| chaîne, jusqu'à 120 caractères | non | Un lieu. |
| chaîne, jusqu'à 120 caractères | non | Une langue, écrite en anglais. |
| chaîne, jusqu'à 160 caractères | non | Une collection, telle que |
| booléen, défaut | non | Ne garder que les notices en ligne. |
|
| non | L'ordre des lignes. |
| entier, 1 à 50, défaut | non | Lignes à servir. |
| entier, 1 à 100, défaut | non | Quelle page de lignes. |
En retour : items, chacun portant identifier, title, creator, year,
date tel que publié, souvent un intervalle, is_collection et source_url. La
bibliothèque tient un catalogue par type de chose, donc une recherche sans
media_type lit le catalogue général, et total y compte les notices
correspondantes.
get_item
Lit une notice. Les parties lourdes se demandent au lieu d'être servies par défaut, et une description longue se pagine.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | L'identifiant que porte une ligne. |
| tableau de | non | Les parties à rendre. |
| entier, 0 ou plus, défaut | non | Où reprendre la description. |
| entier, 200 à 20000, défaut | non | La longueur de description à servir. |
En retour : la notice avec son title, creator, year, date, format
et source_url, plus description, subjects, location, language,
part_of pour les collections et divisions où elle se range, repository qui
nomme le lieu de conservation de l'original, call_number et rights. Un champ
que la notice laisse vide vaut null. next_offset poursuit une description
longue et vaut null à la fin. Un identifiant peut porter des barres obliques :
un numéro de journal est nommé par son titre, sa date et son édition ensemble.
list_collections
Liste les collections numériques, ensembles de documents qu'un conservateur a choisis, décrits et publiés ensemble.
Argument | Type | Requis | Ce qu'il fait |
| entier, 1 à 50, défaut | non | Collections à servir. |
| entier, 1 à 100, défaut | non | Quelle page de collections. |
| booléen, défaut | non | Ne garder que celles auxquelles on peut restreindre une recherche. |
| entier, 80 à 2000, défaut | non | La longueur de chaque description à servir. |
En retour : collections, chacune portant identifier, le slug qui
l'adresse ; title ; collection_filter, la formulation que search_items
reprend ; searchable_media_types ; description ; item_count ; subjects ;
formats pour les types de choses qu'elle contient ; et source_url. total
compte les collections que la bibliothèque publie, ce qui dépasse le nombre
rendu.
Ce que vaut un texte numérisé
Les mots contenus dans une page de journal sont issus de la reconnaissance optique de caractères, donc un extrait porte les erreurs de lecture de ce procédé. Il est servi tel qu'il a été lu plutôt que corrigé. Citez-le comme un texte numérisé, et liez la page pour qu'un lecteur puisse regarder le feuillet lui-même.
Les droits
Une notice énonce ses propres droits dans rights, et les conditions de la
bibliothèque diffèrent d'un dépôt à l'autre. Lisez cette mention avant toute
réutilisation, et redonnez-la à côté de ce qui est montré.
Configuration
Chaque variable est facultative. Elles se posent dans le bloc env de la
configuration du client.
Variable | Défaut | Ce qu'elle fait |
| l'identité du projet | Nomme votre application auprès de la bibliothèque, avec une adresse où joindre une personne. |
|
| Écart entre deux requêtes, de 3000 à 60000. |
|
| Délai d'une requête, de 1000 à 120000. |
|
| Délai d'une recherche dans les journaux, de 1000 à 300000. |
|
| Tentatives après un échec passager, de 0 à 8. |
|
| Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000. |
|
| Réponses gardées en mémoire à la fois, de 1 à 5000. |
|
|
|
Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la sortie d'erreur.
Erreurs
Chaque échec porte un des six codes, un message, et quand cela aide une indication du geste suivant.
Code | Ce qui s'est passé | Que faire |
| La bibliothèque a répondu, et n'a pas cette notice. | Vérifiez l'identifiant avec |
| Les arguments ont été refusés avant toute requête. | Lisez le message, qui nomme l'argument. |
| La bibliothèque demande à ce client de ralentir. | Attendez les secondes indiquées et rappelez avec les mêmes arguments. La notice est toujours là. |
| La réponse est arrivée dans une forme illisible ici. | Signalez-le sur le suivi d'incidents. |
| La requête n'a pas abouti. | Réessayez sous peu. |
| La requête a dépassé son délai. | Augmentez |
Comme bibliothèque
La couche qui lit la bibliothèque est publiée seule, avec son rythme, son cache et ses erreurs, sans protocole attaché.
import { LocClient } from "mcp-libraryofcongress/client";
const client = new LocClient();
const { data, cached } = await client.searchItems({ query: "tenement", mediaType: "photos" });
console.log(data.total, cached);Chaque lecture répond { data, cached }, et lève une erreur portant un des six
codes. Le plancher entre deux requêtes tient également ici.
Rythme et attribution
La bibliothèque publie une limite de 20 requêtes par minute pour son API et de 10
pour l'ensemble du site, et c'est la plus basse qui gouverne : les requêtes
partent une à une avec au moins six secondes entre elles, et le plancher de trois
secondes tient quelle que soit la configuration. Le User-Agent se termine
toujours par l'identité du projet et une adresse où joindre une personne.
Chaque résultat porte l'adresse de la page d'où il a été lu. La Library of Congress est une institution publique, et ses notices énoncent leurs propres droits.
Ce MCP est un projet non officiel, sans affiliation à la Library of Congress.
Confidentialité
Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur
votre machine, ne joint que www.loc.gov et chroniclingamerica.loc.gov, garde ses réponses en mémoire le temps qu'il
tourne, et n'écrit rien sur le disque. PRIVACY.md dit ce qu'une
requête emporte et quels réglages changent cela.
Développement
npm install
npm run build:fixtures
npm test
npm run checkLes tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête.
La suite en direct, npm run test:live, émet une requête par route et tourne
chaque nuit contre la bibliothèque elle-même.
Contribuer
Les anomalies, les questions et les idées ont leur place dans le suivi d'incidents. Les propositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à s'accorder sur la forme du changement. Voir CONTRIBUTING.md.
Licence
MIT, voir LICENSE. Les notices appartiennent à la Library of Congress et aux déposants qu'elle nomme, sous les droits que chaque notice énonce.
Available Tools
4 toolsget_itemRead a recordBRead-onlyIdempotent
Read one Library of Congress record by its identifier, as returned by search_items or search_newspapers. An identifier can carry slashes: a single newspaper issue is named by its paper, its date and its edition together. Sections are opt-in: 'basic' is the default and covers what a description needs. 'date' carries only the precision the record's own words support, and 'date_stated' repeats those words, which can be a span of years the record was filed at the opening of. Where the Library has established no date it files the record under a cataloguing code, which 'date_code' carries while 'date' and 'year' stay null. 'citations' returns the ready-made citations the Library publishes for the record. 'resources' lists the served copies, such as page images and downloadable files. 'full_metadata' returns every field the Library publishes for the record, which is large and rarely needed. A long description paginates: when 'next_offset' is not null, call again with 'offset' set to it.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | Where to resume the description. | |
| sections | No | Which parts to return. Each one beyond 'basic' adds to the size of the answer. | |
| identifier | Yes | Record identifier, such as '2017645459' or 'sn83045462/1929-02-03/ed-1'. | |
| max_description_chars | No | Characters of the description to return in one call. |
Output Schema
| Name | Required | Description |
|---|---|---|
| item | Yes | |
| notes | Yes | |
| offset | Yes | |
| rights | Yes | What the Library says about reuse. Null when it says nothing, which is not permission. |
| part_of | Yes | Collections and divisions the record sits in. |
| language | Yes | |
| location | Yes | |
| subjects | Yes | |
| citations | No | |
| resources | No | |
| repository | Yes | Where the original is held. |
| call_number | Yes | |
| description | Yes | |
| next_offset | Yes | Pass as 'offset' to read the rest of the description. Null when it ends here. |
| full_metadata | No | |
| notes_on_record | Yes | Notes the Library published about the record itself, less any whose words the description already carries. The Library assembles the description of some records out of these notes, and those records would otherwise return one text under two names. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description includes extensive behavioral details, but several of them are false: it mentions 'date', 'date_stated', 'date_code', and 'year' as section options, yet the schema's enum only allows 'basic', 'citations', 'resources', and 'full_metadata'. This actively misleads an agent about the tool's behavior, which is worse than omitting details. The readOnlyHint and idempotentHint annotations are accurate, but the description's incorrect claims undermine transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized with the purpose first, then identifier details, section explanations, and pagination. However, a significant portion is devoted to explaining 'date', 'date_stated', 'date_code', and 'year'—all of which are not valid section values. This makes the description unnecessarily long and misleading, though the structure itself is logical.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers many important aspects: identifier format, pagination, and the purpose of each valid section. With an output schema present, it need not describe return values. However, it omits any mention of the actual allowed section enum and instead lists invalid options, leaving an agent with inaccurate information about how to use the tool. This is a significant completeness gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all four parameters with 100% coverage, giving a baseline of 3. The description does add useful semantics for 'identifier' (slash format) and 'offset' (pagination), but it incorrectly lists non-existent section values, which would cause an agent to pass invalid inputs. This misinformation cancels out the added value and makes the description a net negative for parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with 'Read one Library of Congress record by its identifier', clearly stating the verb, resource, and scope. It also distinguishes itself from sibling tools by noting that the identifier is 'as returned by search_items or search_newspapers', making the tool's purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on when to use the tool: after obtaining an identifier from search tools. It also explains pagination ('call again with offset set to it') and section options. However, it does not explicitly state when not to use this tool or compare it against alternatives like list_collections, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_collectionsList the digital collectionsARead-onlyIdempotent
List the digital collections of the Library of Congress: bodies of material a curator chose, described and published together. Use it to see what is there before searching, since a collection names a corpus that a query would have to guess at. 'collection_filter' on each row is the wording search_items takes as its 'collection' argument, and 'searchable_media_types' names the catalogues that filter can be sent to. A collection whose 'searchable_media_types' is empty gathers a kind of thing the catalogue search is not divided into, such as web archives; set 'searchable_only' to leave those out. 'item_count' is how many records the collection gathers, which is the size of the corpus rather than the number of rows here.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Which page of collections, from 1. | |
| limit | No | Collections to return. | |
| searchable_only | No | Keep only the collections whose formats name a media_type, which are the ones search_items can be asked for. | |
| max_description_chars | No | Budget for one collection's description. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | Yes | |
| notes | Yes | |
| total | Yes | Collections the Library publishes, not the number returned. |
| collections | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context that the annotations do not cover. It explains the meaning of collection_filter, searchable_media_types, and the important distinction that 'item_count' is 'the size of the corpus rather than the number of rows here'. It also clarifies that empty searchable_media_types gathers things like web archives that the catalogue search does not divide into. This enriches the agent's understanding beyond the readOnly/idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average but every sentence serves a purpose: it defines the resource, explains when to use it, clarifies field semantics, and distinguishes row count from item_count. The information is front-loaded with the core action, followed by relevant detail. No redundancy or filler exists, making it as concise as the content permits.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity, the output schema, and strong annotations, the description is fully complete. It explains the relationship to search_items, clarifies the meaning of output fields like collection_filter and item_count, and acknowledges edge cases like empty searchable_media_types. The description preempts likely misunderstandings and gives the agent all necessary context to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for all four parameters, so the baseline is 3. The description adds extra meaning for 'searchable_only' by explaining the condition in context: 'A collection whose searchable_media_types is empty... set searchable_only to leave those out.' This goes beyond the schema's wording and helps clarify the parameter's practical intent. However, the description does not add meaning for page, limit, or max_description_chars beyond what the schema already states, so it does not earn a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'List the digital collections of the Library of Congress', using a specific verb and resource. It then clarifies the concept of a 'collection' as 'bodies of material a curator chose, described and published together', and distinguishes it from sibling search tools by stating 'Use it to see what is there before searching, since a collection names a corpus that a query would have to guess at.' This clearly differentiates it from find/search operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises when to use the tool: 'Use it to see what is there before searching', and explains how it relates to sibling tools: 'collection_filter on each row is the wording search_items takes as its collection argument'. It also gives conditional guidance for searchable_only, explaining that collections with empty searchable_media_types are not searchable and how to exclude them. This goes beyond generic statements and provides concrete usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_itemsSearch the catalogueARead-onlyIdempotent
Search the Library of Congress catalogue: books, photographs, maps, recordings, films, manuscripts, sheet music and newspaper titles. 'media_type' is required, because the Library keeps a separate catalogue for each kind of thing. This matches titles, creators and catalogue descriptions. It does not read the text inside a scan; use search_newspapers for a phrase printed on a newspaper page. Filters take the words the Library itself uses: 'subject' and 'location' as the rows here spell them, 'language' written in English, 'collection' as list_collections reports it under 'collection_filter'. A filter matching nothing is set aside and the search asked again without it; the answer names what was dropped, and the count it reports is then the unfiltered search's. By default only material with a digitised copy is returned; set 'online_only' to false to take in records the Library holds on a shelf alone. A row carries an 'identifier' get_item takes when it names a record. A row that is a collection the Library gathered names no record: 'is_collection' is true there, 'identifier' is null, and 'source_url' opens the collection.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| sort | No | Order of the results. | relevance |
| limit | No | ||
| query | Yes | Words to look for in titles, creators and catalogue descriptions. The catalogue index holds no word of a single letter, so at least one word has to run to two letters or more, unless it is written in a script where one character is a word. | |
| subject | No | A subject heading, such as 'crime'. | |
| year_to | No | Latest year, inclusive. | |
| language | No | A language, written in English: 'english'. | |
| location | No | A place, such as 'oklahoma'. | |
| year_from | No | Earliest year, inclusive. | |
| collection | No | A collection, named exactly as list_collections reports it under 'collection_filter'. | |
| media_type | Yes | Which catalogue to search: books, photos, maps, audio, film-and-videos, manuscripts, notated-music or newspapers. 'newspapers' holds the papers themselves; a phrase printed on a page belongs in search_newspapers. | |
| online_only | No | Keep to material with a digitised copy. Set false to include shelf-only records. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | Yes | |
| items | Yes | |
| notes | Yes | |
| query | Yes | |
| total | Yes | Records matching across this catalogue for the search the rows come from, not the number returned. A filter that matched nothing is set aside, and this then counts the search without it, which the notes name. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite having annotations (readOnlyHint, openWorldHint, idempotentHint, destructiveHint), the description delivers significant additional behavioral context: filter fallback behavior, online_only default, the distinction between records and collections, and how identifiers work. It also explicitly states what the tool does NOT do (does not read text-inside-scans), which is valuable. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place by adding unique, non-redundant behavioral detail. It is front-loaded with the core purpose and then systematically addresses caveats, alternatives, and edge cases. No fluff or repetition of schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the parameter count (12) and presence of an output schema, the description covers essential context: required media_type, exact filter terms, fallback filtering, digitized-copy default, and how to interpret collection rows. It also references sibling tools appropriately. The description is complete enough for an agent to use the tool effectively without surprise.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description enriches schema understanding with practical semantics: media_type required due to separate catalogues, filters must use exact Library vocabulary, behavior when a filter matches nothing, and the meaning of online_only. It also clarifies that rows with is_collection have null identifier and use source_url, going beyond the basic schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it searches the Library of Congress catalogue with a specific list of material types, and explicitly distinguishes itself from sibling search_newspapers by noting it does not read text inside scans. The verb 'search' plus resource 'Library of Congress catalogue' and scope makes the purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool vs search_newspapers, explains why media_type is required, and details special behaviors like filter matching (or being dropped) and online_only default. It even instructs users on how to handle collection rows versus record rows, leaving little ambiguity about usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_newspapersSearch inside scanned newspaper pagesARead-onlyIdempotent
Search the text inside digitised American newspaper pages held by the Library of Congress. This reads what optical recognition took off the scanned pages, so it finds a phrase that appears nowhere in a title or a catalogue record. Double quotes change how the Library matches the words, and it decides what they mean: a page can come back carrying the words apart or in another order rather than the phrase as written. What the quotes do to the number of matching pages varies from one query to the next, so run the search both ways rather than expecting either form to return more. 'total' counts the pages that match, and they page: ask for page 2, 3 and so on to see beyond the first answer. It is not a count of how many times the words occur. Each match names the newspaper, the date, the leaf of the issue and the state it was published in, and 'source_url' opens that leaf with the query applied. 'location' keeps to papers published in one state, 'publication' to a single paper, and 'year_from' with 'year_to' to a span of years. A filter matching nothing is dropped and the answer says so. Every match carries 'excerpt_kind', and the excerpts are labelled with it in the text. A 'passage' is the text around the words that matched. A 'page_opening' is the start of the page, sent because the text the Library returned with the row stops before those words appear, so it does not carry the match and quoting it quotes something else. Use search_items instead when looking for a work by its title, creator or subject.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Which page of matches, from 1. | |
| limit | No | Matches to return. | |
| query | Yes | Words or a quoted phrase, such as '"cure for influenza"'. The index reads the text off the pages themselves and holds single characters, so a query of one character is a query it answers. | |
| year_to | No | Latest year, inclusive. | |
| location | No | The state a paper was published in, written as the Library writes it: 'new york', 'district of columbia'. It is the value 'state' carries on the matches this tool returns. | |
| year_from | No | Earliest year, inclusive. | |
| publication | No | One newspaper, named with its town and the years it ran: 'new-york tribune (new york [n.y.]) 1866-1924'. Take the wording from 'publication' on a match here, or from a title in search_items with media_type 'newspapers'. | |
| max_excerpt_chars | No | Budget for one passage. Read it together with 'max_excerpts_per_match': the size of the answer is the product of the two and the number of matches. | |
| max_excerpts_per_match | No | Passages to keep per match. A page holding the words several times yields several, and the later ones rarely say anything the first did not. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hits | Yes | |
| page | Yes | |
| notes | Yes | |
| query | Yes | |
| total | Yes | Newspaper pages that match, not the number returned and not a count of occurrences. Raise 'page' to read further into it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite strong annotations (readOnlyHint, openWorldHint, idempotentHint), the description adds substantial behavioral context: quote semantics vary, 'total' counts pages not occurrences, unmatched filters are silently dropped, and the page_opening excerpt quirk is explained. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then builds with related behavioral details. It is long, but most sentences earn their place; minor awkwardness like 'and they page' prevents a perfect score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 9-parameter search tool with output schema and annotations, the description is remarkably complete. It covers pagination, filter behavior, return fields, excerpt types, result-count semantics, and when to use an alternative tool, leaving little unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds meaning beyond the schema by explaining quote behavior, the meaning of 'location', 'publication', 'year_from/year_to', and the semantics of 'total' and pagination, going beyond the raw parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Search the text inside digitised American newspaper pages held by the Library of Congress.' It clearly distinguishes from siblings by explaining this is full-text search of OCR content, and explicitly contrasts with 'search_items' for title/creator/subject searches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: full-text newspaper search when the phrase may not appear in catalog records, and 'Use search_items instead when looking for a work by its title, creator or subject.' It also gives practical guidance on double-quote behavior, pagination, and filter usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v2.1.0- Changed
get_item7 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Output schema / properties / item / properties / date / descriptionAdded value: +"The date the Library files the record under, carrying only the precision the record's own words support." - added
Output schema / properties / item / properties / date_codeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The cataloguing code the Library files the record under in place of a date, such as 'uuuu' or '18??'. It stands for digits the Library has not established, so 'date' and 'year' are null beside it. Null wherever the filed value is a date." +} - added
Output schema / properties / item / properties / date_statedAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "When the record was made or issued, in the record's own words, which can be a span of years or a phrase. Null when the record says nothing about it." +} - added
Output schema / properties / item / properties / year / descriptionAdded value: +"The year of 'date', which a span of years makes the first of the span." - changed
Output schema / properties / item / requiredPrevious value: -[ - "identifier", - "title", - "creator", - "year", - "date", - "format", - "source_url" -]New value: +[ + "identifier", + "title", + "creator", + "year", + "date", + "date_code", + "date_stated", + "format", + "source_url" +] - changed
Output schema / properties / notes_on_record / descriptionPrevious value: -"Notes the Library published about the record itself."New value: +"Notes the Library published about the record itself, less any whose words the description already carries. The Library assembles the description of some records out of these notes, and those records would otherwise return one text under two names."
- Changed
list_collections5 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / searchable_onlyAdded value: +{ + "default": false, + "description": "Keep only the collections whose formats name a media_type, which are the ones search_items can be asked for.", + "type": "boolean" +} - changed
Output schema / properties / collections / items / properties / collection_filter / descriptionPrevious value: -"Pass as 'collection' to search_items to keep results within this collection."New value: +"Pass as 'collection' to search_items, together with one of 'searchable_media_types', to keep results within this collection." - added
Output schema / properties / collections / items / properties / searchable_media_typesAdded value: +{ + "description": "The 'media_type' values search_items can be asked with for this collection, read off the formats the Library publishes for it. Empty when none of those formats names a catalogue.", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Output schema / properties / collections / items / requiredPrevious value: -[ - "identifier", - "title", - "collection_filter", - "description", - "item_count", - "subjects", - "formats", - "source_url", - "items_url" -]New value: +[ + "identifier", + "title", + "collection_filter", + "searchable_media_types", + "description", + "item_count", + "subjects", + "formats", + "source_url", + "items_url" +]
- Changed
search_items6 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / query / descriptionPrevious value: -"Words to look for in titles, creators and catalogue descriptions."New value: +"Words to look for in titles, creators and catalogue descriptions. The catalogue index holds no word of a single letter, so at least one word has to run to two letters or more, unless it is written in a script where one character is a word." - added
Output schema / properties / items / items / properties / date_codeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The cataloguing code the Library files the row under in place of a date, such as 'uuuu' or '18??'. It stands for digits the Library has not established, so 'date' and 'year' are null beside it. Null wherever the filed value is a date." +} - added
Output schema / properties / items / items / properties / is_collectionAdded value: +{ + "description": "True when the row is a collection a curator gathered and named rather than a record of the catalogue searched. The item route holds nothing at a collection's address, so 'identifier' is null and 'source_url' is where it opens.", + "type": "boolean" +} - changed
Output schema / properties / items / items / requiredPrevious value: -[ - "identifier", - "title", - "creator", - "year", - "date", - "format", - "location", - "subjects", - "online", - "source_url" -]New value: +[ + "identifier", + "is_collection", + "title", + "creator", + "year", + "date", + "date_code", + "format", + "location", + "subjects", + "online", + "source_url" +] - changed
Output schema / properties / total / descriptionPrevious value: -"Records matching across this catalogue, not the number returned."New value: +"Records matching across this catalogue for the search the rows come from, not the number returned. A filter that matched nothing is set aside, and this then counts the search without it, which the notes name."
- Changed
search_newspapers7 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / query / descriptionPrevious value: -"Words or a quoted phrase, such as '\"cure for influenza\"'."New value: +"Words or a quoted phrase, such as '\"cure for influenza\"'. The index reads the text off the pages themselves and holds single characters, so a query of one character is a query it answers." - changed
Input schema / properties / query / minLengthPrevious value: -2New value: +1 - added
Output schema / properties / hits / items / properties / excerpt_kindAdded value: +{ + "description": "'passage' means the excerpts are the text around the words that matched, centred on them because they were found in the text returned with this row. 'page_opening' means they are the start of the page, sent because that text stops before the searched words appear, so a page_opening does not carry the match.", + "enum": [ + "passage", + "page_opening" + ], + "type": "string" +} - changed
Output schema / properties / hits / items / properties / excerpts / descriptionPrevious value: -"Passages as a machine read them off the page."New value: +"Machine-read text off the page, all of the kind 'excerpt_kind' names." - removed
Output schema / properties / hits / items / properties / words_locatedRemoved value: -{ - "description": "True when the searched words were found in the text returned with this row, in which case the excerpts are centred on them. False when they sit further down the page than that text reaches, in which case the excerpts are its opening.", - "type": "boolean" -} - changed
Output schema / properties / hits / items / requiredPrevious value: -[ - "identifier", - "title", - "creator", - "year", - "page_number", - "published_on", - "publication", - "state", - "words_located", - "excerpts", - "source_url" -]New value: +[ + "identifier", + "title", + "creator", + "year", + "page_number", + "published_on", + "publication", + "state", + "excerpt_kind", + "excerpts", + "source_url" +]
4 tool updates
v1.0.0- First observed
get_item - First observed
list_collections - First observed
search_items - First observed
search_newspapers
TDQS
Each tool has a clearly distinct purpose: full-text newspaper search (search_newspapers), catalog metadata search across media types (search_items), record retrieval by identifier (get_item), and collection browsing (list_collections). The descriptions explicitly cross-reference each other to prevent confusion, such as noting that search_items should be used for titles/creators while search_newspapers is for printed text.
All tool names follow a consistent verb_noun pattern in snake_case: search_newspapers, search_items, get_item, list_collections. The naming convention is uniform and predictable, making it easy to infer tool behavior from names alone.
With just 4 tools, the server is well-scoped for its purpose. It covers the essential operations for searching, retrieving, and browsing Library of Congress resources without unnecessary bloat. Each tool earns its place as a distinct and necessary part of the workflow.
The tool surface covers the core workflows: search both full-text newspapers and catalog metadata, retrieve detailed records, and discover curated collections. Minor gaps exist, such as no dedicated tool for viewing collection details or listing all newspapers, but these can be worked around using existing filters and get_item.
Maintenance
Related MCP Connectors
An MCP server that provides congressional transcripts
An MCP server that provides tools to discover and retrieve podcast episodes transcripts.
MCP server for Open Archives: Dutch genealogical records and historical page transcriptions.
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that searches library catalogs worldwide using the SRU protocol, enabling bibliographic search without API keys.-
- AlicenseAqualityCmaintenanceMCP server for searching and accessing historical Austrian newspapers from ANNO, providing full-text search, snippet extraction, and OCR text download.3Apache 2.0
- AlicenseAqualityBmaintenanceMCP server and CLI for full-text search of the Deutsches Zeitungsportal (German newspaper collection), enabling querying ~33.8 million digitized pages with Solr syntax, date/title/place filters, and snippet highlights.3Apache 2.0
- AlicenseAqualityBmaintenanceMCP server for searching and retrieving full-text pages from the Library of Congress, including newspapers, books, and manuscripts, via the loc.gov API.3Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/smeet666/mcp-libraryofcongress'
If you have feedback or need assistance with the MCP directory API, please join our Discord server