Skip to main content
Glama

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

list_folders

folders this account can read

list_books

books in a folder, newest first

search_books

search titles, descriptions, series, contributors, tags

get_book

one catalog record by id

reading_stats

totals, streak, pace, plus per-work rows

list_highlights

highlights/notes/bookmarks, for one book or the account

get_book_text

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, download

  • read-insights — reading statistics

  • sync — highlights and notes; the book→work join needs this and library-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 below

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

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

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

Environment

Variable

Default

Meaning

LISEUR_URL

required

base URL of the instance

LISEUR_TOKEN / LISEUR_TOKEN_FILE

required

device token secret

MCP_TRANSPORT

stdio

stdio or streamable-http

MCP_HOST / MCP_PORT / MCP_PATH

127.0.0.1 / 8000 / /mcp

HTTP listener

MCP_AUTH_TOKEN / MCP_AUTH_TOKEN_FILE

required for HTTP

bearer token clients present

MCP_ALLOWED_HOSTS

localhost, 127.0.0.1 (any port)

Host headers the HTTP transport accepts

MCP_ALLOWED_ORIGINS

none

Origin headers accepted, listed exactly (no * wildcard); with none, any request carrying an Origin is refused

LOG_LEVEL

INFO

log level

LISEUR_TIMEOUT_SECONDS

30

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 to MCP_ALLOWED_HOSTS; entries match exactly, so write name:* to accept any port (localhost alone does not match Host: localhost:8000).

  • 403 Invalid Origin header — the client sends an Origin and MCP_ALLOWED_ORIGINS is 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. Point LISEUR_URL at 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 pyright

Conformance

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-list

Smoke 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.sh

The 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.py

It 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 tools
get_bookA

Fetch one catalog record by book_id (same shape list_books returns).

ParametersJSON Schema
NameRequiredDescriptionDefault
book_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNo
book_idYes
chapterNo
max_charsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
orderNorecent
folder_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
book_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
rangeNo30d

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes
folder_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

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: '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.

Usage Guidelines4/5

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. 1 tool updatev0.4.0
    • Changedlist_highlights1 field changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "title": "Offset",
        +  "type": "integer"
        +}
  2. 7 tool updatesv0.1.0
    • First observedget_book
    • First observedget_book_text
    • First observedlist_books
    • First observedlist_folders
    • First observedlist_highlights
    • First observedreading_stats
    • First observedsearch_books

TDQS

A4.2/5.0

Scored across 7 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Read-only MCP server for accessing local Kindle library data, exposing tools to query profile, health, and book metadata.
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Read-only MCP server that provides tools to search books, get book details, list authors, and view library statistics from a PostgreSQL database.
    5
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    A 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