Skip to main content
Glama
crunchtools

mcp-feed-reader-crunchtools

by crunchtools
README.md
# mcp-feed-reader-crunchtools

Secure MCP server for RSS/Atom feed reading with SQLite backend.

<!-- mcp-name: io.github.crunchtools/feed-reader -->

## Installation

### uvx (recommended)
```bash
uvx mcp-feed-reader-crunchtools
```

### pip
```bash
pip install mcp-feed-reader-crunchtools
```

### Container
```bash
podman run -v feedreader-data:/data quay.io/crunchtools/mcp-feed-reader
```

## Configuration

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

## Tools (17)

### Feed Management
- `add_feed_tool` — Add an RSS/Atom feed by URL
- `list_feeds_tool` — List all feeds with unread counts
- `get_feed_tool` — Get feed details
- `delete_feed_tool` — Remove a feed
- `refresh_feeds_tool` — Crawl feed sources for new content (slow, prefer systemd timer)

### Entry Management
- `list_entries_tool` — List entries (filterable, paginated)
- `read_entry_tool` — Read full entry content (auto-marks read)
- `mark_read_tool` — Mark entries as read
- `mark_unread_tool` — Mark entry as unread
- `search_entries_tool` — Full-text search (FTS5)

### Category Management
- `list_categories_tool` — List categories with counts
- `create_category_tool` — Create category
- `rename_category_tool` — Rename category
- `delete_category_tool` — Delete category

### Import/Export
- `import_opml_tool` — Import from OPML file
- `export_opml_tool` — Export as OPML
- `get_stats_tool` — Dashboard stats

## Background Fetching

Nothing 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.

```bash
# Fetch all feeds via CLI
mcp-feed-reader-crunchtools --fetch
```

### systemd timer (recommended)

`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:

```bash
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.

## License

AGPL-3.0-or-later

TDQS

B3.4/5.0

Scored across 17 tools

Disambiguation4/5

Most tools target distinct resources and actions (feeds, entries, categories each have clear verbs). Minor overlap exists between read_entry_tool (which auto-marks as read) and mark_read_tool, and between list_entries_tool and search_entries_tool, but the descriptions clarify the boundaries well enough.

Naming Consistency5/5

Every tool follows a consistent snake_case verb_noun_tool pattern (list_feeds_tool, add_feed_tool, delete_category_tool, etc.). The convention is uniform across all 17 tools with no style mixing.

Tool Count4/5

17 tools is slightly above the ideal range but each earns its place across three resource domains (feeds, entries, categories) plus OPML import/export and refresh. No redundant or filler tools are present.

Completeness4/5

Core lifecycle is well covered: feeds (list/get/add/delete/refresh/OPML), entries (list/search/read/mark read/unread), and categories (list/create/rename/delete). Gaps include updating an existing feed (rename or move category) and bulk mark-all-read, but these are minor workarounds.

Maintenance

ActivityActive
ResponsivenessNo issues