Atlas / MCP servers / anki-mcp / Anki AI Tutor

Anki AI TutorCAUTION

mcp/anki-mcp/anki-ai-tutor

A Model Context Protocol (MCP) server that enables AI assistants to interact with Anki, the spaced repetition flashcard application.

Verdict
CAUTION
Grade
C
Trust score
78 /100
Exposed tools
52 34r · 12w · 6d
Transport
stdio · streamable-http
License
MIT
Stars
508
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://github.com/ankimcp/anki-mcp-server/actions/workflows/test.yml) [](https://www.npmjs.com/package/@ankimcp/anki-mcp-server)

Seamlessly integrate Anki with AI assistants through the Model Context Protocol

Beta - This project is in active development. APIs and features may change.

A Model Context Protocol (MCP) server that enables AI assistants to interact with Anki, the spaced repetition flashcard application.

Transform your Anki experience with natural language interaction - like having a private tutor. The AI assistant doesn't just present questions and answers; it can explain concepts, make the learning process more engaging and human-like, provide context, and adapt to your learning style. It can create and edit notes on the fly, turning your study sessions into dynamic conversations. More features coming soon!

Examples and Tutorials

For comprehensive guides, real-world examples, and step-by-step tutorials on using this MCP server with Claude Desktop, visit:

[ankimcp.ai](https://ankimcp.ai) - Complete documentation with practical examples and use cases

See docs/ for supplementary documentation, including the reviewer setup guide and the sample Anki deck.

Example Use Cases

Three representative prompts showing the tool flows this server enables:

  1. "Help me review my Spanish deck." — The assistant offers to sync with AnkiWeb (sync), fetches due cards (get_due_cards with deck filter), presents each card (present_card), and records your rating (rate_card). Natural study conversa
Read from source at commit d18a5b34f348OBSERVED · 2026-10-08
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add anki-mcp-server -- npx -y @ankimcp/[email protected]
03

Exposed tools (52)

34 read · 12 write · 6 destructive. Blast radius: 6 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
addModelFieldwriteAdd a new field to an existing Anki note type (model).
addTagswriteAdd tags to specified notes. Tags is a space-separated string (e.g.,
anki_reviewreadGuidelines for conducting Anki spaced repetition review sessions
areSuspendedreadCheck whether cards are suspended, without changing anything. Card IDs (not note IDs) —
changeDeckwriteMove cards to a different deck. Target deck will be created if it doesn
clearUnusedTagsdestructiveRemove orphaned tags that are not used by any notes in the collection, across the whole collection at once. Removed tags disappear from Anki
collection_statsreadGet aggregated statistics across all decks in the collection including card counts, ease factor distribution, and interval distribution.
createDeckwriteCreate a new empty Anki deck. Use
createModelwriteCreate a new note type (model) in Anki with custom fields, card templates, and styling.
deckStatsreadGet comprehensive statistics for a single deck including card counts, ease and interval distributions. Pass a deck name (e.g.,
deleteMediaFiledestructiveRemove a media file from Anki
deleteNotesdestructiveDelete notes by their IDs. Permanently removes the notes and ALL their cards, including the cards
findNotesreadSearch for notes using Anki query syntax. Returns an array of note IDs matching the query.
forgetCardsdestructiveReset cards to the new queue, discarding their current scheduling (interval, due date, and ease factor).
getMediaFilesNamesreadList media files in Anki
getTagsreadGet all tags in the Anki collection. Use this to discover existing tags before creating notes to maintain consistency and prevent tag duplication (e.g., avoiding
get_cardsreadRetrieve cards from Anki with flexible filtering by deck and card state. Reads the local collection as-is and does not sync with AnkiWeb, so reviews made on other devices since the last sync are not reflected. Answers are not included by default (include_answer=false), so a card
get_due_cardsreadRetrieve cards that are due for review from Anki. Reads the local collection as-is and does not sync with AnkiWeb, so reviews made on other devices since the last sync are not reflected. Answers are not included by default (include_answer=false), so a card
guiAddCardswriteOpens the Add Cards dialog in the Anki desktop app on the user
guiBrowsereadOpens the Card Browser window in the Anki desktop app on the user
guiCurrentCardreadReads the card currently shown in the Anki desktop app
guiDeckBrowserreadSwitches the Anki desktop app
guiDeckOverviewreadMakes the named deck Anki
guiEditNotereadOpens the note editor window in the Anki desktop app on the user
guiSelectCardreadChanges the selection in the Card Browser window open in the Anki desktop app on the user
guiSelectedNotesreadReads the IDs of the notes the user has selected in the Card Browser window of the Anki desktop app. Changes nothing on screen.
guiShowAnswerreadFlips the card on the Anki desktop app
guiShowQuestionreadFlips the card on the Anki desktop app
guiUndoreadTriggers Anki
listDecksreadList all Anki decks, optionally with per-deck study-queue statistics.
modelFieldNamesreadGet the field names for a specific note type (model). Use this to know what fields are required when creating notes of this type.
modelNamesreadGet a list of all available note type (model) names in Anki. Use this to see what note types are available before creating notes.
modelStylingreadGet the CSS styling for a specific note type (model). This CSS is used when rendering cards of this type.
modelTemplatesreadGet the card templates (Front and Back HTML) for a specific note type (model).
notesInforeadGet fields, tags, note type (model) name, card IDs and modification time for each note, by note ID (from findNotes).
present_cardreadReturns a card
rate_cardreadRecords a real review of a card in Anki
removeModelFielddestructiveRemove a field from an existing Anki note type (model).
removeTagsdestructiveRemove tags from specified notes. Tags is a space-separated string (e.g.,
renameModelFieldwriteRename a field in an existing Anki note type (model).
replaceTagswriteRename a tag across specified notes (e.g.,
repositionModelFieldreadChange the position of a field within an Anki note type (model).
retrieveMediaFilereadDownload a media file from Anki
review_statsreadGet review history analysis including temporal patterns, retention metrics, and study streak information.
setDueDatereadReschedule cards to become due in a given number of days, without recording a review.
storeMediaFilewriteUpload a media file to Anki
suspendreadSuspend cards so they
system-inforeadCurrent system information and environment
unsuspendreadUnsuspend cards so they return to normal review. Card IDs (not note IDs) — use get_cards,
updateModelStylingwriteUpdate the CSS styling for an existing note type (model).
updateModelTemplateswriteUpdate the card templates (Front and Back HTML) for an existing note type (model).
updateNoteFieldswriteUpdate the fields of an existing note. The given fields
04

Trust audit

CAUTIONgrade C · trust 78/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeWARN
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (2 observation(s))
Network
declared (2 observation(s))
Shell
none-observed
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
scripts/e2e-full.sh:68
if ! curl -s http://127.0.0.1:3000 > /dev/null 2>&1; then
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
clearUnusedTags, deleteMediaFile, deleteNotes, forgetCards, removeModelField, removeTags
Why it matters. 6 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.binary · CWE-1104
docs/MCP Reviewer Demo.apkg
MCP Reviewer Demo.apkg
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.hidden_file · CWE-1104
.mcpbignore
.mcpbignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/mcp/primitives/essential/tools/__tests__/store-media-file.tool.spec.ts:151
it("should reject non-media file paths (e.g., .ssh/id_rsa)", async () => {
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/mcp/primitives/essential/tools/__tests__/store-media-file.tool.spec.ts:154
path: "/home/user/.ssh/id_rsa",
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/mcp/utils/__tests__/media-validation.utils.spec.ts:81
"/home/user/.ssh/id_rsa",
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/mcp/utils/__tests__/media-validation.utils.spec.ts:101
expect(() => validateMediaFilePath("/some/path/id_rsa")).toThrow(
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/mcp/utils/__tests__/media-validation.utils.spec.ts:133
validateMediaFilePath("/photos/image\0.ssh/id_rsa.jpg"),
Why it matters. touches a credential store
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/cli.spec.ts:347
const packageJsonPath = path.join(__dirname, "../../package.json");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/__tests__/cli.spec.ts:373
const packageJsonPath = path.join(__dirname, "../../package.json");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/cli/args.ts:56
readFileSync(join(__dirname, "../../package.json"), "utf-8"),
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/http/guards/__tests__/dns-rebinding.integration.spec.ts:5
import { AppModule } from "../../../app.module";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/http/guards/__tests__/dns-rebinding.integration.spec.ts:6
import { createMcpHttpServer } from "../../mcp-http.factory";
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/mcp/primitives/essential/tools/__tests__/store-media-file.tool.spec.ts:375
it("blocks cloud metadata endpoint (169.254.169.254)", async () => {
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/mcp/primitives/essential/tools/__tests__/store-media-file.tool.spec.ts:377
{ address: "169.254.169.254", family: 4 },
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/mcp/primitives/essential/tools/__tests__/store-media-file.tool.spec.ts:382
url: "http://169.254.169.254/latest/meta-data/",
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/mcp/utils/__tests__/media-validation.utils.spec.ts:312
["169.254.169.254", "link-local (cloud metadata)"],
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
src/mcp/utils/__tests__/media-validation.utils.spec.ts:608
["64:ff9b::169.254.169.254", "rfc6052 / NAT64 wrapping cloud metadata"],
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:494
| `ALLOWED_ORIGINS` | HTTP mode: comma-separated allowlist of browser `Origin`/`Referer` patterns (wildcards supported, e.g. `https://*.ngrok.io`). | `http://localhost:*,http://127.0.0.1:*,https://loc
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:641
- **MCP endpoint**: `http://127.0.0.1:3000/` (root path)
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:666
- `ALLOWED_ORIGINS` - Comma-separated allowlist of browser `Origin`/`Referer` patterns; wildcards supported (e.g. `https://*.ngrok.io`). Default: `http://localhost:*,http://127.0.0.1:*,https://localho
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/__tests__/app-config.service.spec.ts:17
"http://127.0.0.1:*",
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@nestjs/common, @nestjs/config, @nestjs/core, @nestjs/microservices, @nestjs/platform-express, @rekog/mcp-nest, async-mutex, commander
Why it matters. 50 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
CHANGELOG.md:14
- **Read-only errors carry a read-only hint.** A call blocked by read-only mode used to return the tool's generic hint (e.g. "Make sure Anki is running...") next to the read-only error. The hint now s
Why it matters. asks the agent to read credentials

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha d18a5b34f348full audit observations/trust-audit/mcp-server/anki-mcp__anki-ai-tutor.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-08d18a5b34f348CAUTIONC78first audit
06

Questions

What is the Anki AI Tutor MCP server?

A Model Context Protocol (MCP) server that enables AI assistants to interact with Anki, the spaced repetition flashcard application.

What tools does Anki AI Tutor expose?

52 in total: 34 read-only, 12 that write, and 6 that can delete or overwrite (clearUnusedTags, deleteMediaFile, deleteNotes, forgetCards, removeModelField). Every one is listed on this page with its risk.

Is Anki AI Tutor safe to connect to an agent?

With care. The audit graded it C (78/100) and found 25 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 6 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does Anki AI Tutor need?

It reads ANKI_CONNECT_API_KEY and TUNNEL_AUTH_CLIENT_ID from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Anki AI Tutor run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as @ankimcp/anki-mcp-server at 0.27.0.

How current is this page?

The grade is for one exact copy of the source (d18a5b34f348), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement