内容
<p align="center">
<img src="client/public/pwa-512x512.png" alt="FeedOverflow logo" width="112" />
</p>
<h1 align="center">FeedOverflow</h1>
<p align="center">一款优先考虑阅读、自托管的RSS阅读器。</p>
<p align="center">
<strong>English</strong> · <a href="README.zh-CN.md">简体中文</a>
</p>
一款自托管、全栈RSS阅读器,具有简洁的阅读优先界面、全文本文章提取和播客播放器。它还内置了一个 **MCP服务器**,允许LLM(Claude等)读取和管理您的订阅源,作为工具使用,包括总结您正在阅读的文章。
React + PWA客户端(TypeScript),以及单个二进制 **Go后端**(`server-go/`)通过SQLite提供API和静态客户端。
> **在线演示:** <https://demo.royl.uk:8443> — 公共沙盒,包含示例数据,每6小时重置一次。
<table>
<tr>
<td><img src="docs/images/screenshot-desktop.png" alt="桌面版:三面板订阅源/列表/阅读器布局" width="600"></td>
<td><img src="docs/images/screenshot-mobile.png" alt="移动版:单面板阅读器视图" width="180"></td>
</tr>
</table>
---
## 亮点
- **阅读优先的界面** — 桌面版三面板订阅源/列表/阅读器布局,移动版适配PWA(可安装、离线壳、视差面板过渡)。
- **无已读/未读状态 — 按设计** — 故意放弃未读计数和“标记为已读”机制,这样就不会有收件箱清零的内疚感。按最近程度浏览,并标记值得保留的文章。
- **纯文本模式(无图模式)** — 一个切换开关,去除文章正文中的图片、视频、iframe和嵌入,以便无干扰阅读;偏好设置将持续保存。
- **RSSHub支持** — 使用短URL `rsshub://path`(例如`rsshub://anthropic/research`)订阅,在获取时解析为自己的RSSHub实例,可在设置中配置(默认为`http://localhost:1200`)。
- **全文提取** — 当订阅源仅提供截断的摘要时,获取原始页面并使用Mozilla Readability提取干净的可读内容。
- **播客支持** — 具有音频附件的订阅源将获得内联播放器。
- **全文搜索**,具有订阅源范围的筛选。
- **OPML导入** — 从其他阅读器迁移订阅。
- **持久存档** — 每个获取的文章都将持续保存以便搜索/研究;大小上限维护传递会自动修剪最旧的非星标项目。
- **可选身份验证** — cookie-session基本身份验证门控非localhost访问,因此相同的二进制文件在localhost上完全私密运行,或在Cloudflare隧道后面公开。
## AI / MCP集成
Go服务器公开了一个[模型上下文协议](https://modelcontextprotocol.io)端点(可流式传输的HTTP传输),具有 **13种工具**,挂载在环回仅限的、无身份验证的监听器(`LOCAL_API_PORT`)的`/mcp`上,因此具有MCP能力的客户端可以驱动阅读器的对话式交互:
| 领域 | 工具 |
|------|-------|
| 订阅源 | `list_feeds`, `add_feed`, `rename_feed`, `delete_feed`, `import_opml` |
| 阅读 | `get_all_articles`, `get_today_articles`, `get_feed_articles`, `get_starred_articles`, `get_starred_count` |
| 状态 | `toggle_star`, `get_current_article` |
| 内容 | `fetch_article_content` |
每个工具都是对Web UI使用的相同HTTP API的薄封装,因此AI表面和UI永远不会分离。引人注目的是 **`get_current_article`** — 它读取浏览器UI中打开的文章,因此您可以询问 *"总结我正在阅读的内容"* 或 *"标记这篇文章并查找相关帖子"*,并且它可以直接工作。
## 架构
```
client/ React 19 + TypeScript + Vite + Zustand + react-router, PWA
server-go/ Go + go-sqlite3 (SQLite), chi router — 单个编译二进制文件
├─ 作业 调度订阅源获取/持久化 + 维护
├─ 内容 go-readability全文提取
├─ favicon 获取 + 缓存每个订阅源
├─ mcp 模型上下文协议服务器(13种工具),仅限环回
└─ 维护 数据库大小上限/旧文章修剪
```
- **单个二进制文件。** 后端编译为一个cgo二进制文件(`mattn/go-sqlite3`);无打包器,无运行时依赖项,仅需SQLite文件。
- **唯一的真实来源。** MCP工具通过环回调用HTTP API,而不是重新实现逻辑,保持AI和UI行为相同。
- 在两端进行测试(服务器使用`go test`,客户端使用Vitest);服务器使用`staticcheck`验证,客户端使用[oxlint / oxfmt](https://oxc.rs)进行代码检查/格式化。
## 入门指南
需要 **Go ≥ 1.26**(后端,使用cgo构建)和 **Node ≥ 22**(客户端 + 工具链)。
```bash
# 安装客户端 + 根工具链依赖项(Go后端使用go模块 — 无需npm安装)
npm install && cd client && npm install && cd ..
# 同时运行Go服务器(:3002)和客户端(:3000)
npm run dev
```
打开http://localhost:3000,然后添加订阅源URL或导入OPML文件。
仅限环回、无身份验证的伴侣监听器(`LOCAL_API_PORT`,默认为4002)还在`/mcp`上提供MCP端点(参见上面的AI / MCP集成部分)。
### 身份验证(可选)
设置 `AUTH_USER` / `AUTH_PASS`(在环境中,或在`RSS_ENV_FILE`指向的环境文件中),在每个请求上都需要登录 — 用于通过公共隧道公开阅读器。留空则仅限localhost私密使用。
## 使用Docker运行
无需Go/Node工具链 — 仅需Docker。镜像是一个多阶段构建(客户端 + cgo Go二进制文件),SQLite DB和日志在命名卷上持续存在。
```bash
cp .env.example .env # 可选:设置AUTH_USER/AUTH_PASS,调整
docker compose up -d # 在http://localhost:3002上提供应用
```
对于`rsshub://`订阅源,请启动一个捆绑的RSSHub(如果仅使用普通RSS,则将其省略):
```bash
docker compose --profile rsshub up -d
```
然后在设置中将 **rsshub_base_url** 设置为 `http://rsshub:1200`。数据存放在`rss-data`卷中;备份它(或在不使用`-v`的情况下运行`docker compose down`)以保留您的文章和星标。
## 技术栈
- **前端:** React 19,TypeScript,Vite,Zustand,react-router,vite-plugin-pwa
- **后端:** Go 1.26,chi,mattn/go-sqlite3,go-readability,gofeed,lumberjack
- **AI:** 模型上下文协议(可流式传输的HTTP),通过`modelcontextprotocol/go-sdk`
- **工具链:** go test + staticcheck(服务器),oxlint + oxfmt + Vitest(客户端)
## 许可证
AGPL-3.0 — 参见 [LICENSE](LICENSE)。如果您将修改后的版本作为网络服务运行,则必须向用户提供其源代码。