Skip to main content
Glama

hardcover-mcp

PyPI License: MIT Python 3.14+

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=true to 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

  1. Install uv (a fast Python package runner — the setup takes seconds).

  2. Create an API key at hardcover.app/account/api; see API key and scopes for links that pre-select the right scopes.

  3. Add the config below to your MCP client — no manual install needed, uvx handles 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-mcp

Replace <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-mcp

Claude 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):

Toolset

Scopes needed

core

read:catalog, read:library, read:me, read:social, read:users

catalog

read:catalog, read:vibes

library

read:catalog, read:goals, read:library, read:lists, read:me, write:goals, write:library, write:lists, write:reviews

lists

read:lists, read:me, write:lists

journal

read:journal, read:me, write:library

social

read:me, read:prompts, read:social, read:users, write:prompts, write:social

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

HARDCOVER_TOOLSETS

all

Comma-separated toolsets to load. Fewer tools means less context used and fewer wrong tool picks.

HARDCOVER_READ_ONLY

false

true hides every tool that creates, changes, or deletes anything.

HARDCOVER_API_URL

Hardcover's API

GraphQL endpoint to call instead, e.g. a proxy. Must be https://, since every request carries your token.

Toolset

What it covers

core

Always loaded: search_books, get_user

catalog

Books (with characters and editions), editions, authors, series, publishers, trending, vibes

library

Your library, reading dates and progress, ownership, reviews, goals

lists

Viewing and managing your lists

journal

Reading journal notes and quotes

social

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 null keeps its current value. Clearing a field (e.g. removing a rating) isn't supported yet.

  • rating is the community rating; user_rating is yours (or, in get_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)

search_books

See your profile and reading stats, or look up another user; optionally with library, followers, and following

get_user

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

get_book

Browse an author's catalogue

get_author

Explore a series in reading order

get_series

Look up a publisher and its editions

get_publisher

See what's trending now

get_trending_books

Browse curated recommendation collections (vibes)

get_vibes

library

What you can do

Tool

Browse your library: filter by status, date range, reviewed or owned books; sort by rating/date

get_user_library

Check your status, rating, review, reads, and list memberships for one book (excluding the internal Owned list)

get_user_book

Get your active reading goals and progress

get_reading_goal

✏️ Add a book or update its status, rating, review, notes, privacy, edition, and ownership

set_user_book

✏️ Log or edit reading dates and progress (pages, audiobook time)

set_user_book_read

✏️ Create, update, or archive a reading goal (books/pages, date range)

set_reading_goal

✏️ Delete a reading goal

delete_reading_goal

✏️ Remove a reading entry or a whole book

delete_user_book_read / delete_user_book

lists

What you can do

Tool

View your lists, or one list with its books

get_list

✏️ Create or rename a list, or change its privacy

set_list

✏️ Add or remove a book on one list (list_id) or up to 20 lists (list_ids)

set_list_book

✏️ Delete a list

delete_list

journal

What you can do

Tool

Read your journal entries (notes, quotes, status events)

get_reading_journal

✏️ Add or edit a journal note/quote

set_journal_entry

✏️ Delete a journal entry

delete_journal_entry

social

What you can do

Tool

See recent activity from people you follow (or one user)

get_activity_feed

✏️ Follow or unfollow a user

set_following

Browse community book prompts

get_prompts

✏️ Answer a prompt with a book, or withdraw the answer

set_prompt_answer

Development

git clone https://github.com/kristianedlund/hardcover-mcp.git
cd hardcover-mcp
uv sync

Lint and format checks (using Ruff):

uv run ruff check .
uv run ruff format --check .

Run tests:

uv run pytest tests/ -v

Integration 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 .env

Then run:

uv run pytest tests/integration/ -v

Write tests follow a create → verify → delete lifecycle so the account is left unchanged.

Contributing

Contributions are welcome! Please:

  1. Open an issue first to discuss the change.

  2. Fork the repo and create a branch (feature/short-description or fix/short-description).

  3. Run lint and tests before submitting:

    uv run ruff check .
    uv run ruff format --check .
    uv run pytest tests/ -v
  4. Keep PRs focused — one change per PR.

  5. 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 "UV_LINK_MODE": "copy" to the env block in your config

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 tools
delete_journal_entryA
DestructiveIdempotent

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}.

