hardcover-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| UV_LINK_MODE | No | Set to 'copy' on Windows if you encounter access denied errors | |
| HARDCOVER_API_TOKEN | Yes | Your Hardcover API token from https://hardcover.app/account/api |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| get_userA | 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. |
| search_booksA | 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. |
| get_bookA | 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. |
| get_authorA | 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. |
| get_seriesA | 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. |
| get_publisherA | 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. |
| get_trending_booksA | Get the books trending on Hardcover in a time window ('duration', default 'week'), ranked most popular first and paginated with limit/offset. Read-only. Returns {returned, offset, books} with book_id, slug, title, authors, rating, and release year. For curated themed collections use get_vibes; for a custom query use search_books with sort='users_count:desc'. |
| get_vibesA | 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. |
| get_user_libraryA | 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. |
| get_user_bookA | 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. |
| set_user_bookA | 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. |
| set_user_book_readA | 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. |
| delete_user_book_readA | 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. |
| delete_user_bookA | 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). |
| get_reading_goalA | 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. |
| set_reading_goalA | 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. |
| delete_reading_goalA | 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}. |
| get_listA | 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'). |
| set_listA | 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. |
| delete_listA | 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. |
| set_list_bookA | 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. |
| get_reading_journalA | 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). |
| set_journal_entryA | 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. |
| delete_journal_entryA | 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}. |
| get_activity_feedA | 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). |
| set_followingA | 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. |
| get_promptsA | 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. |
| set_prompt_answerA | 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. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 28 tools
Tools are cleanly separated by resource and action, e.g. get_book vs get_user_book, get_user_library vs get_list, and get_activity_feed vs get_reading_journal. Descriptions explicitly route between near-neighbors, so no two tools appear to do the same job.
All names use snake_case with a predictable verb_noun shape: get_*, set_*, delete_*, and search_*. The broad use of set_ for create/update/upsert is applied consistently across the server.
At 28 tools, the surface is heavy, but it spans many Hardcover subdomains: catalog, library, reads, goals, lists, journal, social, prompts, and discovery. Most tools cover distinct operations, so it is borderline rather than clearly bloated.
CRUD/lifecycle coverage is strong for library entries, reads, goals, lists, and journal entries, with discovery and social flows also represented. Minor gaps remain, such as reordering existing list books or editing prompt-answer descriptions, and no standalone character/edition retrieval beyond embedded options.