Skip to main content
Glama
README.md
# anki-mcp

MCP server that exposes [Anki](https://apps.ankiweb.net/) as tools for Claude and other LLM clients. Powered by [AnkiConnect](https://foosoft.net/projects/anki-connect/).

Create notes, search your collection, review due cards, manage decks, track retention — all from your LLM client.

## Prerequisites

1. **Anki** must be running on the local machine.
2. **AnkiConnect** add-on must be installed: Anki → Tools → Add-ons → Get Add-ons → code `2055492159`.
   - Default port: `8765`. Do not change it.
3. Node.js 18+.

## Quick start

```bash
npm install
npm run build   # tsc → dist/
npm start       # stdio transport
```

Development (no build step):
```bash
npm run dev     # tsx src/index.ts
```

## Claude Desktop integration

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "anki": {
      "command": "node",
      "args": ["/absolute/path/to/anki_mcp/dist/index.js"]
    }
  }
}
```

## Available tools

| Tool | Description |
|---|---|
| `create_notes` | Create Basic or Cloze notes. Supports batch. |
| `search_notes` | Search with Anki browser syntax. Returns up to `limit` notes (default 50). Field search: `Front:*keyword*`. |
| `update_note` | Edit note fields in place by note ID. Preserves all card scheduling data. |
| `add_tags` | Add tags to notes by note ID. Supports `::` hierarchy. |
| `remove_tags` | Remove tags from notes by note ID. |
| `delete_notes` | Delete notes by ID (also deletes associated cards). |
| `move_notes` | Move notes to another deck (resolves note IDs → card IDs internally). |
| `create_deck` | Create deck or subdeck (`Parent::Child::Grandchild`). |
| `list_decks` | List all decks with due/new/learn counts. |
| `get_due_cards` | Get cards due for review in a deck (default limit 20, max 100). Returns `due` field. |
| `submit_answer` | Record answer for a card: 1=Again, 2=Hard, 3=Good, 4=Easy. |
| `reschedule_cards` | Postpone cards by N days. days=0 = due today. |
| `suspend_cards` | Suspend (hide) or unsuspend cards. Never scheduled but not deleted. |
| `forget_cards` | Reset cards to new state. Wipes scheduling; preserves note content and tags. |
| `get_insights` | Retention stats, overdue count, mature/young cards for a deck or all decks. |
| `sync` | Trigger AnkiWeb sync. |

## AnkiConnect conventions

- **ID types**: Note IDs and card IDs are different namespaces. Never pass note IDs where card IDs are expected.
- **Deck names**: Use `::` for hierarchy. Double-quotes in deck names must be escaped (`\"`).
- **Search syntax**: Anki browser syntax — `is:due`, `is:new`, `prop:due<0` (overdue), `deck:"Name"`, `tag:foo`, `nid:123`.
- **Error handling**: All AnkiConnect failures throw `AnkiConnectError(action, message)`. MCP SDK surfaces these to the client as tool errors.

## Architecture

```
src/
  ankiconnect.ts      — HTTP client, branded ID types, AnkiConnectError
  tools/
    notes.ts          — create / search / update / delete / move notes + tag management
    decks.ts          — create / list / delete decks
    study.ts          — get due cards / submit answer / reschedule / suspend / forget
    insights.ts       — retention stats
  index.ts            — McpServer wiring (registerTool), stdio transport
```

## Performance notes

- `search_notes`: always pass a narrow query + explicit `limit` to avoid large payloads.
- `get_insights` on large collections calls `cardsInfo` in 500-card chunks sequentially; expect ~1s per 500 cards.
- `get_insights` without a deck argument fans out `cardReviews` to every deck — adds one request per deck.

## License

MIT