NameRequiredDescriptionDefault
idYesReading journal entry ID.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_listA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
idYesHardcover list ID to delete.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_goalA
DestructiveIdempotent

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}.

NameRequiredDescriptionDefault
idYesReading goal ID to delete.

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_bookA
DestructiveIdempotent

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).

NameRequiredDescriptionDefault
book_idNoHardcover book ID (will look up your library entry).
user_book_idNoDirectly specify user_book ID if known.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_readA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
idYesThe user_book_read ID to delete.

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_feedA
Read-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).

NameRequiredDescriptionDefault
limitNoMax events to return (default 25, max 100).
offsetNoPagination offset (default 0).
user_idNoFetch one user's activity by Hardcover user ID.
usernameNoFetch one user's activity by username.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_authorA
Read-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.

NameRequiredDescriptionDefault
idNoHardcover author ID.
nameNoAuthor name (e.g. 'Brandon Sanderson').
slugNoAuthor slug (e.g. 'brandon-sanderson').
books_limitNoMax books to return (default 20, max 100).

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_bookA
Read-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.

NameRequiredDescriptionDefault
idNoHardcover book ID.
asinNoAmazon ASIN of a specific edition.
slugNoHardcover book slug (e.g. 'project-hail-mary').
isbn_13NoISBN-13 of a specific edition (e.g. '9780593135204').
edition_idNoHardcover edition ID (e.g. from include_editions).
editions_limitNoWith include_editions: max editions to return (default 10, max 50).
include_editionsNoWith id/slug: also return its editions (default false).
include_charactersNoWith id/slug: also return its characters (default false).

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_listA
Read-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').

NameRequiredDescriptionDefault
idNoList ID. Omit to list your own lists.
limitNoWithout id: max lists to return (default 50, max 200).
offsetNoWithout id: offset for pagination (default 0).
books_limitNoWith id: max books to return (default 25, max 100).
books_offsetNoWith id: offset for book pagination (default 0).

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_promptsA
Read-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.

NameRequiredDescriptionDefault
limitNoMax prompts to return (default 25, max 100).
offsetNoPagination offset (default 0).
featuredNoIf true, return only featured prompts (default false).

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_publisherA
Read-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.

NameRequiredDescriptionDefault
idNoHardcover publisher ID.
nameNoPublisher name (e.g. 'Tor Books').
slugNoPublisher slug (e.g. 'tor-books').
editions_limitNoMax editions to return (default 20, max 100).
editions_offsetNoOffset for editions pagination (default 0).

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_goalA
Read-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.

NameRequiredDescriptionDefault
limitNoMax goals to return (default 10, max 100).
offsetNoOffset for pagination (default 0).

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_journalA
Read-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).

NameRequiredDescriptionDefault
eventNoFilter by event type. Examples: 'note', 'quote', 'status_currently_reading', 'status_read', 'rated', 'reviewed', 'progress_updated'.
limitNoMax entries to return (default 25, max 100).
offsetNoPagination offset (default 0).
book_idNoFilter entries to a specific book by Hardcover book ID.

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_seriesA
Read-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.

NameRequiredDescriptionDefault
idNoHardcover series ID.
nameNoSeries name, resolved to the top search match (e.g. 'The Stormlight Archive').
slugNoSeries slug (e.g. 'the-stormlight-archive').

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_userA
Read-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.

NameRequiredDescriptionDefault
idNoHardcover user ID.
nameNoDisplay name to search for (resolves to the top match).
usernameNoHardcover username (e.g. 'adam').
stats_yearNoYear for books_read_this_year (default: current year).
follow_limitNoMax people per follow list (default 25, max 100).
include_statsNoYour own profile only: include reading statistics (default false).
library_limitNoMax library entries to return (default 10, max 50).
library_statusNoOnly library entries with this status.
include_libraryNoIf true, include recent library entries (default false).
include_followersNoInclude who follows the user (default false).
include_followingNoInclude who the user follows (default false).

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_bookA
Read-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.

