mcp-imslp
mcp-imslp connects a chat client to the IMSLP classical music library, letting it search and read works, people, editions, files, and browse catalogued categories.
Search works by title, composer, or any words on the page (
search_works)Search people — composers, editors, arrangers, performers (
search_people)Read a work's full page — title, composer, opus, key, instrumentation, composition year, movements, copyright summary, and more (
get_work)List a work's editions and files — scores, parts, recordings, with publisher, editor, copyright terms, file formats, sizes, ratings, and download counts (
list_work_files)List a person's works — compositions and credited works under a category (
list_person_works)Read a person's biography data — life dates, aliases, authorities, external links (
get_person)Browse categories — genres, keys, instrumentations, and periods (
browse_category)Report copyright status per jurisdiction (Canada, US, EU), including restrictions like Non-PD US
Click on "Deploy 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-imslpfind piano scores for Debussy's Clair de Lune"
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-imslp
IMSLP, the International Music Score Library Project, is also called the Petrucci Music Library. It is a free library of classical music run by volunteers, holding the sheet music, the parts, the arrangements and the recordings of works whose copyright has lapsed, together with what its pages say about each composer. It reviews the copyright of every score for Canada, the United States and the European Union separately, and publishes its pages under CC BY-SA 4.0.
This server connects a chat client to that library. You can search the works and the people it catalogues, read a work with its opus number, its key, its instrumentation and the year it was written, page through the editions a work holds with their publishers, editors and copyright terms, read what the library says about a composer, and browse a genre, a key or an instrumentation. It reads the library and links to it, and it needs no API key and no account.
Install
One-click install
Claude Code
claude mcp add imslp -- npx -y mcp-imslpClaude Desktop, Cursor, and any client using the standard config format
{
"mcpServers": {
"imslp": {
"command": "npx",
"args": ["-y", "mcp-imslp"]
}
}
}Node 24 or later is required, and no environment variable has to be set.
With Docker
{
"mcpServers": {
"imslp": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-imslp:1.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
imslp.org, and nothing else: no volume, no port, no credential.
Bundle, without npm
Download mcp-imslp-1.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: mcp-ytmusic
What you can ask
"What does IMSLP hold of Chopin's nocturnes?"
"Read me the page of Erik Satie and tell me when he lived."
"List the editions of Debussy's Clair de lune, with who published each one."
"Is the Henle edition of that piece free to use in the United States?"
"Show me works for solo cello in the library."
The ordinary path runs from a search to a work: search_works names the page of
a work, and get_work reads that page. The same holds for a person, from
search_people to get_person or list_person_works.
Tools
Tool | What it does |
| Finds the page of a work by title, composer or words on the page. |
| Finds the category a composer, editor, arranger or performer is filed under. |
| Reads one work: its facets, its sections and its copyright terms. |
| Pages through the editions a work holds, with their files. |
| Reads the works the library files under one person. |
| Reads what the library holds about one person. |
| Reads the works filed under a genre, a key or an instrumentation. |
A work is addressed by the title of its page, written Work (Composer), as in
Nocturnes, Op.9 (Chopin, Frédéric). A person is addressed by a category,
written Category:Surname, Forename. Both come back from a search, and the
Category: prefix may be left out.
The library titles a work in the language its composer used, so Die Zauberflöte
finds the opera where The Magic Flute finds the pages written about it. A thin
answer for a famous work is a sign the title is in another language.
search_works
Searches the pages of the works for words appearing anywhere on them, so a title, a composer or a dedication all find the works carrying them.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | What to look for across the pages of the works. |
| integer, 1 to 50, default | no | Rows to serve. |
| integer, 0 or more, default | no | Rows to skip, using the |
In return: rows carrying page, which get_work takes; work and
composer, read off that title; page_url; snippet, the words around the
match; size_bytes, words and last_edited as the library states them. The
envelope carries returned, has_more and next_offset, which is the offset to
read on from. total is always null: the library publishes no count of what a
search matched. composer is null on a title written outside the
Work (Composer) form, and snippet is null on a row the search summarised
with nothing.
search_people
Finds the composers, editors, arrangers and performers by name. The library writes a name its own way, surname first, so searching finds a person where guessing at the spelling reaches nothing.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The name to look for among the people of the library. |
| integer, 1 to 50, default | no | Rows to serve. |
| integer, 0 or more, default | no | Rows to skip, using the |
In return: rows carrying category, which get_person and
list_person_works take; name without the prefix; page_url; snippet; and
redirect_to. A row with a redirect_to stands for another category and holds
no works of its own, so follow the category it names. The envelope is the one
search_works returns, and total is null here for the same reason.
get_work
Reads one work: its title and alternative titles, the composer, the opus and catalogue numbers, the year of composition and of first publication, the dedication, the key, the language, the librettist, the instrumentation, the movements, the first performance, the style and the period.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | one of two | The page title, written |
| integer, positive | one of two | The page id a search returned, as an alternative to |
In return: every facet above, each null when the page leaves it empty, and
each in the wording the page used, so ca.1830 stays ca.1830. Beside them come
genre_categories, which browse_category takes; external_links and
authorities, the records of the work at VIAF, LCCN, WorldCat, BNF and GND;
sections, with the number of entries the site counts in each; and
copyright_summary, one entry per distinct statement, with the number of
editions carrying it. editions holds every edition with its files, and turns
null with editions_truncated true when the work holds more than five, which
list_work_files then pages through. redirected_from names the title asked
for when it led here, and pageid is null for a work addressed by title.
list_work_files
Reads the scores and the recordings of a work, edition by edition. An edition is a set of files published under one set of terms: the publisher, the editor and the copyright statement belong to the edition, and the files sit under it. A block of recordings carries performers and no copyright statement.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | one of two | The page title, written |
| integer, positive | one of two | The page id a search returned, as an alternative to |
| string, 1 to 80 characters | no | One section of the page, in its own wording: |
| integer, 1 to 100, default | no | Editions to serve. |
| integer, 0 or more, default | no | Editions to skip. |
In return: editions, each with its section, publisher_info, editor,
copyright and files. A file carries imslp_id, description, format and
format_code, pages, size_bytes, downloads, rating, uploader,
uploaded_on, the sigla and name of the library that scanned it, and blocked,
which is true while IMSLP reviews the copyright of that file. downloads is
null on an entry printing no counter, and rating is null when nobody has
voted. Alongside come editions_on_page, editions_in_section, returned,
has_more and sections. A section matching nothing comes back with the
sections the page does hold, so a restriction never reads as a work without
scores.
list_person_works
Reads the works the library files under one person: what a composer wrote, and also what an editor, an arranger or a performer is credited on.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The person's category, written |
| integer, 1 to 100, default | no | Rows to serve. |
| string, 1 to 500 characters | no | The |
In return: rows carrying page, work, composer, pageid and page_url,
with has_more and cursor to read on. total is always null: the library
publishes no count of what a category holds. A category the library does not hold
answers the way an empty one does, so an answer with no rows is a reason to check
the spelling with search_people.
get_person
Reads what the library holds about one person: the name as its page prints it, the life dates it states, the other names it files them under, the registers holding a record of them, and the addresses it points to off the site.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The person's category, written |
In return: category, catalogued_as with the surname first, name as the
page prints it, life_dates in the wording the page used, alternative_names
and aliases as published lines, authorities with the register and the
identifier at VIAF, LCCN, WorldCat, BNF and GND, external_links, and
page_url. life_dates is null on a page stating none. This reads the person;
list_person_works reads the works.
browse_category
Reads the works filed under one category: a genre, a key, an instrumentation or a
period. get_work hands these names back for a work under genre_categories,
and passing one of those reaches a category the library holds.
Argument | Type | Required | What it does |
| string, 1 to 300 characters | yes | The category to read, in the library's wording: |
| integer, 1 to 100, default | no | Rows to serve. |
| string, 1 to 500 characters | no | The |
In return: the rows list_person_works returns, with the same has_more and
cursor, and total at null. The library reads one category at a time, so a
question naming both a genre and an instrument is answered by browsing one of
them and reading the other off each work with get_work.
Copyright status
A score on IMSLP carries a status per jurisdiction, and the library reviews
Canada, the United States and the European Union. A file reading
Public Domain - Non-PD US is free in Canada and the European Union and
protected in the United States. This server reports the status as published, per
jurisdiction, under copyright_summary on a work and under copyright on an
edition, with restrictions naming the places a statement excludes. An empty
restrictions says nothing about the countries IMSLP leaves out of its review.
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. The project identity is appended so IMSLP can reach a person. |
|
| Gap between two requests, from 2000 to 60000. A figure under the floor is refused and this one used. |
|
| Deadline for one request, from 1000 to 120000. |
|
| Attempts after a transient failure, from 0 to 10. |
|
| How long a page stays in memory, from 0 to 86400000. |
|
| Pages held in memory at once, from 0 to 10000. |
|
|
|
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 |
| IMSLP answered, and the page asked for is absent. | Check the title with |
| The arguments were refused before any request went out. | Read the message, which names the argument. |
| IMSLP asked this client to slow down. | Wait the number of seconds the hint names and call again with the same arguments. The work is still in the library. |
| The page loaded and the expected content was absent. | 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 IMSLP is published on its own, with its pacing, its cache and its errors, and with no protocol attached.
import { ImslpClient } from "mcp-imslp/client";
const client = new ImslpClient();
const { data, cached } = await client.getWork({ page: "Nocturnes, Op.9 (Chopin, Frédéric)" });
console.log(data.title, data.copyright_summary, cached);renderPage, getWork, search, categoryMembers and getPerson each answer
{ data, cached }, and throw an ImslpError carrying one of the six codes. The
two-second floor between requests holds here as well.
Pacing and attribution
IMSLP publishes Crawl-delay: 2 in its robots.txt, so requests go out one at a
time with at least two seconds between them, and that floor holds however the
server is configured. The User-Agent always ends with the project identity and
an address where a person can be reached.
Reads go through the MediaWiki API at /api.php and through the listing endpoint
IMSLP documents on its own IMSLP:API page. The robots.txt disallows
/index.php, /images/, /imglnks/, /wiki/File:, /works and /library/,
and this server builds no address under any of them: it hands back the link to
the work page, which is what an answer credits.
The library publishes its pages under CC BY-SA 4.0, so anything shown from this server credits IMSLP and links the page it came from.
Privacy
This server collects nothing about you and sends nothing to its author. It runs
on your machine, contacts imslp.org 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
site itself.
Contributing
Issues and pull requests are welcome at the repository. See CONTRIBUTING.md.
License
MIT, see LICENSE. The catalogue and the pages belong to IMSLP and its contributors, published under CC BY-SA 4.0.
mcp-imslp (français)
IMSLP, l'International Music Score Library Project, s'appelle aussi la Petrucci Music Library. C'est une bibliothèque libre de musique classique tenue par des bénévoles, qui rassemble les partitions, les parties séparées, les arrangements et les enregistrements des œuvres tombées dans le domaine public, avec ce que ses pages disent de chaque compositeur. Elle vérifie les droits de chaque partition pour le Canada, les États-Unis et l'Union européenne séparément, et publie ses pages sous CC BY-SA 4.0.
Ce serveur relie un client de conversation à cette bibliothèque. On peut y chercher les œuvres et les personnes qu'elle catalogue, lire une œuvre avec son numéro d'opus, sa tonalité, son instrumentation et son année de composition, parcourir les éditions d'une œuvre avec leurs éditeurs et leurs conditions de droits, lire ce que la bibliothèque dit d'un compositeur, et explorer un genre, une tonalité ou une instrumentation. Il lit la bibliothèque et renvoie vers elle, sans clé d'API ni compte.
Installation
Installation en un clic
Claude Code
claude mcp add imslp -- npx -y mcp-imslpClaude Desktop, Cursor, et tout client au format de configuration standard
{
"mcpServers": {
"imslp": {
"command": "npx",
"args": ["-y", "mcp-imslp"]
}
}
}Node 24 ou plus récent est nécessaire, et aucune variable d'environnement n'est à renseigner.
Avec Docker
{
"mcpServers": {
"imslp": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-imslp:1.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 imslp.org, et de rien d'autre : aucun volume, aucun port, aucun
identifiant.
Bundle, sans npm
Téléchargez mcp-imslp-1.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'est-ce qu'IMSLP a des nocturnes de Chopin ? »
« Lis-moi la page d'Erik Satie et dis-moi quand il a vécu. »
« Liste les éditions du Clair de lune de Debussy, avec qui a publié chacune. »
« Est-ce que l'édition Henle de cette pièce est libre aux États-Unis ? »
« Montre-moi des œuvres pour violoncelle seul dans la bibliothèque. »
Le chemin ordinaire va d'une recherche à une œuvre : search_works nomme la page
d'une œuvre, et get_work lit cette page. Il en va de même pour une personne, de
search_people vers get_person ou list_person_works.
Les outils
Outil | Ce qu'il fait |
| Trouve la page d'une œuvre par son titre, son compositeur ou ses mots. |
| Trouve la catégorie sous laquelle une personne est classée. |
| Lit une œuvre : ses caractéristiques, ses sections et ses droits. |
| Parcourt les éditions d'une œuvre, avec leurs fichiers. |
| Lit les œuvres que la bibliothèque classe sous une personne. |
| Lit ce que la bibliothèque contient sur une personne. |
| Lit les œuvres classées sous un genre, une tonalité, une formation. |
Une œuvre s'adresse par le titre de sa page, écrit Œuvre (Compositeur), comme
Nocturnes, Op.9 (Chopin, Frédéric). Une personne s'adresse par une catégorie,
écrite Category:Nom, Prénom. Les deux viennent d'une recherche, et le préfixe
Category: peut être omis.
La bibliothèque titre une œuvre dans la langue de son compositeur, donc
Die Zauberflöte trouve l'opéra là où La Flûte enchantée trouve les pages
écrites à son sujet. Une réponse maigre sur une œuvre célèbre est le signe d'un
titre dans une autre langue.
search_works
Cherche dans les pages des œuvres les mots qui y figurent, où qu'ils soient : un titre, un compositeur ou une dédicace trouvent les œuvres qui les portent.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | Ce qu'on cherche dans les pages des œuvres. |
| entier, 1 à 50, défaut | non | Lignes à servir. |
| entier, 0 ou plus, défaut | non | Lignes à sauter, avec le |
En retour : des lignes portant page, que get_work reprend ; work et
composer, lus sur ce titre ; page_url ; snippet, les mots autour de la
correspondance ; size_bytes, words et last_edited tels que la bibliothèque
les publie. L'enveloppe porte returned, has_more et next_offset, l'offset
d'où reprendre. total vaut toujours null : la bibliothèque ne publie aucun
compte de ce qu'une recherche a trouvé. composer vaut null sur un titre écrit
hors de la forme Œuvre (Compositeur), et snippet vaut null sur une ligne
que la recherche n'a résumée par rien.
search_people
Trouve les compositeurs, éditeurs, arrangeurs et interprètes par leur nom. La bibliothèque écrit un nom à sa façon, patronyme d'abord, donc la recherche trouve une personne là où une orthographe devinée n'atteint rien.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | Le nom cherché parmi les personnes de la bibliothèque. |
| entier, 1 à 50, défaut | non | Lignes à servir. |
| entier, 0 ou plus, défaut | non | Lignes à sauter, avec le |
En retour : des lignes portant category, que get_person et
list_person_works reprennent ; name sans le préfixe ; page_url ; snippet ;
et redirect_to. Une ligne portant un redirect_to tient lieu d'une autre
catégorie et ne contient aucune œuvre, donc suivez la catégorie qu'elle nomme.
L'enveloppe est celle de search_works, et total y vaut null pour la même
raison.
get_work
Lit une œuvre : son titre et ses titres alternatifs, le compositeur, les numéros d'opus et de catalogue, l'année de composition et celle de première publication, la dédicace, la tonalité, la langue, le librettiste, l'instrumentation, les mouvements, la création, le style et la période.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | l'un des deux | Le titre de la page, écrit |
| entier, positif | l'un des deux | L'identifiant de page rendu par une recherche. |
En retour : chacune des caractéristiques ci-dessus, null quand la page la
laisse vide, et dans les termes de la page, donc ca.1830 reste ca.1830.
À côté viennent genre_categories, que browse_category reprend ;
external_links et authorities, les notices de l'œuvre au VIAF, à la LCCN, à
WorldCat, à la BNF et à la GND ; sections, avec le nombre d'entrées que le site
compte dans chacune ; et copyright_summary, une entrée par mention distincte,
avec le nombre d'éditions qui la portent. editions contient chaque édition et
ses fichiers, et passe à null avec editions_truncated à vrai au-delà de cinq
éditions, que list_work_files parcourt alors. redirected_from nomme le titre
demandé quand il a mené ici, et pageid vaut null pour une œuvre adressée par
son titre.
list_work_files
Lit les partitions et les enregistrements d'une œuvre, édition par édition. Une édition est un ensemble de fichiers publiés sous les mêmes conditions : l'éditeur, le réviseur et la mention de droits appartiennent à l'édition, et les fichiers se rangent dessous. Un bloc d'enregistrements porte des interprètes et aucune mention de droits.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | l'un des deux | Le titre de la page, écrit |
| entier, positif | l'un des deux | L'identifiant de page rendu par une recherche. |
| chaîne, 1 à 80 caractères | non | Une section de la page, dans ses propres termes : |
| entier, 1 à 100, défaut | non | Éditions à servir. |
| entier, 0 ou plus, défaut | non | Éditions à sauter. |
En retour : editions, chacune avec sa section, son publisher_info, son
editor, son copyright et ses files. Un fichier porte imslp_id,
description, format et format_code, pages, size_bytes, downloads,
rating, uploader, uploaded_on, le sigle et le nom de la bibliothèque qui l'a
numérisé, et blocked, vrai tant qu'IMSLP vérifie les droits de ce fichier.
downloads vaut null sur une entrée sans compteur, et rating vaut null
quand personne n'a voté. Viennent aussi editions_on_page,
editions_in_section, returned, has_more et sections. Une section qui ne
correspond à rien revient avec les sections que la page contient, donc une
restriction ne se lit jamais comme une œuvre sans partition.
list_person_works
Lit les œuvres que la bibliothèque classe sous une personne : ce qu'un compositeur a écrit, et aussi ce sur quoi un réviseur, un arrangeur ou un interprète est crédité.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | La catégorie de la personne, écrite |
| entier, 1 à 100, défaut | non | Lignes à servir. |
| chaîne, 1 à 500 caractères | non | Le |
En retour : des lignes portant page, work, composer, pageid et
page_url, avec has_more et cursor pour poursuivre. total vaut toujours
null : la bibliothèque ne publie aucun compte de ce que contient une catégorie.
Une catégorie qu'elle ne contient pas répond comme une catégorie vide, donc une
réponse sans ligne invite à vérifier l'orthographe avec search_people.
get_person
Lit ce que la bibliothèque contient sur une personne : le nom tel que sa page l'imprime, les dates de vie qu'elle indique, les autres noms sous lesquels elle la classe, les registres qui en tiennent une notice, et les adresses vers lesquelles elle renvoie hors du site.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | La catégorie de la personne, écrite |
En retour : category, catalogued_as avec le patronyme d'abord, name tel
que la page l'imprime, life_dates dans les termes de la page,
alternative_names et aliases comme lignes publiées, authorities avec le
registre et l'identifiant au VIAF, à la LCCN, à WorldCat, à la BNF et à la GND,
external_links, et page_url. life_dates vaut null sur une page qui n'en
indique aucune. Cet outil lit la personne ; list_person_works lit les œuvres.
browse_category
Lit les œuvres classées sous une catégorie : un genre, une tonalité, une
instrumentation ou une période. get_work rend ces noms pour une œuvre sous
genre_categories, et en redonner un atteint une catégorie que la bibliothèque
contient.
Argument | Type | Requis | Ce qu'il fait |
| chaîne, 1 à 300 caractères | oui | La catégorie à lire, dans les termes de la bibliothèque : |
| entier, 1 à 100, défaut | non | Lignes à servir. |
| chaîne, 1 à 500 caractères | non | Le |
En retour : les lignes que rend list_person_works, avec les mêmes
has_more et cursor, et total à null. La bibliothèque lit une catégorie à
la fois, donc une question nommant un genre et un instrument se répond en
parcourant l'un et en lisant l'autre sur chaque œuvre avec get_work.
Le statut de droits
Une partition porte sur IMSLP un statut par juridiction, et la bibliothèque
vérifie le Canada, les États-Unis et l'Union européenne. Un fichier marqué
Public Domain - Non-PD US est libre au Canada et dans l'Union européenne, et
protégé aux États-Unis. Ce serveur rend le statut tel qu'il est publié,
juridiction par juridiction, sous copyright_summary pour une œuvre et sous
copyright pour une édition, avec restrictions qui nomme les endroits qu'une
mention exclut. Un restrictions vide n'affirme rien sur les pays qu'IMSLP
laisse hors de sa vérification.
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. L'identité du projet est ajoutée pour qu'IMSLP puisse joindre une personne. |
|
| Écart entre deux requêtes, de 2000 à 60000. Une valeur sous le plancher est refusée au profit de celle-ci. |
|
| Délai d'une requête, de 1000 à 120000. |
|
| Tentatives après un échec passager, de 0 à 10. |
|
| Durée pendant laquelle une page reste en mémoire, de 0 à 86400000. |
|
| Pages gardées en mémoire à la fois, de 0 à 10000. |
|
|
|
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 |
| IMSLP a répondu, et la page demandée est absente. | Vérifiez le titre avec |
| Les arguments ont été refusés avant toute requête. | Lisez le message, qui nomme l'argument. |
| IMSLP demande à ce client de ralentir. | Attendez les secondes indiquées et rappelez avec les mêmes arguments. L'œuvre est toujours dans la bibliothèque. |
| La page a chargé et le contenu attendu est absent. | 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 IMSLP est publiée seule, avec son rythme, son cache et ses erreurs, sans protocole attaché.
import { ImslpClient } from "mcp-imslp/client";
const client = new ImslpClient();
const { data, cached } = await client.getWork({ page: "Nocturnes, Op.9 (Chopin, Frédéric)" });
console.log(data.title, data.copyright_summary, cached);renderPage, getWork, search, categoryMembers et getPerson répondent
chacun { data, cached }, et lèvent une ImslpError portant un des six codes.
Le plancher de deux secondes entre deux requêtes tient également ici.
Rythme et attribution
IMSLP publie Crawl-delay: 2 dans son robots.txt, donc les requêtes partent une
à une avec au moins deux secondes entre elles, et ce plancher tient quelle que
soit la configuration. Le User-Agent se termine toujours par l'identité du
projet et une adresse où joindre une personne.
Les lectures passent par l'API MediaWiki /api.php et par le point d'entrée
qu'IMSLP documente sur sa page IMSLP:API. Le robots.txt interdit /index.php,
/images/, /imglnks/, /wiki/File:, /works et /library/, et ce serveur ne
construit aucune adresse sous ces chemins : il rend le lien de la page de
l'œuvre, qui est ce qu'une réponse crédite.
La bibliothèque publie ses pages sous CC BY-SA 4.0, donc tout ce que ce serveur rend attribue à IMSLP et renvoie vers la page d'origine.
Confidentialité
Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur
votre machine, ne joint que imslp.org, 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 le site lui-même.
Contribuer
Les tickets et les propositions de modification sont bienvenus sur le dépôt. Voir CONTRIBUTING.md.
Licence
MIT, voir LICENSE. Le catalogue et les pages appartiennent à IMSLP et à ses contributeurs, publiés sous CC BY-SA 4.0.
Available Tools
7 toolsbrowse_categoryBrowse a categoryARead-onlyIdempotent
Read the works IMSLP files under a category: a genre, a key, an instrumentation or a period. The library writes these names itself, and get_work hands them back for a work under 'genre_categories': 'Nocturnes', 'For piano', 'Scores featuring the piano', 'B-flat minor'. Pass one of those rather than a name of your own, since a category the library does not hold answers exactly as an empty one does. The 'Category:' prefix may be left out. The library cannot cross two categories, so a question naming both a genre and an instrument is answered by browsing one and reading the other off each work. IMSLP publishes no count of what a category holds, so 'total' is always null; 'has_more' and 'cursor' say whether more rows remain and how to read them. When you show a work to a user, credit IMSLP and link the page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to serve, from 1 to 100. | |
| cursor | No | The 'cursor' a previous answer named, to read on from where it stopped. The library writes it itself, so it is passed back as it was given rather than built. | |
| category | Yes | The category to read, in the library's own wording, for example 'For piano', 'Nocturnes' or 'Category:B-flat minor'. The prefix is added when it is left out. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| notes | Yes | |
| total | Yes | Always null: IMSLP publishes no count of what a category holds. |
| cursor | Yes | The cursor to read on from, as the library named it. Null when it named none. |
| source | Yes | |
| license | Yes | |
| results | Yes | |
| category | Yes | The category as it reached the library, prefix included. |
| has_more | Yes | True when the library named a cursor to continue from. |
| returned | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only and idempotent annotations, the description discloses non-obvious behaviors: category names are library-controlled, missing categories return results indistinguishable from empty ones, the 'Category:' prefix is optional, cross-category queries are unsupported, 'total' is always null, and 'has_more'/'cursor' govern pagination. It also adds an attribution and linking requirement.
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 and every sentence carries a distinct, useful fact. It is somewhat dense and longer than strictly necessary for a listing tool, but the extra length is mostly justified by the category, empty-result, and pagination quirks.
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?
Together with the schema and annotations, the description covers what the tool does, where valid category names come from, how to handle missing categories and combinations, what pagination looks like, and how to credit IMSLP. Nothing needed to invoke the tool correctly is left unexplained.
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 the baseline is 3, but the description adds real value: category values should come from get_work and may omit the prefix, while cursor should be echoed back from a previous response rather than constructed. The limit parameter gains no extra explanation, which keeps this from 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 'Read the works IMSLP files under a category' and enumerates the category kinds (genre, key, instrumentation, period), making the tool’s job unambiguous. It also references get_work and distinguishes browsing a category from searching or fetching a single work.
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?
It gives clear guidance to pass category names from get_work rather than inventing them, explains that unknown categories behave like empty ones, and explicitly handles the common multi-category question by advising the agent to browse one category and read the other off each work. It does not explicitly name sibling alternatives like search_works, but the usage context is still clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_personRead a personARead-onlyIdempotent
Read what IMSLP holds about a person: the name as its page prints it, the life dates it states, the other names it files them under, the registers holding a record of them, and the addresses it points to off the site. The person is named by the category the library addresses them by, written 'Category:Surname, Forename', which search_people finds. The prefix may be left out. Life dates come back in the wording the page used, since the library writes '1861-1934' on one page and '4 March 1861 — 2 November 1934' on another, and a page holding none says so. This reads the person; list_person_works reads what they wrote. When you show a person to a user, credit IMSLP and link the page.
| Name | Required | Description | Default |
|---|---|---|---|
| category | Yes | The person's category, written 'Category:Surname, Forename', for example 'Category:Satie, Erik'. The prefix is added when it is left out. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | The name as the page prints it, which reads forename first. |
| notes | Yes | |
| source | Yes | |
| aliases | Yes | The aliases line as published, separated the same way. |
| license | Yes | |
| category | Yes | The category the library addresses them by. |
| page_url | Yes | |
| life_dates | Yes | The dates beside the name, exactly as published. Null when the page prints none. |
| authorities | Yes | |
| catalogued_as | Yes | The name without the prefix, surname first. |
| external_links | Yes | |
| alternative_names | Yes | The other names and transliterations the library files them under, as the line was published. It separates names with commas and a name written surname first carries one of its own, so the line is not cut into a list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even with readOnlyHint and related annotations covering safety, the description adds valuable behavioral context: date formatting varies by page, missing dates are explicitly reported, the category prefix may be omitted, and the output should credit IMSLP with a link. This goes well beyond what annotations or schema state.
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 contributes: result contents, category format, date-format caveat, sibling distinction, and attribution requirement. It is dense but not padded, though it could be slightly tightened without losing value.
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 output schema exists, the description sufficiently covers how to invoke the tool, what inputs are expected, the variability of life-date formatting, and even user-facing attribution instructions. Nothing critical for correct usage is missing.
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, but the description enriches the single parameter by explaining the category convention, the optional prefix, and how to obtain the category via search_people. This adds meaningful guidance beyond the schema's own text.
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 a specific verb ('Read') and resource ('what IMSLP holds about a person'), enumerating the exact facets returned: name, life dates, aliases, registers, and off-site addresses. It also distinguishes itself from the sibling list_person_works, making the tool's purpose unambiguous.
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?
It explicitly contrasts with list_person_works ('This reads the person; list_person_works reads what they wrote') and directs agents to search_people for finding the category. It does not enumerate every sibling exclusion, but it gives clear context for the main alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_workRead a workARead-onlyIdempotent
Read one work on IMSLP: its title and alternative titles, the composer, the opus and catalogue numbers, the year it was written and the year it was first published, the dedication, the key, the instrumentation, the style and period, and how many scores and recordings the page holds. Address a work by its page title, written 'Work (Composer)', for example 'Nocturnes, Op.9 (Chopin, Frédéric)', or by the page id. Dates and durations come back in the wording the page used: 'ca.1830' stays 'ca.1830', because a bare year would state a certainty the library declined to state. A facet the page leaves empty comes back null rather than guessed. A work holding a few editions comes back with them, files included. One holding many comes back with 'editions' null and 'editions_truncated' true, and list_work_files pages through them. The copyright of a score is stated per jurisdiction: 'Public Domain - Non-PD US' is free in Canada and the European Union and protected in the United States, so never report a score as public domain without saying where. No score file is downloaded or linked; the work page is what an answer links to. When you show a work to a user, credit IMSLP and link that page.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | The title of the work's page, written 'Work (Composer)', for example 'Nocturnes, Op.9 (Chopin, Frédéric)'. Pass this or 'pageid', not both. | |
| pageid | No | The page id a search returns. Pass this or 'page', not both. |
Output Schema
| Name | Required | Description |
|---|---|---|
| key | Yes | |
| notes | Yes | |
| title | Yes | |
| pageid | Yes | The number IMSLP gives the page. Known when the work was addressed by it, and null when it was addressed by title: a rendered page states its title and nothing else. |
| source | Yes | |
| license | Yes | |
| composer | Yes | |
| editions | Yes | Every edition the page holds, files included. Null when the work holds more of them than one answer carries, and list_work_files then pages through them. |
| language | Yes | |
| page_url | Yes | |
| sections | Yes | The sections of the page, with the number of entries the site counts in each. |
| movements | Yes | |
| dedication | Yes | |
| librettist | Yes | |
| page_title | Yes | |
| authorities | Yes | Records of the work in library catalogues: VIAF, LCCN, WorldCat, BNF, GND. |
| piece_style | Yes | |
| external_links | Yes | |
| composer_period | Yes | |
| instrumentation | Yes | |
| redirected_from | Yes | The title asked for, when it redirected here. |
| average_duration | Yes | |
| composition_year | Yes | As published, for example 'ca.1830'. |
| genre_categories | Yes | |
| alternative_title | Yes | |
| composer_page_url | Yes | |
| copyright_summary | Yes | The terms the scores of this work are published under, one entry per distinct statement, with the number of editions on the page carrying it. Stated whether or not the editions themselves fit in this answer. |
| extra_information | Yes | |
| first_performance | Yes | |
| first_publication | Yes | |
| editions_truncated | Yes | |
| opus_catalogue_number | Yes | |
| internal_catalogue_number | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already mark the tool as read-only, idempotent, and non-destructive, the description adds substantial behavior beyond them: dates preserve original wording, empty facets return null, edition truncation is disclosed, copyright is jurisdiction-dependent, and no score files are linked. These are exactly the behavioral nuances an agent needs.
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, covering addressing, truncation behavior, copyright caveats, and linking policy. It is front-loaded with the core purpose and then layers necessary edge-case behavior, making it well-suited to a nuanced read operation.
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 complexity, the availability of an output schema, and the annotation set, the description is complete. It tells the agent how to identify a work, what to expect for truncated editions, how to handle copyright statements, and what to link when presenting results. No critical calling guidance is missing.
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 description coverage is 100%, so the baseline is 3. The description repeats the page title format and the 'pass this or pageid, not both' rule already present in the schema, adding no new parameter-level meaning. It does not compensate beyond the schema because none is needed.
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 'Read one work on IMSLP' and enumerates exactly what fields come back, making the verb, resource, and scope explicit. It is clearly distinguished from siblings like search_works and list_work_files, which search or page through files rather than reading a single work.
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 gives concrete addressing instructions ('page title' vs 'page id') and explicitly points to list_work_files when a work has many editions and 'editions_truncated' is true. This provides a clear when-to-use-this vs when-to-use-that signal, including an alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_person_worksRead the works of a personARead-onlyIdempotent
Read the works IMSLP files under a person: what a composer wrote, and also what an editor, an arranger or a performer is credited on. The person is named by the category the library addresses them by, written 'Category:Surname, Forename', which search_people finds. The prefix may be left out. IMSLP publishes no count of what a category holds, so 'total' is always null; 'has_more' and 'cursor' say whether the library held more rows and how to read them. A category the library does not hold answers exactly as an empty one does, so an answer with no rows means one of the two rather than a person without works. When you show a work to a user, credit IMSLP and link the page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to serve, from 1 to 100. | |
| cursor | No | The 'cursor' a previous answer named, to read on from where it stopped. The library writes it itself, so it is passed back as it was given rather than built. | |
| category | Yes | The person's category, written 'Category:Surname, Forename', for example 'Category:Chopin, Frédéric'. The prefix is added when it is left out. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| notes | Yes | |
| total | Yes | Always null: IMSLP publishes no count of what a category holds. |
| cursor | Yes | The cursor to read on from, as the library named it. Null when it named none. |
| source | Yes | |
| license | Yes | |
| results | Yes | |
| category | Yes | The category as it reached the library, prefix included. |
| has_more | Yes | True when the library named a cursor to continue from. |
| returned | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this read-only and idempotent, and the description adds valuable edge-case behavior: total is always null because IMSLP publishes no count, has_more/cursor control pagination, and an unknown category returns exactly the same empty response as a known empty one. This materially affects how an agent should interpret results.
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 purpose, then covers important edge cases concisely. A small amount of redundancy with the schema (prefix may be omitted) keeps it from being perfectly compact, but every sentence contributes.
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?
For a list tool with an output schema, it explains pagination, the null total, the empty-category ambiguity, and the attribution requirement. An agent has enough behavioral context to call it correctly and interpret results without guessing.
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 the schema already documents category, limit, and cursor. The description adds context that category comes from search_people and that cursor relates to has_more, but it largely repeats schema-level detail rather than adding new parameter semantics.
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 a specific verb and resource: 'Read the works IMSLP files under a person', and expands scope to composer/editor/arranger/performer credits. This clearly distinguishes it from siblings like search_works, get_person, and list_work_files.
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?
It states the tool is for listing works credited to a person and explains that the person must be addressed by a category, which 'search_people finds'. It gives clear identification context but does not explicitly name exclusions or alternate tools to use instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_work_filesRead the editions of a workARead-onlyIdempotent
Read the scores and recordings a work on IMSLP holds, edition by edition. An edition is a set of files published under one set of terms: the publisher, the editor and the copyright statement belong to the edition, and its files are the entries under it. A block of recordings carries performers instead, and no copyright statement at all. Address the work by its page title, written 'Work (Composer)', or by its page id, and read it a page at a time with 'limit' and 'offset'. 'editions_on_page' counts the editions the page holds, so it says how far a reading can go. Restrict to one part of the page with 'section', using the names the page itself prints: 'Scores', 'Parts', 'Arrangements and Transcriptions', 'Recordings', 'Full Scores' and others. A restriction matching nothing comes back with the sections the page does hold rather than as a work without scores. The copyright of a score is stated per jurisdiction: 'Public Domain - Non-PD US' is free in Canada and the European Union and protected in the United States, so never report a score as public domain without saying where. No score file is downloaded or linked; the work page is what an answer links to. When you show an edition to a user, credit IMSLP and link that page.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | The title of the work's page, written 'Work (Composer)', for example 'Nocturnes, Op.9 (Chopin, Frédéric)'. Pass this or 'pageid', not both. | |
| limit | No | Editions to serve, from 1 to 100. | |
| offset | No | Editions to skip, for reading a work whose page holds many. | |
| pageid | No | The page id a search returns. Pass this or 'page', not both. | |
| section | No | One section of the page, in the wording the page prints: 'Scores', 'Parts', 'Recordings', 'Arrangements and Transcriptions', 'Full Scores', 'Synthesized/MIDI'. Matched without regard to case. Left out, every section is read. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| notes | Yes | |
| title | Yes | The work these editions belong to. |
| offset | Yes | |
| pageid | Yes | |
| source | Yes | |
| license | Yes | |
| section | Yes | The restriction this answer was read under. |
| composer | Yes | |
| editions | Yes | |
| has_more | Yes | |
| page_url | Yes | |
| returned | Yes | |
| sections | Yes | The sections of the page, with the number of entries the site counts in each. |
| page_title | Yes | |
| redirected_from | Yes | |
| editions_on_page | Yes | Editions the page holds, counted here rather than published by IMSLP. |
| editions_in_section | Yes | Editions left after the restriction, equal to 'editions_on_page' without one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already indicate read-only, idempotent, open-world, and non-destructive behavior, the description adds valuable behavioral detail: no score files are downloaded or linked, empty section restrictions return available sections, copyright must be reported by jurisdiction, and attribution is required. This goes well beyond the 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 longer than average but every sentence contributes practical guidance for a tool with five parameters and several edge cases. It is front-loaded with the core purpose, then moves through addressing, pagination, sections, copyright, and attribution in a logical order.
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?
For a tool with this complexity, the description covers all essential calling details: how to identify the work, pagination semantics, section restrictions, empty-result behavior, copyright caveats, and linking requirements. An output schema exists and supplies return structure, so the description does not need to restate return fields.
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 the schema already documents each parameter. The description adds real semantic value by defining what an edition is, explaining that editions_on_page bounds pagination, clarifying section value wording, and describing the empty-section fallback. It does not merely repeat the schema.
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 a specific action and resource: reading the scores and recordings a work on IMSLP holds, edition by edition. It clearly distinguishes this from siblings like search_works, get_work, and list_person_works by focusing on editions and files rather than work metadata or person-level listings.
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 gives concrete usage context: address the work by title or page id, paginate with limit and offset, and restrict by section using page-printed names. It does not explicitly name sibling alternatives or state when not to use this tool, but the context is clear enough for correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_peopleSearch the peopleARead-onlyIdempotent
Find the composers, editors, arrangers and performers of IMSLP by name. The library addresses a person by a category, written 'Category:Surname, Forename', and that is what list_person_works and get_person take. A name is written the library's own way, so searching finds it where guessing at the spelling does not. Some rows stand for another category rather than for a person: the library keeps a redirect for a name spelled differently, and 'redirect_to' names the category it leads to. Follow it rather than reading works under the redirect, which holds none. IMSLP publishes no count of what a search matched, so 'total' is always null. When you show a person to a user, credit IMSLP and link the page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to serve, from 1 to 50. | |
| query | Yes | What to look for among the people of the library. Words are matched across the page, not only titles. | |
| offset | No | Rows to skip, using the 'next_offset' a previous answer named. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| notes | Yes | |
| query | Yes | The search as it reached the library. |
| total | Yes | Always null: IMSLP publishes no count of what a search matched. |
| offset | Yes | |
| source | Yes | |
| license | Yes | |
| results | Yes | |
| has_more | Yes | True when the library named an offset to continue from. |
| returned | Yes | |
| next_offset | Yes | The offset to read on from, as the library named it. Null when it named none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description discloses meaningful behaviors: redirects appear as rows and should be followed rather than used for works, 'total' is always null because IMSLP provides no count, and attribution to IMSLP is required when displaying results. This significantly helps the agent interpret results.
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 each subsequent sentence earns its place by explaining redirects, count behavior, downstream usage, or attribution. It is detailed without becoming wasteful.
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 purpose, result interpretation, redirect handling, missing total counts, and how to use the result with sibling tools. With annotations indicating read-only behavior and an output schema present, nothing essential is missing for correct selection and invocation.
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 the baseline is 3, but the description adds useful query semantics: names use the library's own spelling, so searching is more reliable than guessing. It also explains the category format relevant to interpreting the query results, giving the agent a better mental model of what it is matching.
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 identifies the resource (people/contributors in IMSLP) and the action (search by name), and distinguishes it from search_works by focusing on person-oriented entities. It also clarifies that results are categories like 'Category:Surname, Forename', which is essential for downstream use.
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 explains why to use this search rather than guessing spellings, and tells the agent that the resulting category is what list_person_works and get_person consume. It does not explicitly contrast with search_works, but the context is clear enough for an agent to select the right tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_worksSearch the worksARead-onlyIdempotent
Search the works of IMSLP by title, by composer, or by words printed on their pages. Each row names the page of a work, which is how get_work and list_work_files address it: a title is written 'Work (Composer)', and the row splits it into the work and the person it names. IMSLP publishes no count of what a search matched, so 'total' is always null; 'has_more' and 'next_offset' say whether the library held more rows and where to read on from. A snippet is words taken from the page around the match. The library writes its pages in wikitext, so a snippet sometimes shows the name of a file rather than a sentence, and some rows carry none at all. The library titles a work in the language its composer used, so 'Die Zauberflöte' and not 'The Magic Flute', 'Sinfonia' and not 'Symphony'. A title translated into another language finds nothing, or finds only the works written about it: rows that look thin for a famous work are a sign the work sits under its original title, not that the library lacks it. Searching for a person by name finds the works naming them; search_people finds the person. When you show a result to a user, credit IMSLP and link the page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to serve, from 1 to 50. | |
| query | Yes | What to look for in the works of the library. Words are matched across the page, not only titles. | |
| offset | No | Rows to skip, using the 'next_offset' a previous answer named. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| notes | Yes | |
| query | Yes | The search as it reached the library. |
| total | Yes | Always null: IMSLP publishes no count of what a search matched. |
| offset | Yes | |
| source | Yes | |
| license | Yes | |
| results | Yes | |
| has_more | Yes | True when the library named an offset to continue from. |
| returned | Yes | |
| next_offset | Yes | The offset to read on from, as the library named it. Null when it named none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate a safe read-only operation, and the description adds valuable behavior beyond that: 'total' is always null, snippets may show filenames or be absent, wikitext can affect results, and attribution to IMSLP is required. No contradictions with the 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 information-dense, front-loading the core purpose and then adding caveats that materially affect result interpretation. Each paragraph earns its place, though it could be trimmed slightly without losing meaning.
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?
For a search tool with an output schema, the description covers query semantics, title-language pitfalls, pagination fields, snippet behavior, the relationship to sibling tools, and attribution requirements. Nothing essential for correct invocation and interpretation appears to be missing.
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 a baseline of 3 applies, but the description enriches query semantics by explaining that words are matched across the page, not only titles, and that titles are in the composer's original language. It also explains pagination through 'next_offset', adding meaning to the offset parameter beyond the schema's type and default.
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?
States a specific verb and resource: 'Search the works of IMSLP by title, by composer, or by words printed on their pages.' It also differentiates from search_people by explaining that searching a person finds works naming them while 'search_people finds the person,' so an agent can distinguish it from its sibling.
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?
Gives explicit usage context: searches by title, composer, or page text, and warns that translated titles find nothing, pointing users to the original title. It explicitly names the alternative for person lookups ('search_people finds the person'), telling the agent when not to use this tool.
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.
7 tool updates
v1.0.0- First observed
browse_category - First observed
get_person - First observed
get_work - First observed
list_person_works - First observed
list_work_files - First observed
search_people - First observed
search_works
TDQS
Scored across 7 tools
Each tool targets a clearly distinct resource and action: searching works vs people, fetching a single work/person, listing files, and browsing categories. Even where list_person_works and browse_category both return work lists, the descriptions make the boundary explicit.
All tool names follow a consistent verb_noun snake_case pattern: search_*, get_*, list_*, and browse_category. The pattern makes the intended operation and target predictable across the entire set.
Seven tools is well-scoped for an IMSLP access server, covering search, entity retrieval, file listing, and category browsing without redundancy. Each tool earns its place in the workflow.
The surface covers the full read-oriented workflow: discover works/people, fetch metadata, enumerate editions and files, and browse by category. The explicit choice not to download files or link them is consistent, and no major workflow dead-ends are evident.
Maintenance
Related MCP Connectors
Search YouTube, read video metadata, and fetch transcripts with language preferences
Academic literature search, retrieval, and private library management on top of OpenAlex.
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
Search arXiv/Semantic Scholar/OpenAlex + medical evidence (PubMed/Europe PMC) + LaTeX/PDF tools.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Spotify's music catalog through natural language conversations. Search for tracks and artists, get recommendations, explore playlists, and browse artist discographies using the Spotify Web API.-
- FlicenseNot gradedqualityDmaintenanceEnables users to search the YouTube Music catalog and manage playlists using natural language. It provides tools for searching songs, albums, and artists, as well as performing playlist operations like creating, adding, and deleting tracks.-
- FlicenseAqualityDmaintenanceEnables Claude AI to convert, edit, and analyze MuseScore files (.mscz, .musicxml, MIDI) through natural language commands, supporting format conversion, transposition, harmony analysis, and more.201-
- FlicenseNot gradedqualityCmaintenanceEnables music search, metadata retrieval, local audio analysis (tempo, key, energy), recommendations, song recognition, and classical work resolution via Spotify, Last.fm, AudD, MusicBrainz, and Songkick APIs.-