MCP Open Library

Um servidor Model Context Protocol (MCP) para a API do Open Library que permite que assistentes de IA pesquisem informações sobre livros e autores.

Documentação

MCP Open Library

MCP Registry Socket Badge Trust Score Listed on Spark NPM

Um servidor Model Context Protocol (MCP) para a API Open Library que permite que assistentes de IA pesquisem informações sobre livros e autores.

mcp-open-library MCP server

Visão Geral

Este projeto implementa um servidor MCP que fornece ferramentas para assistentes de IA interagirem com a Open Library. Ele permite pesquisar no catálogo por título, autor, assunto e outros campos, pesquisar autores por nome, obter informações detalhadas de autores usando sua chave Open Library e obter URLs para capas de livros e fotos de autores. O servidor retorna projeções JSON das respostas da Open Library em vez dos payloads brutos.

Recursos

  • Pesquisa de Livros: Pesquise em títulos, autores, assuntos, locais, pessoas, editoras e ISBNs, com ordenação e paginação (search_books).
  • Pesquisa de Livros por Título: Pesquise livros usando seu título (get_book_by_title).
  • Pesquisa de Autores por Nome: Pesquise autores usando seu nome, com paginação (get_authors_by_name).
  • Obter Detalhes do Autor: Recupere informações detalhadas de um autor específico usando sua chave Open Library (get_author_info).
  • Obter Foto do Autor: Obtenha a URL da foto de um autor usando seu ID Open Library (OLID) (get_author_photo).
  • Obter Capa do Livro: Obtenha a URL da imagem da capa de um livro usando vários identificadores (ISBN, OCLC, LCCN, OLID, ID) (get_book_cover).
  • Obter Livro por ID: Recupere informações detalhadas do livro usando vários identificadores (ISBN, LCCN, OCLC, OLID) (get_book_by_id).

Os resultados da pesquisa são paginados — cada ferramenta de pesquisa retorna no máximo limit resultados (padrão 10, máximo 50) juntamente com num_found, o número total de correspondências, que você percorre com offset (máximo 1000). As duas ferramentas de capa verificam se uma imagem realmente existe e informam quando não existe, em vez de devolver uma URL que resolve para um espaço reservado em branco.

Cada ferramenta é uma consulta somente leitura e se anuncia como tal com as anotações readOnlyHint e openWorldHint, o que pode permitir que um cliente ignore o prompt de confirmação que mostra para ferramentas que poderiam alterar algo. Estas são dicas: a especificação MCP faz com que os clientes tratem as anotações como não confiáveis, a menos que o servidor seja confiável, então a política de confirmação é decisão do cliente. Falhas — uma API inacessível, um argumento rejeitado — retornam como um resultado de ferramenta sinalizado como isError, para que um assistente possa ler o que deu errado e corrigir sua próxima chamada em vez de a solicitação falhar completamente.

Instalação

Início Rápido

Nada para instalar ou compilar. Aponte um cliente MCP para o pacote com npx e ele será buscado na primeira execução:

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

No Claude Desktop isso vai em claude_desktop_config.json; outros clientes usam a mesma estrutura. Reinicie o cliente e as sete ferramentas abaixo ficam disponíveis.

Registro MCP

Este servidor publica no Registro MCP oficial como io.github.8enSmith/mcp-open-library a partir da v1.0.3. Clientes que suportam o registro podem instalá-lo por esse nome.

Para inspecionar a listagem publicada:

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

Instalação 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

Executando o Servidor

  1. Certifique-se de estar executando o node v22.21.1 (provavelmente funcionará em uma versão mais recente do node, mas é o que estou usando para este teste). Se você tiver nvm instalado, execute nvm use.
  2. No diretório raiz mcp-open-library, execute npm run build
  3. Em seguida, execute npm run inspector. Após a compilação, clique na URL com o parâmetro de string de consulta MCP_PROXY_AUTH_TOKEN para abrir o Inspector.
  4. No Inspector, escolha o transporte 'STDIO'
  5. Certifique-se de que o comando esteja definido como 'build/index.js'
  6. Clique no botão 'Connect' no Inspector — você se conectará ao servidor
  7. Clique em 'Tools' na barra de menu superior direita
  8. Tente executar uma ferramenta, por exemplo, clique em get_book_by_title
  9. Pesquise um livro, por exemplo, no campo de título digite 'The Hobbit' e clique em 'Run Tool'. O servidor retornará os detalhes do livro.

Usando com um Cliente MCP

