Skip to main content
Glama
miniflux-mcp

miniflux-mcp

by si-essence
README.md
# miniflux

MCP connector for a self-hosted [Miniflux](https://github.com/miniflux/v2) server (v2.3.4). It speaks the HTTP API over stdio and over stateless Streamable HTTP on localhost.

Miniflux is Apache-2.0 software. This connector does not copy that code. It only calls the HTTP API on the server you configure. It is not affiliated with Miniflux.

`miniflux.routes.json` lists the 51 REST routes from Miniflux 2.3.4 `internal/api/api.go`. The generator adds `GET /healthcheck` and the deprecated root `GET /version`. That is 53 operations in 9 tools. `scripts/gen-operations.mjs` writes `src/operations.ts` from the route table plus field lists taken from [the official API docs](https://miniflux.app/docs/api.html). Do not edit `src/operations.ts` by hand.

`MINIFLUX_URL` is required. There is no default origin. Hosted accounts on reader.miniflux.app use the same API.

## Setup

```bash
npm install
npm run ci
npm start
npm run start:http
```

`npm start` speaks stdio. `npm run start:http` serves Streamable HTTP at `http://127.0.0.1:3000/mcp` and `GET /health`. HTTP mode has no authentication of its own. Keep it on localhost.

```json
{
  "mcpServers": {
    "miniflux": {
      "command": "node",
      "args": ["/workspace/connectors/miniflux/dist/index.js"],
      "env": {
        "MINIFLUX_URL": "http://127.0.0.1:8080",
        "MINIFLUX_API_KEY": "...",
        "MINIFLUX_ALLOW_WRITES": "false",
        "MINIFLUX_TOOLSETS": "me,categories,feeds,entries,enclosures,icons,opml"
      }
    }
  }
}
```

You can set `MINIFLUX_USERNAME` and `MINIFLUX_PASSWORD` instead of `MINIFLUX_API_KEY`. The connector then sends HTTP basic auth.

Docker (HTTP, no authentication, keep it on localhost):

```bash
docker build -t miniflux .
docker run -p 127.0.0.1:3000:3000 \
  -e MINIFLUX_URL=http://127.0.0.1:8080 \
  -e MINIFLUX_API_KEY=... \
  miniflux
```

Do not put keys in the image.

Regenerate the registry after a route-table bump.

```bash
npm run gen:operations
```

`scripts/live-check.mjs` talks to a real server over stdio. It needs `MINIFLUX_URL` and either `MINIFLUX_API_KEY` or `MINIFLUX_USERNAME` plus `MINIFLUX_PASSWORD`. Set `MINIFLUX_TEST_FEED_URL` to a local RSS file. It sets `MINIFLUX_TOOLSETS=all`. Gated writes run only when `MINIFLUX_ALLOW_WRITES=true`. It prints pass or fail lines only.

## Config

| Variable                 | Meaning                                                                                            |
| ------------------------ | -------------------------------------------------------------------------------------------------- |
| `MINIFLUX_URL`           | Required. Origin, `http` or `https`, no userinfo, query, or hash. Example `http://127.0.0.1:8080`. |
| `MINIFLUX_API_KEY`       | API key from Settings. Sent as the `X-Auth-Token` header.                                          |
| `MINIFLUX_USERNAME`      | Account login. Set together with `MINIFLUX_PASSWORD` when no API key is set.                       |
| `MINIFLUX_PASSWORD`      | Password for that login. Sent as HTTP basic auth. Redacted everywhere.                             |
| `MINIFLUX_ALLOW_WRITES`  | Must be the literal `true` before a confirmed write is sent.                                       |
| `MINIFLUX_TOOLSETS`      | Comma list of toolsets, or `all`. Default is the read-focused set below.                           |
| `MINIFLUX_PER_MINUTE`    | Local request budget. Default 30. Cache hits do not spend it.                                      |
| `MINIFLUX_TIMEOUT_MS`    | Upstream timeout. Default 20000.                                                                   |
| `MINIFLUX_CACHE_TTL_SEC` | Read cache TTL. Default 60. Writes clear the cache.                                                |
| `MINIFLUX_CONTACT`       | Contact token in the User-Agent. Must not contain a secret.                                        |
| `MCP_TRANSPORT`          | `stdio` or `http`. `--http` overrides.                                                             |
| `PORT`                   | HTTP port. Default 3000.                                                                           |

Invalid values are reported by field name and issue code. The rejected value is not included. API keys, passwords, tokens, and authorization headers are redacted in logs, errors, tool results, thrown messages, and URLs.

Auth is `X-Auth-Token` when `MINIFLUX_API_KEY` is set. Otherwise it is `Authorization: Basic` from `MINIFLUX_USERNAME` and `MINIFLUX_PASSWORD`. The connector never puts credentials in the API URL.

## Safety

GET is a read except `GET /v1/entries/{entryID}/fetch-content`, which is gated as a write because `update_content=true` stores the fetched article. POST, PUT, PATCH, and DELETE are writes, except `POST /v1/discover`, which only looks up feed URLs.

A write needs `confirm: true` as a boolean and `MINIFLUX_ALLOW_WRITES=true`. The string `"true"` is rejected. Otherwise the tool returns a dry-run preview of method, path, query, and redacted body, and it sends nothing. Destructive, credential, and exposure operations add a warning line on the tool and on the preview. That set covers delete feed, category, user, or API key; flush history; mark-all-as-read; create or update a user; create an API key; OPML import; and refresh all feeds.

API key create returns the token once, with a shown-only-once note. Later list calls redact it. User objects redact integration secrets (`*_token`, `*_api_key`, `*_password`, `*_secret`, Fever and Google Reader passwords). Error text drops stack traces and filesystem paths.

HTTP 401 is unauthorized. HTTP 403 is forbidden. HTTP 404 is not found. HTTP 400 and 422 are invalid input. HTTP 429 includes Retry-After. Other failures are server, network, or timeout. Response bodies are capped at 1,000,000 bytes. OPML export is returned as text with that cap. Icons stay JSON with `mime_type` and base64 `data`, still under the same cap.

## Tools

Default `MINIFLUX_TOOLSETS` publishes 7 tools. `MINIFLUX_TOOLSETS=all` publishes 9 tools (53 operations, 25 reads and 28 writes). Each tool takes `action` plus optional `params`, `query`, `body`, and `confirm`.

`action` `help` with optional `target` returns the path, query, and body fields for one action. Descriptions list action names only, so the tool list stays small.

| Toolset    | Tool                  | Operations | Default |
| ---------- | --------------------- | ---------- | ------- |
| me         | `miniflux_me`         | 5          | yes     |
| categories | `miniflux_categories` | 9          | yes     |
| feeds      | `miniflux_feeds`      | 13         | yes     |
| entries    | `miniflux_entries`    | 12         | yes     |
| enclosures | `miniflux_enclosures` | 2          | yes     |
| icons      | `miniflux_icons`      | 1          | yes     |
| opml       | `miniflux_opml`       | 2          | yes     |
| users      | `miniflux_users`      | 6          | no      |
| api_keys   | `miniflux_api_keys`   | 3          | no      |

Bookmark and star are both published (`toggle_bookmark` and `toggle_star`). PUT and DELETE flush-history are both published (`flush_history` and `delete_flush_history`). Feed icon is on `miniflux_feeds`. Icon by id is on `miniflux_icons`. Import entry lives on `miniflux_entries`.

## What this is not

This is not the Miniflux web UI, a feed crawler, or a hosted Miniflux service. It does not start Miniflux. It does not download enclosure files or decode icon bytes beyond the JSON the API already returns. It does not mint OAuth apps. Root `GET /version` was removed in Miniflux 2.2.17. The connector still exposes it. Prefer `get_version` (`GET /v1/version`).

## Compared with tssujt/miniflux-mcp

[tssujt/miniflux-mcp](https://github.com/tssujt/miniflux-mcp) is a Go server (MIT, about 27 stars). It exposes about 42 flat tools: `get_version`, `get_me`, users (`get_users`, `get_user_by_id`, `get_user_by_username`, `create_user`, `delete_user`), API keys (`get_api_keys`, `create_api_key`, `delete_api_key`), categories (`get_categories`, `create_category`, `update_category`, `delete_category`, `get_category_feeds`, `get_category_entries`, `get_category_entry`, `refresh_category`, `mark_category_as_read`), feeds (`get_feeds`, `get_feed`, `create_feed`, `update_feed`, `delete_feed`, `refresh_feed`, `refresh_all_feeds`, `mark_feed_as_read`, `get_feed_entries`, `get_feed_entry`, `get_feed_icon`, `fetch_counters`), entries (`get_entries`, `get_entry`, `update_entry_status`, `toggle_starred`, `save_entry`, `fetch_original_content`, `mark_all_as_read`, `flush_history`), `get_icon`, `get_enclosure`, plus discover and export strings. Writes are not confirm-gated and have no dry-run preview.

This connector adds OPML import, update user, entry title/content update, batch status, entry ids, import entry, enclosure update, integrations status, healthcheck, confirm plus env gated writes with previews, secret redaction, toolset scoping, vitest coverage, and a live check that passed against a real Miniflux 2.3.4. It does not ship a Docker image of Miniflux, a Go single binary, or a published container image. Those are what the rival has.

## Live check

PASS, 49 checks, failed=0, on 1 Nov 2026 against a real local Miniflux 2.3.4 (throwaway PostgreSQL, admin basic auth, local RSS file). About 35 of 53 operations ran live; API-key auth is mock-tested only. Details in `LIVE-CHECK.md`.