MCP Open Library

Un servidor del Protocolo de Contexto de Modelo (MCP) para la API de Open Library que permite a los asistentes de IA buscar información sobre libros y autores.

Documentación

MCP Open Library

MCP Registry Socket Badge Trust Score Listed on Spark NPM

Un servidor de Protocolo de Contexto de Modelo (MCP) para la API de Open Library que permite a los asistentes de IA buscar información sobre libros y autores.

mcp-open-library MCP server

Descripción general

Este proyecto implementa un servidor MCP que proporciona herramientas para que los asistentes de IA interactúen con Open Library. Permite buscar en el catálogo por título, autor, materia y otros campos, buscar autores por nombre, recuperar información detallada de autores usando su clave de Open Library y obtener URL de portadas de libros y fotos de autores. El servidor devuelve proyecciones JSON de las respuestas de Open Library en lugar de los datos brutos.

Características

  • Búsqueda de libros: Busca en títulos, autores, materias, lugares, personas, editoriales e ISBN, con ordenación y paginación (search_books).
  • Búsqueda de libros por título: Busca libros usando su título (get_book_by_title).
  • Búsqueda de autores por nombre: Busca autores usando su nombre, con paginación (get_authors_by_name).
  • Obtener detalles de autor: Recupera información detallada de un autor específico usando su clave de Open Library (get_author_info).
  • Obtener foto de autor: Obtiene la URL de la foto de un autor usando su ID de Open Library (OLID) (get_author_photo).
  • Obtener portada de libro: Obtiene la URL de la imagen de portada de un libro usando varios identificadores (ISBN, OCLC, LCCN, OLID, ID) (get_book_cover).
  • Obtener libro por ID: Recupera información detallada del libro usando varios identificadores (ISBN, LCCN, OCLC, OLID) (get_book_by_id).

Los resultados de búsqueda están paginados: cada herramienta de búsqueda devuelve como máximo limit resultados (10 por defecto, máximo 50) junto con num_found, el número total de coincidencias, que se recorren con offset (máximo 1000). Las dos herramientas de portadas comprueban que la imagen realmente existe y lo indican cuando no es así, en lugar de devolver una URL que resuelve a un marcador de posición en blanco.

Cada herramienta es una consulta de solo lectura y se anuncia como tal con las anotaciones readOnlyHint y openWorldHint, lo que puede permitir que un cliente omita el mensaje de confirmación que muestra para herramientas que podrían cambiar algo. Estas son sugerencias: la especificación MCP indica que los clientes tratan las anotaciones como no confiables a menos que el servidor sea confiable, por lo que la política de confirmación la decide el cliente. Los fallos (una API inalcanzable, un argumento rechazado) se devuelven como un resultado de herramienta marcado con isError, de modo que un asistente pueda leer qué salió mal y corregir su siguiente llamada en lugar de que la solicitud falle por completo.

Instalación

Inicio rápido

Nada que instalar o compilar. Apunta un cliente MCP al paquete con npx y se obtendrá en la primera ejecución:

{
  "mcpServers": {
    "mcp-open-library": {
      "command": "npx",
      "args": ["-y", "mcp-open-library"]
    }
  }
}

En Claude Desktop eso va en claude_desktop_config.json; otros clientes usan la misma estructura. Reinicia el cliente y las siete herramientas siguientes estarán disponibles.

Registro MCP

Este servidor se publica en el Registro MCP oficial como io.github.8enSmith/mcp-open-library a partir de la v1.0.3. Los clientes que admiten el registro pueden instalarlo con ese nombre.

Para inspeccionar la publicación:

curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.8enSmith/mcp-open-library"

Instalación manual

# Clone the repository
git clone https://github.com/8enSmith/mcp-open-library.git
cd mcp-open-library

# Install dependencies
npm install

# Build the project
npm run build

Uso

