1 unstable release
Uses new Rust 2024
| 0.1.0 | Jan 26, 2026 |
|---|
#1210 in Command line utilities
415KB
8K
SLoC
ankit
A comprehensive Rust toolkit for Anki deck management via AnkiConnect.
Overview
ankit provides tools for managing Anki flashcard decks programmatically. Whether you're an end user wanting to manage decks through AI assistants, or a developer building Anki integrations, this toolkit has you covered.
Key Features
- 55 MCP tools for AI assistant integration (Claude, etc.)
- Complete AnkiConnect API coverage with async Rust client
- TOML-based deck definitions with .apkg generation
- High-level workflows: bulk import, deduplication, analysis, media management
- Bidirectional sync between TOML files and Anki
For Users: MCP Server
The ankit-mcp server lets AI assistants (like Claude) manage your Anki decks directly.
Installation
# From crates.io
cargo install ankit-mcp
# Or using Docker
docker pull ghcr.io/joshrotenberg/ankit-mcp:latest
Important: Data Safety
Warning: By default, ankit-mcp runs in write mode with full access to modify your Anki collection. This includes the ability to delete notes, reset learning progress, and modify scheduling data.
To protect your data:
- Use read-only mode when exploring or if unsure:
ankit-mcp --read-only - Back up your collection regularly via Anki's File > Export (include scheduling info)
- Test with a copy of your collection first if making bulk changes
- Review operations before confirming - ask Claude to preview changes first
The authors are not responsible for any data loss. Use at your own risk.
Setup with Claude Desktop
Add to your Claude Desktop config (~/.config/claude/claude_desktop_config.json on Linux/macOS):
{
"mcpServers": {
"anki": {
"command": "ankit-mcp"
}
}
}
What You Can Do
Once configured, ask Claude to:
- Create flashcards: "Add a note to my Japanese deck with front 'hello' and back 'konnichiwa'"
- Search and analyze: "Show me cards I'm struggling with in my Spanish deck"
- Bulk operations: "Find and remove duplicate notes in my vocabulary deck"
- Import/export: "Export my Japanese deck to a TOML file"
- Deck health: "Give me a health report on my medical terminology deck"
- Media management: "Find orphaned media files in my collection"
Available Tools (55 total)
| Category | Tools |
|---|---|
| Notes | add, find, get info, update, delete |
| Cards | find, get info, suspend, unsuspend, forget, set ease, set due date |
| Tags | add, remove, replace all, clear unused |
| Decks | list, create, delete, clone, merge |
| Models | list models, get model fields |
| Analysis | study summary, retention stats, find problems |
| Progress | reset deck, tag by performance, suspend by criteria, deck health, bulk tag |
| Import/Export | import notes, validate notes, export deck, export reviews |
| Deduplication | find duplicates, preview, remove |
| Enrichment | find candidates, enrich note, enrich notes |
| Media | audit, cleanup |
| Backup | backup deck, backup collection, restore deck, list backups |
| Organization | move by tag |
| TOML Sync | export, diff, plan sync, sync, import |
| Misc | version, sync with AnkiWeb |
For Developers: Rust Crates
| Crate | Description | Crates.io |
|---|---|---|
| ankit | Complete async AnkiConnect API client | |
| ankit-engine | High-level workflow operations | |
| ankit-builder | TOML deck builder with .apkg generation | |
| ankit-mcp | MCP server for AI assistants |
Quick Start: API Client
use ankit::{AnkiClient, NoteBuilder};
#[tokio::main]
async fn main() -> ankit::Result<()> {
let client = AnkiClient::new();
// Add a note
let note = NoteBuilder::new("Default", "Basic")
.field("Front", "Question")
.field("Back", "Answer")
.build();
client.notes().add(note).await?;
// Search for notes
let notes = client.notes().find("deck:Default").await?;
Ok(())
}
Quick Start: High-Level Workflows
use ankit_engine::Engine;
#[tokio::main]
async fn main() -> ankit_engine::Result<()> {
let engine = Engine::new();
// Analyze study patterns
let stats = engine.analyze().study_summary("Japanese", 30).await?;
println!("Reviews: {}, Retention: {:.1}%",
stats.total_reviews, stats.retention_rate * 100.0);
// Find and remove duplicates
let report = engine.deduplicate().remove_duplicates(&query).await?;
println!("Removed {} duplicates", report.deleted);
Ok(())
}
Quick Start: TOML Deck Builder
Define decks in TOML:
[package]
name = "Spanish Vocabulary"
version = "1.0.0"
[[models]]
name = "Basic Spanish"
fields = ["Spanish", "English"]
markdown_fields = ["English"] # Supports Markdown
[[models.templates]]
name = "Card 1"
front = "{{Spanish}}"
back = "{{English}}"
[[decks]]
name = "Spanish::Vocabulary"
[[notes]]
deck = "Spanish::Vocabulary"
model = "Basic Spanish"
tags = ["food"]
[notes.fields]
Spanish = "el gato"
English = "the **cat**"
Generate .apkg or import via AnkiConnect:
use ankit_builder::DeckBuilder;
fn main() -> ankit_builder::Result<()> {
let builder = DeckBuilder::from_file("vocabulary.toml")?;
// Generate .apkg file
builder.write_apkg("vocabulary.apkg")?;
// Or import directly via AnkiConnect
// builder.import_connect().await?;
Ok(())
}
Requirements
- Anki with AnkiConnect add-on installed
- Rust 1.85+ (for building from source)
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
Dependencies
~21–40MB
~490K SLoC