| name | anki-mcp-server-integration |
| description | Integrate Anki spaced repetition flashcards with AI assistants through Model Context Protocol for study sessions, deck management, and card creation |
| triggers | ["help me review my anki deck","create flashcards in anki","sync anki with ai assistant","manage anki decks and notes","add cards to anki deck","setup anki mcp server","review spaced repetition cards","import media into anki"] |
Anki MCP Server Integration
Skill by ara.so — MCP Skills collection.
A Model Context Protocol (MCP) server that enables AI assistants to interact with Anki, the spaced repetition flashcard application. Transform study sessions into dynamic conversations where AI can create, edit, and review flashcards naturally, explain concepts, and adapt to your learning style.
Installation
Prerequisites
For Claude Desktop (STDIO Mode)
Option 1: MCPB Bundle (Recommended)
Download .mcpb file from releases, then in Claude Desktop:
- Settings → Extensions → drag and drop the
.mcpb file
- Configure AnkiConnect URL if needed (default:
http://localhost:8765)
- Restart Claude Desktop
Option 2: NPM Configuration
Add to claude_desktop_config.json:
{
"mcpServers": {
"anki-mcp": {
"command": "npx",
"args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
"env": {
"ANKI_CONNECT_URL": "http://localhost:8765"
}
}
}
}
Location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
For Cursor IDE / Cline / Zed
Add to MCP configuration file:
{
"mcpServers": {
"anki-mcp": {
"command": "npx",
"args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
"env": {
"ANKI_CONNECT_URL": "http://localhost:8765"
}
}
}
}
Configuration locations:
- Cursor:
~/.cursor/mcp.json
- Cline: VS Code settings UI
- Zed: Extension marketplace
For Web-based AI (HTTP Mode with ngrok)
npm install -g @ankimcp/anki-mcp-server
npm install -g ngrok
ngrok config add-authtoken <YOUR_NGROK_TOKEN>
ankimcp --ngrok
Share the ngrok URL with ChatGPT or Claude.ai as an MCP server endpoint.
Configuration
Environment Variables
ANKI_CONNECT_URL=http://localhost:8765
READ_ONLY=true
CLI Options
ankimcp [options]
--stdio
--port <port>
--host <host>
--anki-connect <url>
--ngrok
--read-only
Core Workflows
1. Interactive Review Session
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "sync",
arguments: {}
});
const dueCards = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "get_due_cards",
arguments: {
deck: "Spanish"
}
});
const presentation = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "present_card",
arguments: {
card_id: dueCards.cards[0].cardId
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "rate_card",
arguments: {
card_id: dueCards.cards[0].cardId,
ease: 3
}
});
2. Batch Card Creation
const models = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "modelNames",
arguments: {}
});
const fields = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "modelFieldNames",
arguments: {
modelName: "Basic"
}
});
const result = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "addNotes",
arguments: {
notes: [
{
deckName: "Arabic::Vocabulary",
modelName: "Basic",
fields: {
Front: "مرحبا",
Back: "Hello"
},
tags: ["arabic", "greetings"]
},
{
deckName: "Arabic::Vocabulary",
modelName: "Basic",
fields: {
Front: ,
:
},
: [, ]
}
]
}
});
.(result.);
.(result.);
3. Media Import from File
const selected = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "guiSelectedNotes",
arguments: {}
});
const media = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "storeMediaFile",
arguments: {
filename: "diagram.png",
data: "/Users/username/Downloads/diagram.png"
}
});
const noteInfo = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "notesInfo",
arguments: {
notes: [selected.result[0]]
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "updateNoteFields",
arguments: {
: {
: selected.[],
: {
:
}
}
}
});
4. Deck Management
const decks = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "listDecks",
arguments: {
includeStats: true
}
});
const stats = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "deckStats",
arguments: {
decks: ["Spanish", "Spanish::Grammar"]
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "createDeck",
arguments: {
deck: "French::Vocabulary"
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "changeDeck",
arguments: {
cards: [1234567890, 9876543210],
deck: "French::Advanced"
}
});
5. Note Search and Update
const notes = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "findNotes",
arguments: {
query: "deck:Spanish tag:verb"
}
});
const noteDetails = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "notesInfo",
arguments: {
notes: notes.result
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "updateNoteFields",
arguments: {
note: {
id: notes.result[0],
fields: {
Front: "¿Cómo estás?",
Back: "How are you? (informal)"
}
}
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "deleteNotes",
arguments: {
notes: [, ]
}
});
6. Tag Management
const allTags = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "getTags",
arguments: {}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "addTags",
arguments: {
notes: [1234567890, 9876543210],
tags: "important grammar advanced"
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "removeTags",
arguments: {
notes: [1234567890],
tags: "beginner"
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "replaceTags",
arguments: {
notes: [1234567890, 9876543210],
tag_to_replace: "old-tag",
replace_with_tag: "new-tag"
}
});
({
: ,
: ,
: {}
});
7. Media Management
const mediaFiles = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "getMediaFilesNames",
arguments: {
pattern: "*.png"
}
});
const mediaData = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "retrieveMediaFile",
arguments: {
filename: "diagram.png"
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "storeMediaFile",
arguments: {
filename: "photo.jpg",
data: "/Users/username/Pictures/photo.jpg"
}
});
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "storeMediaFile",
arguments: {
filename: "diagram.png",
url: "https://example.com/diagram.png"
}
});
({
: ,
: ,
: {
: ,
:
}
});
({
: ,
: ,
: {
:
}
});
Common Patterns
Check Available Decks Before Creating
const decks = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "listDecks",
arguments: {}
});
if (!decks.result.includes("MyDeck")) {
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "createDeck",
arguments: { deck: "MyDeck" }
});
}
Get Tags Before Adding
const tags = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "getTags",
arguments: {}
});
const newTags = tags.result.filter(t => t.includes("spanish"));
Batch Operations for Efficiency
const notes = [];
for (let i = 0; i < 50; i++) {
notes.push({
deckName: "Vocabulary",
modelName: "Basic",
fields: { Front: `Word ${i}`, Back: `Definition ${i}` },
tags: ["batch-import"]
});
}
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "addNotes",
arguments: { notes }
});
Safe Note Updates
const info = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "notesInfo",
arguments: { notes: [noteId] }
});
const currentFields = info.result[0].fields;
await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "updateNoteFields",
arguments: {
note: {
id: noteId,
fields: {
Front: currentFields.Front.value,
Back: "Updated back content"
}
}
}
});
Anki Search Query Syntax
When using findNotes, use Anki's search syntax:
"deck:Spanish"
"tag:verb"
"deck:Spanish tag:verb"
"is:due"
"added:7"
"Front:*hola*"
"deck:Spanish -tag:mastered"
Troubleshooting
AnkiConnect Not Responding
curl http://localhost:8765
export ANKI_CONNECT_URL=http://localhost:8766
ankimcp --stdio
Permission Errors
AnkiConnect requires explicit permission for external access. If operations fail:
- Open Anki
- Tools → Add-ons → AnkiConnect → Config
- Add your application to
webCorsOriginList if using HTTP mode
Media Upload Fails
storeMediaFile({ filename: "img.png", data: "/path/to/img.png" })
storeMediaFile({ filename: "img.png", url: "https://example.com/img.png" })
storeMediaFile({ filename: "img.png", data: "base64..." })
Read-Only Mode Not Working
echo $READ_ONLY
ankimcp --stdio --read-only
Batch Operation Partial Failures
const result = await use_mcp_tool({
server_name: "anki-mcp",
tool_name: "addNotes",
arguments: { notes: [...] }
});
result.success.forEach((id, idx) => {
if (id) console.log(`Note ${idx}: Success - ID ${id}`);
});
result.errors.forEach((err, idx) => {
if (err) console.log(`Note ${idx}: Failed - ${err.error}`);
});
Deck Creation Limits
createDeck({ deck: "Languages::Spanish" })
createDeck({ deck: "Languages::Spanish::Verbs" })
Best Practices
- Always sync before review sessions: Use
sync tool at start of review workflow
- Use file paths for media: Avoid base64 when possible for performance
- Batch note creation: Use
addNotes instead of multiple addNote calls
- Check existing tags: Call
getTags before adding to avoid duplication
- Preserve note content: Get
notesInfo before updateNoteFields to avoid data loss
- Use read-only mode for exploration: Enable
--read-only when testing queries
- Handle partial failures: Check
errors array in addNotes response
- Verify decks exist: Use
listDecks before creating or moving cards
Resources