Ejecutar el servidor

  1. Asegúrate de estar ejecutando node v22.21.1 (probablemente funcione en una versión más reciente de node, pero es la que estoy usando para esta prueba). Si tienes nvm instalado, ejecuta nvm use.
  2. En el directorio raíz de mcp-open-library ejecuta npm run build
  3. A continuación ejecuta npm run inspector. Una vez compilado, haz clic en la URL con el parámetro de cadena de consulta MCP_PROXY_AUTH_TOKEN para abrir el Inspector.
  4. En el Inspector, elige el transporte 'STDIO'
  5. Asegúrate de que el comando esté configurado como 'build/index.js'
  6. Haz clic en el botón 'Connect' en el Inspector: te conectarás al servidor
  7. Haz clic en 'Tools' en la barra de menú superior derecha
  8. Intenta ejecutar una herramienta, por ejemplo, haz clic en get_book_by_title
  9. Busca un libro, por ejemplo, en el cuadro de título ingresa 'The Hobbit' y luego haz clic en 'Run Tool'. El servidor devolverá los detalles del libro.

Uso con un cliente MCP

Este servidor implementa el Protocolo de Contexto de Modelo, lo que significa que puede ser utilizado por cualquier asistente o cliente de IA compatible con MCP, por ejemplo, Claude Desktop. El servidor expone las siguientes herramientas:

  • search_books: Busca en el catálogo por cualquier combinación de consulta, título, autor, materia, lugar, persona, editorial e ISBN
  • get_book_by_title: Busca información de libros por título
  • get_authors_by_name: Busca información de autores por nombre
  • get_author_info: Obtiene información detallada de un autor específico usando su Clave de Autor de Open Library
  • get_author_photo: Obtiene la URL de la foto de un autor usando su ID de Autor de Open Library (OLID)
  • get_book_cover: Obtiene la URL de la imagen de portada de un libro usando un identificador específico (ISBN, OCLC, LCCN, OLID o ID)
  • get_book_by_id: Obtiene información detallada del libro usando un identificador específico (ISBN, LCCN, OCLC u OLID)

Ejemplo de entrada de search_books:

{
  "author": "Ursula K. Le Guin",
  "subject": "fantasy",
  "sort": "old",
  "limit": 2
}

Ejemplo de salida de search_books:

{
  "num_found": 51,
  "offset": 0,
  "limit": 2,
  "results": [
    {
      "title": "A Wizard of Earthsea",
      "authors": ["Ursula K. Le Guin"],
      "first_publish_year": 1968,
      "open_library_work_key": "/works/OL59798W",
      "edition_count": 87,
      "author_keys": ["OL31353A"],
      "best_edition": {
        "edition_key": "OL5613890M"
      },
      "cover_url": "https://covers.openlibrary.org/b/id/13617691-M.jpg",
      "ratings_average": 3.95,
      "ebook_access": "borrowable"
    }
  ]
}

best_edition es una edición específica de la obra: la que Open Library clasifica mejor para tu consulta, con los identificadores propios de esa edición. Los resultados de búsqueda, por lo demás, identifican una obra (open_library_work_key), que ninguna herramienta acepta, por lo que esta es la ruta desde un resultado de búsqueda hasta un libro concreto.

Su edition_key es un OLID que puedes pasar directamente a get_book_by_id para obtener el registro completo de la edición, incluidos sus arrays completos de ISBN:

{ "idType": "olid", "idValue": "OL5613890M" }

Los campos isbn_13 / isbn_10 se omiten cuando Open Library no tiene ISBN para esa edición, como en el ejemplo anterior y en aproximadamente un tercio de los resultados, mientras que edition_key está prácticamente siempre presente. Cuando una edición lista varios ISBN del mismo tipo, se informa del primero; get_book_by_id los devuelve todos.

La herramienta search_books acepta los siguientes parámetros:

  • Al menos uno de q, title, author, subject, place, person, publisher o isbn: la solicitud se rechaza sin uno, ya que una búsqueda sin filtros coincide con todo el catálogo. q acepta una consulta Solr de forma libre como subject:cyberpunk AND first_publish_year:[1980 TO 1990]
  • language: Código de idioma MARC opcional de 3 letras (por ejemplo, eng, fre)
  • sort: Ordenación opcional: new, old, random, key, rating, readinglog, want_to_read, currently_reading, already_read o title. Omítelo para relevancia
  • limit: Opcional, 1–50, por defecto 10
  • offset: Opcional, 0–1000, por defecto 0

