Skip to content

Let a coding agent search the library pedro has read - #19

Merged
bokuweb merged 1 commit into
mainfrom
mcp-server
Aug 24, 2026
Merged

Let a coding agent search the library pedro has read#19
bokuweb merged 1 commit into
mainfrom
mcp-server

Conversation

@bokuweb

@bokuweb bokuweb commented Aug 24, 2026

Copy link
Copy Markdown
Owner

pedro borrows a coding agent's credentials to answer a question about a book.
This runs the same relationship the other way round: a new pedro-mcp crate
serves the library over MCP, so an agent working on your code can search the
documents you actually read and quote the page it found them on.

The tools

Tool
list_books What is in the library, which shelf each book is on, and the id the other tools take
search_library The passages bearing on a query, best first, each naming its page
read_pages A range of pages, verbatim
book_contents The book's own chapters, and where each one starts
add_book A PDF on this machine, added and indexed

The same hybrid index the reader's search box uses: the words, and — once the
embedding model has been fetched — what they mean, the two rankings fused. It
opens the same SQLite database the reader does, in WAL mode, so both can be
open at once and a book added in one is there in the other. Nothing but
add_book needs pdfium, because the pages come from text already extracted
into the library.

cargo build --release -p pedro-mcp
claude mcp add pedro -- "$PWD/target/release/pedro-mcp"

What is deliberately absent

No tool for asking a question. pedro answers questions by handing a passage
to an agent CLI, and whatever is calling these tools is already that agent —
what it wants from pedro is the retrieval, not a second opinion from a second
model one step further away from it.

No tool for removing a book. Adding one costs a file and is undone in the
reader; deleting one takes its highlights and conversations with it, which is
the reader's own decision to make.

Two decisions worth the review

JSON-RPC by hand rather than an SDK. The workspace has no async runtime
anywhere, and MCP's stdio transport is newline-delimited JSON with four
methods, so rmcp would have brought tokio along for nothing. protocol.rs is
85 lines.

Hits are numbered, not scored. The two rankings are fused by position, so
the number that falls out is a rank wearing a score: a genuinely good hit
prints 0.03, and a model shown that would read it as a bad one. Rank order is
the only interpretable signal, so that is what the tool returns.

A limitation to know about

search_library with book_id filters after Store::search has ranked the
whole library and taken its top 40, so a book whose matches sit deep in a
library-wide ranking can come back empty. The tool says "Other books in the
library do match" so a caller can tell that case from a genuine miss, but the
real fix is pushing a book filter into index::search's SQL — upstream in
pedro-core/pedro-search, where passages_for has the same shape. Left for
its own change.

Checks

cargo fmt --all --check, clippy --locked --workspace --all-targets --all-features under RUSTFLAGS=-D warnings, and cargo test --locked --workspace --all-features all pass: 338 tests, 22 of them new.

The new tests drive Session::handle directly, which is what the stdio loop
calls per line, so they cover the protocol and the tools without a subprocess:
parse errors, notifications going unanswered, a stray reply, a request naming
no method (which would otherwise leave a client waiting on an id for ever), and
the whole add → list → search → read path against real PDFs.

Also checked by hand against a real library over an actual pipe — a search for
ヴィジュネル暗号の鍵長を推定する方法 returned the Kasiski-examination pages of
the book on the shelf.

🤖 Generated with Claude Code

pedro borrows a coding agent's credentials to answer a question about a
book. This runs the same relationship the other way round: `pedro-mcp`
serves the library over MCP, so an agent working on your code can search
the documents you actually read and quote the page it found them on.

Five tools — `list_books`, `search_library`, `read_pages`,
`book_contents`, `add_book` — over the same hybrid index the reader's
search box uses. It opens the same SQLite database the reader does, in
WAL mode, so both can be open at once.

JSON-RPC by hand rather than an SDK: the workspace has no async runtime,
and MCP's stdio transport is newline-delimited JSON with four methods,
so a client library would have brought tokio along for nothing.

Two things are deliberately absent. There is no tool for asking a
question: pedro answers questions by handing a passage to an agent CLI,
and whatever is calling these tools is already that agent — what it
wants from pedro is the retrieval, not a second opinion from a second
model one step further away from it. And there is none for removing a
book, because deleting one takes its highlights and conversations with
it, which is the reader's own decision to make.

Hits are numbered rather than scored. The two rankings are fused by
position, so the number that falls out is a rank wearing a score, and a
model shown `0.03` would read a good hit as a bad one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bokuweb
bokuweb merged commit eef30d2 into main Aug 24, 2026
2 checks passed
@bokuweb
bokuweb deleted the mcp-server branch August 25, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant