openlibrary-mcp-server

v0.2.4 pre-1.0

Search books and authors, fetch editions, browse subjects, and resolve cover images from Open Library via MCP. STDIO or Streamable HTTP.

openlibrary.caseyjhand.com/mcp
claude mcp add --transport http openlibrary-mcp-server https://openlibrary.caseyjhand.com/mcp
codex mcp add openlibrary-mcp-server --url https://openlibrary.caseyjhand.com/mcp
{
  "mcpServers": {
    "openlibrary-mcp-server": {
      "url": "https://openlibrary.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http openlibrary-mcp-server https://openlibrary.caseyjhand.com/mcp
{
  "mcpServers": {
    "openlibrary-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://openlibrary.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "openlibrary-mcp-server": {
      "type": "http",
      "url": "https://openlibrary.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://openlibrary.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

10

openlibrary_search_books

open-world

Full-text book search across Open Library works. Supports field filters (title, author, subject, publisher, ISBN, language) and returns work-level records with edition counts, cover IDs, and reading availability. Use query for general search or combine specific field filters. Results are work-level — drill into editions via openlibrary_get_editions.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_search_books",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "query": {
      "description": "Full-text search query. Supports Solr field prefixes: title:, author:, subject:, publisher:, isbn:, language:. Omit to use the filter parameters instead.",
      "type": "string"
    },
    "title": {
      "description": "Filter by title. Matched against work title and alternative titles.",
      "type": "string"
    },
    "author": {
      "description": "Filter by author name. Partial names work.",
      "type": "string"
    },
    "subject": {
      "description": "Filter by subject tag (e.g., \"science fiction\", \"history\").",
      "type": "string"
    },
    "publisher": {
      "description": "Filter by publisher name. Partial names work (e.g., \"Penguin\").",
      "type": "string"
    },
    "isbn": {
      "description": "Find works that have editions with this ISBN (10 or 13 digits, hyphens ignored).",
      "type": "string"
    },
    "language": {
      "description": "Restrict results to one language. Takes a 3-letter MARC code (e.g., \"eng\", \"fre\", \"ger\", \"chi\") — the same vocabulary openlibrary_get_edition and openlibrary_get_editions return. A 2-letter ISO 639-1 code (e.g., \"en\", \"fr\") is accepted and translated to its MARC equivalent; an unrecognized 2-letter code is rejected rather than silently ignored. The equivalent in-query form is language:eng.",
      "type": "string",
      "pattern": "^[A-Za-z]{2,3}$"
    },
    "sort": {
      "default": "relevance",
      "description": "Sort order. \"relevance\" uses Solr scoring. \"new\"/\"old\" sort by first publish year. \"rating\" by average community rating. \"editions\" by edition count.",
      "type": "string",
      "enum": [
        "relevance",
        "new",
        "old",
        "rating",
        "editions"
      ]
    },
    "limit": {
      "default": 10,
      "description": "Max results to return. Higher values increase response size; prefer 10–20 for exploration.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "include_availability": {
      "default": false,
      "description": "Include live reading availability from Internet Archive (borrow/read status). Adds ~200ms latency. Use when the user needs to know if they can read the book online.",
      "type": "boolean"
    }
  },
  "required": [
    "sort",
    "limit",
    "offset",
    "include_availability"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_search_inside

open-world

Search the full text of books scanned by the Internet Archive — the "which book contains this passage?" lookup that the metadata tools cannot answer. Quote a phrase for an exact-phrase match; bare terms match anywhere in the text. Each result is an Internet Archive item with the matching passages as snippets, plus a relevance score. The full-text index is an order of magnitude slower than the metadata endpoints (seconds, not milliseconds), so reach for it when the passage is the question, not as a general book search — use openlibrary_search_books for title, author, or subject. Results key on Internet Archive items rather than Open Library works: chain the returned ia_identifier to archive.org, or match it against the ia_identifiers on openlibrary_search_books results to reach the catalogue record.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_search_inside",
    "arguments": {
      "query": "<query>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Text to find inside scanned books. Wrap in double quotes for an exact-phrase match (e.g., \"the spice must flow\"); unquoted terms match independently and return far broader results."
    },
    "limit": {
      "default": 10,
      "description": "Max matching items to return. Each carries its own snippets, so higher values grow the response quickly — prefer 10–20.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "query",
    "limit",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_work

open-world

Fetch a work by Open Library Work ID (OL…W). Returns title, description, subjects, cover IDs, and linked author IDs for follow-up lookups. Works represent the abstract book concept independent of any specific edition. Note: author names are not included — use openlibrary_get_author or openlibrary_search_books for names.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_work",
    "arguments": {
      "work_id": "<work_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "work_id": {
      "type": "string",
      "description": "Open Library Work ID. Format: OL…W (e.g., \"OL45804W\"). A leading \"/works/\" prefix is stripped if provided."
    }
  },
  "required": [
    "work_id"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_editions

open-world

List editions of a work — different publishers, languages, formats, and print runs. Returns ISBNs, publisher, language, page count, and edition OLIDs. Use after openlibrary_get_work or openlibrary_search_books to find a specific printing.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_editions",
    "arguments": {
      "work_id": "<work_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "work_id": {
      "type": "string",
      "description": "Open Library Work ID (OL…W). A leading \"/works/\" prefix is stripped if provided."
    },
    "limit": {
      "default": 10,
      "description": "Max editions to return. Prefer 10–20 for exploration.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "work_id",
    "limit",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_edition

open-world

Resolve one or more editions by identifier: ISBN-10, ISBN-13, OCLC, LCCN, or Open Library Edition ID (OL…M). Every identifier in a call shares one id_type — pass id_type "isbn" for both ISBN-10 and ISBN-13. Up to 50 identifiers resolve in a single upstream request, so a bibliography or shelf export costs one call rather than one per book; a large batch is a large response, so ask for what you need. Returns full edition metadata including authors, publisher, language, all identifier types, and the parent work ID, with author names inline and no secondary lookup; when the edition record itself lists no authors, they are recovered from the parent work and marked as such. Partial success is the norm — identifiers that resolve come back in editions, the rest are listed in unresolved with a reason, and the call fails only when nothing resolved.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_edition",
    "arguments": {
      "identifiers": "<identifiers>",
      "id_type": "<id_type>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "identifiers": {
      "minItems": 1,
      "maxItems": 50,
      "type": "array",
      "items": {
        "type": "string",
        "description": "One identifier value. For ISBN: 10 or 13 digits, hyphens optional. For OCLC: numeric string. For LCCN: string as-is. For OLID: Open Library edition ID (e.g., OL7353617M)."
      },
      "description": "Identifiers to resolve, 1–50, all of the type named by id_type. Resolved editions come back in request order."
    },
    "id_type": {
      "type": "string",
      "enum": [
        "isbn",
        "oclc",
        "lccn",
        "olid"
      ],
      "description": "Identifier type shared by every entry in identifiers. \"isbn\" handles both ISBN-10 and ISBN-13. \"olid\" is the native Open Library edition ID (OL…M). Mixing types within one call is not supported — issue one call per type."
    }
  },
  "required": [
    "identifiers",
    "id_type"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_search_authors

open-world

Search Open Library authors by name. Returns Open Library Author IDs, names, birth/death dates, top works, and subject associations. Use author IDs for openlibrary_get_author (bio, remote IDs) or openlibrary_get_author_works (list of works).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_search_authors",
    "arguments": {
      "query": "<query>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "Author name search query. Partial names and alternate names work."
    },
    "limit": {
      "default": 10,
      "description": "Max results to return.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "query",
    "limit",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_author

open-world

Fetch author detail by Open Library Author ID (OL…A). Returns bio, birth/death dates, photo IDs, and linked identifiers from Wikidata, VIAF, ISNI, Goodreads, and LibraryThing. Use openlibrary_search_authors to find an author ID first.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_author",
    "arguments": {
      "author_id": "<author_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "author_id": {
      "type": "string",
      "description": "Open Library Author ID. Format: OL…A (e.g., \"OL24638A\"). A leading \"/authors/\" prefix is stripped if provided."
    }
  },
  "required": [
    "author_id"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_author_works

open-world

List works by an author. Returns titles, cover IDs, and work OLIDs for drilling into editions or details. Use openlibrary_get_author for author bio and details, or openlibrary_get_editions to explore specific printings.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_author_works",
    "arguments": {
      "author_id": "<author_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "author_id": {
      "type": "string",
      "description": "Open Library Author ID (OL…A). A leading \"/authors/\" prefix is stripped if provided."
    },
    "limit": {
      "default": 20,
      "description": "Max works to return.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "author_id",
    "limit",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_subject

open-world

Browse works by subject. Returns matching works with edition counts and cover IDs, plus the total work count for the subject. Case and spacing are normalized before lookup, so "Science Fiction" and "science_fiction" are the same request. Subject tags are user-contributed and the vocabulary varies — when a subject returns no works, try a different word form (singular/plural), a synonym, or a broader term.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_subject",
    "arguments": {
      "subject": "<subject>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "subject": {
      "type": "string",
      "description": "Subject name. Normalized before lookup — lowercased with spaces converted to underscores (e.g., \"Science Fiction\" → \"science_fiction\") — so varying case or spacing does not change the result."
    },
    "limit": {
      "default": 12,
      "description": "Max works to return. Subject pages typically show 12 at a time.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Zero-based offset for pagination.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "subject",
    "limit",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

openlibrary_get_cover_url

Resolve a cover image URL for a book or author photo. Returns a direct HTTPS URL in the requested size (S/M/L). The Covers API always returns HTTP 200 — missing covers return a 1×1 placeholder GIF, not a 404 — so the identifier format is validated locally first: "id" must be numeric, "isbn" 10 or 13 digits, "olid" an edition OLID (OL…M) for target "book" and an author OLID (OL…A) for target "author". Identifiers with path separators or control characters, and author-by-ISBN lookups, are rejected before any request. URLs can be embedded in markdown as ![cover](url).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openlibrary_get_cover_url",
    "arguments": {
      "identifier": "<identifier>",
      "id_type": "<id_type>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "description": "The identifier value, validated against id_type before the URL is built. For \"id\": a numeric cover or photo ID from work/edition/author data. For \"isbn\": 10 or 13 digits, hyphens optional. For \"olid\": an edition OLID (OL…M) for target \"book\", an author OLID (OL…A) for target \"author\"."
    },
    "id_type": {
      "type": "string",
      "enum": [
        "id",
        "isbn",
        "olid"
      ],
      "description": "\"id\" is the numeric cover_i / cover ID from search or work results. \"isbn\" and \"olid\" look up the cover from those identifiers."
    },
    "target": {
      "default": "book",
      "description": "\"book\" returns a book cover from covers.openlibrary.org/b/. \"author\" returns an author photo from covers.openlibrary.org/a/ — use with id_type \"id\" (photo_id) or \"olid\" (author OLID).",
      "type": "string",
      "enum": [
        "book",
        "author"
      ]
    },
    "size": {
      "default": "M",
      "description": "Image size. S = small (~45px tall), M = medium (~150px tall), L = large (~400px tall).",
      "type": "string",
      "enum": [
        "S",
        "M",
        "L"
      ]
    }
  },
  "required": [
    "identifier",
    "id_type",
    "target",
    "size"
  ],
  "additionalProperties": false
}
view source ↗

Resources

2

Work detail by Open Library Work ID (OL…W). Provides title, description, subjects, cover IDs, and author IDs as injectable context for a conversation about a specific book.

uri openlibrary://works/{work_id} mime application/json

Author detail by Open Library Author ID (OL…A). Provides name, bio, dates, photo IDs, and linked external identifiers as injectable context for a conversation about a specific author.

uri openlibrary://authors/{author_id} mime application/json