Skip to main content
Glama
OpenRhyme

openrhyme-mcp

Official
by OpenRhyme
README.md
# openrhyme-mcp

A thin [Model Context Protocol](https://modelcontextprotocol.io) server that exposes the timeline captured by the [OpenRhyme engine](https://github.com/OpenRhyme/OpenRhyme) to any agent — Claude, local models, your own scripts — over stdio.

> **Status:** MVP implemented on this branch — a stdio MCP server exposing the engine's raw event timeline and app-allowlist controls, tested against a fixture store and a fake engine binary. The engine it depends on ([OpenRhyme/OpenRhyme](https://github.com/OpenRhyme/OpenRhyme)) has its Part 1 (capture) complete. Pending: dogfooding against a live engine capture; richer retrieval (sessions, search, embeddings) is future work.

## What it is, and is not

OpenRhyme is a local-first, open-source "Computer History" for macOS: a Swift daemon reads your activity through the accessibility API, stores it in tiered SQLite, and compacts it without any bundled model. This repository is the **agent-facing door** to that data. It:

- speaks MCP over **stdio**, so any agent host (Claude Desktop, Claude Code, …) can spawn it;
- reads the engine's SQLite tiers **read-only**;
- shells out to the `openrhyme` CLI (`openrhyme <cmd> --json`) for control commands;
- contains **no capture logic**, holds **no macOS permissions**, and makes **no network calls**.

Everything stays on your machine. The agent host that spawns this server is the trust boundary — it sees exactly what the tools return, nothing more.

## How the pieces fit

```
 openrhyme daemon (Swift, launchd)  ──writes──▶  ~/Library/Application Support/OpenRhyme/*.sqlite
                                                              │
                                                   read-only  │        `openrhyme … --json`
                                                              ▼                 │
                          agent host ──stdio──▶  openrhyme-mcp (this repo) ─────┘
```

The full process topology, the CLI/JSON contract, and the store layout are specified in the engine repo: [`docs/engine-interface.md`](https://github.com/OpenRhyme/OpenRhyme/blob/main/docs/engine-interface.md). That document is the contract this server implements; it is not duplicated here.

## Tools & resources

| MCP tool | Returns |
|---|---|
| `events(since, until, kinds, app, limit, max_value_chars)` | raw events in a time window: `{"events": [...], "count": n}` |
| `status()` | engine trust/daemon/store status, plus this server's schema and db info |
| `apps()` | the capture allowlist and currently running apps |
| `allow_app(bundle_id)` / `deny_app(bundle_id)` | add/remove an app from the capture allowlist, by bundle identifier |

| MCP resource | Contents |
|---|---|
| `openrhyme://events/recent` | the last 15 minutes of raw events, as JSON Lines |

Richer retrieval (sessions, full-text search, embeddings) is future work, not yet built.

## Development

Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).

```sh
make sync        # uv sync --all-groups
make check       # ruff + mypy (strict) + pytest
uv run openrhyme-mcp   # serve on stdio (Ctrl-C to stop)
```

Tests run in-process against a fixture database and a fake `openrhyme` script; they never need the real engine or a macOS permission. CI runs on Ubuntu and macOS 26.

## Using it with an agent

With the engine built (`../OpenRhyme`, `make build`) and on `PATH` — or pointed to via `OPENRHYME_BIN`:

```sh
claude mcp add openrhyme -- uv run --directory /path/to/openrhyme-mcp openrhyme-mcp
```

Then ask: *"What was I doing between 2 and 3 pm?"* — the model calls `events(since="…", until="…")`. Tools: `events`, `status`, `apps`, `allow_app`, `deny_app`; resource: `openrhyme://events/recent`. Environment: `OPENRHYME_DATA_DIR` (engine data dir), `OPENRHYME_BIN` (engine binary).

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.9/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct role: events queries captured activity data, status reports engine/server state, apps lists the allowlist and running apps, and allow_app/deny_app make targeted allowlist changes. There is no functional overlap between any of these tools.

Naming Consistency4/5

The read-only tools use noun-style names (events, status, apps) while the mutations use verb_noun style (allow_app, deny_app). This is fairly predictable and readable, though not as uniform as a single verb_noun convention throughout.

Tool Count5/5

Five tools is well-scoped for this server's purpose: querying activity events, checking engine status, listing apps, and managing the allowlist. Each tool earns its place without the surface feeling bloated or thin.

Completeness5/5

The core workflows are fully covered: retrieve activity data, inspect engine health, view the allowlist, and add or remove apps from it. Since events are an append-only raw log, update/delete operations are not expected here, so there are no obvious gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues