arcade-matter-mcp
# arcade-matter-mcp
An MCP server for [Matter](https://getmatter.com), the read-later app, built with
[arcade-mcp](https://github.com/ArcadeAI/arcade-mcp), hosted on Arcade Cloud via
`arcade deploy`, and used through Arcade MCP Gateways.
It wraps Matter's [public API](https://docs.getmatter.com/api) so agents can search your
library, read articles and highlights, save links, and organize your queue. See
[docs/SPEC.md](docs/SPEC.md) for the full design.
> **Single user.** Matter only offers personal API tokens (no OAuth), and Arcade secrets
> are shared across a project. Everyone who can call this server acts on the token
> owner's library, so keep its gateway to yourself.
## Tools
Phase 1 (read-only):
| Tool | What it does |
|---|---|
| `Matter.GetAccount` | The connected Matter account and its API rate limits |
| `Matter.ListItems` | Items in the queue, inbox or archive, filtered by favorite, tag, type or date |
| `Matter.GetItem` | One item's metadata |
| `Matter.GetItemContent` | An item's full text as Markdown, in bounded chunks |
| `Matter.SearchLibrary` | Full-text search with `"phrase"`, `-term`, `by:`, `site:` and `title:` |
| `Matter.ListHighlights` | Highlights and notes on one item |
| `Matter.ListTags` | Tags and how many items each is on |
| `Matter.ListReadingSessions` | Reading sessions with start time and duration |
Phase 2 (writes):
| Tool | What it does |
|---|---|
| `Matter.SaveItem` | Save a public URL to the queue or archive (have your client [approve each URL](docs/security/save-item-urls.md)) |
| `Matter.UpdateItem` | Archive or re-queue, favorite, or set reading progress |
| `Matter.AddTag` / `Matter.RemoveTag` | Tag or untag an item (tags are created by name) |
| `Matter.RenameTag` | Rename a tag everywhere |
| `Matter.SetHighlightNote` | Add, change or clear a highlight's note |
| `Matter.DeleteItem` / `Matter.DeleteHighlight` / `Matter.DeleteTag` | Permanent deletes (destructive) |
Phase 3 (summaries, read-only):
| Tool | What it does |
|---|---|
| `Matter.GetItemWithHighlights` | An item with all its highlights and notes |
| `Matter.ListRecentHighlights` | Highlights made or edited recently, grouped by item |
| `Matter.SummarizeReadingTime` | Reading time totals, averages, streaks and busiest day for a period |
Every tool is tagged read-only or write (and delete tools as destructive), so a gateway can
expose only the read tools. The server can't enforce approval for writes itself, so use a
read-only gateway day to day and a separate, approval-gated one for writes (see
[Deploy](#deploy)).
## Setup
1. Get a Matter API token (needs Matter Pro) at
[web.getmatter.com/settings](https://web.getmatter.com/settings) → **Generate API
Token**. Generating a token revokes any previous one, so reuse an existing token if
another tool (such as `matter-cli`) already has it.
2. Create `.env` if you don't have one, make it readable only by you, then set
`MATTER_API_TOKEN` in it:
```bash
[ -f .env ] || cp .env.example .env # never overwrites an existing .env
chmod 600 .env
ls -l .env # should show -rw------- (mode 0600)
```
Already have a `.env`? Just run `chmod 600 .env`. Copying `.env.example` over it would
replace your token with the placeholder. `cp` gives a new copy `.env.example`'s mode
(0644, readable by other local users), so the `chmod` is needed either way. `.env` is
Git-ignored; never commit it, and never paste the token into issues, tasks, logs or
chat.
## Development
```bash
uv tool install arcade-mcp # Arcade CLI
uv sync --extra dev # project and dev dependencies
uv run pytest # unit tests (Matter is mocked; no network)
uv run ruff check . && uv run ruff format --check . && uv run mypy src
```
Tool-selection evals (need an LLM API key; they don't call Matter):
```bash
ANTHROPIC_API_KEY=... uv run arcade evals evals/ -p anthropic
```
To try the tools against your own library locally, run the server over stdio (Arcade's
local HTTP transport doesn't serve tools that need secrets):
```bash
uv run src/arcade_matter/server.py # stdio
(cd src/arcade_matter && arcade configure claude -n matter) # add it to Claude Desktop
```
## Deploy
```bash
arcade login
arcade deploy -e src/arcade_matter/server.py # uploads MATTER_API_TOKEN from .env
```
Rotate the token later without redeploying:
```bash
arcade secret set MATTER_API_TOKEN=mat_...
```
Then create two MCP Gateways in the Arcade dashboard, both in Arcade Auth mode:
- a **read-only gateway** with only the read tools, for everyday use;
- a **write-only gateway** with the write tools you want (and the delete tools only if you
need them), connected only through a client that asks you to approve every call to it.
That client also connects the read-only gateway to look up IDs.
Connect a client with, for example, `arcade connect claude-code --gateway <slug>`. See
[docs/security/gateways.md](docs/security/gateways.md) for the tool lists, client
settings and how to check the read connection can't change anything.
## Security
Never commit tokens or personal library data. Keep `.env` readable only by you
(`chmod 600 .env`). Tests use invented data only. The token is held by Arcade and injected
per request; it is never exposed to the model.
Asking the model to confirm before a write is advice, not a safeguard. The safeguards are
the read-only gateway and client-enforced approval for writes; see
[docs/security/](docs/security/).
## License
[MIT](LICENSE)
TDQS
Scored across 20 tools
Most tools target distinct resource+action pairs (tags, items, highlights, sessions). However, ListHighlights, ListRecentHighlights, and GetItemWithHighlights all return highlights and could be confused, though descriptions clarify per-item vs cross-item scope. GetItem vs GetItemContent vs GetItemWithHighlights are also close but distinguishably described.
Every tool uses the Matter_ prefix with a consistent PascalCase verb_noun pattern (GetItem, ListTags, AddTag, RemoveTag, DeleteItem, SearchLibrary). No mixing of conventions.
20 tools is on the heavier side but justified by a genuinely multi-resource domain (items, highlights, tags, sessions, account, summaries). Each tool earns its place with minimal redundancy.
Covers full lifecycle for tags (add/remove/rename/delete/list) and strong coverage for items and highlights, plus search, sessions, account, and reading stats. Highlight creation is absent, but that is an explicit upstream API limitation rather than a design gap.