
A solid RSS/Atom reader that persists everything to SQLite and exposes 17 tools for managing feeds, entries, and categories. You can add feeds, fetch new entries, search with FTS5 full-text search, mark items read or unread, and organize feeds into categories. It handles OPML import/export for migrating feed lists and includes a stats endpoint for dashboard data. The read_entry_tool automatically marks entries as read when you view them. You can run background fetches via CLI to keep everything current without manual triggers. Useful when you want Claude to monitor and summarize RSS feeds, search across multiple sources, or help triage your reading queue without switching to a separate feed reader.
Secure MCP server for RSS/Atom feed reading with SQLite backend.
uvx mcp-feed-reader-crunchtools
pip install mcp-feed-reader-crunchtools
podman run -v feedreader-data:/data quay.io/crunchtools/mcp-feed-reader
| Variable | Default | Description |
|---|---|---|
FEED_READER_DB | ~/.local/share/mcp-feed-reader/feeds.db | SQLite database path |
HTTP_PROXY / HTTPS_PROXY / NO_PROXY | (none) | Standard httpx proxy variables, honoured for every feed fetch. Useful when a publisher rate-limits your egress IP — Reddit returns 429 to datacentre ranges regardless of User-Agent |
add_feed_tool — Add an RSS/Atom feed by URLlist_feeds_tool — List all feeds with unread countsget_feed_tool — Get feed detailsdelete_feed_tool — Remove a feedrefresh_feeds_tool — Crawl feed sources for new content (slow, prefer systemd timer)list_entries_tool — List entries (filterable, paginated)read_entry_tool — Read full entry content (auto-marks read)mark_read_tool — Mark entries as readmark_unread_tool — Mark entry as unreadsearch_entries_tool — Full-text search (FTS5)list_categories_tool — List categories with countscreate_category_tool — Create categoryrename_category_tool — Rename categorydelete_category_tool — Delete categoryimport_opml_tool — Import from OPML fileexport_opml_tool — Export as OPMLget_stats_tool — Dashboard statsNothing in the server crawls on its own. list_entries_tool and friends read a
cache; if no one calls --fetch, that cache goes stale and every reader sees an
empty feed with no error anywhere. A deployment without a crawl trigger is a
broken deployment — this bit the daily briefing, which reported "no news" for
days while all 61 feeds sat unfetched.
# Fetch all feeds via CLI
mcp-feed-reader-crunchtools --fetch
deploy/ ships the two units used in production. Copy them to
/etc/systemd/system/, adjust the container name in the service if yours
differs, then:
sudo systemctl daemon-reload
sudo systemctl enable --now mcp-feeds-refresh.timer
The service runs --fetch inside the running container
(podman exec), so the database keeps the SELinux category of the process that
owns it. Do not bind-mount the data directory into a second container with
:Z to run the crawl — that relabels the volume and locks the live server out.
The timer fires hourly, plus once at 05:45. That second entry is not redundant: consumers window entries on publication time, so an entry published between the last crawl and a 06:00 report is missing from that report and already older than the next day's window start — it is lost for good. Any consumer on a fixed schedule wants a crawl shortly before it.
Feeds are fetched conditionally (ETag / If-Modified-Since). A rate limit,
gateway 5xx, or dropped connection is retried with exponential backoff, up to
three attempts in all, before the feed is recorded as failed.
AGPL-3.0-or-later