paperboy
Paperboy is an MCP server that helps you discover, manage, and deliver research papers to your e-reader (Kindle, PocketBook, or Kobo), with optional Zotero integration for library and queue management.
Search papers across OpenAlex or arXiv by query, returning refs (arXiv ID, DOI, etc.) for use in other tools.
Get recommendations via citation-graph discovery (Semantic Scholar, seeded from your Zotero library or explicit refs) and keyword-based discovery (OpenAlex) — papers you already own are excluded.
Send papers to your e-reader by arXiv ID, DOI, URL, or title; delivered via email (Kindle/PocketBook) or Dropbox (Kobo), with dry-run previews, deduplication, force re-send, and automatic batch splitting for large sets.
Queue papers in Zotero without immediate sending, optionally filing them into topical collections for later bulk delivery.
List Zotero collections to see existing collections (name, item count, parent) and make informed filing decisions.
File queued papers into topical Zotero collections (created on demand) without affecting their delivery state.
View the reading queue with per-item delivery status: unsent, sent, or no-open-access-pdf.
Remove papers from the Zotero Reading Queue by arXiv ID, DOI, URL, or title.
Flush the queue to send all unsent papers at once, auto-batching to respect attachment/size limits and skipping already-sent or inaccessible items.
Check setup status to see which features and credentials are configured and what's still missing — without exposing secrets.
Enables searching and resolving papers on arXiv by ID or general query using the arXiv Atom API.
Facilitates delivery of papers to Kobo e-readers by uploading PDFs to a Dropbox folder synced with the device.
Provides paper recommendations based on citation-graph analysis from Semantic Scholar, seeded from the user's Zotero library.
Manages a reading queue, collections, and tags in Zotero, allowing papers to be filed, queued for delivery, and tracked with tags.
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., "@paperboy find recent papers on quantum machine learning and send to my Kindle"
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.
paperboy

