liseur-mcp
Read-only MCP server for a liseur-sync instance: browse the book catalog, see reading statistics, retrieve highlights, and read EPUB chapter text without writing to the library.
Catalog: list folders, list books in a folder (newest/oldest first), search titles/descriptions/series/contributors/tags, and fetch a full catalog record by book id.
Reading stats: get totals, streak, pace, and per-work rows over a span (all time or 1–3660 days).
Highlights: list highlights/notes/bookmarks for one book or the whole account, with pagination (limit, offset, total/truncated indicators).
Book text: retrieve the table of contents or a specific chapter's text from the locally parsed EPUB, with offset/max_chars pagination for long chapters.
Deployment: runs as stdio or streamable HTTP MCP with bearer-token auth; exposes exactly these seven tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@liseur-mcpshow my reading stats and recent highlights"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
liseur-mcp
Read-only MCP server for a liseur-sync instance: book catalog, reading statistics, highlights and EPUB chapter text, for any MCP client (opencode, Claude Desktop/Code, Cursor, ...).
It talks to the native /v1 API with a device token you mint for it. It never
writes to the catalog or your reading state; the only side effect is that
list_highlights(book_id=...) resolves the book to your per-user reading work,
the same mapping every reading client makes.
Tools
Tool | What it does |
| folders this account can read |
| books in a folder, newest first |
| search titles, descriptions, series, contributors, tags |
| one catalog record by id |
| totals, streak, pace, plus per-work rows |
| highlights/notes/bookmarks, for one book or the account |
| table of contents and chapter text (EPUB parsed locally) |
Related MCP server: mcp-kindle
Scopes
Mint a dedicated device token with exactly:
library-read— folders, books, search, downloadread-insights— reading statisticssync— highlights and notes; the book→work join needs this andlibrary-read
Install
To run a release without a checkout:
uv tool install git+https://github.com/mickeiik/liseur-mcp@v0.1.0
liseur-mcp # stdio; configure with the environment belowThe rest of this file runs uv run liseur-mcp from a checkout.
Run (stdio, for clients on this machine)
uv sync
export LISEUR_URL=https://books.example.com
export LISEUR_TOKEN=...
uv run liseur-mcpopencode example (opencode.json), pointing at the venv binary so no uv lookup happens
at startup:
{
"mcp": {
"servers": {
"liseur": {
"type": "local",
"command": ["/path/to/liseur-mcp/.venv/bin/liseur-mcp"],
"environment": {
"LISEUR_URL": "https://books.example.com",
"LISEUR_TOKEN": "{env:LISEUR_TOKEN}"
}
}
}
}
}Run (streamable HTTP, one endpoint for several agents)
export MCP_TRANSPORT=streamable-http
export MCP_HOST=0.0.0.0
export MCP_AUTH_TOKEN=... # required: the endpoint has no anonymous mode
# every Host header a client reaches this server under; `name:*` accepts any port
export MCP_ALLOWED_HOSTS=books.example.com,books.example.com:*,localhost:*,127.0.0.1:*
export LISEUR_URL=... LISEUR_TOKEN=...
uv run liseur-mcpClients connect to http://<host>:8000/mcp with
Authorization: Bearer $MCP_AUTH_TOKEN.
{
"mcp": {
"servers": {
"liseur": {
"type": "remote",
"url": "http://<host>:8000/mcp",
"oauth": false,
"headers": { "Authorization": "Bearer {env:LISEUR_MCP_TOKEN}" }
}
}
}
}Keep it on your LAN or behind your reverse proxy; the bearer token is the only door.
Docker
docker build -t liseur-mcp .
docker run -d --name liseur-mcp --restart unless-stopped \
-e MCP_TRANSPORT=streamable-http -e MCP_HOST=0.0.0.0 \
-e MCP_AUTH_TOKEN -e LISEUR_URL -e LISEUR_TOKEN \
-e MCP_ALLOWED_HOSTS=books.example.com,books.example.com:*,localhost:*,127.0.0.1:* \
-p 8000:8000 liseur-mcpEnvironment
Variable | Default | Meaning |
| required | base URL of the instance |
| required | device token secret |
|
|
|
|
| HTTP listener |
| required for HTTP | bearer token clients present |
| localhost, 127.0.0.1 (any port) | Host headers the HTTP transport accepts |
| none | Origin headers accepted, listed exactly (no |
|
| log level |
|
| upstream request timeout |
If a client cannot connect
421 Invalid Host header— the request arrived under a Host the transport refuses. Add the name you connect with toMCP_ALLOWED_HOSTS; entries match exactly, so writename:*to accept any port (localhostalone does not matchHost: localhost:8000).403 Invalid Origin header— the client sends anOriginandMCP_ALLOWED_ORIGINSis empty; list that origin.403 {"error":"https required"}— that comes from the liseur-sync instance, not from here: it refuses plain HTTP unless it is configured to allow it. PointLISEUR_URLat the HTTPS name.
At startup the server calls GET /v1/token once to learn the account and the
token's scopes. A refused credential (401/403) ends the process with the
upstream reason on stderr: a 401 means the device token is absent, revoked or
expired, so mint a new one and update LISEUR_TOKEN/LISEUR_TOKEN_FILE; a 403
such as https required means LISEUR_URL is not the HTTPS name. If a scope a
tool needs is missing it logs a warning naming the scope and the tools that
will fail, and starts anyway. If the instance is unreachable, or answers
anything else — a 5xx, a malformed body — it logs a warning and starts too, so
the tools report the real reason rather than the server refusing to boot.
Develop
uv sync
uv run pytest
uv run ruff check
uv run pyrightConformance
The MCP spec conformance gate runs the official
modelcontextprotocol/conformance
suite (server, active) in CI (.github/workflows/conformance.yml, pinned
to v0.1.16). The harness sends no auth header, so runs put a small
auth-injecting proxy (scripts/conformance-proxy.py) in front of the server.
Known-by-design failures (this tools-only server exposes no resources,
prompts, completions, elicitation or sampling) are baselined in
conformance-baseline.yml. No liseur-sync instance is needed: the
protocol-level scenarios never invoke the real tools.
./scripts/conformance-local.sh
# or a single scenario: ./scripts/conformance-local.sh --scenario tools-listSmoke tests
scripts/smoke.sh (also run in CI by .github/workflows/smoke.yml) drives the
shipped binary through the official
MCP Inspector CLI — the
real entry point, both transports, the 7-tool surface, schema portability and
two invalid-argument refusals. Tools are only called with arguments that fail
validation before any liseur-sync request, so no instance is needed.
uv sync
./scripts/smoke.shThe Inspector is pinned in the script (INSPECTOR_VERSION, default 2.8.0);
the weekly watcher files an upstream-drift issue when npm's latest moves
past it, since Dependabot cannot see a shell variable.
Keeping up with upstream
Dependencies are kept current by .github/dependabot.yml (uv, GitHub Actions
and the Dockerfile base image), landing through the gates above.
The liseur-sync API itself is watched by .github/workflows/upstream-spec.yml:
weekly it hashes upstream's docs/openapi.yaml — upstream publishes no tags or
releases, so the spec is the anchor — and compares it with the sha256 recorded
in docs/upstream-openapi.sha. On a change it files an upstream-drift issue
and fails the run; the fix is to re-read the changed endpoints against
src/liseur_mcp/client.py, run the live check below, then update the hash and
close the issue.
scripts/live_check.py shape-checks a real instance through the same client
the tools use: read-only, it asserts the fields the seven tools read and exits
non-zero naming what drifted. Run it before a release, or schedule it wherever
it can reach the instance.
LISEUR_URL=https://books.example.com LISEUR_TOKEN=... \
uv run python scripts/live_check.pyIt is deliberately not run by the workflows here — they target local stubs and dummy credentials, while this one needs a real instance and a token. A drifted shape shows up here before it shows up as a broken tool.
Releasing
Release when a consumer's install or behaviour changes: anything under src/,
the dependencies or metadata in pyproject.toml, or the Dockerfile. CI,
docs, tests and scripts/ changes get no release of their own — they ride into
the next one.
# 1. bump version in pyproject.toml and run uv lock, land it on main, CI green
# 2. tag and push — the workflow does the rest
git tag -a v0.3.1 -m "v0.3.1"
git push origin v0.3.1.github/workflows/release.yml refuses a tag that disagrees with
pyproject.toml, re-runs the checks on the tagged commit, then publishes notes
built from the commits since the previous tag.
Bump levels: feat → minor, fix → patch, a breaking change or a move of the
mcp pin → minor while the version is 0.x. The same rules, aimed at agents, are
in AGENTS.md.
Available Tools
7 toolsget_bookA
Fetch one catalog record by book_id (same shape list_books returns).
| Name | Required | Description | Default |
|---|---|---|---|
| book_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full responsibility. It clearly indicates a read operation ('Fetch') and implies non-destructive behavior, but it doesn't disclose behaviors like not-found handling, error conditions, or any authentication requirements. The 'same shape' note is helpful but minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with zero filler. It front-loads the core action and parameter, and the 'same shape' note is efficient. Every word serves a purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so return values are covered. For a simple get-by-ID tool, the description provides enough to call it correctly if you know book_id, but it omits explicit guidance on when to prefer this over list_books or search_books, and lacks any prerequisite information (e.g., how to obtain a valid book_id). It's sufficient but not comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It names book_id as the lookup key and implies it comes from list_books (via 'same shape list_books returns'), but it doesn't elaborate on its format, provenance, or any constraints beyond the schema's type string. This is adequate but not enriching.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Fetch'), a resource ('catalog record'), and the key parameter ('by book_id'). It also notes the return shape matches list_books, which differentiates it from siblings like get_book_text (text) and search_books (multiple results). This is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when you have a book_id and need a single catalog record, and the 'same shape list_books returns' hint suggests you might already have the data from list_books. However, it doesn't explicitly state when not to use it or name alternatives, so it lacks explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_book_textA
Read the text of a book, one chapter at a time.
Without chapter: returns the table of contents (index, title, chars). With chapter: that chapter's text, cut to max_chars from offset; next_offset continues when the chapter is longer. The EPUB is downloaded from the server and parsed on each call; a download larger than the 128 MiB cap is refused.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | ||
| book_id | Yes | ||
| chapter | No | ||
| max_chars | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It discloses the read-only nature ('Read'), the server-side download-and-parse behavior on each call, and the 128 MiB cap refusal. It doesn't mention authentication requirements or error handling beyond the cap, leaving some gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences, front-loaded with the core purpose and then escalating into operational detail. There is no filler and no repetition of schema defaults.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values don't need restating. The description covers the main calling modes, pagination, and the resource size cap, making it complete for a tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it defines chapter vs no-chapter behavior, offset continuation, and max_chars truncation. It doesn't explain book_id, but its role is self-evident from the name and the required flag in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening phrase uses a specific verb ('Read') plus resource ('text of a book') and the qualifier 'one chapter at a time', which clearly separates it from sibling tools like get_book or list_books. The two operational modes (TOC vs chapter text) add further precision.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the two calling modes and the paging contract: without chapter returns the TOC, with chapter returns text cut to max_chars from offset, and next_offset continues for longer chapters. It doesn't explicitly name alternatives or state when not to use this tool, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_booksA
List books in one folder.
order: "recent" (newest first, default) or "oldest". limit: 1-200; a value outside that range is refused, not clamped. Returns full catalog records: book_id, title, contributors, series, tags.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| order | No | recent | |
| folder_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden and does well: it specifies default ordering, strict limit validation ('refused, not clamped'), and the exact fields returned. It does not cover pagination or error behavior, but core operational behavior is transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Compact and front-loaded: one purpose sentence followed by terse, high-density notes on ordering, limits, and return records. Every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter list tool with an output schema and no annotations, the description covers scope, parameter semantics, and return shape sufficiently. Minor omissions such as pagination and invalid-folder behavior are not critical for correct invocation of this simple operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description compensates by explaining allowed order values, the limit range and its refusal behavior, and the folder scope. It does not elaborate on folder_id formatting, but its meaning is reasonably clear from the purpose and schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('books') with a clear scope ('in one folder'), and describes the returned catalog fields. It does not explicitly reference or contrast sibling tools like search_books or get_book, so differentiation is implied rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly establishes the context—listing books within one folder—and documents order/limit options. However, it never directly says when to prefer this over search_books or get_book, nor provides exclusions or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_foldersA
List the library folders this account can read.
Each folder carries a folder_id to pass to list_books and search_books.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the burden of behavioral disclosure. It notes the read-only nature ('can read') and the output includes folder_id, which is useful. However, it does not describe pagination, ordering, or the full structure of the response, though the output schema likely covers that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, consisting of two sentences. The first sentence states the core action and scope, and the second adds the key relationship to sibling tools, making every word useful. It is front-loaded with the main purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that the tool has no parameters and an output schema exists, the description is sufficient for an agent to understand the tool's role in the workflow. It explains the dependency on folder_id for other tools, which is critical context. Minor gaps like pagination are not critical for a list operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the schema shows an empty properties object with 100% coverage. The description adds context by explaining the purpose of folder_id in the output, which is helpful for downstream usage. Since there are no parameters to document, a baseline of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists library folders accessible to the account, with a specific verb and resource. It also distinguishes itself from siblings by mentioning folder_id as a prerequisite for list_books and search_books, which is not evident from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: before calling list_books or search_books, since it provides the required folder_id. It does not explicitly state when not to use it, but the context is clear given the sibling tools and the dependency.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_highlightsA
List highlights, notes and bookmarks.
With book_id: the annotations of that book, in the server's document order (by progression). The first call joins the catalog book to your reading work — a per-user mapping; nothing shared changes. If the catalog match is too weak to store (confidence "low"), nothing is returned and the answer says so; annotations may still exist under the returned work_id, which the note points out.
Without book_id: every live annotation on the account, most recently changed first (by the server's internal sequence), each carrying its work_id. Both branches return at most limit annotations (1-500, cap 500); a limit below 1 and an offset below 0 are refused. count, total and truncated are reported; total is the size of the whole set and does not depend on limit or offset, while truncated says more annotations remain beyond this page.
Paging: pass the next_offset of a previous page as offset to read on; next_offset is present only when more annotations remain, and every response echoes the offset its page started at. The list is fetched fresh on every call, so if annotations change between pages an item can shift — pass back the next_offset you were given rather than computing your own.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| book_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does so thoroughly. It discloses the per-user mapping side effect, weak-confidence behavior, ordering, pagination semantics, fresh-fetch caveat, and invalid parameter handling. This is exemplary transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence carries essential behavioral information. It is front-loaded with the core purpose, then organized into clear paragraphs for the two branches and pagination. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers ordering, limits, error conditions, return fields (count, total, truncated), pagination via next_offset, and the side effects of the first call. For a tool with three optional parameters and no annotations, this is fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate entirely. It explains limit's 1-500 range and cap, offset's non-negative requirement and paging role, and book_id's branch behavior. This fully adds meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb and resource: 'List highlights, notes and bookmarks.' It then distinguishes two modes (with and without book_id), which precisely defines the tool's scope and separates it from sibling tools like get_book_text or list_books.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance for when to use each branch: pass book_id to get annotations for a specific book, omit it to get every live annotation on the account. It does not name alternative sibling tools, but the two-mode usage guidance is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reading_statsA
Reading totals, streak and pace over a span, plus per-work rows.
range is "all" or a number of days from 1 to 3660 ("7d", "30d"); any other value is refused rather than silently defaulted, because the upstream summary and works endpoints would then disagree on the span. Per-work rows are ordered by time read and capped at 50; current_progression is always the latest position regardless of the span.
| Name | Required | Description | Default |
|---|---|---|---|
| range | No | 30d |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses several behaviors: refusal of invalid range values rather than silent default, ordering of per-work rows, the 50-row cap, and the invariant that current_progression is always latest. It does not explicitly state whether the tool is read-only, but that is strongly implied by the nature of a stats endpoint, and the disclosure of error handling and ordering is valuable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is efficiently structured: a one-line summary up front, followed by two focused sentences detailing the parameter and per-work behavior. Every sentence adds value without padding. The key constraints (refusal, cap, ordering) are front-loaded and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a single optional parameter and an output schema provided, the description is complete. It covers the valid inputs, the behavior on invalid inputs, and the characteristics of the returned rows. The output schema will handle the return field structure, so no further explanation is needed. An agent can confidently invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must fully compensate. It does this exceptionally well: it explains the allowed values ('all' or day counts like '7d', '30d'), the 1–3660 range, the refusal behavior, and the rationale (avoiding disagreement between endpoints). This goes far beyond the bare schema, which only shows a default. The agent gets everything it needs to correctly set the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific statement of what the tool does: 'Reading totals, streak and pace over a span, plus per-work rows.' This identifies the resource (reading statistics) and the action (retrieving them). It is distinct from sibling tools like search_books or get_book_text, though it does not explicitly name a sibling to differentiate from, which is why it does not receive a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on the 'range' parameter, including valid values and the refusal behavior to avoid upstream disagreement. However, it does not explicitly state when to use this tool versus the sibling tools (e.g., when to prefer reading_stats over list_highlights or get_book). The usage is implied by the purpose but not articulated as a recommendation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_booksA
Search titles, descriptions, series, contributors and tags.
Searches every folder when folder_id is omitted. Results are best matches per folder, not alphabetically ordered, gathered folder by folder: earlier folders can fill the limit and later folders then contribute nothing (truncated says the answer was cut). limit: 1-100 (default 20); a value outside that range is refused, not clamped.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| folder_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It reveals the non-obvious per-folder search behavior (results gathered folder by folder, earlier folders can fill the limit, later folders contribute nothing) and the truncation indication. It also states that limit values outside 1-100 are refused, not clamped. These are critical behavioral traits that an agent must know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured. It front-loads the primary purpose in the first sentence, then details folder behavior and limit constraints in a logical sequence. There is no redundant or filler content; every sentence adds actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with an output schema present, the description covers all necessary usage details: search scope, folder filtering, limit validation, and the truncation caveat. It does not need to explain return format since an output schema exists. The description is complete for an agent to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains all three parameters: query (the search terms across listed fields), folder_id (omitted searches all folders), and limit (range 1-100, default 20, refused outside range). This adds substantial meaning beyond the raw schema, which only provides types and defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Search titles, descriptions, series, contributors and tags.' It clearly distinguishes itself from sibling tools like list_books (which lists all books) and get_book (fetches a single book) by indicating it performs a search across multiple metadata fields. The folder-scoping behavior further clarifies its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on how to use the tool: it explains the effect of omitting folder_id (searches every folder) and the limit behavior. While it does not explicitly mention alternatives or when not to use it, the purpose is unambiguous and the usage context is well-defined for a search tool, making the distinction from siblings implicit.
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 tool update
v0.4.0- Changed
list_highlights1 field changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "title": "Offset", + "type": "integer" +}
7 tool updates
v0.1.0- First observed
get_book - First observed
get_book_text - First observed
list_books - First observed
list_folders - First observed
list_highlights - First observed
reading_stats - First observed
search_books
TDQS
Scored across 7 tools
Each tool has a clear, distinct purpose: searching catalog, fetching a specific book, listing books by folder, reading text, listing folders, reading stats, and listing highlights. No two tools could be confused for the same action.
Names follow a consistent snake_case verb_noun pattern (search_books, get_book, list_books, list_folders, get_book_text, list_highlights). The only slight deviation is reading_stats, which uses a gerund instead of a verb, but it remains clear and stylistically aligned.
With 7 tools, the server is well-scoped for a read-focused book application: catalog browsing, searching, text retrieval, stats, and annotations. Each tool earns its place without bloat or thinness.
The surface covers the core read-only workflows: searching, listing, reading text, and viewing stats/highlights. It lacks write operations (e.g., creating highlights or updating progress), but the server appears intentionally read-only; minor gaps like per-book progress detail are workable.
Maintenance
Related MCP Connectors
Read-only MCP server exposing a user ORANO library to their own AI agent.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Read-only MCP server for public WeJob jobs, formations, and companies.
Related MCP Servers
- AlicenseAqualityDmaintenanceA read-only MCP server that provides access to Maimemo study data, including vocabulary progress, word lists, and notepads. It supports both stdio and HTTP transports with authentication and rate limiting for secure data access.622 npmMIT
- AlicenseNot gradedqualityCmaintenanceRead-only MCP server for accessing local Kindle library data, exposing tools to query profile, health, and book metadata.MIT
- FlicenseAqualityDmaintenanceRead-only MCP server that provides tools to search books, get book details, list authors, and view library statistics from a PostgreSQL database.5-
- AlicenseNot gradedqualityAmaintenanceA read-only MCP server for an existing Calibre ebook library, enabling metadata search, full-text search, and category browsing via the Model Context Protocol.MIT