Readwise MCP HTTP Server
This server provides full Readwise and Readwise Reader integration for managing highlights, books, tags, documents, saving URLs, updating progress, and exporting data.
Search highlights using semantic, full-text, or hybrid search with filters for tags, book, and limit.
List, get, create, update, and delete highlights.
List and get books/sources with filters for category, source, recency, and minimum highlight count.
List, create, and delete tags; add or remove tags on highlights.
List and get Reader documents with filters for location, category, and recency.
Save URLs to Readwise Reader with optional title, tags, notes, and location.
Update reading progress for a Reader document.
Bulk export highlights with cursor pagination and filters by date or book IDs.
Provides access to Readwise highlights and documents through vector and full-text search capabilities, enabling retrieval and exploration of saved reading materials and annotations.
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., "@Readwise MCP HTTP Server search my highlights for notes about machine learning"
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.
mcp-readwise
MCP server for Readwise and Readwise Reader, built on FastMCP. Engagement-aware reads, the few write tools the official Readwise connector lacks, and one thing you can't easily do anywhere else: turn a markdown blob into a real, brand-styled EPUB and have it land in your Reader Library a minute later.
It is for Readwise users who work with Claude or another MCP client and want their reading history, engagement signals and long-form drafts to flow into Reader without copy and paste. It is designed to run next to the official Readwise connector, not to replace it.
10 tools, 2 prompts, 6 resources. Python 3.11+, FastMCP 4. Runs over stdio for a local client or as an HTTP server in Docker.
Scope: what this server adds over the official connector
The official claude.ai Readwise connector covers Reader search/list/create/move/tags, highlight CRUD and highlight tags, highlight vector search and daily review. Use it for those. This server keeps only what the connector lacks:
EPUB delivery —
save_markdown_as_epub+verify_epub_received(real EPUB 3 via the email-to-library path).Branded render —
save_markdown(frontmatter + CDIT-styled HTML).Engagement-scored reads —
reading_status,writing_material.Reading progress —
update_progress.By-URL lookup —
reader_get_by_url(canonicalized exact source-URL match; the connector has no URL filter).v2 tag management —
create_tag/delete_tag, pluslist_tagsas the only source of the v2 tag idsdelete_tagneeds.
Related MCP server: Kiseki-Labs-Readwise-MCP
Why this exists
The most common source of "long markdown that needs a reading home" in 2026 is research output from Claude, OpenAI, and other agent loops. Deep-research mode produces 3000–8000 word briefs in a single tool turn. They arrive as markdown in a chat window, and they shouldn't stay there — they want chapter navigation, a TOC sidebar, downloadable export to a Kobo / Boox / Kindle, and most often the Readwise iOS and iPad apps, which are quietly the best long-form reading and highlighting clients on those devices.
This MCP server is the transporter for that markdown into Reader. An agent calls save_markdown_as_epub, the EPUB appears in your Library a minute later, and the chat window is no longer your reading place.
The niche-but-nice part: markdown → real EPUB in Reader