Ejemplo de entrada de get_book_by_title:

{
  "title": "The Hobbit",
  "limit": 1
}

Ejemplo de salida de get_book_by_title:

{
  "num_found": 224,
  "offset": 0,
  "limit": 1,
  "results": [
    {
      "title": "The Hobbit",
      "authors": ["J.R.R. Tolkien"],
      "first_publish_year": 1937,
      "open_library_work_key": "/works/OL27482W",
      "edition_count": 481,
      "author_keys": ["OL26320A"],
      "best_edition": {
        "edition_key": "OL51709286M",
        "isbn_13": "9780395520215",
        "isbn_10": "0395520215"
      },
      "cover_url": "https://covers.openlibrary.org/b/id/14627509-M.jpg",
      "ratings_average": 4.29,
      "ebook_access": "borrowable"
    }
  ]
}

Ejemplo de entrada de get_authors_by_name:

{
  "name": "J. R. R. Tolkien",
  "limit": 2
}

Ejemplo de salida de get_authors_by_name:

El key de cada resultado se puede pasar a get_author_info para obtener el registro completo de ese autor. alternate_names está abreviado aquí.

{
  "num_found": 2,
  "offset": 0,
  "limit": 2,
  "results": [
    {
      "key": "OL26320A",
      "name": "J.R.R. Tolkien",
      "alternate_names": ["John Ronald Reuel Tolkien", "Tolkien"],
      "birth_date": "3 January 1892",
      "top_work": "The Hobbit",
      "work_count": 355
    },
    {
      "key": "OL332676A",
      "name": "J. R. R. Tolkien Centenary Conference (1992 Keble College, Oxford)",
      "top_work": "Proceedings of the J.R.R. Tolkien Centenary Conference, 1992",
      "work_count": 2
    }
  ]
}

Ejemplo de entrada de get_author_info:

{
  "author_key": "OL26320A"
}

Ejemplo de salida de get_author_info:

{
  "name": "J. R. R. Tolkien",
  "personal_name": "John Ronald Reuel Tolkien",
  "birth_date": "3 January 1892",
  "death_date": "2 September 1973",
  "bio": "John Ronald Reuel Tolkien (1892-1973) was a major scholar of the English language, specializing in Old and Middle English. He served as the Rawlinson and Bosworth Professor of Anglo-Saxon and later the Merton Professor of English Language and Literature at Oxford University.",
  "alternate_names": ["John Ronald Reuel Tolkien"],
  "photos": [6791763],
  "key": "/authors/OL26320A",
  "remote_ids": {
    "viaf": "95218067",
    "wikidata": "Q892"
  },
  "revision": 43,
  "last_modified": {
    "type": "/type/datetime",
    "value": "2023-02-12T05:50:22.881"
  }
}

Ejemplo de entrada de get_author_photo:

{
  "olid": "OL26320A"
}

Ejemplo de salida de get_author_photo:

https://covers.openlibrary.org/a/olid/OL26320A-L.jpg

Cuando Open Library no tiene foto para ese autor, la herramienta lo indica en lugar de devolver una URL:

No author photo available for OLID OL99999999A.

Ejemplo de entrada de get_book_cover:

{
  "key": "ISBN",
  "value": "9780547928227",
  "size": "L"
}

Ejemplo de salida de get_book_cover:

https://covers.openlibrary.org/b/isbn/9780547928227-L.jpg

Al igual que con las fotos de autores, un libro sin portada produce un mensaje en lugar de una URL:

No cover image available for OLID OL00000000M.

La herramienta get_book_cover acepta los siguientes parámetros:

  • key: El tipo de identificador (uno de: ISBN, OCLC, LCCN, OLID o ID)
  • value: El valor del identificador
  • size: Tamaño de portada opcional (S para pequeño, M para mediano, L para grande, por defecto L)