An MCP server that delivers research papers and books to your e-reader, with Zotero as the source of truth. Ask Claude for a reading list, then say "queue them and send to my Kindle." (MCP is the plugin protocol Claude uses: this program runs on your machine or your cloud project, and Claude calls its tools during conversation.) Works locally in Claude Code and Claude Desktop; a Cloud Run deployment adds claude.ai and the Claude mobile app, so papers can be sent from a phone (docs/deploy.md).
Two things are kept separate: delivering a paper to your device and cataloguing a work in Zotero. You can do either. A book you own, a paywalled reference, or a PDF you already have can all be tracked in the library without being staged for the e-reader.
Zotero itself is optional: without it you can still search and send papers one-off. The reading queue, collections, and duplicate protection across sessions need it.
How it works
You ask Claude for papers; it uses paperboy's tools to find, queue, and deliver them. What that looks like in practice:
Papers you queue land in a Reading Queue collection in Zotero, created on demand.
Once a paper reaches your device, paperboy tags it
sent-to-ereaderin Zotero, so it skips papers already sent to your e-reader, even in a later conversation. (Without Zotero there's no memory between sends, so this protection needs it.)Claude can file papers into your topical collections too. It proposes one from the paper's topic and your existing collection names, and asks you when the fit is unclear. A paper can sit in several collections at once, so filing never disturbs the queue.
Papers are found by arXiv id, DOI, or title (a close-enough title match, so a reading list Claude wrote in the chat can be sent as-is). When a title matches only loosely, paperboy offers the closest candidate to confirm rather than guessing or failing silently.
Books work too:
add_bookresolves an ISBN, a book DOI, or a title into a proper Zotero book item (publisher, edition, ISBN, pages). Books are catalogued, not delivered.Have the PDF already (a working paper, lecture notes, an open-access textbook)?
attach_pdffiles it in Zotero with the PDF attached, using metadata you give it, and can send it to the e-reader in the same step.When a reference can't be resolved, the receipt says why and which tool fits, rather than sending you hunting for a better URL. A paper with no open-access PDF is a normal library record, not an error.
Zotero holds all of this, so the server keeps no state of its own: no database to run, and safe to redeploy at any time.
Delivery backends
Backend | Devices | How |
| Kindle, PocketBook, anything with an email intake | SMTP to the device address. Kindle constraints enforced: 25 attachments / 50 MB per email; sender must be on the Approved Personal Document E-mail List |
| Kobo (native Dropbox sync on the device) | Uploads via the Dropbox API. Kobo only syncs |
Related MCP server: Academic Paper Search MCP Server
Tools
Tool | What it does |
| Search OpenAlex (general) or arXiv ( |
| Discover related or new papers: citation-graph recommendations (Semantic Scholar) seeded from your Zotero library, plus keyword discovery from interests Claude distills out of the conversation. Excludes papers you already have |
| One-off send by arXiv id, DOI, URL, or title (also records in Zotero if configured) |
| Add papers to the Zotero Reading Queue without sending (optionally filed into topical collections) |
| Track papers in Zotero without queueing or sending them (owned, paywalled, or read-later); a missing OA PDF is not treated as a failure |
| Catalogue a book by ISBN, book DOI, or title as a Zotero |
| Ingest a PDF you already have (grey literature, open-access textbooks) with the PDF attached and metadata you supply; optionally send it |
| List Zotero collections so Claude can propose where to file a paper, or ask you |
| File queued papers into a topical collection (created on demand; queue membership unaffected) |
| Remove papers from one collection (for misfiled items); the papers themselves and their queue/sent state are untouched |
| Show the queue with per-item status (unsent / sent / no-open-access-pdf) |
| Delete queue items by exact ref or title |
| Send every unsent queue item (auto-split under email limits), then tag as sent |
| Report what's configured and what's missing (no secrets) so Claude can guide setup |
Setup
Run the interactive wizard. It asks which e-reader you have, walks through only the credentials that device needs, and validates each one as you enter it: SMTP login test, Zotero key check with automatic library ID lookup, full Dropbox OAuth exchange.
uv sync && uv run paperboy setupdocs/setup.md is the step-by-step version: where to find each credential in Zotero, Amazon, Gmail, and Dropbox, with links to the official page for every step.
How much setup you need depends on the device:
You have | Credentials needed |
Kindle | 2 — Send-to-Kindle address + an SMTP app password |
PocketBook | 2 — Send-to-PocketBook address + an SMTP app password |
Kobo | a Dropbox app (key/secret + one OAuth approval) + a contact email |
+ Zotero queue (optional) | 1 — a Zotero API key (library ID auto-detected) |
If you'd rather set up by hand, cp .env.example .env and fill it in;
every variable is documented there. Then register with Claude Code:
claude mcp add paperboy -- uv run --directory /path/to/paperboy paperboy--directory matters: the server loads .env from its working
directory (set PAPERBOY_ENV=/path/to/.env to point elsewhere).
If paperboy is added but half-configured, ask Claude to "check my
paperboy setup". The setup_status tool reports what's missing and
what to do next, without passing secrets through the chat.
Remote use
You were given a URL and a token
If someone shared their deployment with you, this is your whole setup:
claude mcp add --transport http paperboy <URL>/mcp \
--header "Authorization: Bearer <token>"The URL needs the /mcp path suffix. Treat the token like a password:
it lets you act fully as the owner: send email from their address,
deliver to their e-reader, and read and edit their Zotero library.
There is no reduced-permission mode; if that's not what you both want,
deploy your own instance.
Deploy your own
One script creates a locked-down, single-tenant Cloud Run service. You need the gcloud CLI and a Google Cloud account with billing enabled, so a card has to be on file. What you pay depends on how much you use it: a personal deployment sending papers now and then usually falls inside Cloud Run's free tier and costs nothing, but heavy or shared use can go past it. The script sets a $1/month budget alert so you hear about it if your bill ever starts to climb.
uv run paperboy setup && ./deploy/deploy.sh my-paperboy-projectHow a client connects to the deployed server depends on the client:
Claude Code and the API use a bearer token the script generates. You paste it into an
Authorizationheader, as in the section above.claude.ai and the Claude mobile app usually can't send a bearer token from their connector dialog, so they sign in with Google instead. That needs a one-time Google OAuth client, which you create in your own Cloud project (a Web-application client with one redirect URI). Sign-in is restricted to your own email address, and because paperboy only asks Google for your email, the sign-in doesn't expire.
docs/deploy.md has the full procedure for both, including the OAuth console steps, the security model, and cost bounds. The deploy script also prints the exact OAuth steps with your project's URLs already filled in, so you're not copying them from here.
Development & contributing
uv for packaging, ruff (Google style), ty, pytest behind an enforced
80% coverage gate. uv sync && uv run pre-commit install, then
uv run pytest. The suite runs entirely offline; no credentials
needed to develop.
Contributions are welcome. CONTRIBUTING.md covers setup, testing conventions, and what makes a change easy to merge; SECURITY.md covers how to report vulnerabilities (privately, please).
Roadmap
reMarkable delivery backend (real cloud API)
arXiv HTML → EPUB via pandoc for reflowable reading (opt-in per paper; conversion is lossy for dense math, so PDF stays the default)
Kindle highlights → Zotero notes round-trip (
My Clippings.txtparser with fuzzy title matching)
Prior art & acknowledgments
Ideas paperboy builds on: the tag-driven Zotero→Kindle idea from stakats/zotero-to-kindle (circa 2011, by one of Zotero's original directors); wahiggins3/send-to-kindle-mcp; openags/paper-search-mcp; and 54yyyu/zotero-mcp, the model for our setup wizard; paperboy leaves library management to it.
Thank you to arXiv for use of its open access interoperability. Paper metadata and open-access links come from OpenAlex, Crossref, and Unpaywall, all run as open scholarly infrastructure. Recommendations via the Semantic Scholar Recommendations API (Allen Institute for AI). Library management via the Zotero web API. Built on FastMCP, pyzotero, and httpx.
paperboy was built with Claude Code.
Available Tools
14 toolsadd_bookA
Catalogue a book in Zotero by ISBN, book DOI, or title.
Resolves an ISBN-10/13, a book DOI, or a title (Crossref, then Open
Library, then Google Books) into a proper Zotero book item with
publisher, edition, ISBN, series, and page count — never a
journalArticle, which would corrupt citations. Books are catalogued,
NOT queued or delivered: to put an open-access textbook PDF on the
e-reader, use attach_pdf with item_type="book". Pass collections
to file it topically (created on demand). A title that matches only
loosely returns the closest candidate for you to confirm rather than
guessing. Deduplicates by ISBN.
Inputs: identifier (required), collections. Returns: result
add_to_libraryA
Track papers in Zotero WITHOUT staging them for e-reader delivery.
The "just catalogue it" path, distinct from queue_papers: resolves
each ref (arXiv id, DOI, URL, or title) and files it into the library
(and any collections, created on demand) but never adds it to the
Reading Queue and never sends it. A paper with no open-access PDF is
catalogued normally here — it is a library record, not a delivery
failure, so nothing is tagged no-oa-pdf. Use this for references you
want to keep (owned, paywalled, or read-later) rather than deliver.
Duplicates report the collections they already live in. Relay any
unresolvable refs to the user.
Inputs: refs (required), collections. Returns: result
attach_pdfA
Ingest a PDF you already have into Zotero, with the PDF attached.
For grey literature and works no registry indexes (author-circulated
preprints, lecture notes, working papers, open-access textbooks).
Downloads the PDF from an http(s) URL (or reads a local path when
running locally), creates a Zotero item of item_type from the
metadata YOU supply, and attaches the PDF to it — no registry lookup,
so a title/authors the model already knows is enough. item_type
is one of journalArticle, book, bookSection, report, thesis, preprint,
conferencePaper, manuscript, document (default journalArticle); use
'book' for an open-access textbook PDF. Files into collections
(created on demand) and, unlike queue_papers, does NOT queue. With
send=True it also delivers the PDF to your e-reader in the same call.
Requires Zotero.
Inputs: title (required), authors (required), url_or_path (required), doi, +4 more. Returns: result
file_papersA
File already-queued papers into a Zotero collection.
Only papers ALREADY in the Reading Queue can be filed — to file a fresh paper, queue_papers it first, or pass collections=[...] to queue_papers to queue and file in one step. The collection is created on demand, but only if at least one paper matches (a call that files nothing leaves no empty collection behind). Items stay in the queue — Zotero items can live in many collections — so delivery state is unaffected. Refs match like remove_from_queue: exact arXiv id, DOI, URL, or title.
Inputs: refs (required), collection (required). Returns: result
list_collectionsA
List the user's Zotero collections (name, item count, parent).
Check this before queueing or sending new papers: if a topical collection clearly fits the paper, pass it via collections=[...]; if several could fit or none do, ask the user where to file — never guess silently. Naming a new collection in other tools creates it on demand.
Inputs: no named parameters. Returns: result
list_queueA
List the Zotero Reading Queue with delivery status per item.
Status is 'unsent', 'sent', or 'no-open-access-pdf'. Use this to
show the user their queue, before send_queue (which flushes every
unsent item), or to find refs for remove_from_queue. Each entry
also carries key, the Zotero item key — the one id that stays
unique when the queue holds duplicate entries of the same paper;
every ref-taking tool accepts it. added dates are UTC.
Inputs: no named parameters. Returns: result
queue_papersA
Add papers to the Zotero Reading Queue without sending them.
Accepts arXiv ids, DOIs, URLs, or paper titles. Papers already in
the queue are reported as such, not re-added. collections
optionally files the papers into topical Zotero collections
(created on demand) as well — check list_collections and ask the
user when placement is unclear. Unresolvable papers are reported
back — relay those to the user.
Inputs: refs (required), collections. Returns: result
recommend_papersA
Discover papers the user may want to read — old or new.
Blends two signals: citation-graph recommendations (Semantic
Scholar) seeded from seed_refs, or — by default — the user's
Zotero library (what they queue and read IS their interest
profile); and keyword discovery (OpenAlex) from interests —
pass 2-4 short phrases distilled from the current conversation.
recent_only=True favors newly published work; False searches the
all-time pool (computer science only, an upstream limit).
Papers already in the user's library are excluded (the queue plus
the 100 most recently added items). max_results is capped at 20.
Returns {"picks": [...], "problems": [...]}: picks carry refs for
send_papers / queue_papers, and each pick has a via field
saying why it appeared — 'interest-keyword' (matched a stated
interest), 'related-to-seeds' (citation graph of explicit seeds),
or 'related-to-library' (citation graph of the OWNER'S Zotero
library; can look off-topic to anyone else). When interests are
given they lead the results. problems reports any discovery arm
that failed or seed that didn't resolve — ALWAYS relay problems,
or a stated interest may silently go uncovered. Present picks and
let the user choose; don't send unasked.
Inputs: interests, seed_refs, max_results, recent_only. Returns: object
remove_from_queueA
Remove papers from the Zotero Reading Queue by ref or title.
Matches each ref (arXiv id, DOI, URL, or exact title) against queue items. Items filed into other collections keep their library record (and sent-state) and only leave the queue; items that live nowhere else are moved to Zotero's Trash (restorable in the Zotero app for ~30 days). Trashed items no longer count for duplicate protection — sending those again later will deliver them again. Nothing is ever deleted from the e-reader, and nothing is ever permanently deleted from Zotero.
A ref that matches more than one queue item (duplicate titles or a duplicated record) removes nothing; the receipt lists each candidate's Zotero item key, which is accepted as a ref and is unique even for exact duplicates. Relay the choice to the user — never pick for them.
Inputs: refs (required). Returns: result
search_papersA
Search for papers across the scholarly literature.
source is 'all' (OpenAlex: journals, conferences, and preprint
servers including arXiv — broad coverage, but ranking can miss on
arXiv-native topics) or 'arxiv' (arXiv's own search — better for
recent preprints or when 'all' returns off-topic results); unknown
values fall back to 'all'.
max_results is clamped to the 1-25 range. Each result has a ref
(arXiv id, DOI, or exact title) to pass to send_papers /
queue_papers.
open_access_pdf means an OA PDF link was found; delivery can
still fail if the link is dead (arXiv-hosted papers are the most
reliable).
Inputs: query (required), source, max_results. Returns: result
send_papersA
Send papers to the e-reader by arXiv id, DOI, or title.
refs accepts arXiv ids ('2401.12345', 'arXiv:...'), arXiv
abs/pdf URLs, DOIs, doi.org URLs, and paper titles — the same
ref values search and recommendation results carry. Publisher
landing-page URLs are NOT resolvable — use the DOI or title.
Version suffixes ('2401.12345v2') are ignored; the latest arXiv
version is delivered.
collections optionally files the papers into topical Zotero
collections (created on demand) in addition to the Reading Queue —
check list_collections and ask the user when placement is unclear.
Refs are deduplicated, and papers already tagged as sent in Zotero are skipped unless force=True. Large batches are split automatically to fit the 25-attachment / 50 MB per-email limits. dry_run=True previews what would be sent, with estimated sizes, without downloading or delivering — use it before big sends.
Papers without an open-access PDF are not sent; if Zotero is configured they are still queued (tagged no-oa-pdf) so they can be delivered manually later. Without Zotero there is NO cross-call duplicate protection — re-sending the same ref ships another copy. Relay the full receipt — sizes, skips, and failures — to the user.
Inputs: refs (required), force, dry_run, collections. Returns: result
send_queueA
Send EVERY unsent paper in the Zotero Reading Queue.
This flushes the whole queue — for specific papers use send_papers. Items tagged sent or no-oa-pdf are skipped; items whose PDF turns out to be unavailable are tagged no-oa-pdf so they are not retried forever. Batches are split under the email limits automatically. Check list_queue first when unsure what will go.
Inputs: no named parameters. Returns: result
setup_statusA
Report which paperboy features are configured and what's missing.
Returns configuration state only — never secret values. Use this to guide the user through finishing setup. Credentials themselves must be entered by running 'paperboy setup' in a terminal, never pasted into the chat.
Inputs: no named parameters. Returns: object
unfile_papersA
Remove papers from one Zotero collection, and nothing else.
The inverse of file_papers, for misfiled items: membership in the named collection is dropped, while the item, its other collections (including the Reading Queue), and its sent-state are untouched. The Reading Queue itself is refused as a target — leaving the queue is remove_from_queue's job, with its keep-or-trash safeguards. To move a paper between collections, file it into the new one and unfile it from the old. Refs match like remove_from_queue: exact arXiv id, DOI, URL, or title, against the collection's items; an ambiguous ref (matching several items) removes nothing.
Inputs: refs (required), collection (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 14 tools
Each tool targets a distinct workflow step: search, recommend, queue, send, catalogue, attach PDF, manage collections, and check status. Overlapping actions like send_papers vs send_queue or add_to_library vs queue_papers are explicitly differentiated in their descriptions.
Most tool names follow a clear verb_noun snake_case pattern (search_papers, send_papers, queue_papers, list_collections). Minor deviations like remove_from_queue and setup_status break the simple two-word pattern but remain stylistically consistent.
14 tools is well-scoped for a scholarly literature manager spanning discovery, queueing, delivery, cataloguing, and collection organization. Each tool serves a clear purpose with no obvious redundancy or bloat.
The toolset covers the full workflow lifecycle: find papers, add to queue, send to e-reader, catalogue items, organize collections, and inspect setup state. Only deep library editing operations like metadata updates or permanent deletion are absent, which is reasonable for this domain.
Maintenance
Related MCP Connectors
Zotero MCP server for Claude and ChatGPT: search, citations, safe writes, PDF passages and pages.
Remote MCP server for full read/write access to a Zotero library
MCP server for Project Gutenberg: 78,000+ public-domain ebooks with full plain-text retrieval.
Personal knowledge base MCP server with semantic search, auto-categorization, metadata extraction
Related MCP Servers
- AlicenseAqualityAmaintenanceThe ArXiv MCP Server bridges the gap between AI models and academic research by providing a sophisticated interface to arXiv's extensive research repository. This server enables AI assistants to perform precise paper searches and access full paper content, enhancing their ability to engage with scientific literature.1910,735 PyPI3,258Apache 2.0
- AlicenseCqualityDmaintenanceEnables real-time search and retrieval of academic paper information from multiple sources, providing access to paper metadata, abstracts, and full-text content when available, with structured data responses for integration with AI models that support tool/function calling.3119AGPL 3.0
- AlicenseAqualityDmaintenanceA server that enables MCP clients like Anthropic Claude App to interact with local Zotero libraries, allowing users to search papers, manage notes, and access research materials through natural language.1029Apache 2.0
- AlicenseAqualityBmaintenanceConnects your Zotero research library with Claude and other AI assistants via the Model Context Protocol, allowing you to search your library, access content, discuss papers, get summaries, and analyze citations.358,531 PyPI5,884MIT