hardcover-mcp
This server connects an AI assistant to your Hardcover account so you can search the catalog, track your reading, manage lists and goals, and browse social activity — all in natural conversation.
Discover catalog content — full-text search across books, authors, series, lists, users, publishers, characters, and prompts (
search_books), plus book/edition lookup by ID, slug, ISBN, ASIN, or edition ID (get_book), and details on authors (get_author), series in reading order (get_series), and publishers (get_publisher).Browse recommendations — see currently trending books by time window (
get_trending_books) and curated themed collections (get_vibes).View your profile and stats — get your own or another user's profile, bio, follower counts, optional library, followers/following lists, and reading statistics (
get_user).Track your library — list and filter your books by status, date range, reviewed, or owned (
get_user_library); inspect one book's status, rating, review, notes, edition, and read entries (get_user_book).Update your library — add books or change status, rating, review, privacy, notes, edition, and ownership (
set_user_book); log or edit reading dates and page/audiobook progress (set_user_book_read); delete read entries or remove books entirely (delete_user_book_read,delete_user_book).Manage reading goals — view active goals with progress (
get_reading_goal), create/update/archive goals (set_reading_goal), and delete them (delete_reading_goal).Manage lists — view your lists or one list with its books (
get_list), create/rename/change privacy (set_list), add or remove books (set_list_book), and delete lists (delete_list).Keep a reading journal — read notes, quotes, and status events (
get_reading_journal), add or edit notes/quotes (set_journal_entry), and delete entries (delete_journal_entry).Social features — see activity from people you follow or a specific user (
get_activity_feed), follow/unfollow users (set_following), browse community prompts (get_prompts), and answer or withdraw prompt answers (set_prompt_answer).
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., "@hardcover-mcpAdd Project Hail Mary to my library as currently reading"
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.
hardcover-mcp
Talk to your Hardcover library from any AI assistant.
hardcover-mcp connects your Hardcover library to AI assistants like Claude and Copilot. Search for books, update your reading status, manage lists, explore series — all through natural conversation instead of clicking through menus.
What you can say
"What's on my currently reading list?"
"Add Project Hail Mary to my library as currently reading"
"Search for books by Brandon Sanderson"
"Look up ISBN 9780547928227"
"Create a list called 'Summer Reading' and add The Hobbit to it"
"Show me the Stormlight Archive series in reading order"
"Move Project Hail Mary and The Martian to currently reading"
"What books has Andy Weir written? Add any I haven't read to my want-to-read list"
"Compare my rating of Dune with the Hardcover average"
What's covered
Library tracking — status, ratings, reading dates
List management — create, edit, add/remove books
Discovery — search books, authors, series, editions, and more
Account info — your profile and reading stats
Related MCP server: booklore-mcp
Safety & control
You control your API key — it stays on your machine, never shared with third parties
Runs locally through your MCP client — no external server involved
Actions only happen when explicitly requested — nothing runs in the background
You review prompts and outputs in your client before anything is sent
Read-only mode — set
HARDCOVER_READ_ONLY=trueto hide every tool that can change your account (see Configuration)Least-privilege keys — give the key only the scopes you need; a read-only key makes Hardcover itself refuse writes (see API key and scopes)
Quick Start
Install uv (a fast Python package runner — the setup takes seconds).
Create an API key at hardcover.app/account/api; see API key and scopes for links that pre-select the right scopes.
Add the config below to your MCP client — no manual install needed,
uvxhandles it.
VS Code
Add to .vscode/mcp.json:
{
"servers": {
"hardcover": {
"command": "uvx",
"args": ["hardcover-mcp"],
"env": {
"HARDCOVER_API_TOKEN": "<your token>",
"HARDCOVER_TOOLSETS": "all",
"HARDCOVER_READ_ONLY": "false"
}
}
}
}Claude Code
claude mcp add --scope user hardcover --env HARDCOVER_API_TOKEN=<your token> -- uvx hardcover-mcpReplace <your token> with your Hardcover API key. --scope user makes the server available
in every project; leave it out to add it to the current project only (see the
Claude Code MCP documentation for scopes). Other settings
from Configuration are extra --env KEY=value flags after the server name,
e.g. --env HARDCOVER_READ_ONLY=true.
To keep the token off the command line, put the variables in a file (start from
.env.example) and let uvx read it:
claude mcp add --scope user hardcover -- uvx --env-file /path/to/hardcover.env hardcover-mcpClaude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"hardcover": {
"command": "uvx",
"args": ["hardcover-mcp"],
"env": {
"HARDCOVER_API_TOKEN": "<your token>",
"HARDCOVER_TOOLSETS": "all",
"HARDCOVER_READ_ONLY": "false"
}
}
}
}HARDCOVER_TOOLSETS and HARDCOVER_READ_ONLY are optional and shown with their defaults;
Configuration lists every setting, including HARDCOVER_API_URL.
To keep the token out of the client config, copy .env.example to a file outside any
repository (for example ~/hardcover.env), put in your token, and point uvx at it. The server
never reads a .env file by itself; it only gets the variables from the file you name:
"command": "uvx",
"args": ["--env-file", "/path/to/hardcover.env", "hardcover-mcp"]API key and scopes
Hardcover API keys carry scopes that limit what the key can do. Create a key with only the scopes this server needs (the links open Hardcover's key form with them pre-selected):
Everything: create a key with all scopes
Read-only: create a read-only key. Pair it with
HARDCOVER_READ_ONLY=true; Hardcover then refuses writes even if a tool tried one.
Toolset | Scopes needed |
|
|
|
|
|
|
|
|
|
|
|
|
read:me is needed almost everywhere because tools look up who you are first. write:reviews
is only needed to write or edit a review with set_user_book; without it, status, rating, and
notes changes still work. If you only load
some toolsets (see Configuration), the key only needs those rows plus core.
Keys created before August 2026 have full access and keep working.
When you create a key, Hardcover asks for an expiry date. After it, every tool returns "Hardcover rejected the API token … expired" with a link to create a new one.
If a tool needs a scope your key lacks, its error names the missing scopes and links to a key form with them pre-selected.
Configuration
Optional environment variables, set in the same env block as your token:
Variable | Default | Effect |
|
| Comma-separated toolsets to load. Fewer tools means less context used and fewer wrong tool picks. |
|
|
|
| Hardcover's API | GraphQL endpoint to call instead, e.g. a proxy. Must be |
Toolset | What it covers |
| Always loaded: |
| Books (with characters and editions), editions, authors, series, publishers, trending, vibes |
| Your library, reading dates and progress, ownership, reviews, goals |
| Viewing and managing your lists |
| Reading journal notes and quotes |
| Activity feed, following users, community prompts |
For example, a read-only assistant for browsing books and your own library:
"env": {
"HARDCOVER_API_TOKEN": "<your token>",
"HARDCOVER_TOOLSETS": "catalog,library",
"HARDCOVER_READ_ONLY": "true"
}An unknown toolset name stops the server at startup with a message listing the valid names.
Tools
Grouped by toolset (see Configuration). Tools marked ✏️ can change your account and are hidden in read-only mode.
A few rules hold for every tool:
Write tools change only the fields you pass; leaving a field out or passing
nullkeeps its current value. Clearing a field (e.g. removing a rating) isn't supported yet.ratingis the community rating;user_ratingis yours (or, inget_user, that user's).A write tool whose target doesn't exist, or isn't yours, returns an error. A read tool that finds nothing returns an empty list, or "No … found." when looking up one thing.
core (always loaded)
What you can do | Tool |
Search for books, authors, series, lists, users, and more (with sort/filter) |
|
See your profile and reading stats, or look up another user; optionally with library, followers, and following |
|
catalog
What you can do | Tool |
Look up a book by ID or slug, including contributors and their roles (optionally with characters and editions), or a specific edition by ISBN, ASIN, or edition ID |
|
Browse an author's catalogue |
|
Explore a series in reading order |
|
Look up a publisher and its editions |
|
See what's trending now |
|
Browse curated recommendation collections (vibes) |
|
library
What you can do | Tool |
Browse your library: filter by status, date range, reviewed or owned books; sort by rating/date |
|
Check your status, rating, review, reads, and list memberships for one book (excluding the internal Owned list) |
|
Get your active reading goals and progress |
|
✏️ Add a book or update its status, rating, review, notes, privacy, edition, and ownership |
|
✏️ Log or edit reading dates and progress (pages, audiobook time) |
|
✏️ Create, update, or archive a reading goal (books/pages, date range) |
|
✏️ Delete a reading goal |
|
✏️ Remove a reading entry or a whole book |
|
lists
What you can do | Tool |
View your lists, or one list with its books |
|
✏️ Create or rename a list, or change its privacy |
|
✏️ Add or remove a book on one list ( |
|
✏️ Delete a list |
|
journal
What you can do | Tool |
Read your journal entries (notes, quotes, status events) |
|
✏️ Add or edit a journal note/quote |
|
✏️ Delete a journal entry |
|
social
What you can do | Tool |
See recent activity from people you follow (or one user) |
|
✏️ Follow or unfollow a user |
|
Browse community book prompts |
|
✏️ Answer a prompt with a book, or withdraw the answer |
|
Development
git clone https://github.com/kristianedlund/hardcover-mcp.git
cd hardcover-mcp
uv syncLint and format checks (using Ruff):
uv run ruff check .
uv run ruff format --check .Run tests:
uv run pytest tests/ -vIntegration Tests
Integration tests hit the live Hardcover API and require a valid token. They are skipped automatically in CI and when the token is absent.
To run them locally, copy .env.example to .env in the repository root and put in your
token. The tests load .env (it's git-ignored); the server itself never does:
cp .env.example .envThen run:
uv run pytest tests/integration/ -vWrite tests follow a create → verify → delete lifecycle so the account is left unchanged.
Contributing
Contributions are welcome! Please:
Open an issue first to discuss the change.
Fork the repo and create a branch (
feature/short-descriptionorfix/short-description).Run lint and tests before submitting:
uv run ruff check . uv run ruff format --check . uv run pytest tests/ -vKeep PRs focused — one change per PR.
Use conventional commit prefixes:
feat:,fix:,chore:,docs:.
Rate Limiting
The Hardcover API allows 60 requests per minute with a short burst allowance, and a daily limit (5,000 requests on the free plan). The server queues requests, follows the API's rate-limit headers, and retries when asked to wait. It waits at most a minute at a time; if Hardcover asks for longer, the call stops and says how long to wait. Once the daily limit is used up it stops immediately with a message saying so (it resets at midnight UTC). Your usage is shown at hardcover.app/account/api. Keys created after August 2026 get twice the burst allowance of older keys.
Troubleshooting
Problem | Fix |
"API token is not set" | Add your token to the config (see Quick Start above) |
"Hardcover rejected the API token" | The key is invalid or expired; create a new one with the link in the error |
"missing the scope(s) this tool needs" | Create a key that includes them; the error links to a pre-filled form |
"daily API limit … is used up" | Wait until midnight UTC, or load fewer tools to make fewer calls |
"rate limit asks to wait N seconds" | Hardcover is throttling this key; try again after that time |
"Hardcover didn't answer within 30 seconds" | Try again; if you asked for a change, check whether it was saved first |
"Access is denied" on Windows | Add |
Slow or repeated errors | The server retries automatically — wait a moment and try again |
Unexpected results | Check for a newer version: the Hardcover API may have changed |
Disclaimer
Unofficial project. Not affiliated with Hardcover.
Available Tools
28 toolsdelete_journal_entryADestructiveIdempotent
Permanently delete one of your reading journal entries by id (from get_reading_journal). Only that entry is removed; the book, its status, and other entries are unaffected. Cannot be undone. Returns {deleted: true, id}.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Reading journal entry ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, yet the description adds real value beyond them: it scopes the blast radius ('Only that entry is removed; the book, its status, and other entries are unaffected'), flags irreversibility ('Cannot be undone'), and specifies the return shape. This is exactly the extra context a destructive tool needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the action and scope, then the blast-radius constraint, then the return value. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return value ({deleted: true, id}), and the irreversibility and scoping statements fully cover what an agent must know before invoking an irreversible delete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single documented id parameter, so the baseline is 3. The description goes beyond the schema by identifying the provenance of the id (get_reading_journal), which meaningfully helps the agent supply a valid value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Permanently delete one of your reading journal entries by id'. It also names get_reading_journal as the source of the id, separating it cleanly from sibling delete tools (delete_list, delete_user_book).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells the agent where to obtain the id ('from get_reading_journal'), which routes usage correctly. It lacks explicit when-not-to-use guidance or named alternatives for the adjacent set_journal_entry, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_listADestructiveIdempotent
Permanently delete a list you own by id. The books themselves stay in your library; only the list and its entries are removed. Cannot be undone. Returns {deleted: true, id}. To take a single book off use set_list_book with on_list=false.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Hardcover list ID to delete. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is known; the description goes further by clarifying blast radius ('the books themselves stay in your library; only the list and its entries are removed') and irreversibility ('Cannot be undone'), which annotations cannot express. It also discloses the return payload.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, each earning its place: action, blast radius, reversibility, return shape, and sibling routing. The destructive action is front-loaded in the first clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, the description covers what is destroyed, what survives, irreversibility, the return shape, and the alternative tool. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single documented 'id' parameter, so the schema already carries the semantics; baseline 3 applies. The description adds only the ownership constraint ('you own'), with no format or ID-source detail beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Permanently delete a list') plus the ownership scope ('you own'), which distinguishes it from sibling delete tools like delete_user_book and delete_journal_entry. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It routes the adjacent case explicitly: 'To take a single book off use set_list_book with on_list=false,' naming the alternative and its parameter. It does not spell out prerequisites (e.g. ownership checks) or when deletion is inappropriate, but the key sibling disambiguation is present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_reading_goalADestructiveIdempotent
Permanently delete one of your reading goals by id (from get_reading_goal). Cannot be undone; to just hide a goal use set_reading_goal(id, archived=true). Your books and reading progress are unaffected. Returns {deleted: true, id}.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Reading goal ID to delete. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and non-readOnly, but the description adds that the action is irreversible and, importantly, that books and reading progress are unaffected — a side-effect scope that annotations cannot express. It also discloses the return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each earning its place: what it does, the alternative, and the collateral-effect clarification plus return value. Front-loaded with the verb and permanence caveat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description states the return value ({deleted: true, id}), and it covers irreversibility, alternatives, and unaffected resources. Nothing needed to invoke it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the id parameter is already documented, but the description adds that the id comes from get_reading_goal, which helps the agent source the value correctly. Minor value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (delete) and resource (reading goal) plus scope (by id) and permanence. It is clearly distinguishable from siblings like set_reading_goal and delete_user_book.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use set_reading_goal(id, archived=true) to hide instead of delete, and names get_reading_goal as the source of the id. Both the when and the when-not are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_user_bookADestructiveIdempotent
Permanently remove a book from your library (by book_id or user_book_id), including its status, rating, review, and private notes. Cannot be undone. Returns {deleted: true, user_book_id}. To change status instead use set_user_book; to take it off a custom list use set_list_book(on_list=false).
| Name | Required | Description | Default |
|---|---|---|---|
| book_id | No | Hardcover book ID (will look up your library entry). | |
| user_book_id | No | Directly specify user_book ID if known. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true, but the description adds material context beyond them: the cascade of destroyed data (status, rating, review, private notes), irreversibility ('Cannot be undone'), and the literal return payload. With no output schema, disclosing the return shape is genuinely valuable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences: what it does, what it destroys, the return value, then the two alternatives. Front-loaded with the destructive action and every clause carries new information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive delete with no output schema, the description covers scope, side effects, irreversibility, return shape, and sibling routing. An agent has everything needed to call it correctly and to prefer alternatives where appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented ('Hardcover book ID (will look up your library entry)' / 'Directly specify user_book ID if known'). The description's 'by book_id or user_book_id' adds the either/or framing but no format or lookup semantics beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('delete/remove') and resource ('book from your library'), plus the two addressing modes (book_id or user_book_id). It explicitly separates itself from set_user_book and set_list_book, so an agent can pick it without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not guidance with named alternatives: use set_user_book to change status, set_list_book(on_list=false) to remove from a custom list. Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_user_book_readADestructiveIdempotent
Permanently delete one read entry (a single start/finish/progress record) by its user_book_read id from get_user_book. The book stays in your library with its status, rating, and review; only that read is removed. Cannot be undone. Returns {deleted: true, id}. To remove the whole book use delete_user_book.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The user_book_read ID to delete. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, but the description adds genuinely new context: exactly what is destroyed ('only that read is removed' while the book, status, rating, and review survive), that it is irreversible, and the return payload. That scoping detail is not derivable from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the action and scope, followed by consequences, return shape, and the sibling alternative. No filler and nothing repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, the description covers the action, blast radius, reversibility, return value, and the alternative tool. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with one documented parameter, so the baseline is 3. The description adds provenance value by specifying the id is a user_book_read id obtained from get_user_book, which the schema's terse 'The user_book_read ID to delete' does not establish.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource ('Permanently delete one read entry'), defines the granularity (a single start/finish/progress record), and names the sibling it is not ('To remove the whole book use delete_user_book'). An agent can distinguish this from delete_user_book without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use this for a single read record, use delete_user_book to remove the whole book. It also tells where the id comes from ('from get_user_book'), giving the agent a prerequisite source rather than leaving it to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activity_feedARead-only
Get recent social activity events (status changes, ratings, reviews, list updates), newest first. Read-only. Defaults to the feed of users you follow (empty if you follow nobody); pass user_id or username for one user's activity. Returns {returned, offset, activities} with event type, book, user, and timestamp per event. For your own detailed notes, quotes, and progress log use get_reading_journal; for your review texts use get_user_library(has_review=true).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max events to return (default 25, max 100). | |
| offset | No | Pagination offset (default 0). | |
| user_id | No | Fetch one user's activity by Hardcover user ID. | |
| username | No | Fetch one user's activity by username. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the bar is lower, yet the description still adds ordering (newest first), default-scope behavior including the empty-feed case, and the shape of the return object. It repeats 'Read-only' from the annotations rather than adding to it, keeping it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then scope, then return shape, then sibling disambiguation — good ordering with little waste. The return-shape sentence is justified only because there is no output schema; otherwise it is slightly dense at four sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Annotations cover safety and the schema covers all four parameters, so the description only needs to add scope and behavior — which it does, including the empty-feed edge case and response keys. Nothing an agent needs in order to invoke it correctly is missing, though rate limits or ordering guarantees for large offsets go unmentioned.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema doesn't: the semantic distinction that omitting user_id/username yields the followed-users feed and passing either targets a single user. limit/offset are left to the schema, which documents them adequately.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Get recent social activity events') and enumerates the event types (status changes, ratings, reviews, list updates). It also names the sibling tools it is not (get_reading_journal, get_user_library(has_review=true)), making the boundary clear without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the default scope (feed of followed users, empty if you follow nobody) and the condition to override it (pass user_id or username for one user's activity). It also routes to better-fitting alternatives for notes/quotes/progress and review texts, so when-not-to-use is covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_authorARead-only
Get an author by Hardcover id, slug, or name (provide at least one; a name resolves to the top search match). Read-only. Returns bio, birth/death year, book and reader counts, and up to books_limit of their books (title, year, rating). Use search_books(query_type='Author') to compare several candidates.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Hardcover author ID. | |
| name | No | Author name (e.g. 'Brandon Sanderson'). | |
| slug | No | Author slug (e.g. 'brandon-sanderson'). | |
| books_limit | No | Max books to return (default 20, max 100). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description redundantly confirms read-only. It adds genuinely new behavioral context: the name-resolution ambiguity, and the shape of the response payload since no output schema exists. It does not cover error cases when no identifier matches.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with purpose and lookup keys, then return shape, then the alternative. No filler and every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by enumerating the returned fields (bio, birth/death year, counts, book list with title/year/rating). Combined with the annotation safety profile, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: at-least-one identifier requirement, the top-match resolution semantics for name, and that books_limit caps the embedded book list. The other params add no extra syntax detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (get an author) plus the three accepted lookups (id, slug, name). It clearly differentiates itself from the sibling search_books, which is named as the multi-candidate alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the constraint 'provide at least one' identifier, explains the disambiguation behavior of a name lookup ('resolves to the top search match'), and routes the agent to search_books(query_type='Author') when comparing several candidates. Both the when-to-use and the alternative are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_bookARead-only
Look up a book or one specific edition of it. Read-only. With id or slug: the book (the work, across all editions) — title, authors, pages, community rating. With exactly one of isbn_13, asin, or edition_id: that specific printing, ebook, or audiobook — format, pages, audio length, release date, language, publisher, and a summary of its book. For a book, include_characters=true adds a 'characters' array in book order (id, name, slug, biography, plus 'spoiler' and 'only_mentioned' flags; don't reveal spoiler characters unless asked), and include_editions=true adds an 'editions' array, most-read first, up to editions_limit. Edition ids work with set_user_book (edition_id, owned). Use search_books first if you only have a title; for your own status/rating of the book use get_user_book.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Hardcover book ID. | |
| asin | No | Amazon ASIN of a specific edition. | |
| slug | No | Hardcover book slug (e.g. 'project-hail-mary'). | |
| isbn_13 | No | ISBN-13 of a specific edition (e.g. '9780593135204'). | |
| edition_id | No | Hardcover edition ID (e.g. from include_editions). | |
| editions_limit | No | With include_editions: max editions to return (default 10, max 50). | |
| include_editions | No | With id/slug: also return its editions (default false). | |
| include_characters | No | With id/slug: also return its characters (default false). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered. The description adds real beyond-annotation behavior: the spoiler/only_mentioned flags with a handling instruction ('don't reveal spoiler characters unless asked') and editions returned 'most-read first' up to editions_limit. It restates 'Read-only' redundantly, but the spoiler semantics are genuinely additive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the core work-vs-edition distinction leads, followed by the toggle behaviors and routing advice. Every sentence carries information, though the single-block paragraph is slightly heavy to scan for an 8-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates fully by enumerating the fields returned for both the work and the edition, plus the shapes of the include_characters and include_editions arrays. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes beyond it by explaining the semantic role of each input group (work-level id/slug vs edition-level isbn/asin/edition_id) and what the include_* toggles inject (characters in book order, editions most-read first). This adds meaning the schema descriptions alone don't convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('look up') and resource ('a book or one specific edition of it'), then draws the exact work-vs-edition distinction that defines the tool. It explicitly separates itself from siblings (search_books, get_user_book), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit selection rules: id or slug yields the work, exactly one of isbn_13/asin/edition_id yields the edition. It also names alternatives and their triggers ('Use search_books first if you only have a title; for your own status/rating... use get_user_book') and points edition ids to set_user_book.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_listARead-only
Without id: list the lists you own, most recently updated first, as {total, returned, offset, lists} (id, name, slug, description, books count, privacy; no books), paginated with limit/offset. With id: get that list (yours or another user's) including a 'books' array in list order (position, book_id, title, slug, authors), paginated with books_limit/books_offset. Read-only. Find other users' lists with search_books(query_type='List').
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | List ID. Omit to list your own lists. | |
| limit | No | Without id: max lists to return (default 50, max 200). | |
| offset | No | Without id: offset for pagination (default 0). | |
| books_limit | No | With id: max books to return (default 25, max 100). | |
| books_offset | No | With id: offset for book pagination (default 0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnly/openWorld; the description goes much further by disclosing default sort order (most recently updated first), the pagination scheme in each mode, and that list contents come back in list order with a books array. It also clarifies cross-user readability, which the annotations do not.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the mode split, then per-mode return shape and pagination, then the sibling pointer. Three dense clauses, no repetition, every phrase carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return contract, and it does: it enumerates the top-level envelope {total, returned, offset, lists}, the per-list fields, and the nested books fields. An agent has everything needed to call it and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter description already states 'Without id' / 'With id' scope plus defaults and maxima. The description restates that same mode-to-parameter mapping and adds no syntax or format detail beyond it, so it sits at the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource and splits the tool into its two modes (list your own lists vs. fetch a single list) with the exact return shape for each. That dual-mode framing lets an agent distinguish it from siblings like search_books or get_user_library without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly conditions usage: omit id to enumerate your own lists, supply id to fetch one list (yours or another user's). It also names the alternative for discovering other users' lists, search_books(query_type='List'), which is the exact routing decision an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_promptsARead-only
List community book prompts (questions like 'best sci-fi of 2025'), most answered first, paginated with limit/offset. Read-only. Set featured=true for featured prompts only. Returns {returned, offset, prompts} with id, question, description, answers_count, and books_count. Use it to browse; to find a prompt by words in its question use search_books(query_type='Prompt'). Pass a prompt id to set_prompt_answer to submit a book.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max prompts to return (default 25, max 100). | |
| offset | No | Pagination offset (default 0). | |
| featured | No | If true, return only featured prompts (default false). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the brief 'Read-only' line is largely redundant, but the description adds genuinely new behavior: default ordering by answer count, pagination via limit/offset, the shape of the returned object, and the featured filter semantics. It does not mention result caps or failure modes, but for a simple read tool this is close to sufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose and ordering, then routing, then return shape, then next step – a sensible information hierarchy with no filler. The 'Read-only' sentence is the only line that does not earn its place given the annotation, keeping it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description enumerates the return envelope ({returned, offset, prompts}) and key fields (id, question, description, answers_count, books_count), which is exactly what the agent needs. Combined with the sibling routing and the set_prompt_answer handoff, nothing material is missing for a 3-param read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and all three parameters (limit, offset, featured) are already documented in the schema, so the description's restatement of featured and pagination adds no syntax or constraint information beyond it. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (list community book prompts) with a concrete example of what a prompt is, plus the default ordering (most answered first). It is clearly distinguishable from search_books, which it explicitly names as the retrieval-by-keyword alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use split: browse here vs. search_books(query_type='Prompt') to find by words in the question. It also chains forward by naming set_prompt_answer as the consumer of a prompt id, so the agent knows the follow-up action.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_publisherARead-only
Look up a publisher by Hardcover id, slug, or name (provide one; a name resolves to the top search match). Read-only. Returns name, editions count, parent publisher, and a page of its editions (the same edition fields as get_book, plus each edition's book: id, title, slug, rating, release year) via editions_limit/editions_offset.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Hardcover publisher ID. | |
| name | No | Publisher name (e.g. 'Tor Books'). | |
| slug | No | Publisher slug (e.g. 'tor-books'). | |
| editions_limit | No | Max editions to return (default 20, max 100). | |
| editions_offset | No | Offset for editions pagination (default 0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, and the description adds the non-obvious resolution behavior (name → top search match) plus what the response includes. It stops short of stating failure behavior when nothing resolves or when multiple identifiers are supplied, which matters for an openWorld lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One tight passage with the lookup constraint front-loaded and the return shape trailing; every clause (identifier exclusivity, name resolution, editions paging) carries information the schema and annotations do not.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully names the returned fields, including the embedded book stubs and paging controls, so return values are covered. Remaining gap is edge-case behavior: no-result, ambiguous name, or multiple identifiers passed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description exceeds it by explaining that exactly one identifier should be supplied, how name matching resolves, and that editions_limit/editions_offset page the embedded editions list.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (look up) and resource (publisher), enumerates the three accepted identifier forms, and clarifies that a name resolves to the top match. An agent can distinguish this from get_book/get_author immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical "provide one" states the selection constraint across id/slug/name, which is real usage guidance given zero required parameters. It does not name an alternative tool or say when to prefer this over search_books, so it falls short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_reading_goalARead-only
Get your active (non-archived) reading goals, soonest end date first. Read-only. Returns {returned, offset, goals} with each goal's id, target, metric (book/page), progress, date range, privacy, and state; 'goals' is empty if you have none. To create or change or archive a goal use set_reading_goal; to delete one use delete_reading_goal.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max goals to return (default 10, max 100). | |
| offset | No | Offset for pagination (default 0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered; the description reinforces 'Read-only' and adds genuine behavioral context: the return shape ({returned, offset, goals}), per-goal fields, ordering, and that 'goals' is empty when none exist. It stops short of discussing pagination behavior beyond the shape, but that is minor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and scope, followed by return shape and then sibling routing — no filler sentences. Every clause (scope, ordering, return fields, empty case, alternatives) carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description compensates by enumerating the return structure and the fields of each goal. Combined with the two fully-documented parameters and the readOnly annotation, an agent has everything needed to call and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (limit, offset) are fully documented in the schema, so the description need not compensate. It only implies pagination via the returned/offset fields in the response shape, adding no syntax or default details beyond the schema — baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get ... reading goals') plus a clear scope constraint ('active (non-archived)') and an ordering rule ('soonest end date first'). It also names the sibling tools that handle the other operations (set_reading_goal, delete_reading_goal), so an agent can distinguish it without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use set_reading_goal to create/change/archive and delete_reading_goal to delete. The condition selecting this tool (read the current active goals) is unambiguous, and the empty-result case is disclosed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_reading_journalARead-only
Get your own reading journal, newest first: notes, quotes, status changes, ratings, reviews, and progress updates. Read-only. Filter by book_id and/or event type; paginate with limit/offset. Returns {returned, offset, entries}; each entry has its id, event, text, timestamp, privacy, and book. This is your personal log; for what people you follow are doing use get_activity_feed; for review texts use get_user_library(has_review=true).
| Name | Required | Description | Default |
|---|---|---|---|
| event | No | Filter by event type. Examples: 'note', 'quote', 'status_currently_reading', 'status_read', 'rated', 'reviewed', 'progress_updated'. | |
| limit | No | Max entries to return (default 25, max 100). | |
| offset | No | Pagination offset (default 0). | |
| book_id | No | Filter entries to a specific book by Hardcover book ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description reinforces read-only while adding ordering ('newest first') and a full return shape. It does not mention pagination edge behavior or rate limits, but with annotation coverage the remaining gap is minor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences: description of contents first, mechanics second, disambiguation last. Slightly dense (return-shape detail inline), but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by specifying the returned envelope {returned, offset, entries} and per-entry fields, plus ordering and filter combinations. An agent has everything needed to call and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all four parameters are already documented with examples and defaults. The description only restates that book_id and event can be combined and that limit/offset paginate, adding no syntax or format beyond the schema — baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get your own reading journal') and enumerates the event content it contains (notes, quotes, status changes, ratings, reviews, progress). It explicitly distinguishes itself from get_activity_feed and get_user_library(has_review=true), so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names two alternatives with the exact condition that selects each: social feed → get_activity_feed, review texts → get_user_library(has_review=true). It also states the filtering/pagination mechanics, leaving nothing to inference about when to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_seriesARead-only
Get a book series by id, slug, or name (provide one; a name resolves to the top search match). Read-only. Returns series info (authors, books count, completed flag) and all its books in reading order with position, title, release year, and rating. Use search_books(query_type='Series') if a name might be ambiguous.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Hardcover series ID. | |
| name | No | Series name, resolved to the top search match (e.g. 'The Stormlight Archive'). | |
| slug | No | Series slug (e.g. 'the-stormlight-archive'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so 'Read-only' adds nothing. The description does add real behavioral context beyond them: name resolution silently picks the top search match, and the response is described as series info plus the full ordered book list. It stops short of noting any limits on how many books are returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the identifier options, then return payload, then the sibling escape hatch. No filler and nothing repeated from the schema verbatim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the return contract, and it does: series metadata fields plus per-book position, title, release year, and rating in reading order. Combined with the identifier guidance, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so each parameter is already documented, and the baseline would be 3. The description earns more by supplying the one-of relationship ('provide one') that the schema cannot express, since no parameter is marked required, and by flagging the fuzzy-match semantics of 'name'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb plus resource ('Get a book series') with the three accepted identifiers named, and it enumerates what comes back (series info plus books in reading order). An agent can distinguish it from get_book, get_author, and search_books without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the selection constraint ('provide one') and names the alternative explicitly: use search_books(query_type='Series') if a name might be ambiguous. It also warns that a name resolves to the top search match, which tells the agent when this tool's shortcut is unsafe.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_trending_booksARead-only
Get the books trending on Hardcover in a time window ('duration', default 'week'), ranked most popular first and paginated with limit/offset. Read-only. Returns {returned, offset, books} with book_id, slug, title, authors, rating, and release year. For curated themed collections use get_vibes; for a custom query use search_books with sort='users_count:desc'.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max books to return (default 25, max 100). | |
| offset | No | Pagination offset (default 0). | |
| duration | No | Time window (default 'week'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the 'Read-only' restatement adds little. However, the description adds real behavioral context beyond the annotations: ranking order (most popular first), pagination via limit/offset, and the exact return envelope and fields, which lets an agent plan consumption of results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, all front-loaded: purpose, semantics, then disambiguation. No filler, and the sibling routing comes last where it belongs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by naming the return shape ({returned, offset, books}) and key book fields. Combined with 100% parameter coverage and annotations, an agent has everything needed to call and consume the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is documented with defaults and bounds, so the schema carries the semantics. The description mentions 'duration' default 'week' and limit/offset pagination, which largely repeats the schema rather than adding new meaning (e.g., ordering interplay with offset, or how duration buckets are computed). Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('books trending on Hardcover'), plus scope details (time window, popularity ranking, pagination). Explicitly distinguishes itself from get_vibes and search_books, so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit alternatives with the condition that selects each: 'For curated themed collections use get_vibes; for a custom query use search_books with sort=users_count:desc.' That is exactly the when-to-use-this-vs-alternatives guidance the dimension rewards.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_userARead-only
Get a Hardcover user's profile. With no arguments, returns your own profile (the owner of the API token) including your user id; otherwise look someone up by id, username, or name (name resolves to the top search match). Read-only. Returns bio, book/follower counts, and privacy. Optional sections: include_library (recent library entries, each with the book's community 'rating' and the user's own 'user_rating'; a private user's comes back empty unless you follow them), include_following / include_followers (who they follow / who follows them, newest first), and include_stats (your own profile only: totals per status, average rating, books read in stats_year, default this year). For activity use get_activity_feed; to follow someone use set_following. Fails if the token is missing or invalid.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Hardcover user ID. | |
| name | No | Display name to search for (resolves to the top match). | |
| username | No | Hardcover username (e.g. 'adam'). | |
| stats_year | No | Year for books_read_this_year (default: current year). | |
| follow_limit | No | Max people per follow list (default 25, max 100). | |
| include_stats | No | Your own profile only: include reading statistics (default false). | |
| library_limit | No | Max library entries to return (default 10, max 50). | |
| library_status | No | Only library entries with this status. | |
| include_library | No | If true, include recent library entries (default false). | |
| include_followers | No | Include who follows the user (default false). | |
| include_following | No | Include who the user follows (default false). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/openWorldHint; the description adds substantive traits beyond that: private users' libraries return empty unless followed, stats are restricted to your own profile, follow lists are newest-first, name lookups resolve to the top match, and the call fails on a missing/invalid token. These are real behavioral constraints an agent could not infer from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior, then optional sections, then sibling routing, so it reads in priority order. It is a single dense paragraph with heavy parentheticals that could be broken into bullets, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter, no-output-schema tool, the description covers return contents (bio, book/follower counts, privacy), each optional section's payload, ordering, and failure conditions. An agent has everything needed to call it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds semantics the schema lacks: include_library explains what each entry contains (community rating vs user_rating) and the privacy caveat, include_stats is scoped to own profile only, and stats_year defaults to the current year. It leaves the limit parameters (follow_limit, library_limit) to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a Hardcover user's profile') plus the scope rule (no args = token owner, otherwise by id/username/name). It explicitly names the adjacent tools it is not (get_activity_feed, set_following), so an agent can distinguish it from siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing: default to self with no arguments, look up others by id/username/name, and 'For activity use get_activity_feed; to follow someone use set_following.' Both when-to-use and when-to-use-something-else are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_bookARead-only
Get your own library entry for one book: pass book_id or slug (book_id wins if both are given). Read-only. Returns user_book_id, status, user_rating (your rating), privacy, review, private notes, chosen edition, and every read entry (with their ids, needed by set_user_book_read/delete_user_book_read), plus the lists of yours it's on (not Owned; change them with set_list_book). Returns 'Book not in your library' if you haven't added it, or 'No book found with slug …' for an unknown slug. This is your relationship to the book; for the book itself (description, pages, community rating) use get_book, and to browse many of your books use get_user_library.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | Hardcover book slug (e.g. 'project-hail-mary'). | |
| book_id | No | Hardcover book ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description enumerates the return payload (user_book_id, status, ratings, review, private notes, edition, read entries, lists), and discloses exact error strings ('Book not in your library', 'No book found with slug …') plus the caveat that Owned is excluded from the returned lists. This is rich context an agent cannot get from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core operation and parameter precedence before diving into return fields, and each clause carries information (return shape, error messages, sibling routing). It is a dense single paragraph rather than a tightly segmented one, which slightly hurts scanability but wastes little.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates fully by describing the returned fields and their downstream use (read-entry ids needed by set_user_book_read/delete_user_book_read). Nothing an agent needs to invoke or interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3; the description adds genuine value by stating the precedence rule 'book_id wins if both are given', resolving an ambiguity the schema does not address. It does not restate slug/ID formats, but the schema handles that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Get your own library entry for one book') and immediately distinguishes this from the sibling tools get_book and get_user_library by naming their distinct scopes. An agent can tell exactly which tool handles 'my relationship to this book' versus the book record itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes to alternatives: 'for the book itself ... use get_book, and to browse many of your books use get_user_library', and notes list changes go through set_list_book rather than here. This gives concrete when-to-use-this vs when-to-use-another guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_libraryARead-only
List books in your own library (any status), paginated with limit/offset. Read-only. Filter by status, by finished-date range (start_date + end_date), or has_review=true for books you have reviewed (adds review text, spoiler flag, and review date; newest review first). Sort by updated, rating, date_added, or reviewed. Returns user_book_id, book_id, title, authors, status, and user_rating (your rating) per book (with a date range, also the read's dates). E.g. sort='rating' for top-rated; a date range answers 'what did I read in May?' (always newest finish first, so it can't take sort/order). owned=true keeps only books with an edition in your Owned list (set with set_user_book); owned books that aren't in your library are not listed. Filters combine, e.g. owned=true with status='Want to Read'. For one book's full entry use get_user_book.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort field: 'updated' (default), 'rating', 'date_added', or 'reviewed' (default when has_review=true). | |
| limit | No | Max books to return (default 25, max 100). | |
| order | No | Sort direction: 'desc' (default) or 'asc'. | |
| owned | No | Only books with an edition in your Owned list. Combines with the other filters. | |
| offset | No | Offset for pagination (default 0). | |
| status | No | Only books with this status. | |
| end_date | No | Latest finished_at date (ISO 8601, e.g. '2025-12-31'). Must be paired with start_date. | |
| has_review | No | Only books you have reviewed, with review fields included. Can't be combined with start_date/end_date. | |
| start_date | No | Earliest finished_at date (ISO 8601, e.g. '2025-01-01'). Must be paired with end_date. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, it discloses that the operation is read-only, what fields are returned, how date-range results are ordered ('always newest finish first'), and a subtle ownership caveat ('owned books that aren't in your library are not listed'). It also explains filter combination behavior, which is valuable operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded with the core purpose and then proceeds through filters, sorting, return fields, examples, and the sibling alternative. Despite covering nine parameters, every sentence adds useful information; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With nine optional parameters, no output schema, and open-world behavior, the description supplies the return-field list, filter interaction rules, sorting defaults, and edge cases. An agent has enough information to call the tool correctly without needing the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds meaningful semantics beyond the schema: it explains how sort interacts with has_review, that date ranges cannot take sort/order, that filters combine, and gives example values such as sort='rating'. This materially helps an agent choose parameters correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('List books in your own library') and defines scope ('any status'), pagination, filtering, sorting, and returned fields. It also explicitly distinguishes itself from the sibling tool get_user_book for a single book's full entry.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete when-to-use examples: sort='rating' for top-rated books, a date range for 'what did I read in May?', and owned=true combined with status filters. It also names the alternative tool to use for one book's full entry and explains constraints such as date ranges not accepting sort/order.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_vibesARead-only
List Hardcover 'vibes': curated, themed book recommendation collections (e.g. 'Hidden Gem Fantasy'). Read-only. Only featured vibes are returned unless featured=false; paginate with limit/offset. Returns {returned, offset, vibes}; each vibe includes title, description, likes, and up to books_per_vibe books. For popularity rankings use get_trending_books; for user-made lists use get_list.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max vibes to return (default 10, max 50). | |
| offset | No | Pagination offset (default 0). | |
| featured | No | If true (default), return only featured vibes. | |
| books_per_vibe | No | Books to include per vibe (default 10, max 50). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds useful behavioral context: featured filtering is on by default, pagination uses limit/offset, and the result shape includes vibes with nested book data. It does not cover auth or rate limits, so it falls short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: purpose first, then read-only status, filtering/pagination, return shape, and alternatives. Every sentence carries useful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although there is no output schema, the description explains the return object and the fields included per vibe. Combined with full schema coverage and safety annotations, it gives the agent enough to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the four parameters are already documented with defaults and limits. The description reinforces featured filtering and pagination, but it mostly restates what the schema provides rather than adding new parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: 'List Hardcover vibes'. It immediately defines vibes as curated, themed book recommendation collections and includes an example, so the agent can distinguish this from sibling list-related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use alternatives: get_trending_books for popularity rankings and get_list for user-made lists. It also explains the featured-vibes default and pagination behavior, leaving little ambiguity about scope.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_booksARead-only
Full-text search across Hardcover's catalog by title, author, ISBN, or keyword; set query_type to search authors, series, lists, users, publishers, characters, or prompts instead of books. Read-only. Returns {total, returned, page, } (e.g. 'books', 'authors') with compact hits (book hits: book_id, title, authors, series; others: id, name, slug, plus type-specific fields) ranked by relevance unless 'sort' is given. Use it to discover ids, then call get_book, get_author, get_series, etc. for full details. If you already have an id, slug, or ISBN, call the matching get_* tool directly.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1). | |
| sort | No | Typesense sort expression, e.g. 'rating:desc' or 'users_count:desc' for most popular first. | |
| query | Yes | Search query (title, author name, ISBN, etc.). | |
| per_page | No | Results per page (default 10, max 25). | |
| filter_by | No | Typesense filter expression, e.g. 'release_year:>2020' or 'release_year:[2020..2024]'. | |
| query_type | No | Entity type to search (default: 'Book'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnlyHint and openWorldHint, and the description's 'Read-only' only restates them. However it adds real behavioral context beyond annotations: the default relevance ranking, the effect of supplying 'sort', paging behavior via {total, returned, page}, and the compact hit shape per entity type. It stops short of describing rate limits or errors, so a 4 rather than 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph with the core purpose front-loaded, followed by entity-type scope, return shape, and a routing rule. Every sentence carries distinct information and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by specifying the return envelope ({total, returned, page, <type>}) and the per-hit fields. For a 6-parameter read-only search tool, an agent has everything needed to call it and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds meaning on top: it explains that query_type selects alternate entity types rather than books, and that results are relevance-ranked unless 'sort' is provided. It doesn't clarify filter_by/per_page interactions, so not a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('full-text search') and resource ('Hardcover's catalog'), plus the searchable fields (title, author, ISBN, keyword) and the query_type expansion to other entities. It is clearly distinguishable from the get_* siblings it names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use it to discover ids and then call get_book/get_author/etc., and gives a concrete exclusion: if you already have an id, slug, or ISBN, call the matching get_* tool directly. This is textbook when/when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_followingADestructiveIdempotent
Follow (following=true) or unfollow (following=false) another Hardcover user, identified by user_id or username (provide one; user_id wins if both are given). Idempotent: if you already are in the requested state nothing changes. Followed users' activity appears in get_activity_feed. Returns user_id, following, and 'changed' (whether anything was done); an unknown user is an error.
| Name | Required | Description | Default |
|---|---|---|---|
| user_id | No | Hardcover user ID. | |
| username | No | Username (resolved to an ID). | |
| following | Yes | true to follow, false to unfollow. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotency, destructiveness, and open-world behavior; the description adds concrete meaning beyond them: what 'idempotent' means here ('nothing changes'), that an unknown user is an error, and exactly which fields are returned. This is a meaningful behavioral supplement rather than a restatement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph that front-loads the core action, then identifier resolution, idempotency, downstream effect, and return shape. Every sentence carries actionable information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by naming the returned fields (user_id, following, changed) and the error condition for an unknown user. For a three-parameter mutation tool this is fully sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds the non-obvious precedence rule that user_id wins when both identifiers are supplied. The boolean semantics are already in the schema, so it falls short of a full 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb pair (follow/unfollow) and resource (another Hardcover user), with the boolean flag semantics spelled out. No sibling tool does this, so it is unambiguous against the provided tool list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says how to trigger each mode via following=true/false, how to identify the target (user_id or username, user_id wins), and points to get_activity_feed as the downstream consumer. An agent has everything needed to choose and call it correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_journal_entryADestructive
Add a note or quote to your reading journal (omit id; book_id, entry, and event required) or edit one of your existing notes/quotes (pass its id from get_reading_journal; only the fields you pass change, the book can't). New entries are public unless privacy says otherwise. Each create makes a separate entry. Status, rating, and progress entries can't be created or edited here; they come from set_user_book and set_user_book_read. Returns the entry with its id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Journal entry ID to edit. Omit to create a new entry. | |
| entry | No | Journal entry text (required when creating). | |
| event | No | Entry type (required when creating). | |
| book_id | No | Hardcover book ID (required when creating). | |
| privacy | No | Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public. | |
| edition_id | No | Optional Hardcover edition ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses the default visibility of new entries (public), that each create produces a separate entry (consistent with idempotentHint=false), and the immutability of book_id on edit — real behavioral context. It does not explicitly warn that editing replaces the existing entry text, which is the main destructive risk flagged by destructiveHint=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the create/edit fork and very dense with useful content; the parenthetical clauses carry the conditional rules efficiently. It is slightly cramped — two distinct modes packed into one sentence — but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter mutation tool with no output schema, everything an agent needs is present: mode selection, conditional required fields, defaults, what cannot be changed, sibling routing for excluded entry types, and the return value (the entry with its id).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description adds meaning the schema cannot express: the schema marks zero required parameters, while the description states book_id, entry, and event are required when creating. It also ties id to get_reading_journal and notes privacy's default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb pair (add vs. edit) and the exact resource (a reading journal note/quote), and it explicitly carves out the entry types it does not handle by pointing at set_user_book and set_user_book_read. An agent can distinguish this from get_reading_journal or delete_journal_entry without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Mode selection is spelled out precisely: omit id to create, pass an id obtained from get_reading_journal to edit. It also states an exclusion (status/rating/progress entries belong to set_user_book and set_user_book_read) and a behavioral rule for updates (only the fields you pass change, the book can't).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_listADestructive
Create a list (omit id; name required) or change the name, description, or privacy of a list you own (pass id plus at least one field; only the fields you pass are overwritten). Creating twice makes two lists, so check get_list first. Returns the list's id, name, slug, description, and privacy. Does not change which books are on it: use set_list_book for that.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | List ID to update. Omit to create a new list. | |
| name | No | List name (required when creating). | |
| privacy | No | Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public. | |
| description | No | List description. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=false and openWorldHint=true. Still missing is any disclosure of permission/auth requirements or what happens to fields you omit; a 3 is warranted since the annotation set already carries part of the load and the remaining gaps are real.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: mode selection is front-loaded, then the duplicate-write warning, then the return shape, then the sibling boundary. No filler and no repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, and the description compensates by naming the returned fields (id, name, slug, description, privacy). For a 4-param mutation with good schema coverage, nothing an agent needs to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents every parameter including the privacy enum values and the create default. The description mirrors the schema's own mode rules but adds no syntax or format detail beyond what structured fields already provide, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States precise verbs and resource: create a list or change name/description/privacy of an owned list. It also explicitly names the boundary against set_list_book ('Does not change which books are on it') and against get_list, so an agent can separate it from siblings without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit mode-selection rules (omit id + name to create; pass id plus at least one field to update) and an explicit prerequisite ('check get_list first' because creating twice makes two lists). It also names the alternative tool for book membership, which is a clear when-not-to-use signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_list_bookADestructiveIdempotent
Put a book on your lists (on_list=true) or take it off (on_list=false): one list with list_id (optionally at a position), or up to 20 at once with list_ids. Idempotent: lists already in the requested state don't change, and an existing entry's position is not moved. Does not touch your library or reading status (use set_user_book). With list_id returns list_id, book_id, on_list, 'changed', and list_book_id; with list_ids returns one result per list, and a list that isn't yours or fails gets an 'error' while the others still change. Find list ids with get_list (or a book's current lists with get_user_book) and book ids with search_books.
| Name | Required | Description | Default |
|---|---|---|---|
| book_id | Yes | Hardcover book ID. | |
| list_id | No | Hardcover list ID. Use this or list_ids. | |
| on_list | Yes | true to add the book, false to remove it. | |
| list_ids | No | Several list IDs (up to 20). Use this or list_id. | |
| position | No | Position when adding to a single list_id (optional; ignored when removing). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by spelling out partial-failure semantics: with list_ids, a list that isn't yours or fails returns an 'error' while the others still change. It also pins down idempotency concretely (already-in-state lists don't change, existing positions are not moved) and enumerates return fields for both modes, which annotations alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One dense paragraph that front-loads the core action and mode switch, then layers idempotency, side-effect exclusions, return shape, and ID discovery. Nearly every clause carries information an agent needs; nothing is repeated from the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return fields for both single and bulk modes and describes the per-list error envelope. Combined with the destructive and idempotent annotations, an agent has everything needed to invoke this correctly and to interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds mode-level meaning by framing list_id as the single-list path (with optional position) and list_ids as the bulk path capped at 20. It does not add format or range detail beyond what the schema already documents, so it sits just above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opening clause states a specific verb pair and resource ('Put a book on your lists... or take it off') with the boolean that selects each mode. It explicitly separates itself from set_user_book (library/reading status) and from set_list, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit mode selection via on_list, an either/or between list_id and list_ids with a stated cap, and redirects to set_user_book when the user actually wants library/reading status changes. It also names the discovery tools (get_list, get_user_book, search_books) for the IDs the caller must supply.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_prompt_answerADestructiveIdempotent
Answer a community prompt with a book (answered=true, optionally with a description of why it fits) or withdraw that answer (answered=false). Idempotent: if you already answered the prompt with that book, nothing changes and the existing description is kept. Changes take a few seconds to show, so don't repeat a call immediately. You can answer one prompt with several different books. Returns prompt_id, book_id, answered, 'changed', and answer_id. Find prompt ids with get_prompts and book ids with search_books.
| Name | Required | Description | Default |
|---|---|---|---|
| book_id | Yes | Hardcover book ID. | |
| answered | Yes | true to submit the book, false to withdraw it. | |
| prompt_id | Yes | Hardcover prompt ID (use get_prompts to find IDs). | |
| description | No | Why this book fits the prompt (optional; when adding). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare write/idempotent/destructive/open-world, but the description adds semantics beyond them: idempotency means the existing description is preserved, not overwritten, and there is a propagation delay of a few seconds before changes appear. It also enumerates the returned fields in the absence of an output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core operation is front-loaded in sentence one, then idempotency, timing, cardinality, and return fields follow in order of usefulness. Four sentences, no filler, no repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter mutation tool with no output schema, the description covers the mode switch, idempotency, latency, cardinality, return payload, and how to source the two ids. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes slightly further by explaining the behavioral meaning of answered (submit vs withdraw) and by tying description to the add path only ('optionally with a description of why it fits'). It does not add format or constraint detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource pair — answer/withdraw a book on a community prompt — and names the two modes (answered=true/false) in the first sentence. It is clearly distinguishable from read-oriented siblings like get_prompts and search_books, which it references rather than duplicates.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains the when: true to submit, false to withdraw, optional description only when adding. It also gives the when-not ('don't repeat a call immediately') and the alternatives for obtaining inputs (get_prompts for prompt ids, search_books for book ids), plus the allowance to attach several books to one prompt.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_reading_goalADestructiveIdempotent
Create, update, or archive a reading goal. Without id: goal, metric, start_date, and end_date are required; if an active goal with the same metric and dates exists it is updated (only the fields you pass change), otherwise a new goal is created. With id (from get_reading_goal): edit that goal, changing only the fields you pass; archived=true hides it from get_reading_goal and archived=false brings it back. Returns the goal with id, target, progress, state, and archived. To remove a goal for good use delete_reading_goal.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Goal ID to edit (from get_reading_goal). Omit to create. | |
| goal | No | Target count to reach by end_date. | |
| metric | No | Goal metric: 'book' or 'page'. | |
| privacy | No | Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). | |
| archived | No | With id: true archives the goal, false restores it. | |
| end_date | No | End date (ISO 8601, e.g. '2026-12-31'). | |
| start_date | No | Start date (ISO 8601, e.g. '2026-01-01'). | |
| description | No | Optional goal description. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavior beyond annotations: it explains the upsert rule for matching metric and dates, that only passed fields change, that archive hides from get_reading_goal and is reversible, that permanent deletion is handled elsewhere, and what fields the response contains. This is far richer than the destructive/idempotent hints alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then proceeds through create-vs-edit branches, archive behavior, return shape, and the permanent-deletion alternative. Every sentence carries operational information and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers creation, editing, archiving, restoration, conditional required fields, return fields, and the correct sibling for permanent deletion. It is complete enough for an agent to choose and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema already documents each parameter at 100% coverage, the description adds conditional semantics the schema does not capture: goal, metric, start_date, and end_date are required when creating without an id, and with an id only passed fields are changed. The archived parameter behavior is also contextualized relative to get_reading_goal.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource combination — 'Create, update, or archive a reading goal' — and explicitly distinguishes the operation from get_reading_goal and delete_reading_goal. An agent can immediately tell this is the write/upsert/archive tool for reading goals.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit branching guidance: without an id, create or update based on matching metric and dates; with an id from get_reading_goal, edit that goal. It also names the alternative for permanent deletion — delete_reading_goal — and clarifies that archived=false restores rather than deletes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_user_bookADestructiveIdempotent
Add a book to your library or update your entry for it: status, rating, review, privacy, private notes, edition, and whether you own it. Upsert: creates the entry if the book isn't in your library yet, otherwise overwrites only the fields you pass (null leaves a field as it is; clearing one isn't supported). owned=true/false marks ownership of edition_id (or of the entry's current edition if edition_id is omitted; errors if there is none); passing edition_id also makes it the edition you're reading. Ownership changes are idempotent. Returns user_book_id, status, privacy, user_rating, edition_id, and owned/owned_changed when owned was given. Use set_user_book_read for start/finish dates and progress, set_list_book for custom lists, and delete_user_book to remove the book.
| Name | Required | Description | Default |
|---|---|---|---|
| owned | No | true/false: you own (or no longer own) edition_id, or the current edition if edition_id is omitted. | |
| rating | No | Your rating (e.g. 4.0, 3.5); returned as user_rating. Omit to leave unchanged. | |
| status | No | Reading status. | |
| book_id | Yes | Hardcover book ID. | |
| privacy | No | Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). | |
| edition_id | No | Edition ID (from get_book). Sets which edition you're reading. | |
| review_raw | No | Plain-text review content (converted to Slate format). | |
| reviewed_at | No | ISO date of the review (e.g. '2025-06-01'). | |
| private_notes | No | Private notes visible only to you. | |
| review_has_spoilers | No | Whether the review contains spoilers. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations: it explains that null leaves a field untouched, that clearing a field is NOT supported, the cross-field side effect of edition_id on the reading edition, the error case when no edition exists, and which fields are echoed back. That is exactly the kind of hidden behavior an agent needs before a destructive upsert. It stops short of five only because the destructiveHint consequence (what a mistaken overwrite actually costs) is implied rather than stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation and the field list, then the upsert rule, then the tricky owned/edition_id case, then sibling routing — a sensible ordering. It is dense with nested parentheticals, though, and a bulleted split of the owned semantics would read faster.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Ten parameters, one required, no output schema — yet the description covers mutation semantics, the null-vs-clear rule, cross-field effects, an error condition, and the return fields. Nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so baseline is 3; the description earns more by documenting the interaction between owned and edition_id (ownership of the given edition, falling back to the current edition, erroring if none) and the rating-to-user_rating rename. The remaining parameters are left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Add a book to your library or update your entry') and immediately pins the operation type as an upsert. It enumerates the exact fields under scope and distinguishes itself from the read/list/delete siblings by name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes three adjacent concerns to other tools: set_user_book_read for dates/progress, set_list_book for custom lists, delete_user_book for removal. The when-to-use question is answered without requiring the agent to compare schemas.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_user_book_readADestructive
Log or edit reading dates and progress (pages or audiobook seconds). With id (a user_book_read id from get_user_book): edit that read, overwriting only the fields you pass, e.g. to fix a past finish date. Without id: pass book_id or user_book_id; if the book has an unfinished read it is updated (progress, a later finish date, or the same start date), otherwise a new read is created, e.g. a re-read or a past read with its own dates. The book must already be in your library (add it with set_user_book). Returns the read entry with its id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | user_book_read ID to edit. Omit to log on a book. | |
| book_id | No | Without id: book ID (auto-resolves your user_book). | |
| edition_id | No | Edition ID (required for audiobook progress tracking). | |
| started_at | No | Date started reading (ISO 8601, e.g. '2025-01-15'). | |
| finished_at | No | Date finished reading (ISO 8601, e.g. '2025-02-20'). | |
| user_book_id | No | Without id: user_book ID if known (skips lookup). | |
| progress_pages | No | Pages read so far. | |
| progress_seconds | No | Seconds of audiobook listened to so far. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation profile (readOnlyHint=false, destructiveHint=true), but the description adds real context beyond them: partial-update semantics ('overwriting only the fields you pass'), the update-vs-create branch resolution logic, and the library-membership precondition. It stops short of warning about duplicate-read risk on repeated id-less calls, which matters given idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb and the primary mode split, then the branch details, then the return value. Dense but nearly every clause carries decision-relevant information; the parenthetical examples ('a re-read or a past read with its own dates') are the only mildly expendable content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 optional parameters, no required fields, and no output schema, the description covers the decision logic (mode split), the precondition (library membership), and the return shape ('the read entry with its id'). Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description goes further by explaining how `id`, `book_id`, and `user_book_id` relate and are mutually exclusive by mode, and where `id` comes from (get_user_book). That interplay is not expressed in the schema descriptions, which only state each field in isolation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Log or edit reading dates and progress (pages or audiobook seconds)') and immediately splits the two operating modes by presence of `id`. It also names the sibling that supplies the id (get_user_book) and the sibling that must run first (set_user_book), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use branches: with `id` to edit an existing read, without `id` to log a new one via book_id/user_book_id. It also states the precondition ('The book must already be in your library (add it with set_user_book)') and names the tool to call first, which is exactly the alternative-routing an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
10 tool updates
v1.0.0- Changed
get_list4 fields changed- removed
Input schema / properties / book_limitRemoved value: -{ - "description": "With id: max books to return (default 25, max 100).", - "type": "integer" -} - removed
Input schema / properties / book_offsetRemoved value: -{ - "description": "With id: offset for book pagination (default 0).", - "type": "integer" -} - added
Input schema / properties / books_limitAdded value: +{ + "description": "With id: max books to return (default 25, max 100).", + "type": "integer" +} - added
Input schema / properties / books_offsetAdded value: +{ + "description": "With id: offset for book pagination (default 0).", + "type": "integer" +}
- Changed
get_reading_goal1 field changed- added
Input schema / properties / offsetAdded value: +{ + "description": "Offset for pagination (default 0).", + "type": "integer" +}
- Changed
get_series1 field changed- changed
Input schema / properties / name / descriptionPrevious value: -"Exact series name (e.g. 'The Stormlight Archive')."New value: +"Series name, resolved to the top search match (e.g. 'The Stormlight Archive')."
- Changed
get_user2 fields changed- changed
Input schema / properties / library_status / descriptionPrevious value: -"Filter library entries by status (e.g. 'Read', 'Currently Reading')."New value: +"Only library entries with this status." - added
Input schema / properties / library_status / enumAdded value: +[ + "Want to Read", + "Currently Reading", + "Read", + "Paused", + "Did Not Finish", + "Ignored" +]
- Changed
get_user_library2 fields changed- changed
Input schema / properties / status / descriptionPrevious value: -"Status filter (e.g. 'Read', 'Currently Reading')."New value: +"Only books with this status." - added
Input schema / properties / status / enumAdded value: +[ + "Want to Read", + "Currently Reading", + "Read", + "Paused", + "Did Not Finish", + "Ignored" +]
- Changed
set_journal_entry2 fields changed- added
Input schema / properties / privacyAdded value: +{ + "description": "Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public.", + "type": "string" +} - removed
Input schema / properties / privacy_setting_idRemoved value: -{ - "description": "1 public (default when creating), 2 followers, 3 private.", - "type": "integer" -}
- Changed
set_list1 field changed- changed
Input schema / properties / privacy / descriptionPrevious value: -"'public', 'followers_only', or 'private'. Default when creating: public."New value: +"Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public."
- Changed
set_list_book4 fields changed- changed
Input schema / properties / list_id / descriptionPrevious value: -"Hardcover list ID."New value: +"Hardcover list ID. Use this or list_ids." - added
Input schema / properties / list_idsAdded value: +{ + "description": "Several list IDs (up to 20). Use this or list_id.", + "items": { + "type": "integer" + }, + "type": "array" +} - changed
Input schema / properties / position / descriptionPrevious value: -"Position when adding (optional; ignored when removing)."New value: +"Position when adding to a single list_id (optional; ignored when removing)." - changed
Input schema / requiredPrevious value: -[ - "list_id", - "book_id", - "on_list" -]New value: +[ + "book_id", + "on_list" +]
- Changed
set_reading_goal2 fields changed- added
Input schema / properties / privacyAdded value: +{ + "description": "Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3).", + "type": "string" +} - removed
Input schema / properties / privacy_setting_idRemoved value: -{ - "description": "Optional privacy setting ID.", - "type": "integer" -}
- Changed
set_user_book4 fields changed- changed
Input schema / properties / privacy / descriptionPrevious value: -"Privacy setting: 'Public', 'Followers', or 'Private' (or numeric ID 1/2/3)."New value: +"Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3)." - changed
Input schema / properties / rating / descriptionPrevious value: -"Rating (e.g. 4.0, 3.5). Omit to leave unchanged."New value: +"Your rating (e.g. 4.0, 3.5); returned as user_rating. Omit to leave unchanged." - changed
Input schema / properties / status / descriptionPrevious value: -"Status name (e.g. 'Read') or numeric ID (1-5)."New value: +"Reading status." - added
Input schema / properties / status / enumAdded value: +[ + "Want to Read", + "Currently Reading", + "Read", + "Paused", + "Did Not Finish", + "Ignored" +]
10 tool updates
v0.9.0- Added
delete_reading_goal - Changed
get_book6 fields changed- added
Input schema / properties / asinAdded value: +{ + "description": "Amazon ASIN of a specific edition.", + "type": "string" +} - added
Input schema / properties / edition_idAdded value: +{ + "description": "Hardcover edition ID (e.g. from include_editions).", + "type": "integer" +} - added
Input schema / properties / editions_limitAdded value: +{ + "description": "With include_editions: max editions to return (default 10, max 50).", + "type": "integer" +} - changed
Input schema / properties / include_characters / descriptionPrevious value: -"Also return the book's characters (default false)."New value: +"With id/slug: also return its characters (default false)." - added
Input schema / properties / include_editionsAdded value: +{ + "description": "With id/slug: also return its editions (default false).", + "type": "boolean" +} - added
Input schema / properties / isbn_13Added value: +{ + "description": "ISBN-13 of a specific edition (e.g. '9780593135204').", + "type": "string" +}
- Removed
get_edition - Removed
get_owned_books - Removed
get_reading_stats - Changed
get_user5 fields changed- added
Input schema / properties / follow_limitAdded value: +{ + "description": "Max people per follow list (default 25, max 100).", + "type": "integer" +} - added
Input schema / properties / include_followersAdded value: +{ + "description": "Include who follows the user (default false).", + "type": "boolean" +} - added
Input schema / properties / include_followingAdded value: +{ + "description": "Include who the user follows (default false).", + "type": "boolean" +} - added
Input schema / properties / include_statsAdded value: +{ + "description": "Your own profile only: include reading statistics (default false).", + "type": "boolean" +} - added
Input schema / properties / stats_yearAdded value: +{ + "description": "Year for books_read_this_year (default: current year).", + "type": "integer" +}
- Changed
get_user_library1 field changed- added
Input schema / properties / ownedAdded value: +{ + "description": "Only books with an edition in your Owned list. Combines with the other filters.", + "type": "boolean" +}
- Removed
set_edition_owned - Changed
set_reading_goal3 fields changed- added
Input schema / properties / archivedAdded value: +{ + "description": "With id: true archives the goal, false restores it.", + "type": "boolean" +} - added
Input schema / properties / idAdded value: +{ + "description": "Goal ID to edit (from get_reading_goal). Omit to create.", + "type": "integer" +} - removed
Input schema / requiredRemoved value: -[ - "goal", - "metric", - "start_date", - "end_date" -]
- Changed
set_user_book2 fields changed- changed
Input schema / properties / edition_id / descriptionPrevious value: -"Edition ID (from get_edition). Sets which edition you're reading."New value: +"Edition ID (from get_book). Sets which edition you're reading." - added
Input schema / properties / ownedAdded value: +{ + "description": "true/false: you own (or no longer own) edition_id, or the current edition if edition_id is omitted.", + "type": "boolean" +}
23 tool updates
v0.8.0- Removed
add_book_to_list - Removed
add_journal_entry - Removed
add_user_book_read - Removed
answer_prompt - Removed
create_list - Removed
follow_user - Changed
get_book1 field changed- added
Input schema / properties / include_charactersAdded value: +{ + "description": "Also return the book's characters (default false).", + "type": "boolean" +}
- Removed
get_characters - Changed
get_list6 fields changed- changed
Input schema / properties / book_limit / descriptionPrevious value: -"Max books to return (default 25, max 100)."New value: +"With id: max books to return (default 25, max 100)." - changed
Input schema / properties / book_offset / descriptionPrevious value: -"Offset for book pagination (default 0)."New value: +"With id: offset for book pagination (default 0)." - changed
Input schema / properties / id / descriptionPrevious value: -"Hardcover list ID (use get_my_lists to find IDs)."New value: +"List ID. Omit to list your own lists." - added
Input schema / properties / limitAdded value: +{ + "description": "Without id: max lists to return (default 50, max 200).", + "type": "integer" +} - added
Input schema / properties / offsetAdded value: +{ + "description": "Without id: offset for pagination (default 0).", + "type": "integer" +} - removed
Input schema / requiredRemoved value: -[ - "id" -]
- Removed
get_my_lists - Changed
get_user_library3 fields changed- added
Input schema / properties / has_reviewAdded value: +{ + "description": "Only books you have reviewed, with review fields included. Can't be combined with start_date/end_date.", + "type": "boolean" +} - changed
Input schema / properties / sort / descriptionPrevious value: -"Sort field: 'updated' (default), 'rating', or 'date_added'."New value: +"Sort field: 'updated' (default), 'rating', 'date_added', or 'reviewed' (default when has_review=true)." - changed
Input schema / properties / sort / enumPrevious value: -[ - "updated", - "rating", - "date_added" -]New value: +[ + "updated", + "rating", + "date_added", + "reviewed" +]
- Removed
get_user_reviews - Removed
me - Removed
remove_book_from_list - Added
set_following - Added
set_journal_entry - Added
set_list - Added
set_list_book - Added
set_prompt_answer - Added
set_user_book_read - Removed
unfollow_user - Removed
update_list - Removed
update_user_book_read
7 tool updates
v0.7.1- Added
follow_user - Added
get_activity_feed - Added
get_trending_books - Added
get_user - Added
get_vibes - Changed
search_books2 fields changed- added
Input schema / properties / filter_byAdded value: +{ + "description": "Typesense filter expression, e.g. 'release_year:>2020' or 'release_year:[2020..2024]'.", + "type": "string" +} - added
Input schema / properties / sortAdded value: +{ + "description": "Typesense sort expression, e.g. 'rating:desc' or 'users_count:desc' for most popular first.", + "type": "string" +}
- Added
unfollow_user
2 tool updates
v0.6.0- Added
answer_prompt - Added
get_prompts
4 tool updates
v0.5.0- Changed
add_user_book_read1 field changed- added
Input schema / properties / edition_idAdded value: +{ + "description": "Edition ID (required for audiobook progress tracking).", + "type": "integer" +}
- Added
get_characters - Added
get_publisher - Changed
update_user_book_read1 field changed- added
Input schema / properties / edition_idAdded value: +{ + "description": "Edition ID (required for audiobook progress tracking).", + "type": "integer" +}
29 tool updates
v0.4.0- First observed
add_book_to_list - First observed
add_journal_entry - First observed
add_user_book_read - First observed
create_list - First observed
delete_journal_entry - First observed
delete_list - First observed
delete_user_book - First observed
delete_user_book_read - First observed
get_author - First observed
get_book - First observed
get_edition - First observed
get_list - First observed
get_my_lists - First observed
get_owned_books - First observed
get_reading_goal - First observed
get_reading_journal - First observed
get_reading_stats - First observed
get_series - First observed
get_user_book - First observed
get_user_library - First observed
get_user_reviews - First observed
me - First observed
remove_book_from_list - First observed
search_books - First observed
set_edition_owned - First observed
set_reading_goal - First observed
set_user_book - First observed
update_list - First observed
update_user_book_read
TDQS
Scored across 28 tools
Tools are cleanly separated by resource and action, e.g. get_book vs get_user_book, get_user_library vs get_list, and get_activity_feed vs get_reading_journal. Descriptions explicitly route between near-neighbors, so no two tools appear to do the same job.
All names use snake_case with a predictable verb_noun shape: get_*, set_*, delete_*, and search_*. The broad use of set_ for create/update/upsert is applied consistently across the server.
At 28 tools, the surface is heavy, but it spans many Hardcover subdomains: catalog, library, reads, goals, lists, journal, social, prompts, and discovery. Most tools cover distinct operations, so it is borderline rather than clearly bloated.
CRUD/lifecycle coverage is strong for library entries, reads, goals, lists, and journal entries, with discovery and social flows also represented. Minor gaps remain, such as reordering existing list books or editing prompt-answer descriptions, and no standalone character/edition retrieval beyond embedded options.
Maintenance
Related MCP Connectors
Read and update your Hardcover library, progress, lists, and goals. Sign in with Hardcover OAuth.
The media memory layer for AI agents and their humans. Your AI client can search your collection, add and log what you've finished, update ratings and lists, and find patterns across everything you've read, watched, played, and listened to.
- LeafOAuthapp.readwithleaf
AI assistant integration for Leaf — track books, log reading sessions, and manage your library.
Search books and authors, fetch editions, browse subjects, and resolve cover images.
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.-
- FlicenseAqualityCmaintenanceEnables AI assistants to interact with BookLore self-hosted libraries, allowing natural language queries to search books, manage reading status, ratings, series, authors, and highlights.71-
- AlicenseAqualityDmaintenanceConnects AI assistants to the Open Library API for searching books and authors, retrieving metadata, and comparing works.12174 npmMIT

SPINES MCP Serverofficial
AlicenseAqualityBmaintenanceEnables AI assistants to search books, manage reading lists, and access book collections and bookshelf data from SPINES via the Model Context Protocol.1149 npmMIT