Ejemplo de entrada de get_book_by_id:

{
  "idType": "isbn",
  "idValue": "9780547928227"
}

Ejemplo de salida de get_book_by_id:

{
  "title": "The Hobbit",
  "authors": [
    "J. R. R. Tolkien"
  ],
  "publishers": [
    "Houghton Mifflin Harcourt"
  ],
  "publish_date": "October 21, 2012",
  "number_of_pages": 300,
  "isbn_13": [
    "9780547928227"
  ],
  "isbn_10": [
    "054792822X"
  ],
  "oclc": [
    "794607877"
  ],
  "olid": [
    "OL25380781M"
  ],
  "open_library_edition_key": "/books/OL25380781M",
  "open_library_work_key": "/works/OL45883W",
  "cover_url": "https://covers.openlibrary.org/b/id/8231496-M.jpg",
  "info_url": "https://openlibrary.org/books/OL25380781M/The_Hobbit",
  "preview_url": "https://archive.org/details/hobbit00tolkien"
}

La herramienta get_book_by_id acepta los siguientes parámetros:

  • idType: El tipo de identificador (uno de: isbn, lccn, oclc, olid)
  • idValue: El valor del identificador

Un ejemplo de esta herramienta usada en Claude Desktop se puede ver aquí:

image

Docker

Puedes probar este servidor MCP usando Docker. Para ello, primero ejecuta:

docker build -t mcp-open-library .
docker run -p 8080:8080 mcp-open-library

Luego puedes probar el servidor ejecutándose dentro de Docker mediante el inspector, por ejemplo:

npm run inspector http://localhost:8080

Desarrollo

Estructura del proyecto

  • src/index.ts - El servidor MCP: construye los clientes HTTP y maneja ambos manejadores de solicitudes desde el registro de herramientas
  • src/index.test.ts - Pruebas para el cableado del servidor, incluida una instantánea de los esquemas de herramientas publicados
  • src/tools/<tool-name>/ - Un directorio por herramienta, cada uno con index.ts (el manejador, su esquema de argumentos Zod y su ToolDefinition), index.test.ts y, para herramientas con una respuesta de API no trivial, un types.ts que describe esa forma de respuesta
  • src/tools/registry.ts - El array TOOLS, la lista única de lo que expone el servidor
  • src/tools/types.ts - Los contratos ToolDefinition y ToolHandler
  • src/utils/ - Infraestructura compartida: http.ts (los clientes Axios de API y portadas), errors.ts (análisis de argumentos y resultados de error), results.ts, schema.ts (Zod → JSON Schema), search.ts (la proyección de búsqueda compartida y los esquemas de paginación), covers.ts
  • scripts/ - Automatización de lanzamientos (sync-server-json.mjs, promote-changelog.mjs, assert-release-consistency.mjs) y sus pruebas

El contrato de entrada de una herramienta se declara una sola vez, como un esquema Zod. El JSON Schema que ven los clientes MCP se genera a partir de él mediante toInputSchema, por lo que no pueden divergir. Las descripciones de campos provienen de .describe() en el esquema Zod. Ten en cuenta que las restricciones de .refine() se omiten en la traducción: una regla entre campos debe indicarse también en el description de la herramienta, o los clientes nunca se enterarán de ella.

Agregar una herramienta implica crear el directorio y agregar una entrada a TOOLS en src/tools/registry.ts. src/index.test.ts deriva sus expectativas de ese array, por lo que el único cambio de prueba es una instantánea de esquema actualizada (npx vitest run -u).

Scripts disponibles

  • npm run build - Compila el código TypeScript
  • npm run watch - Observa cambios y recompila
  • npm test - Ejecuta la suite de pruebas en modo de observación
  • npm run test:precommit - Ejecuta la suite de pruebas una vez y sale
  • npm run lint / npm run lint:fix - Lint de src y scripts con ESLint
  • npm run format - Formatea el código con Prettier
  • npm run inspector - Ejecuta el Inspector MCP contra el servidor