Este servidor implementa o Model Context Protocol, o que significa que pode ser usado por qualquer assistente de IA ou cliente compatível com MCP, por exemplo, Claude Desktop. O servidor expõe as seguintes ferramentas:

  • search_books: Pesquise no catálogo por qualquer combinação de consulta, título, autor, assunto, local, pessoa, editora e ISBN
  • get_book_by_title: Pesquise informações de livros por título
  • get_authors_by_name: Pesquise informações de autores por nome
  • get_author_info: Obtenha informações detalhadas de um autor específico usando sua Chave de Autor Open Library
  • get_author_photo: Obtenha a URL da foto de um autor usando seu ID de Autor Open Library (OLID)
  • get_book_cover: Obtenha a URL da imagem da capa de um livro usando um identificador específico (ISBN, OCLC, LCCN, OLID ou ID)
  • get_book_by_id: Obtenha informações detalhadas do livro usando um identificador específico (ISBN, LCCN, OCLC ou OLID)

Exemplo de entrada search_books:

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

Exemplo de saída 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 é uma edição específica da obra — aquela que a Open Library classifica melhor para sua consulta — carregando os identificadores próprios dessa edição. Os resultados da pesquisa, caso contrário, identificam uma obra (open_library_work_key), que nenhuma ferramenta aceita, então esta é a rota de um resultado de pesquisa para um livro concreto.

Seu edition_key é um OLID que você pode passar diretamente para get_book_by_id para obter o registro completo da edição, incluindo seus arrays completos de ISBN:

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

Os campos isbn_13 / isbn_10 são omitidos quando a Open Library não possui ISBN para aquela edição — como no exemplo acima, e em aproximadamente um terço dos resultados — enquanto edition_key está essencialmente sempre presente. Quando uma edição lista vários ISBNs de um tipo, o primeiro é relatado; get_book_by_id retorna todos eles.

A ferramenta search_books aceita os seguintes parâmetros:

  • Pelo menos um de q, title, author, subject, place, person, publisher ou isbn — a solicitação é rejeitada sem um, pois uma pesquisa sem filtro corresponde ao catálogo inteiro. q aceita uma consulta Solr de forma livre, como subject:cyberpunk AND first_publish_year:[1980 TO 1990]
  • language: Código de idioma MARC opcional de 3 letras (por exemplo, eng, fre)
  • sort: Ordenação opcional — new, old, random, key, rating, readinglog, want_to_read, currently_reading, already_read ou title. Omita para relevância
  • limit: Opcional, 1–50, padrão 10
  • offset: Opcional, 0–1000, padrão 0

Exemplo de entrada get_book_by_title:

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

Exemplo de saída 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"
    }
  ]
}

Exemplo de entrada get_authors_by_name:

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

Exemplo de saída get_authors_by_name:

O key de cada resultado pode ser passado para get_author_info para obter o registro completo desse autor. alternate_names é abreviado aqui.

{
  "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
    }
  ]
}

Exemplo de entrada get_author_info:

{
  "author_key": "OL26320A"
}

Exemplo de saída 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"
  }
}

Exemplo de entrada get_author_photo:

{
  "olid": "OL26320A"
}

Exemplo de saída get_author_photo:

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

Quando a Open Library não tem foto para esse autor, a ferramenta informa isso em vez de retornar uma URL:

No author photo available for OLID OL99999999A.

Exemplo de entrada get_book_cover:

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

Exemplo de saída get_book_cover:

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

Assim como nas fotos de autores, um livro sem capa produz uma mensagem em vez de uma URL:

No cover image available for OLID OL00000000M.

A ferramenta get_book_cover aceita os seguintes parâmetros:

  • key: O tipo de identificador (um de: ISBN, OCLC, LCCN, OLID ou ID)
  • value: O valor do identificador
  • size: Tamanho da capa opcional (S para pequeno, M para médio, L para grande, padrão L)

Exemplo de entrada get_book_by_id:

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

Exemplo de saída 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"
}

A ferramenta get_book_by_id aceita os seguintes parâmetros:

  • idType: O tipo de identificador (um de: isbn, lccn, oclc, olid)
  • idValue: O valor do identificador

Um exemplo desta ferramenta sendo usada no Claude Desktop pode ser visto aqui:

image

Docker

Você pode testar este servidor MCP usando Docker. Para fazer isso, primeiro execute:

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

Você pode então testar o servidor rodando dentro do Docker via o inspector, por exemplo:

npm run inspector http://localhost:8080

Desenvolvimento