Readwise's Reader API has no file-upload endpoint — I verified this against their v3 docs and their own official CLI, which doesn't expose one either. The closest thing the API offers is "save URL" or "save HTML." Neither produces a true EPUB in Reader, which is the format with proper chapter nav, TOC, and downloadable export to Kobo / Boox / Kindle.
The one path that does produce a real EPUB is the email-to-library mechanism: every Reader account has a <custom>@library.readwise.io address that accepts EPUB attachments and ingests them properly. So save_markdown_as_epub automates that path:
markdown blob → pandoc renders to EPUB 3 (with CDIT brand styling)
→ aiosmtplib delivers via Resend SMTP
→ email lands at <custom>@library.readwise.io
→ Readwise ingest pipeline picks it up (1–5 min)
→ real EPUB appears in LibraryThe tool returns immediately after SMTP delivery — the ingest is async by nature. A companion tool verify_epub_received polls Reader to confirm the document landed, with time-aware retry guidance baked into the response so an LLM caller knows when to retry vs. when to surface a failure.
Setup
Three environment variables, all required (the server still boots without them — only save_markdown_as_epub refuses to run; every other tool, including verify_epub_received, works normally):
# Your custom Readwise Library email
# Find at: read.readwise.io → Account → Personalize email addresses
# Bearer credential — rotate via Readwise if it leaks.
READWISE_LIBRARY_EMAIL=your-name@library.readwise.io
# Resend API key, used as SMTP password (username is literal "resend")
RESEND_API_KEY=re_…
# Verified sender registered in Resend
EPUB_FROM_ADDRESS=reader@example.comCalling it
# From any MCP client (Claude, agents, scripts):
result = save_markdown_as_epub(
markdown="""---
title: Q2 Planning Brief
author: Casey
tags: [planning, brief]
note: Context for the team — read this before Thursday's call.
---
# Background
...
""",
idempotency_key="brief-2026-q2-v1", # optional — collapses retry duplicates
)
# → EpubSendResult(title=..., accepted_at=..., recipient=...,
# identifier_scheme="x-mcp-readwise-idempotency", ...)
# Wait 1–2 minutes, then:
verify = verify_epub_received(title=result.title, since=result.accepted_at)
# → VerifyResult(found=True, document=ReaderDocument(...),
# note="Found in Reader Library.")The docstring leads with the async contract loudly so LLM agents reading the schema know not to tell the human "done" until verify_epub_received confirms.
Brand stylesheet (CDIT)
EPUB output is styled by a hand-tuned CSS at mcp_readwise/assets/epub/cdit-style.css, inheriting the palette from cdit-works.de:
Carbon
#272f38(body text), Cloud Dancer#f0eee9(page background)Strong Blue
#1f5da0(links, H1 underline), Mint#5cc6c3(blockquote rail, Note preface)Inter weights 400 / 700 / 800 embedded as static woff2 subsets (latin + latin-ext, ~170KB)
Headings deliberately diverge from the website's display face: chapter heads use Inter weight 800 with tracking
-0.02em, not League Gothic — condensed display fonts fatigue across long-form chapter breaksbody { line-height: 1.7; text-align: left; hyphens: auto; }tuned for sustained reading
To customize, fork the CSS file. It's a first-class editable asset, not generated from Python.
Frontmatter
Both save_markdown and save_markdown_as_epub accept YAML frontmatter for self-describing markdown:
---
title: My Note
author: Casey
summary: A brief description.
tags: [research, draft]
note: Context for the reader.
published_date: 2026-05-11
image_url: https://example.com/cover.jpg
---
# Body starts here
Content with **markdown** features — tables, footnotes, fenced code, smart quotes
all render properly through the `extra` + `sane_lists` + `smarty` extensions.Title resolution (first non-empty wins): explicit title= param → frontmatter title: → first # H1 in body → "Untitled". Same precedence for other fields (without the H1 fallback).
Limits
EPUB ceiling: 20 MiB raw binary (Readwise's email ingest caps at 30 MB; base64 inflates ~33%, MIME adds ~1 MB, so 20 MiB fits with margin). Larger EPUBs raise
EpubTooLargeErrorbefore SMTP.Pandoc binary in the Docker image: ~150 MB. Accepted cost.
Inline images in markdown must use absolute HTTPS URLs — pandoc fetches them at build time; relative paths don't resolve.
The other 8 tools
Read (engagement-aware)
These two collapsed an earlier 7-tool read surface into intent-shaped calls. They're built on a per-source engagement score that joins Readwise v2 books with their Reader v3 documents, so books and articles, finished and saved, recent and legacy, all sit on one comparable axis.
Tool | Description |
| Single-call snapshot — recent activity, evergreen top, current attention, junk drawer, signal density. Accepts |
| Bundle highlights for drafting. Source-first ( |
Read (direct Reader lookup)
This bypasses the engagement cache to look up a document anywhere in the Reader library (e.g. archived docs the cache doesn't surface).
Tool | Description |
| Look up a single Reader document by its source URL. |
Write
Tool | Description |
| Save a markdown blob to Reader as rendered HTML with |
| The real-EPUB-via-email path described above. Async, returns |
| Confirm a |
| Update reading progress (0.0–1.0). |
Tags
Tool | Description |
| List user-created custom tags (with the ids |
| Tag create/delete. |
Ways to save your own content into Reader
You want | Use | Sync / Async | Fidelity | Setup |
Save a URL (Readwise fetches & parses) | official connector | sync | HTML article | none |
Save markdown as HTML with epub-UX hint |
| sync | HTML with | none |
Save markdown as a real EPUB book |
| async (1–5 min) | true EPUB 3 with TOC, chapter nav, brand styling | three env vars |
Requirements
Python 3.11 or newer and uv
A Readwise access token (get one)
Pandoc, only for
save_markdown_as_epub(included in the Docker image)For the EPUB path: an SMTP account (Resend by default) with a verified sender address
Installation and running
git clone https://github.com/CaseyRo/mcp-readwise.git
cd mcp-readwise
uv sync
# stdio (default), for a local MCP client
READWISE_TOKEN=... uv run mcp-readwise
# streamable HTTP on HOST:PORT, path /mcp
READWISE_TOKEN=... MCP_API_KEY=... TRANSPORT=http uv run mcp-readwiseFor local development install Pandoc with your package manager (for example brew install pandoc). The other tools work without it.
Docker
cp .env.example .env # fill in the values
docker compose up -d --buildcompose.yaml builds the image from source, runs with TRANSPORT=http and publishes the server on host port 8010. GIT_COMMIT and APP_VERSION can be passed as build args so /health reports the running build.
Configuration
All settings are environment variables (see .env.example).
Variable | Required | Default | Description |
| Yes | (empty) | Readwise API access token |
| When | (empty) | Bearer token clients must send; the server refuses to start in HTTP mode without it |
| No |
|
|
| No |
| HTTP bind address |
| No |
| HTTP port |
| No |
| Readwise API base URL |
| No |
| TTL for the engagement index cache (4 hours) |
| No | (built-in) | Comma-separated tags excluded from the annotation bonus |
| No |
|
|
EPUB sender (optional, but all three required together) | |||
| Only for | (empty) | Your |
| Only for | (empty) | SMTP password (Resend API key by default) |
| Only for | (empty) | Verified sender address |
| No |
| Override to use Postmark, SES, etc. |
| No |
| |
| No |
| EPUB OPF |
| No |
| 20 MiB ceiling before send |
Build metadata (optional) | |||
| No |
| Commit reported by |
| No | package version | Release version reported by |
Authentication
In stdio mode there is no server-side auth; the client that starts the process owns it. In HTTP mode every request to /mcp must carry Authorization: Bearer <MCP_API_KEY>. The key is compared in constant time. Put the server behind TLS (a reverse proxy or tunnel) before exposing it beyond localhost, and keep MCP_API_KEY and READWISE_TOKEN out of version control.
Health endpoint
GET /healthReturns build identifier, git commit, uptime, registered tool count, engagement index status, and the epub_sender configured flags (without ever exposing the API key or library email in plaintext).
{
"status": "healthy",
"version": "0.7.0",
"build": "0.7.0+6ec5b6b",
"tools": 10,
"engagement_index": { "built": true, "source_count": 152, "age_seconds": 312 },
"epub_sender": {
"configured": true,
"smtp_host": "smtp.resend.com",
"smtp_port": 587,
"from_address": "reader@example.com",
"library_email_set": true
}
}How the engagement score works
Every source — book or article, Reader-imported or legacy Kindle — gets a vector engagement score with four components:
rawranks "current attention" (recency-weighted overall score)intensityranks "evergreen interests" (recency removed; pure depth)recencysmall modifier from how recently the source was last highlightedreturn_strengthcaptures multi-year highlight clusters and recent Reader re-opens
Computed from a layered sum of:
Base layer —
legacy(v2-only Kindle/iBooks book),highlighted,finished_no_hl,reading,saved_warm,saved_coldDensity — non-discarded highlight count
Recency — last-highlight age, banded (30d / 1y / 5y)
Annotation — does any highlight carry a user note, a non-structural tag, or
is_favorite?Return signal — multi-year highlight clusters AND/OR Reader-era reopens
See openspec/changes/archive/2026-05-11-workflow-shaped-tools/design.md for the full formula and decision rationale.
Project structure
mcp_readwise/
server.py # FastMCP app, tool registration, /health
config.py # pydantic-settings configuration
client.py # Centralized httpx client (auth, retries, rate limits)
auth.py # Bearer token verifier for MCP Portal
engagement.py # The engagement index + scoring formula
markdown_render.py # Frontmatter parser + Markdown → HTML helper
epub_render.py # Pandoc wrapper + EPUB metadata builder
smtp_client.py # Async SMTP transport (aiosmtplib)
assets/epub/ # CDIT brand stylesheet + embedded Inter woff2 subsets
models/ # Pydantic response models
tools/
status.py, writing.py # Engagement-aware reads
markdown.py # save_markdown (HTML path)
epub_sender.py, epub_verifier.py # Real-EPUB-via-email path
reader.py, tags.py # Progress, by-URL lookup, v2 tagsTelemetry
A vendored usage.py middleware writes one JSON line per tool call to stderr: server, tool, duration, outcome and protocol. Tool arguments are never logged. Tool failures are raised as ToolError, so clients receive a proper MCP error.
Development
uv sync
uv run pytest
uv run ruff check .CI (.github/workflows/ci.yml) runs the same lint and tests as the required test check. main is branch-protected, so changes land through a pull request. A separate security workflow runs dependency audits.
Releases
Releases are tag-only. After a merge to main, .github/workflows/release.yml runs the tests and pip-audit, then pushes the next vX.Y.Z tag. Nothing is committed back to the branch and there are no version-bump commits; the git tag is the version. Deployments build the image from source.
Support
If this server saves you time, you can buy me a coffee.
License
MIT, see LICENSE.
Available Tools
17 toolscreate_highlightB
Create a new highlight on a book.
Requires the highlight text and the book_id it belongs to. Optionally add a note and tags. Returns the full created highlight.
Inputs: text (required), book_id (required), note, tags. Returns: id, text, note, tags, +7 more
create_tagB
Create a new tag.
Returns the created tag with its ID and name.
Inputs: name (required). Returns: id, name
delete_highlightB
Delete a highlight by ID.
Returns a confirmation with the deleted highlight's ID.
Inputs: highlight_id (required). Returns: object
delete_tagB
Delete a tag by ID.
Returns a confirmation with the deleted tag's ID.
Inputs: tag_id (required). Returns: object
export_highlightsA
Bulk export highlights, optionally filtered by date or specific books.
Use cursor from a previous response to paginate through large exports. Each result includes the full highlight with book metadata attached.
This uses the export endpoint — use it for bulk data retrieval, not for interactive queries. For interactive use, prefer search_highlights or list_highlights instead.
Inputs: updated_after, book_ids, cursor. Returns: results, next_cursor
get_bookB
Get a single book/source by ID.
Returns full book metadata including title, author, category, source, highlight count, cover image URL, and source URL.
Inputs: book_id (required). Returns: id, title, author, category, +6 more
get_documentA
Get a single Reader document by ID with full content.
Returns the complete document including title, author, content, summary, reading progress, tags, and source URL.
Inputs: document_id (required). Returns: id, title, author, source_url, +9 more
get_highlightA
Get a single highlight by ID with book metadata included.
Returns the full highlight including text, note, tags, book title, book author, and source URL.
Inputs: highlight_id (required). Returns: id, text, note, tags, +7 more
list_booksA
List books and sources with optional filtering.
category accepts: 'books', 'articles', 'tweets', 'podcasts', 'supplementals'. Use num_highlights_gte to filter to sources with at least N highlights. Use updated_after with an ISO 8601 date to get recently updated sources.
Inputs: category, source, num_highlights_gte, updated_after, +2 more. Returns: results, total, next_page
list_documentsB
List documents in Readwise Reader with optional filters.
location accepts: 'new' (inbox), 'later', 'shortlist', 'archive', 'feed'. category accepts: 'article', 'email', 'rss', 'highlight', 'note', 'pdf', 'epub', 'tweet', 'video'. Use updated_after with an ISO 8601 date to get recently updated docs.
Inputs: location, category, updated_after, page, +1 more. Returns: results, total, next_page
list_highlightsA
List highlights with optional filtering by book, tag, or recency.
Use updated_after with an ISO 8601 date string to get recent highlights, e.g. '2024-01-01' or '2024-01-01T00:00:00Z'.
Returns highlights plus total count and next_page for pagination.
Inputs: book_id, tag, updated_after, page, +1 more. Returns: results, total, next_page
list_tagsA
List all tags in your Readwise library.
Returns every tag with its ID and name. No pagination needed — tag collections are typically small.
Inputs: no named parameters. Returns: result
save_urlA
Save a URL to Readwise Reader.
This is the primary way to add content to Reader. The service fetches and parses the article automatically. Only http:// and https:// URLs are accepted.
location controls where it appears: 'new' (inbox), 'later', 'shortlist', or 'archive'. Default is 'new'.
Inputs: url (required), title, tags, location, +1 more. Returns: id, title, author, source_url, +9 more
search_highlightsA
Search highlights using semantic (vector), full-text, or hybrid search.
Use 'semantic' for concept/meaning queries like 'ideas about habit formation'. Use 'fulltext' for exact phrase matching like 'atomic habits'. Use 'hybrid' (default) when unsure — combines both signals.
Returns highlights with book title, author, and source URL inline.
Inputs: query (required), search_type, book_id, tags, +1 more. Returns: results, total, next_page
tag_highlightA
Add or remove a tag on a highlight.
Use action='add' to tag a highlight (creates the tag if it doesn't exist). Use action='remove' to untag it. Returns the highlight's updated list of tag names.
Inputs: highlight_id (required), tag (required), action (required). Returns: result
update_highlightA
Update an existing highlight's text or note.
Only the provided fields are updated. Returns the full updated highlight.
Inputs: highlight_id (required), text, note. Returns: id, text, note, tags, +7 more
update_progressA
Update the reading progress for a Reader document.
reading_progress is a float from 0.0 (unread) to 1.0 (finished). Returns the updated document.
Inputs: document_id (required), reading_progress (required). Returns: id, title, author, source_url, +9 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Every tool has a clearly distinct purpose targeting specific resources and actions. For example, create_highlight, get_highlight, update_highlight, and delete_highlight form a complete CRUD set for highlights, while list_highlights, search_highlights, and export_highlights serve different retrieval purposes with no overlap. Tools like save_url and update_progress address unique Reader-specific functions.
All tools follow a consistent verb_noun naming pattern throughout. The pattern is strictly maintained across all 17 tools, with clear action verbs (create, delete, export, get, list, save, search, tag, update) paired with specific nouns (highlight, tag, book, document, progress, url). There are no deviations in style or convention.
The 17 tools are well-scoped for the Readwise domain, covering both the core highlights library and Reader document management. Each tool earns its place by addressing distinct operations like CRUD for highlights/tags, listing/filtering books/documents, saving URLs, and updating reading progress. The count is appropriate for the comprehensive functionality offered.
The tool surface provides complete coverage for the Readwise domain. It includes full CRUD operations for highlights and tags, comprehensive listing and filtering for books, documents, and highlights, specialized search and export capabilities, and key Reader functions like saving URLs and updating progress. No obvious gaps exist—agents can perform all expected workflows without dead ends.
Related MCP Connectors
Search your Glasp web and Kindle highlights, notes, and AI memories from any MCP client. Read-only.
Personal context for every AI: search, read, and write back to your private Markdown library.
Read-only memory search and task context for AI clients. Requires a Mem.Center Pro account.
Highlight anything you read. Then ask your AI about it: search, read and edit your highlights.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server enabling LLMs to search, retrieve, and manage documents through Rememberizer's knowledge management API.36Apache 2.0
- FlicenseAqualityDmaintenanceA Model Context Protocol Server that enables language models to access and manipulate Readwise documents and highlights programmatically.49-
- AlicenseAqualityDmaintenanceA Model Context Protocol server that connects MCP-compatible clients like Claude and VS Code to your Readwise Reader library, allowing them to list, retrieve, and update documents in your personal knowledge repository.711MIT

Readwise MCPofficial
AlicenseDqualityDmaintenanceA local Model Context Protocol server that connects LLM clients (like Claude) to Readwise, enabling AI assistants to access and interact with your saved reading content.1122 npm152MIT