Ejecutar pruebas

npm test inicia Vitest en modo de observación:

npm test

Para una sola pasada (lo que ejecutan el hook de pre-commit y CI), usa:

npm run test:precommit

Para ejecutar un archivo o un caso de prueba:

npx vitest run src/tools/get-book-by-id/index.test.ts
npx vitest run -t "should return book details when given a valid OLID"

Lanzamientos

Los lanzamientos están automatizados. Pulsar una etiqueta v* activa publish-mcp.yml, que ejecuta las comprobaciones, publica el paquete en npm, registra la nueva versión en el Registro MCP y luego crea un Lanzamiento de GitHub usando la sección CHANGELOG.md de esa versión como notas. Tanto npm como el registro se autentican mediante GitHub OIDC, por lo que no hay secretos de publicación que gestionar.

El version de package.json es la única fuente de verdad. npm version deriva todo lo demás de él mediante un hook de ciclo de vida version, por lo que un lanzamiento es un solo comando:

npm version patch   # or minor / major
git push --follow-tags

Ese único comando incrementa package.json, reescribe server.json para que coincida, promueve el encabezado ## [Unreleased] del changelog a la nueva versión y la fecha de hoy, y confirma todo bajo una sola etiqueta. Dos cosas que debes saber antes de ejecutarlo:

  • Escribe primero tus entradas de changelog. Van bajo un encabezado ## [Unreleased] en CHANGELOG.md a medida que fusionas trabajo. npm version falla si falta ese encabezado, en lugar de publicar algo sin documentar. Si falla, deshaz el incremento parcial con git restore --source=HEAD --staged --worktree package.json package-lock.json server.json.
  • El árbol de trabajo debe estar limpio, y el hook de pre-commit (lint + suite de pruebas completa) se ejecuta dentro de npm version.

CI vuelve a verificar que la etiqueta, package.json, server.json y CHANGELOG.md coincidan antes de publicar cualquier cosa — consulta scripts/assert-release-consistency.mjs. La misma verificación se ejecuta en pull requests que tocan esos archivos.

npm version no es un reintento

Una vez que imprime la nueva etiqueta, el commit y la etiqueta existen y el lanzamiento está hecho localmente — el siguiente paso es git push --follow-tags, no ejecutar npm version de nuevo. Una segunda ejecución intenta la versión siguiente, y fallará por el encabezado ## [Unreleased] faltante (que la primera ejecución consumió). Ese fallo es seguro por diseño, pero deja package.json, package-lock.json y server.json incrementados y sin commit. Deshazlo con:

git restore --source=HEAD --staged --worktree package.json package-lock.json server.json

Si el flujo de trabajo de publicación falla

Re-ejecutar el trabajo desde la pestaña de Actions solo ayuda con un fallo transitorio. GitHub ejecuta el flujo de trabajo tal como existía en el commit etiquetado, por lo que un error en el propio flujo de trabajo o en server.json no puede solucionarse con una re-ejecución — la corrección debe estar en el commit al que apunta la etiqueta.

Nada se publica hasta que el flujo de trabajo llega a su paso de npm, así que si falló antes de eso, la versión sigue libre y puedes mover la etiqueta:

# fix the problem on main and commit it first
VERSION="$(node -p "require('./package.json').version")"

git push origin ":v${VERSION}"            # delete the remote tag e.g. git push origin :v1.0.3
git tag -d "v${VERSION}"                  # delete it locally
git tag -a "v${VERSION}" -m "${VERSION}"  # re-tag at the fixed commit
git push origin "v${VERSION}"

El commit de corrección debe dejar package.json en esa misma versión, o la verificación de consistencia rechazará la etiqueta. Si npm ya publicó, no reutilices la versión — ese lanzamiento es inmutable. Incrementa a la siguiente versión de parche en su lugar; el paso de npm protegido significa que una re-ejecución omite lo que ya tuvo éxito.

Contribuciones

¡Las contribuciones son bienvenidas! No dudes en enviar un pull request.

Agradecimientos