Estrutura do Projeto

  • src/index.ts - O servidor MCP: constrói os clientes HTTP e aciona ambos os manipuladores de solicitação a partir do registro de ferramentas
  • src/index.test.ts - Testes para a fiação do servidor, incluindo um snapshot dos esquemas de ferramentas publicados
  • src/tools/<tool-name>/ - Um diretório por ferramenta, cada um contendo index.ts (o manipulador, seu esquema de argumentos Zod e seu ToolDefinition), index.test.ts e — para ferramentas com uma resposta de API não trivial — um types.ts descrevendo essa forma de resposta
  • src/tools/registry.ts - O array TOOLS, a lista única do que o servidor expõe
  • src/tools/types.ts - Os contratos ToolDefinition e ToolHandler
  • src/utils/ - Infraestrutura compartilhada: http.ts (os clientes Axios da API e de capas), errors.ts (análise de argumentos e resultados de erro), results.ts, schema.ts (Zod → JSON Schema), search.ts (a projeção de pesquisa compartilhada e esquemas de paginação), covers.ts
  • scripts/ - Automação de lançamento (sync-server-json.mjs, promote-changelog.mjs, assert-release-consistency.mjs) e seus testes

O contrato de entrada de uma ferramenta é declarado uma vez, como um esquema Zod. O JSON Schema que os clientes MCP veem é gerado a partir dele por toInputSchema, então os dois não podem divergir. As descrições de campos vêm de .describe() no esquema Zod. Observe que as restrições .refine() são descartadas na tradução — uma regra entre campos precisa ser declarada também no description da ferramenta, ou os clientes nunca ficarão sabendo dela.

Adicionar uma ferramenta significa criar o diretório e adicionar uma entrada ao TOOLS em src/tools/registry.ts. src/index.test.ts deriva suas expectativas desse array, então a única mudança de teste é um snapshot de esquema atualizado (npx vitest run -u).

Scripts Disponíveis

  • npm run build - Compilar o código TypeScript
  • npm run watch - Observar mudanças e recompilar
  • npm test - Executar a suíte de testes em modo de observação
  • npm run test:precommit - Executar a suíte de testes uma vez e sair
  • npm run lint / npm run lint:fix - Lint src e scripts com ESLint
  • npm run format - Formatar código com Prettier
  • npm run inspector - Executar o MCP Inspector contra o servidor

Executando Testes

npm test inicia o Vitest em modo de observação:

npm test

Para uma única execução — o que o hook de pré-commit e o CI executam — use:

npm run test:precommit

Para executar um arquivo ou um caso de teste:

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"

Lançamento

Os lançamentos são automatizados. Enviar uma tag v* aciona publish-mcp.yml, que executa as verificações, publica o pacote no npm, registra a nova versão no Registro MCP e então cria um GitHub Release usando a seção CHANGELOG.md dessa versão como notas. Tanto o npm quanto o registro autenticam via GitHub OIDC, então não há segredos de publicação para gerenciar.

O version de package.json é a fonte única de verdade. npm version deriva todo o resto dele via um hook de ciclo de vida version, então um lançamento é um único comando:

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

Esse único comando incrementa package.json, reescreve server.json para corresponder, promove o cabeçalho ## [Unreleased] do changelog para a nova versão e a data de hoje, e confirma tudo sob uma única tag. Duas coisas para saber antes de executar:

  • Escreva suas entradas de changelog primeiro. Elas ficam sob um título ## [Unreleased] em CHANGELOG.md conforme você integra o trabalho. npm version falha se esse título estiver ausente, em vez de publicar algo sem documentação. Se falhar, desfaça o incremento parcial com git restore --source=HEAD --staged --worktree package.json package-lock.json server.json.
  • A árvore de trabalho deve estar limpa, e o hook de pré-commit (lint + suíte de testes completa) é executado dentro de npm version.

O CI reafirma que a tag, package.json, server.json e CHANGELOG.md estão todos de acordo antes de qualquer coisa ser publicada — veja scripts/assert-release-consistency.mjs. A mesma verificação é executada em pull requests que alteram esses arquivos.

npm version não é uma repetição

Assim que ele imprime a nova tag, o commit e a tag existem e o release está concluído localmente — o próximo passo é git push --follow-tags, não executar npm version novamente. Uma segunda execução tenta a versão seguinte e falhará no título ## [Unreleased] ausente (que a primeira execução consumiu). Essa falha é segura por design, mas deixa package.json, package-lock.json e server.json incrementados e não commitados. Desfaça com:

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

Se o workflow de publicação falhar

Reexecutar o job na aba Actions só ajuda em uma falha transitória. O GitHub executa o workflow como ele existia no commit da tag, então um bug no próprio workflow ou no server.json não pode ser corrigido por uma reexecução — a correção precisa estar no commit para o qual a tag aponta.

Nada é publicado até o workflow alcançar a etapa npm, então se ele falhou antes disso, a versão ainda está livre e você pode mover a tag:

# 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}"

O commit de correção deve deixar package.json na mesma versão, ou a verificação de consistência rejeitará a tag. Se o npm já publicou, não reutilize a versão — esse release é imutável. Incremente para o próximo patch; a etapa npm protegida significa que uma reexecução pula o que já foi concluído com sucesso.

Contribuindo

Contribuições são bem-vindas! Sinta-se à vontade para enviar um pull request.

Agradecimentos