Skip to main content
Glama
README.md
[![CI](https://github.com/Danathar/goodreads-mcp/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Danathar/goodreads-mcp/actions/workflows/ci.yml)
[![Nightly compliance](https://github.com/Danathar/goodreads-mcp/actions/workflows/nightly-compliance.yml/badge.svg?branch=main)](https://github.com/Danathar/goodreads-mcp/actions/workflows/nightly-compliance.yml)
[![Ask DeepWiki](https://img.shields.io/badge/Ask-DeepWiki-1f6feb)](https://deepwiki.com/Danathar/goodreads-mcp)
[![Maintenance assisted by Hivecommons Hive](https://img.shields.io/badge/maintenance%20assisted%20by-Hivecommons%20Hive-1f6feb)](https://github.com/hivecommons/hive)
[![ACMM L6 Fully Autonomous](https://img.shields.io/badge/ACMM-L6%20Fully%20Autonomous-2da44e)](https://github.com/Danathar/goodreads-mcp/blob/main/docs/maintenance.md)
[![AI assisted](https://img.shields.io/badge/AI-assisted-d29922)](https://github.com/Danathar/goodreads-mcp#about-this-project)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://github.com/Danathar/goodreads-mcp/blob/main/LICENSE)

# 📚 goodreads-mcp

> **Thank you, [Shreeya Chand](https://github.com/shreeyachand).** This project is a fork of [`shreeyachand/goodreads-mcp`](https://github.com/shreeyachand/goodreads-mcp), and it would not exist without that work. The core idea of reaching Goodreads without its retired API, and the tool set this server offers, come from Shreeya's project. We're grateful for it, and for the MIT licence that let us build on it. If this server is useful to you, please go star the original.

A **read-only** MCP server for Goodreads — built without the Goodreads API, because there hasn't been one since December 2020. Lets an LLM find and research books, ratings, and reviews. Tools ride on RSS feeds, the JSON autocomplete endpoint, the `__NEXT_DATA__` blob embedded in book pages, and the AppSync GraphQL backend the Goodreads website itself uses. No login, no cookies, no writes — public data only.

<!-- Ownership token the official MCP registry checks in the PyPI README
     before it accepts a listing; must match `name` in server.json. Keep it
     on its own line. mcp-name: io.github.Danathar/goodreads-mcp-ai -->

## tools

| tool | source / what it returns |
|---|---|
| `search_books` | JSON autocomplete endpoint (stable) — book_id, title, author, rating, cover; `max_results` defaults to 10, but the endpoint returns about 5 matches at most |
| `get_book` | `__NEXT_DATA__` via the `.xml` page (stable) — details, cover, ratings histogram, every series membership, review-language breakdown (`review_language_limit`, default 5, max 25); edition `publication_date` and the work's `first_published`, `original_title`, `language`, `isbn` / `isbn13` / `asin`, `author_url` (each null when absent) |
| `get_reviews` | GraphQL — paginated reader reviews (text, rating, likes, date, spoiler flag, permalink); `limit` default 10, capped at 100; server-side `min_rating` / `max_rating` (1–5, min ≤ max), `sort` (`relevance` default, `newest`, `oldest`), `language` (two-letter code, as in `get_book`'s `review_languages`) and `search` over review text; `exclude_spoilers`; reports `has_more` |
| `similar_books` | GraphQL — paginated "readers also enjoyed" recommendations; `limit` up to 100 |
| `author_books` | GraphQL — paginated author bibliography, ranked by popularity, from any of their books, plus `author_url`; `limit` up to 100 |
| `series_books` | GraphQL — paginated series books with reading-order placement; `series_index` (zero-based, in `get_book`'s `series_memberships` order) picks the series; `limit` up to 100 |
| `get_editions` | GraphQL — paginated editions (format, ISBN, publisher, publication date as `publication_date` YYYY-MM-DD plus raw `publication_time` in epoch ms); `limit` up to 100 |
| `book_lists` | GraphQL — paginated Listopia lists a book appears on (title, votes, size); `limit` up to 100 |
| `popular_books` | GraphQL — most popular books by release `year`, or a single `month` (1–12), ranked; `limit` capped at 50 |
| `compare_books` | `get_book` for each id (`__NEXT_DATA__` via `.xml`) — ranks 1–10 distinct books by rating with positive/critical share; a repeated id is fetched once; more than 10 ids is refused; a book that fails comes back as an `error` entry |
| `get_shelf` | shelf RSS feed (stable) — books on a public shelf (rating and year as ints, `None` when absent; dates as `YYYY-MM-DD`; plus `cover`, `pages`, `my_review`); `page` starts at 1, about 100 items per page; `user_id` overrides the configured user; raises `LoginRequired` for a private profile |
| `list_shelves` | best-effort HTML scrape of the public profile page — shelf names; raises `LoginRequired` for a private profile |

Every tool is registered with MCP read-only annotations (read-only, non-destructive, idempotent).

The discovery tools all take a `book_id` and return results carrying `book_id`/title/author/rating/url, so an agent can chain them — e.g. `similar_books` → `get_reviews` on a recommendation. `book_id` is a string on both sides (`"54493401"`, or the slug form `"54493401-title"` on input), so a value copied out of one result is accepted as-is by the next call. `average_rating` is a number (or null) in every tool, so results from different tools sort together. This is the structured book graph a general web search can't assemble.

The five paginated discovery tools (`similar_books`, `author_books`, `series_books`, `get_editions`, `book_lists`) page in batches of 20 and accept a total `limit` up to 100; `popular_books` caps `limit` at 50. Responses include `returned` and `has_more`, keeping larger lookups useful without allowing unbounded traffic.

> **WAF and login note:** Goodreads book HTML pages now sit behind an AWS WAF
> JavaScript challenge (HTTP 202) that plain HTTP clients can't solve. `get_book`
> routes around it via the `.xml`-suffixed page, so it still works without a
> browser. If Goodreads ever extends the WAF to a path we depend on, the client
> raises `WAFChallenge` with a clear message instead of a confusing parse error.
> The review-list page (`/review/list/{uid}`) became login-only in Sep 2026; the
> client raises `LoginRequired` on a sign-in redirect for the same reason, and
> `list_shelves` reads the public profile page instead.

## install

With pip:

```bash
cd goodreads-mcp
python3.11 -m venv .venv && .venv/bin/pip install -e .
```

Or with [uv](https://docs.astral.sh/uv/), which is also what the Claude Desktop bundle uses:

```bash
cd goodreads-mcp
uv sync
uv run goodreads-mcp
```

Requires Python ≥ 3.11.

Each date-numbered release is also published to PyPI as [`goodreads-mcp-ai`](https://pypi.org/project/goodreads-mcp-ai/) (the `goodreads-mcp` name there belongs to an unrelated project) and listed on the [official MCP registry](https://registry.modelcontextprotocol.io) as `io.github.Danathar/goodreads-mcp-ai`, from [`server.json`](https://github.com/Danathar/goodreads-mcp/blob/main/server.json). The listing carries a `uvx` runtime hint; a client that follows it runs `uvx goodreads-mcp-ai`, which you can also run yourself.

## config (optional)

No login or cookies — everything is public data. The only setting is your numeric `user_id`, the default for the shelf tools. It's the number in `goodreads.com/user/show/<ID>-yourname`; you can also pass `user_id` to each shelf tool per call.

```bash
mkdir -p ~/.config/goodreads-mcp
cat > ~/.config/goodreads-mcp/config.json << 'EOF'
{ "user_id": "12345678" }
EOF
```

Env var `GOODREADS_USER_ID` overrides the file. A config file that can't be read, isn't valid JSON, isn't a JSON object, or has a `user_id` that is neither a string nor a whole number is ignored with a warning on stderr (a bare number such as `12345678` is accepted and used as its string form; booleans, floats, lists and objects are ignored); the server still starts.

## Claude Desktop config

**Bundle.** Each [release](https://github.com/Danathar/goodreads-mcp/releases) carries a `goodreads-mcp.mcpb`. Releases come out monthly when the server itself changed, numbered by date (`2026.10.0`, `2026.10.1`, `2026.11.0`); `0.1.1` was the last of the old numbering, and every date-numbered release is newer than it. See [CONTRIBUTING.md](https://github.com/Danathar/goodreads-mcp/blob/main/CONTRIBUTING.md#releases) for how one is cut. Open the `.mcpb` in Claude Desktop to install. The bundle ships no dependencies — the manifest launches the server with `uv run`, and the host resolves `pyproject.toml` into a private environment on first launch — so one bundle runs on macOS, Windows and Linux with any Python ≥ 3.11. The bundle's optional "Goodreads User ID" setting (`user_config.goodreads_user_id`) is passed to the server as `GOODREADS_USER_ID`; left empty, it is passed as an empty value, and the server falls back to the config file.

**Manual.** Add the server to `claude_desktop_config.json` — on macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, on Windows `%APPDATA%\Claude\claude_desktop_config.json`; in any version, Settings → Developer → Edit Config opens it:

```json
{
  "mcpServers": {
    "goodreads": {
      "command": "/path/to/goodreads-mcp/.venv/bin/goodreads-mcp"
    }
  }
}
```

Or for development, `mcp dev goodreads_mcp/server.py` gives you the Inspector UI to poke each tool.

## first-run verification

The endpoints are unofficial, so verify in this order:

1. `search_books("project hail mary")` — should just work
2. `get_book("54493401")` — confirms the `.xml`/WAF workaround; check the histogram is populated
3. `get_reviews("54493401")` — should return real review text
4. `get_shelf("to-read")` — checks your `user_id` + RSS
5. `list_shelves()` — best-effort shelf-name scrape

For an end-to-end example that chains the tools, see [prompts/research-a-book.md](https://github.com/Danathar/goodreads-mcp/blob/main/prompts/research-a-book.md).

## tests

```bash
.venv/bin/pip install -e ".[test]"     # pytest + pytest-cov
.venv/bin/pytest                       # offline parser/unit tests
GOODREADS_LIVE=1 .venv/bin/pytest      # + live network smoke tests
```

The offline suite runs on fixtures; CI runs it with `pytest-cov` and enforces a coverage floor (`--cov-fail-under` in [ci.yml](https://github.com/Danathar/goodreads-mcp/blob/main/.github/workflows/ci.yml)). The live smoke tests are in [tests/e2e/test_smoke_live.py](https://github.com/Danathar/goodreads-mcp/blob/main/tests/e2e/test_smoke_live.py) and skip unless `GOODREADS_LIVE=1` is set. The [nightly compliance run](https://github.com/Danathar/goodreads-mcp/blob/main/.github/workflows/nightly-compliance.yml) runs the live suite against the real endpoints every night, so upstream drift shows up within a day.

## documentation

- [docs/design.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/design.md) — design notes: the data surfaces, WAF and login handling, politeness and concurrency
- [docs/roadmap.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/roadmap.md) — ideas not built yet
- [docs/maintenance.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/maintenance.md) — how this repository is maintained (Hive, ACMM L6, outreach PRs held for human review)
- [docs/ai-ops-runbook.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/ai-ops-runbook.md) — what to check and do for each automated signal
- [docs/quality.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/quality.md) — what the tests and numbers do and do not prove
- [docs/risk-tiers.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/risk-tiers.md) — the risk tier every pull request declares
- [docs/review-rubric.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/review-rubric.md) — the review checklist
- [docs/metrics.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/metrics.md) — outcome metrics
- [docs/strategy.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/strategy.md) — what the project is for, what it won't do, and the commands that say whether it is on track
- [docs/reflections/](https://github.com/Danathar/goodreads-mcp/tree/main/docs/reflections/) — lessons learned about this codebase
- [docs/SECURITY-AI.md](https://github.com/Danathar/goodreads-mcp/blob/main/docs/SECURITY-AI.md) — what AI agents may and may not touch

## about this project

> [!NOTE]
> Work on this fork is done with AI assistance and should be treated cautiously.
>
> This is a third-party tool. It is not an official Goodreads or Amazon product, is not sanctioned by either, and uses no official API — there hasn't been one since December 2020. "Goodreads" is a trademark of its owner and is used here only to say what this software talks to.
>
> It reads public data only: no login, no cookies, no writes. It is provided as-is, with no promise that the endpoints it depends on will keep working or that using it is consistent with Goodreads' terms. Keep request volume modest. The maintainer is not responsible for rate limiting, blocking, data loss, or other consequences of using this software.

## license

This fork is licensed under the [GNU General Public License v3.0](https://github.com/Danathar/goodreads-mcp/blob/main/LICENSE), version 3 only (`GPL-3.0-only`) — no automatic upgrade to later versions.

It incorporates code from [`shreeyachand/goodreads-mcp`](https://github.com/shreeyachand/goodreads-mcp), Copyright (c) 2026 Shreeya Chand, released under the MIT License. That code remains under MIT; its licence text and copyright notice are preserved in [LICENSE.MIT](https://github.com/Danathar/goodreads-mcp/blob/main/LICENSE.MIT) as the MIT licence requires. The combined work — upstream code together with this fork's changes — is distributed under GPL-3.0.

TDQS

A4.5/5.0

Scored across 12 tools

Disambiguation5/5

Each tool targets a distinct Goodreads resource or relation (search, book details, editions, lists, popular chart, shelves, reviews, similar/author/series books, compare). The 'related books' tools could superficially overlap, but descriptions clearly specify different data sources and use cases.

Naming Consistency4/5

All names use snake_case, but the set mixes verb_noun (get_book, search_books, compare_books, list_shelves) with noun_books (book_lists, popular_books, similar_books, author_books, series_books). The pattern is readable and largely predictable, with only minor stylistic drift.

Tool Count5/5

Twelve tools is a well-scoped set for a Goodreads MCP: enough to cover search, details, reviews, shelves, lists, editions, and related books without bloat. Each tool clearly earns its place.

Completeness4/5

Core read-only workflows are covered: book search/details, editions, reviews, similar/author/series discovery, shelves, Listopia, popular charts, and comparison. Minor gaps exist, such as direct author search by name or retrieving all books in a Listopia list, but agents can work around them via existing tools.

Maintenance

ActivityActive
ResponsivenessResponsive