feedly-mcp
# feedly-mcp
Read your Feedly subscriptions from Claude. Ask *"what's new in my AI feeds?"* and
get an answer, without opening a browser.
> **Not published yet.** The server works and all six tools have been exercised
> against a live account, but it is not on npm and there are no releases.
> [Install from source](#step-2--install) — that path works today; the `npx` and
> `.mcpb` ones do not.
---
## What it does
Six tools that let an agent read your Feedly account:
| Tool | What it gives you |
|---|---|
| `list_folders` | your folders, with unread counts |
| `list_feeds` | the feeds in a folder |
| `get_articles` | recent articles, cleaned up and trimmed |
| `unread_counts` | how much is waiting, total and per folder |
| `search_feeds` | find new sources to subscribe to |
| `mark_read` | mark articles as read *(off by default)* |
## What it does not do
This is a **connector, not a reader app**. It translates a request into a Feedly
API call and hands back a clean answer. It does not store your articles, build a
searchable archive, rank things over time, or send you digests.
Those are all good things to want — build them *on top* of this, in a Claude
Project, a skill, or a scheduled task. Keeping them out is what makes this small
enough to trust.
## Privacy
Everything runs on your own machine.
- Your Feedly token stays local. It is never sent anywhere except `api.feedly.com`.
- No account with us, no server in the middle, no telemetry.
- Nothing about what you read is stored beyond a short-lived local cache.
---
## Requirements
- **Node.js 20 or newer** — check with `node --version`
- **A Feedly account** and an API token (step 1 below)
- Claude Desktop, Claude Code, or any other MCP client
---
## Step 1 — Get a Feedly API token
1. Log in to Feedly in your browser.
2. Visit **<https://feedly.com/v3/auth/dev>**.
3. Follow the instructions there to generate a developer access token.
4. Copy the token somewhere safe for the next step. It is a password — treat it
like one.
> **Two things to know before you go further.**
>
> **Tokens expire.** On a free account a developer token is valid for about
> **30 days**, after which you repeat this step. Paid plans can refresh
> automatically. This is Feedly's policy, not something this tool can work around.
>
> **Token availability depends on your plan.** Feedly's own documentation is
> inconsistent about which account tiers can self-issue API tokens. If the page
> above does not give you a token, this connector cannot work with your account,
> and there is no workaround short of contacting Feedly.
---
## Step 2 — Install
### Build from source — the only path that works today
```bash
git clone https://github.com/fredrsat/feedly-mcp
cd feedly-mcp
npm install
npm run build
```
Then store your token in a file only you can read, so it never has to go into a
client config in plain text:
```bash
mkdir -p ~/.config/feedly-mcp
printf '%s' 'paste-your-token-here' > ~/.config/feedly-mcp/token
chmod 600 ~/.config/feedly-mcp/token
```
The server refuses to read that file if it is group- or world-readable, and tells
you how to fix it.
Register it with your client, using an **absolute path** to the built entry point:
```bash
# Claude Code — --scope user makes it available in every directory
claude mcp add feedly --scope user -- node /absolute/path/to/feedly-mcp/dist/cli.js
claude mcp list # should report: feedly ... ✔ Connected
```
For Claude Desktop, add this to
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
`%APPDATA%\Claude\claude_desktop_config.json` (Windows), then quit and reopen the
application — closing the window does not reload MCP servers:
```json
{
"mcpServers": {
"feedly": {
"command": "node",
"args": ["/absolute/path/to/feedly-mcp/dist/cli.js"]
}
}
}
```
Already have other servers under `mcpServers`? Add `feedly` alongside them rather
than replacing the block.
If you move the repository afterwards, re-register it — the path is absolute.
Rebuilding in place is picked up automatically.
### Once published
Neither of these works yet; they are what installing will look like after the
first release.
**One-click, Claude Desktop.** Download `feedly-mcp.mcpb` from the Releases page
and drag it into **Settings → Extensions**. A settings form appears; the token
goes into your operating system's keychain rather than a plain-text file, and
everything in [Configuration](docs/configuration.md) is editable from that form.
**From npm.** `npx -y feedly-mcp` as the command, with `FEEDLY_TOKEN` in the
client's `env` block, or the token file above.
---
## Step 3 — Check that it works
Before asking Claude anything, confirm the connection from your terminal:
```bash
node dist/cli.js doctor
```
A healthy result looks like this:
```
✓ Config loaded from /Users/you/.config/feedly-mcp/config.toml
scope.default_folder = Tech ← file
✓ Token found (file /Users/you/.config/feedly-mcp/token)
✓ Connected to Feedly you@example.com
plan: FeedlyProYearly
✓ 8 folders, 70 feeds
Tech 70 feeds 4317 unread user/<uuid>/category/Tech
Tech - Research 11 feeds 68 unread user/<uuid>/category/<uuid>
Tech - Tooling 6 feeds 171 unread user/<uuid>/category/<uuid>
…
API calls used today: 4 of 50 (resets in 11h34m)
Configured ceiling: 40/day account-wide, 10/session
Through this server: 4 today, 4 in this run
✓ Everything checks out.
```
Useful flags: `-v` prints every resolved setting and where it came from,
`--refresh` clears the cache first.
`doctor` never prints your token. Use the folder list it gives you when filling
in `scope` in step 4.
If something is wrong, jump to [Troubleshooting](#troubleshooting).
---
## Step 4 — Configure (optional)
The defaults are sensible and you can skip this entirely. The one setting worth
looking at early is **scope** — which folders Claude is allowed to see at all.
Create `~/.config/feedly-mcp/config.toml`:
```toml
[scope]
# Only these folders are visible to the agent. Leave empty for all of them.
include_folders = ["AI", "Longform"]
# Used when you ask about articles without naming a folder.
default_folder = "AI"
[defaults]
hours = 8 # how far back get_articles looks
limit = 100 # max articles per call
```
Two reasons to set `include_folders`:
- **Privacy.** Your work folder does not need to be readable by an agent.
- **Focus.** Fewer folders means shorter answers and less context spent on
material you did not ask about.
If you installed via Option A, edit these in the extension's settings form
instead — same options, no file to find.
Full list of settings: **[docs/configuration.md](docs/configuration.md)**
---
## Using it
Just ask. Some things that work well:
- *"What's new in my AI feeds since yesterday?"*
- *"Anything worth reading in AI - Research this week?"*
- *"How many unread articles do I have, broken down by folder?"*
- *"Find me feeds about local LLM inference"*
- *"Summarise the top 5 by engagement from the last 8 hours"*
You don't need to know folder IDs. Folder names work, and Claude can list them.
Full tool reference: **[docs/tools.md](docs/tools.md)**
---
## Limits worth knowing before you build on this
These come from running it against a real, busy account rather than from theory.
**Volume beats your time window.** On a folder producing ~42 articles an hour,
asking for 24 hours with a limit of 320 actually covers under eight — `limit`
runs out first. Responses report `covered_hours` alongside `window_hours` so the
gap is visible, but raising the limit is usually the wrong fix: it costs more
quota and more context to move the blind spot slightly. Narrow the folder.
**Scope works on folders, not feeds.** If one noisy source and one excellent
source sit in the same folder, no configuration here separates them — on the
account this was tested against, a single feed produced 140 of 320 articles and
none of the useful stories, while a feed with 2 articles produced most of them.
The fix was unsubscribing in Feedly. Practical order: drop dead-weight feeds
first, then set scope. The other way round throws away good sources to escape
bad ones.
**Counts that report what a write did deserve suspicion.** Feedly returns no
count for folder-level marking, so `mark_read` measures unread totals before and
after. That is close, not exact — Feedly's own counts lag a moment. For anything
that matters, check `unread_counts` yourself.
**A cleanup window older than your backlog marks nothing.** Unread settles at
roughly `window_days × articles_per_day`. A 7-day `older_than` against ~570
articles a day holds the backlog near 4000 forever, however often you sweep.
**Budget from the response, not from a plan.** Every result carries
`calls_left_today` and `calls_left_session`. Read them and adapt rather than
deciding a call count up front — the daily figure is account-wide, so your own
browsing moves it underneath you.
---
## Your API quota — please read this
**Your daily API quota is small — smaller than Feedly's documentation suggests.**
Measured against the live API, a developer token on a paid Pro Plus account
reports a ceiling of **50 calls per day**, resetting around midnight UTC. Feedly's
own docs describe 250 on free and 500 on Pro. Plan for 50.
That is roughly eight conversations a day if the agent is chatty, and the quota
is shared with everything else touching your account — **including Feedly in your
browser**, which stops working too if an agent drains it.
So this tool defends the budget on your behalf:
- Folder and subscription lists are cached on disk for 24 hours.
- Repeated identical requests within 15 minutes are served from cache.
- One call fetches a whole folder — never one call per feed.
- Hard ceilings at 10 calls per session and 40 per day, leaving headroom for you.
The daily one is measured account-wide, so browsing Feedly yourself counts
against it — that is deliberate, so an agent cannot lock you out of your own
reader.
- Every response reports how much quota is left and how stale the data is. Below
10 calls remaining, you get a warning.
Check your own ceiling with `doctor` — it prints the limit your account actually
reports. If it says something higher than 50, you can safely raise the budget in
[configuration](docs/configuration.md#budget).
---
## Marking articles as read
`mark_read` is **permanent**. Feedly has no undo, and recovery means emailing
their support. So it ships disabled.
To enable single-article marking:
```toml
[writes]
enabled = true
```
To also allow marking an entire folder read in one go — a much bigger blast
radius — you must turn on a second switch deliberately:
```toml
[writes]
enabled = true
bulk_mark_read = true
```
Unsubscribing is not implemented at all, on purpose. Do that in Feedly.
---
## Troubleshooting
### `doctor` says the token is missing
The server looks in this order: the `FEEDLY_TOKEN` environment variable, then
the file named by `feedly.token_file`. Confirm your token reached whichever one
you used — a common cause is editing the config file while Claude Desktop passes
an empty environment variable that wins over it.
### "Token expired" or 401
Free-account tokens last about 30 days. Repeat [step 1](#step-1--get-a-feedly-api-token)
and update the token where you stored it. This is expected and will keep
happening; it is not a bug.
### Claude doesn't see the tools
Quit and reopen Claude Desktop completely — a window restart does not reload MCP
servers. Then check your JSON is valid (a trailing comma is the usual culprit),
and that `node --version` reports 20 or higher.
### "Rate limit exceeded" (429)
You have used your Feedly quota for the day. It resets on Feedly's schedule; the
error message includes the reset time. The server will not retry automatically —
retrying would only dig the hole deeper.
### "Daily budget exhausted"
Different from the above: this is *this tool's* ceiling, not Feedly's, and you
still have real quota left. Raise `budget.daily_calls` if you want more.
### A folder is "outside configured scope"
`scope.include_folders` is set and that folder isn't in it. Add it, or clear the
list to allow everything.
### Cached data looks like it belongs to another account
Clear the cache and try again:
```bash
rm -rf ~/.cache/feedly-mcp
```
---
## Development
```bash
npm run build # compile to dist/
npm test # 104 tests, no API calls
npm run typecheck # tsc --noEmit
```
There is also an end-to-end check that drives the built server over stdio as a
real MCP client and exercises every tool against your account. It costs a handful
of API calls out of the daily 50, and prints the remaining quota as it goes:
```bash
node --env-file=.env scripts/smoke.mjs
```
`mark_read` is only exercised in its refusal paths, there and everywhere else.
It is irreversible, so there is no safe way to test the success path.
## Contributing
Issues and pull requests welcome. The design rationale — including which
features are deliberately excluded — lives in
[feedlymcpspec.md](feedlymcpspec.md). Read it before proposing a feature; if
your idea is in the "not in scope" list, that is a decision rather than an
oversight, though it is one you are welcome to argue with.
The spec and these docs are the contract. If you change a return shape or a
config key, change both together or neither.
## License
MIT
TDQS
Scored across 6 tools
Tool names largely describe distinct actions on distinct resources (get_articles, mark_read, list_folders, list_feeds, search_feeds, unread_counts). The only mild overlap is search_feeds vs list_feeds and get_articles vs unread_counts, but names alone make intent discernible. Descriptions are unusable (identical startup errors), so disambiguation rests entirely on names.
Most tools follow a verb_noun snake_case pattern (get_articles, search_feeds, mark_read, list_folders, list_feeds). The one deviation is unread_counts, which is a noun phrase rather than an action, a minor inconsistency but still readable.
Six tools is a reasonable, well-scoped set for a Feedly reader covering reading, searching, folder/feed listing, and read-state. It is slightly lean for the domain but nothing feels padded or redundant.
The surface covers read-side operations and mark_read, but there are no operations to subscribe/unsubscribe feeds, create or edit folders, or save articles to boards for later, which are core Feedly workflows. Agents would hit dead ends for feed management tasks.