goodreads-mcp
Provides tools for controlling a Goodreads account, including searching books, adding books to shelves (want to read, currently reading, read), listing shelf contents, and queueing actions to be applied after authentication.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@goodreads-mcpput Project Hail Mary on want to read"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
goodreads-mcp
Voice control for a Goodreads shelf from a Pebble Index ring.
Say "put Project Hail Mary on want to read" or "what am I reading" and it happens.
Pebble ring ──MCP/HTTPS──▶ this server ──Chromium──▶ goodreads.com
(voice) (Pi, :8005) (headless) (signed in as you)Runs on the same Raspberry Pi as the rest of my home services — see pi-home-services for the Docker Compose orchestration and Cloudflare Tunnel setup.
Why a browser and not an API
Because there is no API. Goodreads retired its public API in December 2020 and has not issued keys since. There is no sanctioned programmatic way to shelve a book, so the only route left is to be a signed-in browser.
That's a real trade-off and worth stating plainly:
It breaks when Goodreads changes their markup. The selectors in
_shelve()are the fragile part; everything else is stable.It's slower than an API — several seconds per action, since a real page has to load.
It needs a human occasionally, for a captcha or a two-factor prompt.
Alternatives with real APIs exist (Hardcover has a proper GraphQL one). This is Goodreads on purpose — that's where the books already are.
Related MCP server: hardcover-mcp
How the session works
Two entry points, one Chromium profile:
Mode | Where | |
Normal operation |
| invisible, never touches the screen |
Authentication | headed | the Pi's touchscreen, on request |
They share one profile directory, so cookies earned by the headed login
are exactly what the headless runs use afterwards. --headless=new is not
optional: the legacy headless mode doesn't share a profile with a headed run
reliably, which would mean re-authenticating constantly.
The profile lives in a volume. Losing it means signing in again — nothing worse.
When the session dies
Actions are queued, not failed. Say "add X to want to read" while signed out and it's recorded; the next authentication applies it.
The tools say "queued", never "added". A queued book isn't shelved yet, and reporting otherwise would mean the ring tells you something is done when it isn't.
add_to_shelf → "Goodreads is signed out, so I've queued 'Piranesi' for
want to read. It'll go up next time you authenticate."
pending_books → what's waiting
sync_books → apply the queue (also runs automatically after signing in)Tools
Tool | What it does |
| Signed in? Anything queued? |
| Find a book, to confirm which one is meant |
| Shelve it — want to read / currently reading / read |
| Read a shelf back |
| What's queued while signed out |
| Apply the queue |
Only the three built-in shelves are supported. Spoken variants map onto them —
"finished" and "done" both mean read, "wishlist" means to-read.
Signing in
docker compose exec goodreads-mcp python authenticate.pyA Chromium window opens on the touchscreen over the kiosk. Sign in, clear any captcha or two-factor prompt, and it closes once it sees a valid session, then applies anything queued. The kiosk keeps running underneath.
This runs inside the container, not against the host's Chromium, because Chrome upgrades a profile forward and won't open one written by a newer build. One Chromium, one profile, no version skew.
Being a good citizen
This drives a real site as a real signed-in user, and it's deliberately
unhurried — a POLITE_DELAY between navigations, no parallelism, one browser
at a time. It touches your own shelves and the search page, nothing else. It
is not a crawler and shouldn't be turned into one.
Setup
cp .env.example .env # fill in MCP_BEARER_TOKEN
docker build -t goodreads-mcp .
docker run -p 8005:8000 --env-file .env -v goodreads-profile:/profile goodreads-mcpPoint the Pebble app at https://<your-host>/mcp with the bearer token, then
sign in with authenticate.py.
Environment variables
Variable | Default | Meaning |
| — | Static token Pebble sends as |
|
| Persistent Chromium profile — the signed-in session |
|
| Queued actions |
|
| Seconds the sign-in window waits for you |
|
| Port inside the container |
This server cannot be deployed
Maintenance
Related MCP Connectors
- AchriomOAuthcom.achriom
Media memory for AI agents and their humans: books, movies, music, shows, anime, podcasts, games.
The media memory layer for AI agents and their humans. Your AI client gets 29 tools to search your collection, add items, update ratings, preview music, and find patterns across everything you've read, watched, and listened to.
Headless browser primitives for AI agents when sites need real JS rendering.
Real Chrome for agents: start a browser, read pages as numbered markdown, click, type, hand off.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to help users manage their reading experience by searching books, tracking reading progress, managing bookmarks, and generating personalized recommendations and summaries.-
- AlicenseBqualityAmaintenanceConnects AI assistants to the Hardcover book library, enabling natural language book searches, reading status updates, list management, and library exploration.3949 PyPI6MIT
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Google NotebookLM through a real Chrome browser, allowing natural language queries, source ingestion, and audio overview generation.1,667 npmMIT
- AlicenseAqualityDmaintenanceEnables searching, managing library, wishlist, and credits on Audible through browser automation.66 npmMIT