NameRequiredDescriptionDefault
slugNoHardcover book slug (e.g. 'project-hail-mary').
book_idNoHardcover book ID.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_libraryA
Read-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.

NameRequiredDescriptionDefault
sortNoSort field: 'updated' (default), 'rating', 'date_added', or 'reviewed' (default when has_review=true).
limitNoMax books to return (default 25, max 100).
orderNoSort direction: 'desc' (default) or 'asc'.
ownedNoOnly books with an edition in your Owned list. Combines with the other filters.
offsetNoOffset for pagination (default 0).
statusNoOnly books with this status.
end_dateNoLatest finished_at date (ISO 8601, e.g. '2025-12-31'). Must be paired with start_date.
has_reviewNoOnly books you have reviewed, with review fields included. Can't be combined with start_date/end_date.
start_dateNoEarliest finished_at date (ISO 8601, e.g. '2025-01-01'). Must be paired with end_date.

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_vibesA
Read-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.

NameRequiredDescriptionDefault
limitNoMax vibes to return (default 10, max 50).
offsetNoPagination offset (default 0).
featuredNoIf true (default), return only featured vibes.
books_per_vibeNoBooks to include per vibe (default 10, max 50).

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_booksA
Read-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.

NameRequiredDescriptionDefault
pageNoPage number (default 1).
sortNoTypesense sort expression, e.g. 'rating:desc' or 'users_count:desc' for most popular first.
queryYesSearch query (title, author name, ISBN, etc.).
per_pageNoResults per page (default 10, max 25).
filter_byNoTypesense filter expression, e.g. 'release_year:>2020' or 'release_year:[2020..2024]'.
query_typeNoEntity type to search (default: 'Book').

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_followingA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
user_idNoHardcover user ID.
usernameNoUsername (resolved to an ID).
followingYestrue to follow, false to unfollow.

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_entryA
Destructive

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.

NameRequiredDescriptionDefault
idNoJournal entry ID to edit. Omit to create a new entry.
entryNoJournal entry text (required when creating).
eventNoEntry type (required when creating).
book_idNoHardcover book ID (required when creating).
privacyNoWho can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public.
edition_idNoOptional Hardcover edition ID.

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_listA
Destructive

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.

NameRequiredDescriptionDefault
idNoList ID to update. Omit to create a new list.
nameNoList name (required when creating).
privacyNoWho can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public.
descriptionNoList description.

TDQS

A4.3/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_bookA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
book_idYesHardcover book ID.
list_idNoHardcover list ID. Use this or list_ids.
on_listYestrue to add the book, false to remove it.
list_idsNoSeveral list IDs (up to 20). Use this or list_id.
positionNoPosition when adding to a single list_id (optional; ignored when removing).

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_answerA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
book_idYesHardcover book ID.
answeredYestrue to submit the book, false to withdraw it.
prompt_idYesHardcover prompt ID (use get_prompts to find IDs).
descriptionNoWhy this book fits the prompt (optional; when adding).

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_goalA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
idNoGoal ID to edit (from get_reading_goal). Omit to create.
goalNoTarget count to reach by end_date.
metricNoGoal metric: 'book' or 'page'.
privacyNoWho can see it: 'public', 'followers', or 'private' (or 1, 2, 3).
archivedNoWith id: true archives the goal, false restores it.
end_dateNoEnd date (ISO 8601, e.g. '2026-12-31').
start_dateNoStart date (ISO 8601, e.g. '2026-01-01').
descriptionNoOptional goal description.

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_bookA
DestructiveIdempotent

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.

NameRequiredDescriptionDefault
ownedNotrue/false: you own (or no longer own) edition_id, or the current edition if edition_id is omitted.
ratingNoYour rating (e.g. 4.0, 3.5); returned as user_rating. Omit to leave unchanged.
statusNoReading status.
book_idYesHardcover book ID.
privacyNoWho can see it: 'public', 'followers', or 'private' (or 1, 2, 3).
edition_idNoEdition ID (from get_book). Sets which edition you're reading.
review_rawNoPlain-text review content (converted to Slate format).
reviewed_atNoISO date of the review (e.g. '2025-06-01').
private_notesNoPrivate notes visible only to you.
review_has_spoilersNoWhether the review contains spoilers.

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_readA
Destructive

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.

