Reported issues for Goodreads MCP
Pod holds 20 of 20 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.
Back to Goodreads MCP.
Most discussed
[strategist] Distribute goodreads-mcp on PyPI for uvx/pip install and MCP registry listing
Strategic Finding
Type: adoption-blocker Horizon: near-term
goodreads-mcp is only distributed as a GitHub-hosted .mcpb bundle (see .github/workflows/release.yml) or via manual git clone + pip install -e .. pyproject.toml (hatchling build backend, [project.scripts] goodreads-mcp) is already packaging-ready but nothing publishes the built wheel/sdist to PyPI.
Rationale
The MCP ecosystem's dominant install pattern is uvx <package> (or an entry in a client's server…
Read the thread · 2026-09-24 · closed · external user · 4 comments
[scanner] release.yml: publish goodreads-mcp-ai to PyPI with Trusted Publishing (needs workflow-permission to land)
Finding
This is the part of #153 (publish to PyPI) that lives in .github/workflows/release.yml. The scanner agent runs in ISSUES_AND_PRS mode. Its GitHub App token has no workflows permission, so GitHub rejects any push that touches .github/workflows/**. A human, or an ISSUES_PRS_MERGE-tier agent, has to land this change. I have not opened a PR for it because nothing I can push could contain it.
The rest of #153 is in #164 (branch feat/153-pypi-metadata, hold-gated). That PR…
Read the thread · 2026-09-25 · closed · external user · 2 comments
series_books and popular_books return a different shape from the other discovery tools
Tool / function
series_books, popular_books
Summary
The README says the GraphQL discovery tools return returned and has_more, and each tool's docstring says results carry the book's id and title so calls can be chained. Two tools break that contract, so an agent handling their output needs special cases.
Evidence (live, 2026-09-20, main at 885a036)
series_books("2767052", limit=3)returns keysbooks, has_more, returned, series, series_index. The input book's…
Read the thread · 2026-09-20 · closed · 1 comment
Out-of-range tool inputs are accepted silently and return misleading results
Tool / function
get_reviews, search_books, compare_books, get_shelf
Summary
Several tools accept arguments outside their documented ranges without complaint and return output that reads like real data. Only popular_books validates its inputs (month). An agent that mistypes a filter gets a plausible empty or truncated answer instead of an error it could correct.
Evidence (live, 2026-09-20, main at 885a036)
get_reviews("54493401", min_rating=6), `(min_rating=4,…
Read the thread · 2026-09-20 · closed · 1 comment
A config.json that is not a JSON object, or is unreadable, crashes the server at import
Tool / function
config._load_config_file / load_user_id; evaluated at import by server.py (DEFAULT_USER_ID)
Summary
_load_config_file catches only FileNotFoundError and json.JSONDecodeError. A config file that holds valid JSON which is not an object, or a file the process cannot read, raises out of load_user_id(). Because server.py calls it at import time, the server exits before the MCP handshake and the client only sees a dead process with no message.
Input…
Read the thread · 2026-09-20 · closed · 1 comment
Tools are sync functions, so one Goodreads request stalls the whole server: pings wait and parallel tool calls serialize
Tool / function
All tools in server.py; GoodreadsClient._request in client.py
Summary
Every @mcp.tool is a plain def that calls the blocking httpx.Client, and the MCP SDK calls sync tools directly on the event loop (mcp 1.30.0, func_metadata.call_fn_with_arg_validation: return fn(**arguments_parsed_dict)). While a tool waits on Goodreads, the server cannot answer a ping, act on a cancellation, or start another tool call. The 30 s HTTP timeout and the 429/503 backoff…
Read the thread · 2026-09-20 · closed · 1 comment
list_shelves returns [] for every user: Goodreads now redirects /review/list/{uid} to the sign-in page
Tool / function
list_shelves
Summary
list_shelves returns an empty list for every user, including public profiles. Goodreads now answers /review/list/{uid} with a 302 to the sign-in page. The client follows the redirect, the sign-in page has no shelf= links, and the regex finds nothing. Nothing raises, so the result looks like "this user has no shelves". The nightly compliance run cannot see this because the live suite has no list_shelves test.
Input…
Read the thread · 2026-09-20 · closed · 1 comment
[architect] get_book picks the first titled Book in Apollo state, not the book the page is for
get_book does not look up the book it was asked for. _find_book returns the first Book: entry in the page's Apollo state that has a title, and its book_id argument is only used in the error message. Live book pages also carry stub Book: entries for other editions. Today those stubs have no title, and that alone is what keeps get_book correct. If Goodreads adds a title to a stub, get_book (and compare_books) will return a different edition's data, with no error. That is the…
Read the thread · 2026-09-27 · closed · external user · 0 comments
Most recent
The MCP handshake reports the mcp SDK's version as the server version
In the MCP initialize response, serverInfo.version should be this server's version. It is the installed mcp SDK's version instead. server.py:114 creates OffLoopFastMCP("goodreads", ...) without a version, and the SDK then falls back to importlib.metadata.version("mcp"). A host log that shows goodreads 1.30.0 can't be matched to a release, and the number changes whenever the mcp dependency moves.
Checked at main b6f0e75 and on the published 2026.9.2 package.
Input
initialize…
Read the thread · 2026-09-27 · closed · 0 comments
config.json saved with a byte-order mark or as UTF-16 is ignored as not valid JSON
config.py reads the config file with CONFIG_PATH.read_text() and hands the text to json.loads (config.py:40). A file that starts with a UTF-8 byte-order mark, or is UTF-16, is rejected as "not valid JSON" with a warning on stderr, and the shelf tools then report that no user id is configured. Those are the encodings Windows PowerShell 5.1, the default shell on Windows 10 and 11, writes: Set-Content -Encoding UTF8 adds a BOM, and > / Out-File write UTF-16. manifest.json lists…
Read the thread · 2026-09-27 · closed · 0 comments
pyproject allows mcp>=1.0, but the server crashes at startup on any mcp before 1.14
pyproject.toml declares mcp[cli]>=1.0,<2, but goodreads_mcp.server does not import on any mcp release before 1.14.0. An installer only upgrades what a constraint forces, so installing goodreads-mcp-ai into an environment that already has an older mcp keeps it, and the server dies before the MCP handshake. uvx and the .mcpb are unaffected, since they resolve a fresh environment and get the newest mcp.
Checked at main b6f0e75 and on the published 2026.9.2 wheel.
Input
uv…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/207) · 2026-09-27 · closed · 0 comments
### A cancelled tool call keeps running and still makes every remaining Goodreads request
When an MCP client cancels a tool call, `_in_worker_thread` returns at once (`abandon_on_cancel=True`), but the worker thread runs the rest of the tool body. Every request the tool had not made yet still goes to Goodreads. Each one takes one of the two `MAX_IN_FLIGHT` slots, so the user's next call waits behind work nobody will read. The docstring (`server.py:63-66`) and #101 promise less than that: "the thread finishes its Goodreads request on its own and the result is dropped". In fact a…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/206) · 2026-09-27 · closed · 0 comments
### A hyphenated ISBN passed as book_id silently returns an unrelated book
Every tool accepts a `book_id` that only has to start with digits. A hyphenated ISBN-13 such as `978-0-593-13520-4` (Project Hail Mary) is read as book `978` followed by a slug. `get_book` returns *Point Deception* by Marcia Muller, and the GraphQL tools answer for book 978, or 979 for a `979-` ISBN. An ISBN-10 ending in `X` goes wrong in the GraphQL tools too. There is no error. The only clue is that the returned `book_id` differs from the input. ISBNs sit next to ids in tool output…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/205) · 2026-09-27 · closed · 0 comments
### get_shelf returns the user's whole library when the shelf name doesn't exist
Goodreads' shelf RSS does not reject an unknown shelf name. It answers HTTP 200 with the user's first 100 books from every shelf, the same list `shelf=""` gives. `get_shelf` returns that list as the requested shelf. A wrong case (`Norway` for `norway`), a space for a hyphen (`historical fiction`), or a typo gives the model 100 unrelated books and no hint that anything went wrong.
Checked at main b6f0e75.
**Tool / function**
`get_shelf`
**Input**
Public user 1, live on 2026-09-27.
**Expected…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/204) · 2026-09-27 · closed · 0 comments
### popular_books accepts any year, and get_reviews and popular_books treat a negative limit as 0
#94 made the tools refuse out-of-range inputs instead of answering as if they were valid. Three inputs were missed. `popular_books` sends any `year` to Goodreads, and a nonsense year comes back as an empty chart. `get_reviews` and `popular_books` quietly turn a negative `limit` into 0, while every other tool raises `limit must be zero or greater.`
Checked at main b6f0e75.
**Tool / function**
`popular_books` (`year`, `limit`), `get_reviews` (`limit`).
**Input / expected vs actual**
| call |…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/203) · 2026-09-27 · closed · 0 comments
### GraphQL tools report an empty or complete result when Goodreads answers with an error
`client.graphql()` raises `GraphQLError` only when the response has no `data` at all. AppSync reports a failed query as `{"data": {"<rootField>": null}, "errors": [...]}`, so the error is dropped and each tool turns the null into an empty result. The model gets `returned: 0, has_more: false`, which reads as "no results", when Goodreads actually refused the query. When a later page fails, a list is cut short and reported as complete.
Checked at main b6f0e75.
**Tool / function**…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/202) · 2026-09-27 · closed · 0 comments
### guard-bash.py: a glob at the start of a pytest word expands to an @FILE and reads .env past the gate
## Security finding
**Severity**: medium (needs a file named `@…` in the checkout; a contributor can add one in a PR)
**Type**: permission-boundary bypass, residual of #195 / #196
#196 refuses any pytest word that starts with `@`. bash can still produce such a word from a glob that the guard reads literally: `guard-bash.py` refuses a glob only where an option stands (`.claude/README.md`: "a glob standing where an option goes"), so a glob in a value or positional slot is passed to the shell as…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/197) · 2026-09-27 · closed · 0 comments
### [sec-check] pytest @FILE argument files bypass guard-bash.py: -k @.env prints .env, a listed outside test module runs
## Security Finding
**Severity**: high
**Type**: unsafe-pattern (permission-boundary bypass)
`.claude/settings.json` allows `Bash(pytest *)`, and `.claude/hooks/guard-bash.py` is what keeps that row from meaning "run any code, read any file". `_check_pytest` checks option names against a safe list and positional paths against `tests/`, but it never looks for a word that starts with `@`.
pytest's parser is argparse with `fromfile_prefix_chars="@"`. Before parsing, it replaces every word that…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/195) · 2026-09-27 · closed · external user · 0 comments
### [architect] book_id is an integer in GraphQL tool results but every tool rejects an integer book_id
## Summary
The GraphQL tools return `book_id` as a JSON integer, but every tool that takes a book id declares it as a string, and the MCP layer rejects an integer. So an agent that copies `book_id` from one result into the next call, exactly as the README and `prompts/add-discovery-tool.md` promise ("one tool's `book_id` feeds the next"), gets a validation error unless its host happens to convert the value to a string first.
## Evidence
Output side: `_book_summary`, `_work_summary`,…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/193) · 2026-09-26 · closed · external user · 0 comments
### [strategist] Submit goodreads-mcp-ai to the official MCP servers registry
## Strategic Finding
**Type**: adoption-blocker
**Horizon**: near-term
#153 shipped the PyPI publish step (now live as `goodreads-mcp-ai` on PyPI, per `pyproject.toml`'s naming note) but the second half of that issue's proposed next step — submitting to the official MCP servers registry — has not happened. A search of `registry.modelcontextprotocol.io` for 'goodreads' returns zero results.
## Rationale
PyPI presence alone does not give discoverability; the registry is where MCP clients and…
[Read the thread](https://github.com/Danathar/goodreads-mcp/issues/180) · 2026-09-26 · closed · external user · 0 comments
The remaining reports are on [the project's issue tracker](https://github.com/Danathar/goodreads-mcp/issues).