NameRequiredDescriptionDefault
idNouser_book_read ID to edit. Omit to log on a book.
book_idNoWithout id: book ID (auto-resolves your user_book).
edition_idNoEdition ID (required for audiobook progress tracking).
started_atNoDate started reading (ISO 8601, e.g. '2025-01-15').
finished_atNoDate finished reading (ISO 8601, e.g. '2025-02-20').
user_book_idNoWithout id: user_book ID if known (skips lookup).
progress_pagesNoPages read so far.
progress_secondsNoSeconds of audiobook listened to so far.

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 10 tool updatesv1.0.0
    • Changedget_list4 fields changed
      • removedInput schema / properties / book_limit
        Removed value: -{
        -  "description": "With id: max books to return (default 25, max 100).",
        -  "type": "integer"
        -}
      • removedInput schema / properties / book_offset
        Removed value: -{
        -  "description": "With id: offset for book pagination (default 0).",
        -  "type": "integer"
        -}
      • addedInput schema / properties / books_limit
        Added value: +{
        +  "description": "With id: max books to return (default 25, max 100).",
        +  "type": "integer"
        +}
      • addedInput schema / properties / books_offset
        Added value: +{
        +  "description": "With id: offset for book pagination (default 0).",
        +  "type": "integer"
        +}
    • Changedget_reading_goal1 field changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "description": "Offset for pagination (default 0).",
        +  "type": "integer"
        +}
    • Changedget_series1 field changed
      • changedInput schema / properties / name / description
        Previous value: -"Exact series name (e.g. 'The Stormlight Archive')."New value: +"Series name, resolved to the top search match (e.g. 'The Stormlight Archive')."
    • Changedget_user2 fields changed
      • changedInput schema / properties / library_status / description
        Previous value: -"Filter library entries by status (e.g. 'Read', 'Currently Reading')."New value: +"Only library entries with this status."
      • addedInput schema / properties / library_status / enum
        Added value: +[
        +  "Want to Read",
        +  "Currently Reading",
        +  "Read",
        +  "Paused",
        +  "Did Not Finish",
        +  "Ignored"
        +]
    • Changedget_user_library2 fields changed
      • changedInput schema / properties / status / description
        Previous value: -"Status filter (e.g. 'Read', 'Currently Reading')."New value: +"Only books with this status."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "Want to Read",
        +  "Currently Reading",
        +  "Read",
        +  "Paused",
        +  "Did Not Finish",
        +  "Ignored"
        +]
    • Changedset_journal_entry2 fields changed
      • addedInput schema / properties / privacy
        Added value: +{
        +  "description": "Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3). Default when creating: public.",
        +  "type": "string"
        +}
      • removedInput schema / properties / privacy_setting_id
        Removed value: -{
        -  "description": "1 public (default when creating), 2 followers, 3 private.",
        -  "type": "integer"
        -}
    • Changedset_list1 field changed
      • changedInput schema / properties / privacy / description
        Previous 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."
    • Changedset_list_book4 fields changed
      • changedInput schema / properties / list_id / description
        Previous value: -"Hardcover list ID."New value: +"Hardcover list ID. Use this or list_ids."
      • addedInput schema / properties / list_ids
        Added value: +{
        +  "description": "Several list IDs (up to 20). Use this or list_id.",
        +  "items": {
        +    "type": "integer"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / position / description
        Previous value: -"Position when adding (optional; ignored when removing)."New value: +"Position when adding to a single list_id (optional; ignored when removing)."
      • changedInput schema / required
        Previous value: -[
        -  "list_id",
        -  "book_id",
        -  "on_list"
        -]New value: +[
        +  "book_id",
        +  "on_list"
        +]
    • Changedset_reading_goal2 fields changed
      • addedInput schema / properties / privacy
        Added value: +{
        +  "description": "Who can see it: 'public', 'followers', or 'private' (or 1, 2, 3).",
        +  "type": "string"
        +}
      • removedInput schema / properties / privacy_setting_id
        Removed value: -{
        -  "description": "Optional privacy setting ID.",
        -  "type": "integer"
        -}
    • Changedset_user_book4 fields changed
      • changedInput schema / properties / privacy / description
        Previous 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)."
      • changedInput schema / properties / rating / description
        Previous 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."
      • changedInput schema / properties / status / description
        Previous value: -"Status name (e.g. 'Read') or numeric ID (1-5)."New value: +"Reading status."
      • addedInput schema / properties / status / enum
        Added value: +[
        +  "Want to Read",
        +  "Currently Reading",
        +  "Read",
        +  "Paused",
        +  "Did Not Finish",
        +  "Ignored"
        +]
  2. 10 tool updatesv0.9.0
    • Addeddelete_reading_goal
    • Changedget_book6 fields changed
      • addedInput schema / properties / asin
        Added value: +{
        +  "description": "Amazon ASIN of a specific edition.",
        +  "type": "string"
        +}
      • addedInput schema / properties / edition_id
        Added value: +{
        +  "description": "Hardcover edition ID (e.g. from include_editions).",
        +  "type": "integer"
        +}
      • addedInput schema / properties / editions_limit
        Added value: +{
        +  "description": "With include_editions: max editions to return (default 10, max 50).",
        +  "type": "integer"
        +}
      • changedInput schema / properties / include_characters / description
        Previous value: -"Also return the book's characters (default false)."New value: +"With id/slug: also return its characters (default false)."
      • addedInput schema / properties / include_editions
        Added value: +{
        +  "description": "With id/slug: also return its editions (default false).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / isbn_13
        Added value: +{
        +  "description": "ISBN-13 of a specific edition (e.g. '9780593135204').",
        +  "type": "string"
        +}
    • Removedget_edition
    • Removedget_owned_books
    • Removedget_reading_stats
    • Changedget_user5 fields changed
      • addedInput schema / properties / follow_limit
        Added value: +{
        +  "description": "Max people per follow list (default 25, max 100).",
        +  "type": "integer"
        +}
      • addedInput schema / properties / include_followers
        Added value: +{
        +  "description": "Include who follows the user (default false).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / include_following
        Added value: +{
        +  "description": "Include who the user follows (default false).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / include_stats
        Added value: +{
        +  "description": "Your own profile only: include reading statistics (default false).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / stats_year
        Added value: +{
        +  "description": "Year for books_read_this_year (default: current year).",
        +  "type": "integer"
        +}
    • Changedget_user_library1 field changed
      • addedInput schema / properties / owned
        Added value: +{
        +  "description": "Only books with an edition in your Owned list. Combines with the other filters.",
        +  "type": "boolean"
        +}
    • Removedset_edition_owned
    • Changedset_reading_goal3 fields changed
      • addedInput schema / properties / archived
        Added value: +{
        +  "description": "With id: true archives the goal, false restores it.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Goal ID to edit (from get_reading_goal). Omit to create.",
        +  "type": "integer"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "goal",
        -  "metric",
        -  "start_date",
        -  "end_date"
        -]
    • Changedset_user_book2 fields changed
      • changedInput schema / properties / edition_id / description
        Previous 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."
      • addedInput schema / properties / owned
        Added value: +{
        +  "description": "true/false: you own (or no longer own) edition_id, or the current edition if edition_id is omitted.",
        +  "type": "boolean"
        +}
  3. 23 tool updatesv0.8.0
    • Removedadd_book_to_list
    • Removedadd_journal_entry
    • Removedadd_user_book_read
    • Removedanswer_prompt
    • Removedcreate_list
    • Removedfollow_user
    • Changedget_book1 field changed
      • addedInput schema / properties / include_characters
        Added value: +{
        +  "description": "Also return the book's characters (default false).",
        +  "type": "boolean"
        +}
    • Removedget_characters
    • Changedget_list6 fields changed
      • changedInput schema / properties / book_limit / description
        Previous value: -"Max books to return (default 25, max 100)."New value: +"With id: max books to return (default 25, max 100)."
      • changedInput schema / properties / book_offset / description
        Previous value: -"Offset for book pagination (default 0)."New value: +"With id: offset for book pagination (default 0)."
      • changedInput schema / properties / id / description
        Previous value: -"Hardcover list ID (use get_my_lists to find IDs)."New value: +"List ID. Omit to list your own lists."
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Without id: max lists to return (default 50, max 200).",
        +  "type": "integer"
        +}
      • addedInput schema / properties / offset
        Added value: +{
        +  "description": "Without id: offset for pagination (default 0).",
        +  "type": "integer"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "id"
        -]
    • Removedget_my_lists
    • Changedget_user_library3 fields changed
      • addedInput schema / properties / has_review
        Added value: +{
        +  "description": "Only books you have reviewed, with review fields included. Can't be combined with start_date/end_date.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / sort / description
        Previous 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)."
      • changedInput schema / properties / sort / enum
        Previous value: -[
        -  "updated",
        -  "rating",
        -  "date_added"
        -]New value: +[
        +  "updated",
        +  "rating",
        +  "date_added",
        +  "reviewed"
        +]
    • Removedget_user_reviews
    • Removedme
    • Removedremove_book_from_list
    • Addedset_following
    • Addedset_journal_entry
    • Addedset_list
    • Addedset_list_book
    • Addedset_prompt_answer
    • Addedset_user_book_read
    • Removedunfollow_user
    • Removedupdate_list
    • Removedupdate_user_book_read
  4. 7 tool updatesv0.7.1
    • Addedfollow_user
    • Addedget_activity_feed
    • Addedget_trending_books
    • Addedget_user
    • Addedget_vibes
    • Changedsearch_books2 fields changed
      • addedInput schema / properties / filter_by
        Added value: +{
        +  "description": "Typesense filter expression, e.g. 'release_year:>2020' or 'release_year:[2020..2024]'.",
        +  "type": "string"
        +}
      • addedInput schema / properties / sort
        Added value: +{
        +  "description": "Typesense sort expression, e.g. 'rating:desc' or 'users_count:desc' for most popular first.",
        +  "type": "string"
        +}
    • Addedunfollow_user
  5. 2 tool updatesv0.6.0
    • Addedanswer_prompt
    • Addedget_prompts
  6. 4 tool updatesv0.5.0
    • Changedadd_user_book_read1 field changed
      • addedInput schema / properties / edition_id
        Added value: +{
        +  "description": "Edition ID (required for audiobook progress tracking).",
        +  "type": "integer"
        +}
    • Addedget_characters
    • Addedget_publisher
    • Changedupdate_user_book_read1 field changed
      • addedInput schema / properties / edition_id
        Added value: +{
        +  "description": "Edition ID (required for audiobook progress tracking).",
        +  "type": "integer"
        +}
  7. 29 tool updatesv0.4.0
    • First observedadd_book_to_list
    • First observedadd_journal_entry
    • First observedadd_user_book_read
    • First observedcreate_list
    • First observeddelete_journal_entry
    • First observeddelete_list
    • First observeddelete_user_book
    • First observeddelete_user_book_read
    • First observedget_author
    • First observedget_book
    • First observedget_edition
    • First observedget_list
    • First observedget_my_lists
    • First observedget_owned_books
    • First observedget_reading_goal
    • First observedget_reading_journal
    • First observedget_reading_stats
    • First observedget_series
    • First observedget_user_book
    • First observedget_user_library
    • First observedget_user_reviews
    • First observedme
    • First observedremove_book_from_list
    • First observedsearch_books
    • First observedset_edition_owned
    • First observedset_reading_goal
    • First observedset_user_book
    • First observedupdate_list
    • First observedupdate_user_book_read

TDQS

A4.4/5.0

Scored across 28 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count3/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to help users manage their reading experience by searching books, tracking reading progress, managing bookmarks, and generating personalized recommendations and summaries.
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to interact with BookLore self-hosted libraries, allowing natural language queries to search books, manage reading status, ratings, series, authors, and highlights.
    7
    1
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI assistants to search books, manage reading lists, and access book collections and bookshelf data from SPINES via the Model Context Protocol.
    11
    49 npm
    MIT