Doramagic 项目包 · 项目说明书

anki-mcp-server 项目

生成时间:2026-05-31 19:46:39 UTC

项目介绍

Anki MCP Server 是一个基于 Model Context Protocol (MCP) 的 Anki 间隔重复记忆应用服务端。该项目使 AI 助手能够与 Anki 进行自然语言交互,实现学习辅助、卡片管理、复习调度等功能。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 主要能力

继续阅读本节完整说明和来源证据。

章节 技术架构

继续阅读本节完整说明和来源证据。

章节 核心模块

继续阅读本节完整说明和来源证据。

概述

Anki MCP Server 是一个基于 Model Context Protocol (MCP) 的 Anki 间隔重复记忆应用服务端。该项目使 AI 助手能够与 Anki 进行自然语言交互,实现学习辅助、卡片管理、复习调度等功能。

资料来源:manifest.json:3-6

核心功能

主要能力

功能类别具体功能
复习管理获取到期卡片、呈现卡片、评分卡片、同步
笔记操作添加笔记、批量添加笔记、编辑笔记、删除笔记
模型管理创建笔记类型、获取字段名称、获取样式、更新样式
牌组管理获取牌组列表、管理牌组
媒体文件存储媒体文件、获取媒体文件
统计信息集合级统计、复习统计

资料来源:manifest.json:25-48

技术架构

该项目采用 NestJS 框架构建,基于 MCP 协议实现与 AI 助手的通信,通过 AnkiConnect 插件与 Anki 桌面应用交互。

graph TD
    A[AI 助手] -->|MCP 协议| B[Anki MCP Server]
    B -->|HTTP API| C[AnkiConnect 插件]
    C --> D[Anki 桌面应用]
    
    B --> E[STDIO 传输]
    B --> F[Streamable HTTP 传输]
    B --> G[ngrok 隧道]

资料来源:CLAUDE.md:1-20

项目结构

anki-mcp-server/
├── src/
│   ├── mcp/
│   │   ├── clients/          # AnkiConnect HTTP 客户端
│   │   ├── config/           # 配置接口
│   │   ├── types/            # TypeScript 类型定义
│   │   ├── utils/            # 工具函数
│   │   └── primitives/
│   │       ├── essential/    # 核心工具
│   │       └── gui/          # GUI 交互工具
│   └── main.ts               # 应用入口
├── bin/                      # CLI 入口脚本
├── dist/                     # 编译输出
├── package.json
└── server.json               # MCP 服务器配置

资料来源:CLAUDE.md:1-15

模块系统

项目采用 NestJS 的模块化设计,通过依赖注入组织各个功能模块:

graph LR
    A[AppModule] --> B[McpModule]
    A --> C[McpPrimitivesAnkiEssentialModule]
    A --> D[McpPrimitivesAnkiGuiModule]
    
    B --> E[STDIO / HTTP 传输]
    C --> F[核心工具集]
    D --> G[GUI 交互工具]

核心模块

模块职责
McpModuleMCP 协议传输层,支持 STDIO 和 Streamable HTTP
McpPrimitivesAnkiEssentialModule核心工具:复习、笔记、牌组管理等
McpPrimitivesAnkiGuiModuleGUI 工具:浏览窗口、卡片选择等

资料来源:CLAUDE.md:18-25

工具系统

工具定义模式

所有 MCP 工具遵循统一的实现模式:

// 1. Zod schema 用于输入验证
// 2. @Injectable() 类注入 AnkiConnectClient
// 3. @Tool() 装饰器定义工具元数据
// 4. execute() 方法调用 ankiClient.invoke()
// 5. 成功返回匹配 outputSchema 的原始对象
// 6. 错误返回 createErrorResponse()

资料来源:CLAUDE.md:42-52

工具注解

每个工具在 @Tool 装饰器中声明注解:

注解说明
readOnlyHint标识是否为只读操作
destructiveHint标识是否为破坏性操作
idempotentHint标识是否为幂等操作

资料来源:CLAUDE.md:54-55

配置选项

IAnkiConfig 接口

配置项类型默认值说明
ankiConnectUrlstring'http://localhost:8765'AnkiConnect 服务地址
ankiConnectApiVersionnumber6API 版本
ankiConnectApiKeystring-认证密钥(可选)
ankiConnectTimeoutnumber5000请求超时(毫秒)
readOnlybooleanfalse只读模式,阻止所有写入操作

资料来源:src/mcp/config/anki-config.interface.ts:5-30

只读模式

只读模式通过 readOnly 配置项启用,可阻止所有写入操作,防止意外修改 Anki 牌组。此功能响应社区需求(#18),为需要限制 MCP 服务器操作权限的用户提供解决方案。

资料来源:src/mcp/config/anki-config.interface.ts:25-26

传输方式

支持的传输协议

传输方式说明使用场景
STDIO标准输入输出Claude Desktop、本地 CLI
Streamable HTTPHTTP 长连接远程访问、Web 集成
ngrok 隧道公共 URL 访问无公网 IP 的远程访问

资料来源:CLAUDE.md:8-10

启动方式

# STDIO 模式(默认)
npx -y @ankimcp/anki-mcp-server --stdio

# HTTP 模式
npx -y @ankimcp/anki-mcp-server --http

# ngrok 隧道模式
npx -y @ankimcp/anki-mcp-server --ngrok

数据类型

核心类型定义

interface AddNoteParams {
  deckName: string;           // 目标牌组
  modelName: string;         // 笔记类型(Basic、Cloze 等)
  fields: Record<string, string>;  // 字段键值对
  tags?: string[];           // 标签数组
  options?: NoteOptions;     // 重复检查选项
}

interface Model {
  name: string;              // 模型名称
  id: number;                // 唯一标识符
  css: string;               // CSS 样式
  fields: string[];          // 字段名称数组
}

interface NoteInfo {
  noteId: number;            // 笔记 ID
  modelName: string;          // 使用的模型
  tags: string[];             // 标签
  fields: Record<string, { value: string; order: number }>;
  cards: number[];            // 关联的卡片 ID
}

资料来源:src/mcp/types/anki.types.ts:25-50

依赖项

核心依赖

依赖版本用途
@nestjs/core^11.x核心框架
@modelcontextprotocol/sdk1.29.0MCP 协议实现
ky^1.14.3HTTP 客户端
zod^4.x数据验证
pino^10.x日志记录
commander^14.xCLI 解析

已知兼容性问题

Node.js 版本要求:项目需要 Node.js 20.19+ 或更高版本。由于 ky 是纯 ESM 包,不支持 Node.js 21.x(该版本未包含 require(esm) 功能)。

资料来源:package.json:1-50

安全特性

媒体操作安全

v0.15.1 版本引入了多层安全验证:

  • 路径遍历防护:防止通过 storeMediaFile 路径参数读取任意文件
  • SSRF 防护:防止通过 URL 参数发起服务端请求伪造攻击
  • MIME 类型白名单:验证上传文件的实际类型

此安全加固由 Hideaki Takahashi 报告并修复。

资料来源:CHANGELOG.md:1-10

版本历史

版本主要变更
0.18.x最新稳定版,支持隧道功能
0.15.x媒体安全加固
0.14.x批量添加笔记、牌组统计
0.8.x早期版本,存在 ESM 兼容性问题

资料来源:CHANGELOG.md:1-25

快速开始

前置要求

  1. 安装 Anki 桌面应用
  2. 安装 AnkiConnect 插件(插件编号 2055492159)
  3. 确保 Node.js >= 20.19

安装步骤

# 通过 npx 运行
npx -y @ankimcp/anki-mcp-server --stdio

# 或全局安装
npm install -g @ankimcp/anki-mcp-server

Claude Desktop 配置

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"]
    }
  }
}

社区反馈

高优先级功能请求

Issue功能状态
#22创建卡片超时问题建议使用 addNotes 批量操作
#21批量创建卡片性能addNotes 工具已可用
#19changeDeck 和 reposition 工具规划中
#14牌组和集合级统计部分可用

资料来源:社区上下文

相关资源

  • 官网:https://ankimcp.ai
  • 文档:https://github.com/ankimcp/anki-mcp-server#readme
  • 问题反馈:https://github.com/ankimcp/anki-mcp-server/issues
  • 隐私政策:https://ankimcp.ai/privacy/

资料来源:manifest.json:10-15

资料来源:manifest.json:3-6

安装与配置

Anki MCP Server 是一个基于 Model Context Protocol (MCP) 的服务器,为 Anki 间隔重复记忆应用提供 AI 交互能力。本页面详细说明该服务器的安装前置条件、多种安装方式、配置选项以及各客户端集成方法。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 运行时环境

继续阅读本节完整说明和来源证据。

章节 AnkiConnect 插件安装

继续阅读本节完整说明和来源证据。

章节 方式一:全局安装 (npm)

继续阅读本节完整说明和来源证据。

系统要求

运行时环境

组件最低版本要求推荐版本备注
Node.js>=20.19.020.x LTS禁止使用 Node 21.x,该版本存在 ERR_REQUIRE_ESM 兼容性问题
npm最新稳定版最新稳定版用于全局安装或本地依赖管理
Anki2.1.x2.1.50+桌面版,必须安装 AnkiConnect 插件
AnkiConnect最新版本最新版本Anki 插件,版本号 6.0.0+

重要提示:Node.js 21.x 版本不支持 ESM 模块的 CommonJS 导入方式,会导致 ky 依赖库加载失败,产生 ERR_REQUIRE_ESM 错误。如果当前系统使用 Node 21.x,请降级至 Node 20.19+ 或升级至 Node 22+。资料来源:package.json:dependencies 和 issues/#17

AnkiConnect 插件安装

  1. 启动 Anki 桌面应用
  2. 进入 Tools → Add-ons → Get Add-ons
  3. 在代码框中输入插件编号:2055492159
  4. 点击 OK 安装插件
  5. 重启 Anki 确保插件生效

插件安装后,AnkiConnect 默认监听 http://127.0.0.1:8765 端口。资料来源:manifest.json

安装方式

方式一:全局安装 (npm)

npm install -g @ankimcp/anki-mcp-server

安装完成后,使用以下命令启动:

# STDIO 模式(适用于 Claude Desktop 等 MCP 客户端)
anki-mcp --stdio

# HTTP 模式(适用于 Web 集成)
anki-mcp --http

# Ngrok 隧道模式(适用于远程访问)
anki-mcp --ngrok

资料来源:package.json:bin

方式二:npx 临时运行

无需预先安装,直接通过 npx 运行:

# STDIO 模式
npx -y @ankimcp/anki-mcp-server --stdio

注意:使用 npx 时,首次运行会临时下载并执行,可能存在网络延迟。资料来源:issues/#16

方式三:Docker 部署

对于需要隔离环境的用户,可通过 Docker 运行:

FROM node:20-slim
RUN npm install -g @ankimcp/anki-mcp-server
CMD ["anki-mcp", "--stdio"]

运行容器时需将 AnkiConnect 端口映射到宿主机:

docker run -p 8765:8765 anki-mcp-container

传输模式

Anki MCP Server 支持三种传输模式,适用于不同的使用场景:

graph TD
    A[Anki MCP Server] --> B[STDIO 模式]
    A --> C[HTTP 模式]
    A --> D[Ngrok 隧道模式]
    
    B --> B1[Claude Desktop]
    B --> B2[Cursor]
    B --> B3[其他 MCP 客户端]
    
    C --> C1[Web 应用集成]
    C --> C2[自定义 HTTP 客户端]
    
    D --> D1[ngrok 隧道]
    D --> D2[远程访问]
    
    style B fill:#90EE90
    style C fill:#87CEEB
    style D fill:#FFB6C1

STDIO 模式

标准输入/输出模式,适合本地 MCP 客户端集成,如 Claude Desktop、VS Code 等。

anki-mcp --stdio

配置文件示例 (~/.claude/desktops/claude_desktop_config.json):

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
      "env": {
        "ANKI_CONNECT_URL": "http://127.0.0.1:8765"
      }
    }
  }
}

资料来源:server.json

HTTP 模式

HTTP 服务器模式,适合需要远程访问或 Web 集成的场景。

anki-mcp --http --port 8080
参数默认值说明
--port8080HTTP 服务监听端口
--host127.0.0.1绑定地址(建议仅本地使用)

Ngrok 隧道模式

通过 ngrok 创建公网可访问的隧道,适合需要远程访问 Anki 的场景。

anki-mcp --ngrok --api-key YOUR_NGROK_API_KEY

前提条件

  • 已安装 ngrok 并配置 API Key
  • ngrok 版本 >= 3.0

已知问题:部分 ngrok 3.24.x 版本可能存在启动问题,如遇此情况可降级至 7.0 版本。资料来源:issues/#9

环境变量配置

环境变量默认值说明
ANKI_CONNECT_URLhttp://127.0.0.1:8765AnkiConnect API 地址
ANKI_CONNECT_TIMEOUT30000请求超时时间(毫秒)
ANKI_CONNECT_RETRIES3失败重试次数
DEBUGfalse启用调试日志输出

AnkiConnect 连接配置

AnkiConnect 默认配置位于 Anki 插件设置中,主要参数:

参数默认值说明
API Key可选的安全认证密钥
允许来源["127.0.0.1", "localhost"]CORS 允许的来源地址
最大并发请求6同时处理的最大请求数

客户端集成

Claude Desktop 配置

在 Claude Desktop 配置文件中添加以下内容:

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
      "env": {
        "ANKI_CONNECT_URL": "http://127.0.0.1:8765",
        "ANKI_CONNECT_TIMEOUT": "30000"
      }
    }
  }
}

配置文件位置:

已知问题:某些 Claude Desktop 版本可能存在 MCP 服务器配置兼容性问题,如安装后无法启动,请确保使用最新版本的 Claude Desktop。资料来源:issues/#10

VS Code MCP 扩展配置

使用 VS Code 的 MCP 扩展时,在 VS Code 设置中添加:

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"]
    }
  }
}

Cursor IDE 配置

在 Cursor 的 MCP 设置中配置:

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"]
    }
  }
}

架构概览

graph LR
    A[MCP 客户端<br/>Claude/VS Code] --> B[Anki MCP Server]
    B --> C[AnkiConnect Client<br/>ky HTTP]
    C --> D[AnkiConnect API]
    D --> E[Anki 应用]
    
    B --> F[NestJS IoC 容器]
    F --> G[MCP Tools]
    F --> H[MCP Resources]
    F --> I[MCP Prompts]
    
    style C fill:#FFD700
    style E fill:#87CEEB

常见问题排查

ERR_REQUIRE_ESM 错误

症状:启动时报 Error [ERR_REQUIRE_ESM]: require() of ES Module 错误

原因:Node.js 版本不兼容,当前使用 Node 21.x

解决方案

# 检查 Node 版本
node --version

# 切换到 Node 20.x
nvm install 20
nvm use 20

资料来源:issues/#12

AnkiConnect 连接超时

症状:创建卡片时频繁超时

原因:AnkiConnect 单线程 Qt 事件循环无法处理高并发请求

解决方案

  • 批量操作时使用 addNotes 而非多次 addNote
  • 降低请求频率
  • 确保 Anki 窗口未最小化或被遮挡

资料来源:issues/#22

Ngrok 启动失败

症状failed to start ngrok 错误

解决方案

  1. 确认 ngrok 已正确安装并配置 API Key
  2. 尝试降级 ngrok 版本:npx [email protected]

资料来源:issues/#9

安全注意事项

  1. 网络隔离:默认情况下,AnkiConnect 仅允许本地连接(127.0.0.1)
  2. API Key:在公共网络环境下使用 HTTP 模式,建议配置 API Key
  3. 媒体文件:服务器包含媒体路径遍历和 SSRF 攻击防护机制
  4. 只读模式:生产环境中可考虑使用只读模式限制写操作

资料来源:v0.15.1 release notesissues/#18

资料来源:package.json:bin

系统架构

anki-mcp-server 是一个基于 Model Context Protocol (MCP) 的 Anki 间隔重复闪卡应用服务器。它允许 AI 助手(如 Claude)与 Anki 进行自然语言交互,实现复习会话、卡组管理、笔记创建与编辑等功能。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心模块结构

继续阅读本节完整说明和来源证据。

章节 模块依赖关系

继续阅读本节完整说明和来源证据。

章节 工具分类

继续阅读本节完整说明和来源证据。

概述

anki-mcp-server 是一个基于 Model Context Protocol (MCP) 的 Anki 间隔重复闪卡应用服务器。它允许 AI 助手(如 Claude)与 Anki 进行自然语言交互,实现复习会话、卡组管理、笔记创建与编辑等功能。

核心架构采用 NestJS 框架构建,通过 AnkiConnect 插件与 Anki 桌面应用通信,支持 STDIO 和 HTTP 两种传输模式。

技术栈

层级技术/框架版本要求
运行时Node.js≥20.19.0(明确排除 21.x)
框架NestJS^11.x
MCP 协议@modelcontextprotocol/sdk精确版本 1.29.0
HTTP 客户端ky^1.14.3(ESM 专有)
数据验证Zod^4.3.6(非 v3)
日志pino^10.3.1
注意:Node 21.x 不被支持,因为 require(esm) 功能在 Node 21 中不存在(该功能在 Node 22 和 Node 20.17+ 中才被引入)。用户报告在 Node 21 环境下会遇到 ERR_REQUIRE_ESM 错误。资料来源:package.json

整体架构图

graph TB
    subgraph "MCP 客户端 (AI Agent)"
        A[Claude Desktop / VS Code / 其他 MCP 客户端]
    end

    subgraph "anki-mcp-server"
        B[入口层<br/>bootstrap.ts]
        C[传输层<br/>STDIO / HTTP]
        D[核心模块<br/>AppModule]
        E[MCP 协议层<br/>@rekog/mcp-nest]
        F[业务层<br/>Primitives Modules]
        G[通信层<br/>AnkiConnectClient]
    end

    subgraph "外部服务"
        H[AnkiConnect 插件]
        I[Anki 桌面应用]
    end

    A -->|MCP 协议| B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G -->|HTTP| H
    H --> I

模块系统

核心模块结构

项目采用 NestJS 的模块化架构,核心模块包括:

AppModule.forStdio()   // STDIO 传输模式
AppModule.forHttp()    // HTTP 传输模式

模块依赖关系

graph LR
    subgraph "传输层"
        A[STDIO 传输]
        B[HTTP 传输]
    end

    subgraph "核心层"
        C[McpModule]
        D[McpPrimitivesAnkiEssentialModule]
        E[McpPrimitivesAnkiGuiModule]
    end

    subgraph "工具层"
        F[Review 工具]
        G[Deck 工具]
        H[Note 工具]
        I[Media 工具]
        J[GUI 工具]
    end

    A --> C
    B --> C
    C --> D
    C --> E
    D --> F
    D --> G
    D --> H
    D --> I
    E --> J

工具分类

项目中的 MCP 工具分为两大类:

类别模块说明权限级别
EssentialMcpPrimitivesAnkiEssentialModule核心复习、笔记操作普通权限
GUIMcpPrimitivesAnkiGuiModule需要用户确认的界面操作需用户批准

Essential 工具包括:

  • sync - 与 AnkiWeb 同步
  • get_due_cards - 获取待复习卡片
  • get_cards - 按状态获取卡片
  • present_card - 展示卡片问题面
  • rate_card - 评分卡片
  • addNote / addNotes - 创建笔记
  • modelNames / modelFieldNames - 获取笔记类型信息
  • getTags - 获取所有标签
  • modelStyling / updateModelStyling - 样式管理
  • createModel - 创建笔记类型

GUI 工具包括:

  • guiBrowse - 打开卡片浏览器
  • guiSelectCard - 选择卡片
  • guiSelectedNotes - 获取选中笔记
用户请求功能:工具权限控制(只读模式)是一个被关注的功能需求,详见 Issue #18

核心组件

1. AnkiConnectClient

AnkiConnectClient 是与 Anki 通信的核心 HTTP 客户端:

特性说明
协议HTTP POST
默认地址http://127.0.0.1:8765
请求库ky(ESM)
重试机制内置重试逻辑
只读守卫可配置的 read-only guard

关键文件:src/mcp/clients/anki-connect.client.ts

// 核心调用模式
class AnkiConnectClient {
  invoke<T>(action: AnkiAction, params?: Record<string, unknown>): Promise<T>
  // 支持重试和错误处理
}

2. 配置系统

配置系统采用分层设计:

graph TB
    A[命令行参数 / 环境变量]
    B[AnkiConfigService]
    C[IAnkiConfig 接口]
    D[注入令牌 ANKI_CONFIG]
    
    A --> B
    B --> C
    C --> D

IAnkiConfig 接口 定义:

配置项类型说明默认值
hoststringAnkiConnect 主机地址127.0.0.1
portnumberAnkiConnect 端口8765
readOnlyboolean只读模式false
retriesnumber重试次数3

关键文件:

3. 工具模式 (Tool Pattern)

所有 MCP 工具遵循统一的实现模式:

graph LR
    A[Zod 输入验证] --> B[Tool 装饰器]
    B --> C[execute 方法]
    C --> D[调用 AnkiConnectClient]
    D --> E[返回结果或错误]

标准工具结构

// 1. Zod schema 用于输入验证
// 2. @Injectable() 类注入 AnkiConnectClient
// 3. @Tool 装饰器定义元数据
// 4. execute() 方法执行业务逻辑

关键文件:src/mcp/primitives/essential/tools/get-tags.tool.ts

工具响应格式

场景返回方式说明
成功路径返回原始对象匹配 outputSchema,handler 自动包装
错误路径createErrorResponse()返回 isError: true,绕过 schema 验证

4. 类型系统

核心类型定义位于 anki.types.ts

类型用途
AddNoteParams添加笔记参数
Model笔记类型信息
NoteInfo笔记详细信息
AnkiCard卡片信息
CardRating评分枚举

关键文件:src/mcp/types/anki.types.ts

传输模式

STDIO 模式

适用于命令行和桌面 AI 客户端(如 Claude Desktop):

npx -y @ankimcp/anki-mcp-server --stdio

HTTP 模式

支持远程访问和 ngrok 隧道:

# 本地 HTTP
npx -y @ankimcp/anki-mcp-server --http

# 带 ngrok 隧道
npx -y @ankimcp/anki-mcp-server --tunnel
注意:用户报告 ngrok 在某些版本下可能启动失败(Issue #9

数据流

笔记创建流程

sequenceDiagram
    participant AI as AI Agent
    participant MCP as anki-mcp-server
    participant ACC as AnkiConnectClient
    participant AK as AnkiConnect
    participant AN as Anki

    AI->>MCP: addNote / addNotes
    MCP->>ACC: invoke("addNotes")
    ACC->>AK: HTTP POST
    AK->>AN: 创建笔记
    AN-->>AK: 响应
    AK-->>ACC: 结果
    ACC-->>MCP: 格式化响应
    MCP-->>AI: 成功/错误
批量操作:建议使用 addNotes 而非多个 addNote 调用,因为 AnkiConnect 基于 Qt 单线程事件循环,并行调用可能导致超时(Issue #22Issue #21

复习流程

graph LR
    A[获取待复习卡片] --> B[展示问题]
    B --> C[用户响应]
    C --> D{评分}
    D -->|Again| E[标记失败]
    D -->|Hard| F[标记困难]
    D -->|Good| G[标记成功]
    D -->|Easy| H[标记简单]
    E --> I[安排下次复习]
    F --> I
    G --> I
    H --> I

入口与引导

bootstrap.ts

启动流程:

// 1. 创建 NestJS 应用
// 2. 读取配置
// 3. 选择传输模式 (STDIO/HTTP)
// 4. 初始化 MCP 模块
// 5. 启动监听

关键文件:src/bootstrap.ts

AppModule 结构

@Module({
  imports: [
    // MCP 核心模块
    McpModule.forRoot(),           // STDIO 或 STREAMABLE_HTTP
    McpPrimitivesAnkiEssentialModule.forRoot(),
    McpPrimitivesAnkiGuiModule.forRoot(),
  ],
  providers: [
    // 显式声明的工具列表
    // ESSENTIAL_MCP_TOOLS
    // GUI_MCP_TOOLS
  ],
})
export class AppModule {}
MCP-Nest 1.9.0+ 要求工具必须同时在 AppModule.providers 中声明。资料来源:CLAUDE.md

安全机制

媒体操作安全

v0.15.1 版本引入了多层安全验证:

安全措施说明
MIME 类型白名单验证文件类型
路径遍历防护防止通过路径参数读取任意文件
SSRF 防护防止通过 URL 参数发起请求

此修复由 Hideaki Takahashi 报告,详见 Release v0.15.1

只读模式

可通过配置启用只读模式,限制所有写操作:

配置项效果
readOnly: true禁止创建、修改、删除笔记

AnkiConnect 已知特性

项目中记录了以下 AnkiConnect 上游行为:

行为影响
updateNoteFields 在笔记打开时静默失败请求返回 200 但字段未保存
Model CSS 是按笔记类型的使用 modelStyling 获取
sync 需要桌面应用登录 AnkiWeb无 API 路径可认证
deleteNotes 不可逆且级联删除需显式 confirmDeletion: true

资料来源:CLAUDE.md

依赖关系

关键生产依赖

依赖版本用途
@nestjs/core^11.xNestJS 框架核心
@modelcontextprotocol/sdk1.29.0MCP 协议实现
@rekog/mcp-nest-MCP-Nest 集成
ky^1.14.3HTTP 客户端(ESM)
zod^4.3.6数据验证
pino^10.3.1日志框架
passport^0.7.0认证中间件

开发依赖

依赖用途
@anthropic-ai/mcpbMCPB 配置
@nestjs/cliNestJS CLI
@nestjs/testing测试框架
typescriptTypeScript 编译器

项目结构

anki-mcp-server/
├── src/
│   ├── app.module.ts           # 主应用模块
│   ├── bootstrap.ts            # 启动入口
│   ├── anki-config.service.ts  # 配置服务
│   └── mcp/
│       ├── clients/
│       │   └── anki-connect.client.ts  # AnkiConnect 通信客户端
│       ├── config/
│       │   └── anki-config.interface.ts # 配置接口
│       ├── types/
│       │   └── anki.types.ts   # 类型定义
│       ├── utils/
│       │   ├── anki.utils.ts   # 工具函数
│       │   └── markdown.utils.ts # Markdown 处理
│       └── primitives/
│           ├── essential/      # 核心工具
│           │   ├── tools/      # 工具实现
│           │   └── prompts/    # 提示词模板
│           └── gui/            # GUI 工具
├── package.json
└── tsconfig.json

版本信息

版本说明
当前版本0.18.5
最新测试版本v0.18.5-tunnel.2
语义化版本主版本 0(Beta 阶段)

详见 CHANGELOG.md

资料来源:CLAUDE.md

传输模式

Anki MCP Server 支持两种主要的传输模式,用于 MCP 客户端与服务器之间的通信。正确选择传输模式对于集成、部署和安全性都有重要影响。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 工作原理

继续阅读本节完整说明和来源证据。

章节 启动命令

继续阅读本节完整说明和来源证据。

章节 源码实现

继续阅读本节完整说明和来源证据。

概述

传输模式用途适用场景安全级别
STDIO标准输入输出Claude Desktop、本地集成高(本地通信)
HTTP + NgrokHTTP 远程访问远程客户端、跨网络访问中(需 Ngrok 配置)

STDIO 模式

STDIO(标准输入/输出)是 MCP 协议的默认传输方式,适用于本地进程间通信。

工作原理

graph LR
    A["MCP 客户端<br/>(Claude Desktop)"] -->|stdin| B["Anki MCP Server<br/>(子进程)"]
    B -->|stdout| A
    B --> C["AnkiConnect API<br/>(localhost:8765)"]
    C --> D["Anki 应用"]

启动命令

# 通过 npx 直接运行
npx -y @ankimcp/anki-mcp-server --stdio

# 或指定特定版本
npx -y @ankimcp/anki-mcp-server@latest --stdio

源码实现

入口文件src/main-stdio.ts

STDIO 模式使用 NestJS 框架的模块系统初始化服务:

// 伪代码示例
AppModule.forStdio()
  .then(() => bootstrap())

资料来源:src/main-stdio.ts:1-50

配置方式

在 Claude Desktop 配置文件中添加 STDIO 传输:

{
  "mcpServers": {
    "anki-mcp": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
      "env": {
        "ANKI_HOST": "localhost",
        "ANKI_PORT": "8765"
      }
    }
  }
}

HTTP 模式

HTTP 传输模式提供基于 HTTP 的远程访问能力,支持 MCP Streamable HTTP 规范。

工作原理

graph TD
    A["MCP 客户端"] -->|HTTPS| B["Ngrok Tunnel"]
    B -->|HTTP| C["Anki MCP Server"]
    C --> D["AnkiConnect API"]
    D --> E["Anki 应用"]
    
    F["本地客户端"] -->|HTTP| C

启动命令

# 基本 HTTP 模式
npx -y @ankimcp/anki-mcp-server --http

# 带 Ngrok 隧道的远程访问
npx -y @ankimcp/anki-mcp-server --http --ngrok

# 指定端口
npx -y @ankimcp/anki-mcp-server --http --port 8080

# 带认证令牌
npx -y @ankimcp/anki-mcp-server --http --auth-token <TOKEN>

源码实现

入口文件src/main-http.ts

HTTP 模式使用 AppModule.forHttp() 初始化,提供完整的 HTTP 服务器支持:

// 伪代码示例
AppModule.forHttp({
  port: 8080,
  ngrok: process.env.USE_NGROK === 'true',
  authToken: process.env.AUTH_TOKEN
})

资料来源:src/main-http.ts:1-80

HTTP 服务配置参数

参数环境变量默认值说明
端口PORT8080HTTP 服务器监听端口
HostHOST0.0.0.0绑定地址
NgrokUSE_NGROKfalse是否启用 Ngrok 隧道
认证令牌AUTH_TOKENHTTP 认证令牌
Anki 地址ANKI_HOSTlocalhostAnkiConnect 服务地址
Anki 端口ANKI_PORT8765AnkiConnect 服务端口

Ngrok 隧道服务

Ngrok 提供安全的公共 URL 用于远程访问本地 MCP 服务器。

服务实现

// 伪代码示例 - NgrokService
class NgrokService {
  async startTunnel(port: number): Promise<string> {
    // 1. 启动 ngrok 进程
    // 2. 轮询 ngrok API 获取公网 URL
    // 3. 返回 HTTPS 端点 URL
    return ngrokUrl;
  }
}

资料来源:src/services/ngrok.service.ts:1-100

Ngrok 配置要求

  1. 安装 Ngrok:需要预先安装 ngrok CLI 工具
  2. 认证:配置 ngrok auth token(用于持久化隧道)
  3. 版本注意:推荐使用 ngrok 3.x 版本

已知问题

社区反馈 #9 指出 Ngrok 在某些版本上可能启动失败:

"ngrok fails to start with latest version... I was able to work around this by using version 7.0"

如遇问题,可尝试降级或使用 npx [email protected]

安全机制

来源验证

HTTP 模式包含来源验证保护,防止 DNS 重绑定攻击:

@Injectable()
export class OriginValidationGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    // 验证请求来源
    // 防止 DNS rebinding 攻击
  }
}

资料来源:src/http/guards/origin-validation.guard.ts:1-50

认证机制

HTTP 模式支持令牌认证:

# 设置认证令牌
export AUTH_TOKEN="your-secret-token"

# 启动服务
npx -y @ankimcp/anki-mcp-server --http

客户端连接时需要在请求头中包含令牌:

Authorization: Bearer <your-secret-token>

只读模式

社区功能请求 #18 建议添加只读模式,可限制服务器仅执行读取操作:

npx -y @ankimcp/anki-mcp-server --stdio --read-only

该功能可以防止意外修改 Anki 数据,适合学习和浏览场景。

传输模式选择指南

graph TD
    A["选择传输模式"] --> B{使用场景}
    B -->|Claude Desktop| C["STDIO 模式"]
    B -->|VS Code| C
    B -->|远程访问| D["HTTP + Ngrok"]
    B -->|本地开发| E{"需要 Ngrok?"}
    E -->|是| F["HTTP + Ngrok"]
    E -->|否| G["HTTP 模式"]
    
    C --> H["高安全性<br/>本地通信"]
    F --> I["中等安全性<br/>公网访问"]
    G --> J["中等安全性<br/>内网访问"]

性能考虑

模式延迟并发支持适用卡组规模
STDIO极低单一客户端任何规模
HTTP多客户端任何规模
HTTP + Ngrok中等(网络延迟)多客户端建议配合 addNotes 批量操作

社区问题 #22 报告了大量创建卡片时的超时问题,建议在批量操作时使用 addNotes 工具而非多次调用 addNote

模块系统

根据 CLAUDE.md 的模块架构,两种传输模式共享核心功能:

AppModule.forStdio() / forHttp()
  ├─ McpModule.forRoot()          # 传输层
  ├─ McpPrimitivesAnkiEssentialModule.forRoot()  # 核心工具
  └─ McpPrimitivesAnkiGuiModule.forRoot()         # GUI工具

资料来源:CLAUDE.md 模块系统章节

命令行参数参考

参数模式说明
--stdioSTDIO启用标准输入输出传输
--httpHTTP启用 HTTP 传输
--port <num>HTTP指定 HTTP 端口
--ngrokHTTP启用 Ngrok 隧道
--auth-token <token>HTTP设置认证令牌
--read-only通用限制为只读操作

故障排除

STDIO 常见问题

问题解决方案
ERR_REQUIRE_ESM确认 Node.js 版本 >= 20.19(项目已排除 21.x)
连接超时确保 AnkiConnect 插件已安装并运行

HTTP 常见问题

问题解决方案
Ngrok 启动失败检查 ngrok 安装和认证状态
连接被拒绝确认端口未被占用,检查防火墙设置

Node.js 版本要求

项目要求 Node.js >= 20.19,明确排除 21.x 版本(社区问题 #17):

"users on Node 21.x get ERR_REQUIRE_ESM because the require(esm) feature doesn't exist in Node 21"

资料来源:src/main-stdio.ts:1-50

核心工具参考

Anki MCP Server 的核心工具是实现 AI 助手与 Anki 闪卡应用交互的基础组件。所有工具均通过 AnkiConnectClient 与 AnkiConnect 插件通信,利用 NestJS 依赖注入和 @rekog/mcp-nest 框架自动发现和注册。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 工具实现模式

继续阅读本节完整说明和来源证据。

章节 错误处理机制

继续阅读本节完整说明和来源证据。

章节 addNote - 创建单条笔记

继续阅读本节完整说明和来源证据。

概述

Anki MCP Server 的核心工具是实现 AI 助手与 Anki 闪卡应用交互的基础组件。所有工具均通过 AnkiConnectClient 与 AnkiConnect 插件通信,利用 NestJS 依赖注入和 @rekog/mcp-nest 框架自动发现和注册。

核心工具按照功能分为以下几类:

类别工具数量主要用途
笔记管理4创建、查询、更新、删除笔记
复习管理5获取待复习卡片、显示卡片、评分
卡组管理2获取卡组列表、卡组统计
模型管理4列表字段、样式、创建模型
媒体管理2存储媒体文件、检索笔记媒体
标签管理1获取所有标签
同步管理1AnkiWeb 同步

资料来源:manifest.json:manifest.json.tools

工具架构

工具实现模式

所有核心工具遵循统一的实现模式:

graph TD
    A[MCP Client 调用工具] --> B[@Tool 装饰器]
    B --> C[Zod 参数校验]
    C --> D[execute 方法执行]
    D --> E[AnkiConnectClient.invoke]
    E --> F{成功?}
    F -->|是| G[返回原始对象]
    F -->|否| H[createErrorResponse]
    G --> I[mcp-nest 自动包装]
    H --> J[返回错误结果]

工具类结构如下:

@Injectable()
export class SomeTool {
  constructor(private readonly ankiClient: AnkiConnectClient) {}

  @Tool({
    name: "toolName",
    description: "工具描述",
    parameters: z.object({ /* 参数 schema */ }),
    outputSchema: z.object({ /* 输出 schema */ }),
    annotations: {
      readOnlyHint: boolean,
      destructiveHint: boolean,
      idempotentHint?: boolean
    }
  })
  async execute(params: SomeParams, context: Context) {
    // 实现逻辑
  }
}

资料来源:CLAUDE.md

错误处理机制

工具错误处理使用 createErrorResponse 函数,返回 CallToolResult 类型,绕过 outputSchema 验证:

return createErrorResponse(error, {
  hint: "错误提示信息"
});

资料来源:src/mcp/utils/anki.utils.ts:anki.utils.ts.createErrorResponse

笔记管理工具

addNote - 创建单条笔记

创建单条笔记到指定卡组,使用前需要确保理解卡片创建的最佳实践。

参数定义:

参数类型必填说明
deckNamestring目标卡组名称
modelNamestring笔记类型(如 "Basic", "Cloze")
fieldsRecord<string, string>字段名到值的映射
tagsstring[]标签数组
optionsNoteOptions重复检查等选项

重要提示:

  • 批量创建时推荐使用 addNotes 工具,单独调用 addNote 会产生多次 HTTP 请求
  • 如果需要创建多条卡片,应使用 addNotes 批量操作以提高性能

重复检查选项:

interface NoteOptions {
  checkDuplicate: boolean;      // 是否检查重复
  duplicateScope: string;       // 检查范围:"deck" | "deckAndNotes"
  duplicateScopeDeckId?: number;
  duplicateScopeOptions?: {
    checkAllModels?: boolean;
  };
}

资料来源:src/mcp/primitives/essential/tools/add-note.tool.ts 资料来源:src/mcp/types/anki.types.ts:AddNoteParams

社区反馈: 用户报告创建卡片时遇到 AnkiConnect 超时问题,建议批量操作使用 addNotes 而非多次调用 addNote。参见 Issue #22。

addNotes - 批量创建笔记

批量创建多条笔记,显著提高大量卡片创建效率。

设计背景: Claude Desktop 等 MCP 客户端会并行触发多个 addNote 调用,这会压垮 AnkiConnect 的单线程 Qt 事件循环。addNotes 工具专门为此场景设计。

参数结构:

interface AddNotesParams {
  notes: Array<{
    deckName: string;
    modelName: string;
    fields: Record<string, string>;
    tags?: string[];
    options?: NoteOptions;
  }>;
}

返回结果:

{
  success: boolean;
  results: Array<{
    index: number;
    success: boolean;
    error?: string;
    noteId?: number;
  }>;
  added: number;
  failed: number;
}

资料来源:src/mcp/primitives/essential/tools/add-notes.tool.ts 资料来源:Issue #23

findNotes - 搜索笔记

通过查询条件搜索笔记。

查询参数:

参数类型说明
querystringAnki 查询语法字符串
limitnumber最大返回数量(默认 100)

Anki 查询语法示例:

deck:FDNY-CAPTAIN tag:10-codes
"Code 1"  // 全文搜索
is:new     // 新卡片
is:due     // 到期卡片

资料来源:src/mcp/primitives/essential/tools/find-notes.tool.ts

updateNoteFields - 更新笔记字段

更新已有笔记的字段内容。

参数:

参数类型必填说明
notenumber笔记 ID
fieldsRecord<string, string>要更新的字段

注意事项: 如果目标笔记在 Anki 浏览窗口中打开,updateNoteFields 会静默失败(请求返回 200 但字段未保存)。这是上游 AnkiConnect 的行为。

资料来源:CLAUDE.md - Upstream AnkiConnect Quirks

deleteNotes - 删除笔记

永久删除指定笔记及其所有关联卡片。

参数:

{
  notes: number[];        // 笔记 ID 数组
  confirmDeletion: true;  // 必须设置为 true
}

安全提示:

  • 此操作不可逆,会级联删除笔记的所有卡片
  • 工具注释标记 destructiveHint: true

资料来源:manifest.json:deleteNotes

复习管理工具

getDueCards - 获取到期卡片

获取需要复习的卡片。

{
  deck?: string;  // 可选卡组过滤
}

返回卡片结构包含:卡片 ID、笔记 ID、卡片类型、到期时间、间隔、难度等。

资料来源:src/mcp/types/anki.types.ts:AnkiCard

getCards - 灵活卡片筛选

按状态和卡组筛选卡片。

状态选项:

状态说明
due到期需要复习
new新卡片
learning学习中的卡片
suspended暂停的卡片
buried隐藏的卡片

presentCard - 显示卡片问题

显示卡片正面内容供复习使用。

rateCard - 评分卡片

对复习的卡片进行评分并安排下次复习时间。

评分选项:

评分说明
Again完全忘记,需要重新学习
Hard记得但很困难
Good正常回忆
Easy太简单了

卡组管理工具

deckNames - 列出所有卡组

返回 Anki 中所有卡组的名称列表。

deckStats - 卡组统计信息

获取指定卡组的详细统计数据。

参数:

{
  deck: string;           // 卡组名称
  includeRevLogs?: boolean; // 包含复习日志
  days?: number;          // 统计天数(默认 30)
}

返回数据:

{
  deck: string;
  date: string;
  cards: {
    total: number;
    new: number;
    learning: number;
    mature: number;
  };
  reviews: number;
  averageTime: number;
  retention?: number;
  breakdown?: {
    again: number;
    hard: number;
    good: number;
    easy: number;
  };
}

功能特性:

  • 支持子卡组统计(默认包含子卡组数据)
  • 可选包含复习日志用于详细分析
  • 支持自定义统计时间范围

资料来源:src/mcp/primitives/essential/tools/deck-stats.tool.ts

模型管理工具

modelNames - 列出笔记类型

返回所有可用的笔记类型/模型名称列表。

modelFieldNames - 获取字段名

获取指定笔记类型的字段名称列表。

{
  modelName: string;  // 模型名称
}

modelStyling - 获取 CSS 样式

获取笔记类型的 CSS 样式信息。

用途:

  • 查看当前样式
  • 为 RTL(从右到左)语言(希伯来语、阿拉伯语等)添加样式支持
  • 自定义卡片外观

createModel - 创建笔记类型

创建自定义笔记类型,包含字段、卡片模板和 CSS 样式。

{
  model: {
    name: string;
    inOrderFields: string[];      // 字段列表
    css: string;                  // CSS 样式
    isCloze: boolean;             // 是否为填空模板
    cardTemplates?: Array<{
      Name: string;
      Question: string;          // 正面模板
      Answer: string;            // 反面模板
    }>;
  };
}

注意: Model CSS 是按笔记类型共享的,不是按笔记单独设置。使用 notesInfo 可获取笔记使用的模型。

资料来源:CLAUDE.md - Upstream AnkiConnect Quirks

标签管理工具

getTags - 获取所有标签

获取 Anki 集合中的所有标签列表。

参数:

参数类型说明
patternstring可选的过滤模式(大小写不敏感)

返回结构:

{
  success: boolean;
  tags: string[];        // 标签列表
  total: number;         // 总数
  message: string;
  filtered?: boolean;    // 是否被过滤
  totalUnfiltered?: number; // 过滤前的总数
}

使用场景:

  • AI 代理在创建笔记前发现现有标签
  • 防止标签重复(如 "roman-empire" vs "roman_empire")
  • 维护标签命名一致性

社区需求: 此工具是为了解决 Issue #13 中用户反馈的问题:AI 代理无法看到现有标签,导致标签不一致。

资料来源:src/mcp/primitives/essential/tools/get-tags.tool.ts 资料来源:Issue #13

媒体管理工具

storeMediaFile - 存储媒体文件

将媒体文件存储到 Anki 集合中。

安全特性(v0.15.1+):

  • MIME 类型白名单验证
  • 路径遍历攻击防护
  • SSRF 风险防护

参数:

{
  path: string;      // 文件路径或 URL
  name: string;      // 目标文件名
  source: "path" | "url";  // 来源类型
}

支持的 MIME 类型: 图像、音频、视频等常见格式。

安全修复: v0.15.1 版本修复了路径遍历漏洞,该漏洞可能允许通过 storeMediaFile 路径参数进行任意文件读取,以及通过 URL 参数的 SSRF 风险。

资料来源:src/mcp/primitives/essential/tools/store-media-file.tool.ts 资料来源:v0.15.1 Release Notes

同步管理工具

sync - AnkiWeb 同步

与 AnkiWeb 同步以获取最新数据并推送更改。

前置条件: 桌面版 Anki 必须已登录 AnkiWeb 账户。MCP 服务器没有 API 路径来进行身份验证。

错误处理: 如果未登录,会返回提示建议检查 Anki 连接设置。

资料来源:src/mcp/primitives/essential/tools/sync.tool.ts 资料来源:CLAUDE.md - Upstream AnkiConnect Quirks

工具权限控制

只读模式

可通过 --read-only 全局标志限制所有写操作,防止意外修改 Anki 卡组。

受影响的工具:

  • addNote / addNotes
  • updateNoteFields
  • deleteNotes
  • createModel
  • updateModelStyling
  • sync(需要写权限)

社区需求: 参见 Issue #18:用户希望配置工具权限以防止 AI 意外修改卡组。

常用工作流

创建批量卡片

graph TD
    A[开始] --> B[获取可用标签<br>getTags]
    B --> C[确认标签列表]
    C --> D[获取卡组名称<br>deckNames]
    D --> E[确认目标卡组]
    E --> F[获取模型字段<br>modelFieldNames]
    F --> G[构建笔记数据]
    G --> H[批量创建笔记<br>addNotes]
    H --> I{成功?}
    I -->|是| J[完成]
    I -->|否| K[检查错误]
    K --> G

复习工作流

graph TD
    A[开始复习] --> B[获取到期卡片<br>getDueCards]
    B --> C{有到期卡片?}
    C -->|否| Z[完成]
    C -->|是| D[获取卡片详情]
    D --> E[显示问题<br>presentCard]
    E --> F[用户回忆]
    F --> G[显示答案]
    G --> H[用户评分]
    H --> I[rateCard]
    I --> J{继续复习?}
    J -->|是| D
    J -->|否| K[可选: sync]
    K --> Z

类型定义参考

AnkiCard - 卡片类型

interface AnkiCard {
  cardId: number;      // 卡片 ID
  fields: Record<string, { value: string; order: number }>;
  buttons: string[];  // 评分按钮 ["Again", "Hard", "Good", "Easy"]
  css: string;
  front: string;       // 清理后的正面内容
  back: string;        // 清理后的背面内容
  cardType: CardType;  // "new" | "learning" | "review" | "relearning"
  interval: number;    // 间隔(天)
  due: number;         // Unix 时间戳
  dueString: string;
  lapses: number;      // 遗忘次数
  reps: number;        // 复习次数
  leftToday: number;
  newToday: number;
  reviewedToday: number;
  remaining: number;
}

资料来源:src/mcp/types/anki.types.ts:AnkiCard

CardRating - 评分枚举

enum CardRating {
  Again = 1,  // 重新学习
  Hard = 2,   // 困难
  Good = 3,   // 良好
  Easy = 4    // 简单
}

最佳实践

卡片创建

  1. 使用批量工具:创建多条卡片时使用 addNotes 而非多次调用 addNote
  2. 预先验证:使用 getTagsmodelFieldNames 确认目标结构
  3. 标签一致性:建立统一的标签命名规范,避免重复

复习流程

  1. 定期同步:复习后使用 sync 保持与 AnkiWeb 同步
  2. 批量评分:连续复习时批量使用 rateCard
  3. 状态检查:使用 getCards 检查不同状态的卡片

性能优化

场景建议
大量卡片创建使用 addNotes 批量创建
标签发现使用 getTags 一次性获取,避免重复查询
卡组统计设置合理的 days 参数避免返回过多数据
媒体上传验证文件类型,使用 source: "path" 避免网络请求

相关文档

资料来源:manifest.json:manifest.json.tools

GUI 工具集

GUI 工具集是 anki-mcp-server 中用于与 Anki 桌面应用程序图形界面进行交互的工具模块。与核心复习工具不同,GUI 工具需要用户的显式操作批准,因为它们会打开或操作 Anki 的图形界面组件。这些工具主要用于笔记编辑和创建工作流,而非复习会话。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 模块结构

继续阅读本节完整说明和来源证据。

章节 工具分类

继续阅读本节完整说明和来源证据。

章节 GuiBrowseTool

继续阅读本节完整说明和来源证据。

概述

GUI 工具集是 anki-mcp-server 中用于与 Anki 桌面应用程序图形界面进行交互的工具模块。与核心复习工具不同,GUI 工具需要用户的显式操作批准,因为它们会打开或操作 Anki 的图形界面组件。这些工具主要用于笔记编辑和创建工作流,而非复习会话。

根据 CLAUDE.md 的规范,GUI 工具必须包含双重警告:

  • "IMPORTANT: Only use when user explicitly requests..."
  • "This tool is for note editing/creation workflows, NOT for review sessions"

资料来源:CLAUDE.md

架构设计

模块结构

GUI 工具集采用 NestJS 模块化架构,通过 McpPrimitivesAnkiGuiModule 统一管理所有 GUI 相关工具。

graph TD
    A[McpPrimitivesAnkiGuiModule] --> B[Browser Tools]
    A --> C[Dialog Tools]
    A --> D[Utility Tools]
    
    B --> B1[GuiBrowseTool]
    B --> B2[GuiSelectCardTool]
    B --> B3[GuiSelectedNotesTool]
    
    C --> C1[GuiAddCardsTool]
    C --> C2[GuiEditNoteTool]
    C --> C3[GuiDeckOverviewTool]
    C --> C4[GuiDeckBrowserTool]
    
    D --> D1[GuiCurrentCardTool]
    D --> D2[GuiShowQuestionTool]
    D --> D3[GuiShowAnswerTool]
    D --> D4[GuiUndoTool]

工具分类

分类用途典型场景
Browser Tools卡片浏览器操作搜索、选择笔记
Dialog Tools对话框交互添加卡片、编辑笔记、查看牌组
Utility Tools界面状态查询查看当前卡片、显示问答、撤销操作

资料来源:src/mcp/primitives/gui/index.ts:1-50

浏览器工具

GuiBrowseTool

用于打开 Anki 的卡片浏览器并搜索指定的卡片。此工具不执行复习会话相关的操作。

@Tool({
  name: "guiBrowse",
  description: "Open Anki Card Browser and search for cards...",
  annotations: {
    title: "Browse Cards",
    readOnlyHint: false,
    destructiveHint: false
  }
})

输入参数:

参数类型必需说明
querystringAnki 搜索查询语法

使用限制:

  • 仅用于笔记编辑/创建工作流
  • 不适用于复习会话

资料来源:src/mcp/primitives/gui/tools/gui-browse.tool.ts

GuiSelectCardTool

在卡片浏览器中选中指定 ID 的卡片,用于笔记编辑流程中的卡片定位。

GuiSelectedNotesTool

获取卡片浏览器中当前选中的笔记 ID 列表,返回结果为笔记 ID 数组。

输出结构:

outputSchema: z.object({
  noteIds: z.array(z.number())
})

资料来源:src/mcp/primitives/gui/tools/gui-selected-notes.tool.ts

对话框工具

GuiAddCardsTool

打开 Anki 的添加卡片对话框,允许用户通过图形界面添加新卡片。

GuiEditNoteTool

打开笔记编辑器,允许用户编辑现有笔记的内容和标签。

关键约束: 根据 CLAUDE.md 的说明,updateNoteFields 在目标笔记已在 Anki 浏览窗口中打开时会静默失败,请求返回 200 但字段不会保存。

GuiDeckOverviewTool

打开指定牌组的概览界面。

GuiDeckBrowserTool

打开牌组浏览器界面。

实用工具

GuiCurrentCardTool

获取当前在 Anki 界面中显示的卡片信息。

sequenceDiagram
    Client->>GuiCurrentCardTool: 请求当前卡片
    GuiCurrentCardTool->>AnkiConnectClient: invoke('guiCurrentCard')
    AnkiConnectClient->>Anki: 获取当前卡片
    Anki-->>AnkiConnectClient: 卡片数据
    AnkiConnectClient-->>GuiCurrentCardTool: CardInfo
    GuiCurrentCardTool-->>Client: { cardId, front, back, ... }

资料来源:src/mcp/primitives/gui/tools/gui-current-card.tool.ts

GuiShowQuestionTool

显示卡片的问答面(问题/正面),在复习流程中呈现问题给用户。

GuiShowAnswerTool

显示卡片的答案面(回答/背面),在复习流程中呈现答案给用户。

@Tool({
  name: "guiShowAnswer",
  description: "Show the answer (back) of a card...",
  annotations: {
    title: "Show Answer",
    readOnlyHint: true,
    destructiveHint: false
  }
})

资料来源:src/mcp/primitives/gui/tools/gui-show-answer.tool.ts

GuiUndoTool

撤销 Anki 中的最后一次操作。

工具注解

所有 GUI 工具都必须在 @Tool 装饰器中声明 annotations,包含以下属性:

注解类型说明
titlestring工具的可读标题
readOnlyHintboolean是否为只读操作
destructiveHintboolean是否为破坏性操作
idempotentHintboolean(可选) 操作是否幂等

资料来源:CLAUDE.md

安全考虑

用户批准机制

GUI 工具通过 AnkiConnect API 与 Anki 桌面应用交互,用户在 Anki 中的操作(如打开编辑器、选择卡片)需要用户显式批准。这提供了一层保护,防止 AI 代理在用户不知情的情况下修改笔记。

读/写模式

根据 issue #18 的功能请求,用户希望配置可配置的工具有限权限(只读模式)。GUI 工具集中的写操作工具(如 GuiEditNoteTool)在只读模式下应被禁用。

区分复习和工作流

文档明确区分了两种使用场景:

场景适用工具工具描述
复习会话presentCard, rate_card核心复习工具
笔记编辑/创建GUI 工具需要用户界面交互

资料来源:manifest.json, issue #18

与核心工具的区别

特性核心复习工具GUI 工具集
传输方式STDIO/Streamable HTTP需要 Anki 桌面应用运行
用户批准自动执行需要用户界面操作
适用场景自动化复习笔记编辑/创建工作流
依赖AnkiConnect APIAnkiConnect API + GUI 交互

错误处理

GUI 工具使用统一的错误响应格式:

return createErrorResponse(error, {
  context: "额外错误上下文信息",
  hint: "用户可执行的修复建议"
});

错误处理会捕获常见的失败场景,如:

  • Anki 未运行
  • 指定的卡片/笔记不存在
  • 网络连接问题

资料来源:src/mcp/utils/anki.utils.ts

模块导出

src/mcp/primitives/gui/index.ts 统一导出所有 GUI 相关的工具和类型:

// Tools - Browser
export { GuiBrowseTool } from "./tools/gui-browse.tool";
export { GuiSelectCardTool } from "./tools/gui-select-card.tool";
export { GuiSelectedNotesTool } from "./tools/gui-selected-notes.tool";

// Tools - Dialog
export { GuiAddCardsTool } from "./tools/gui-add-cards.tool";
export { GuiEditNoteTool } from "./tools/gui-edit-note.tool";
export { GuiDeckOverviewTool } from "./tools/gui-deck-overview.tool";
export { GuiDeckBrowserTool } from "./tools/gui-deck-browser.tool";

// Tools - Utility
export { GuiCurrentCardTool } from "./tools/gui-current-card.tool";
export { GuiShowQuestionTool } from "./tools/gui-show-question.tool";
export { GuiShowAnswerTool } from "./tools/gui-show-answer.tool";
export { GuiUndoTool } from "./tools/gui-undo.tool";

资料来源:src/mcp/primitives/gui/index.ts:9-30

资料来源:CLAUDE.md

故障排除

本页面汇总了 anki-mcp-server 使用过程中常见的错误场景、根本原因分析以及解决方案。所有错误处理逻辑均基于源代码中的实际实现。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 1. ERRREQUIREESM 启动崩溃

继续阅读本节完整说明和来源证据。

章节 2. AnkiConnect 超时错误

继续阅读本节完整说明和来源证据。

章节 3. Ngrok 隧道启动失败

继续阅读本节完整说明和来源证据。

常见错误与解决方案

1. ERR_REQUIRE_ESM 启动崩溃

错误信息:

Error [ERR_REQUIRE_ESM]: require() of ES Module...

影响版本: v0.8.5 及更早版本 根本原因: ky 是一个纯 ESM 模块,在 Node.js 21.x 环境下无法通过 CommonJS 的 require() 加载。

解决方案:

操作说明
升级 Node.js升级到 Node.js 22.x 或 Node.js 20.17+
检查版本运行 node --version 确认版本

项目 package.json 中已明确声明 engines 字段要求 Node.js >= 20.19.0:

"engines": {
  "node": ">=20.19.0"
}

资料来源:package.json:38

2. AnkiConnect 超时错误

错误信息:

AnkiConnect request timeout

社区反馈: Issue #22 报告在批量创建卡片时频繁出现超时。 根本原因: AnkiConnect 基于 Qt 单线程事件循环,高并发请求会导致响应延迟。

解决方案:

  1. 使用批量操作工具 - 优先使用 addNotes 而非多次调用 addNote
// 正确方式:批量添加
addNotes({
  notes: [
    { deckName: "MyDeck", modelName: "Basic", fields: {...} },
    { deckName: "MyDeck", modelName: "Basic", fields: {...} }
  ]
})

// 避免:连续多次调用
for (const note of notes) {
  addNote(note) // 每次调用都产生网络往返
}
  1. 检查 Anki 运行状态 - 确保 Anki 应用程序正在运行且 AnkiConnect 插件已启用
  1. 增加超时配置 - 在 AnkiConnect 设置中调整超时时间

资料来源:CLAUDE.md (Upstream AnkiConnect Quirks 部分)

3. Ngrok 隧道启动失败

错误信息:

failed to start ngrok

社区反馈: Issue #9 报告 ngrok 3.24.0-msix 版本与服务器不兼容。 解决方案: 使用 ngrok v7.0 或更高版本:

npx [email protected]

4. 卡片创建时字段为空被拒绝

社区反馈: Issue #20 报告部分笔记类型的字段是可选的,但工具拒绝空字段。

当前行为: 系统会验证必填字段,阻止创建包含空值的笔记。

建议方案:

  • 检查笔记类型定义,确认哪些字段是可选的
  • 如需支持空字段,可考虑使用 updateNoteFields 事后清空

错误处理架构

错误响应生成流程

graph TD
    A[AnkiConnect 请求] --> B{请求成功?}
    B -->|是| C[返回原始数据]
    B -->|否| D[捕获 AnkiConnectError]
    D --> E{错误类型识别}
    E -->|模型未找到| F[生成错误提示<br/>使用 modelNames 获取可用模型]
    E -->|笔记未找到| G[生成错误提示<br/>检查笔记ID]
    E -->|其他错误| H[通用错误信息]
    F --> I[createErrorResponse]
    G --> I
    H --> I
    I --> J[返回 CallToolResult<br/>isError: true]

createErrorResponse 函数负责将各种错误场景转换为统一的 MCP 错误响应格式:

// src/mcp/utils/anki.utils.ts
export function createErrorResponse(
  error: AnkiConnectError,
  context?: Record<string, string>
): CallToolResult {
  return {
    content: [
      {
        type: "text",
        text: formatAnkiError(error, context),
      },
    ],
    isError: true,
  };
}

资料来源:src/mcp/utils/anki.utils.ts

AnkiConnect 客户端重试机制

graph LR
    A[MCP Tool 调用] --> B[ky HTTP Client]
    B --> C{请求成功?}
    C -->|是| D[返回结果]
    C -->|否| E{重试次数 < 3?}
    E -->|是| F[等待后重试]
    F --> B
    E -->|否| G[抛出 AnkiConnectError]

客户端实现了自动重试机制,默认最多重试 3 次:

// src/mcp/clients/anki-connect.client.ts
export class AnkiConnectClient {
  async invoke<T>(action: string, params?: Record<string, unknown>): Promise<T> {
    // ... 重试逻辑实现
  }
}

资料来源:src/mcp/clients/anki-connect.client.ts

AnkiConnect 上游特性与限制

以下行为属于 AnkiConnect 本身的特性,anki-mcp-server 无法绕过:

行为描述规避方案
updateNoteFields 在笔记打开时静默失败在 Anki 浏览器中打开笔记后更新不会生效更新前关闭浏览器或切换笔记
Model CSS 是按笔记类型共享的所有使用同一模型的卡片共享 CSS使用 modelStyling 获取,updateNoteFields 保留内联样式
sync 需要桌面应用登录无法通过 API 路径认证确保 Anki 已登录 AnkiWeb
deleteNotes 不可逆删除笔记会级联删除所有关联卡片必须设置 confirmDeletion: true

资料来源:CLAUDE.md

安全验证错误

媒体文件安全

v0.15.1 版本后添加了多层安全验证:

验证类型攻击场景处理方式
MIME 类型检查上传恶意文件绕过扩展名白名单验证
路径遍历检查通过 ../ 读取任意文件规范化路径后验证
SSRF 检查通过 URL 参数访问内网资源URL 源验证

验证失败时会返回安全错误:

// src/mcp/utils/media-validation.utils.ts
export function validateMediaPath(path: string): ValidationResult {
  // 路径遍历检测
  // MIME 类型白名单验证
  // 返回验证结果
}

资料来源:src/mcp/utils/media-validation.utils.ts

调试步骤

1. 环境检查

# 检查 Node.js 版本
node --version

# 检查 anki-mcp-server 版本
npx @ankimcp/anki-mcp-server --version

# 验证 Anki 运行状态
curl http://localhost:8765 -d '{"action": "version", "version": 6}'

2. 启用调试日志

项目使用 Pino 进行日志记录:

# 启动服务并查看详细日志
DEBUG=pino:* npx @ankimcp/anki-mcp-server --stdio

3. MCP Inspector 调试

使用 MCP Inspector 检查工具调用:

npx @modelcontextprotocol/inspector \
  npx @ankimcp/anki-mcp-server --stdio

版本历史问题

版本问题状态
v0.8.5ERR_REQUIRE_ESM 在 Node 21.x已修复 - Node >= 20.19.0
v0.15.1媒体路径遍历漏洞已修复 - 安全验证
v0.14.0批量添加工具缺失已修复 - addNotes 工具
v0.18.5-tunnel.2ngrok 兼容性问题持续改进

资料来源:CHANGELOG.md

获取帮助

如果以上方案无法解决您的问题:

  1. 检查 GitHub Issues - 搜索类似问题的解决方案
  1. 提交新 Issue - 请包含以下信息:
  • 操作系统和 Node.js 版本
  • anki-mcp-server 版本
  • Anki 版本和 AnkiConnect 插件版本
  • 完整的错误日志
  • 重现步骤

资料来源:package.json:38

命令行参考

Anki MCP Server 提供多种命令行启动方式,支持 STDIO 传输和 HTTP 隧道两种主要模式。本页面详细说明所有可用的命令行选项、配置参数和使用场景。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 前置要求

继续阅读本节完整说明和来源证据。

章节 安装方式

继续阅读本节完整说明和来源证据。

章节 基本语法

继续阅读本节完整说明和来源证据。

概述

Anki MCP Server 是一个基于 Model Context Protocol (MCP) 的 Anki 闪卡应用程序服务器。它通过 AnkiConnect 插件与 Anki 通信,使 AI 助手能够与用户的 Anki 集合进行交互。

支持的运行模式:

模式传输协议典型用途
STDIO标准输入输出Claude Desktop、VS Code 等 MCP 客户端
HTTP + NgrokStreamable HTTP + 隧道远程访问、跨网络连接

安装与前置条件

前置要求

  • Node.js: >=20.19.0(Node 21.x 不支持,详见 Issue #17
  • Anki: 已安装并运行
  • AnkiConnect 插件: 在 Anki 中安装(插件 ID: 2055492159

安装方式

# 全局安装
npm install -g @ankimcp/anki-mcp-server

# 或使用 npx 直接运行
npx -y @ankimcp/anki-mcp-server --stdio

STDIO 模式

STDIO 模式是 MCP 客户端(如 Claude Desktop)的标准连接方式。

基本语法

anki-mcp --stdio

选项参数

参数类型默认值说明
--stdiobooleanfalse启用 STDIO 传输模式
--anki-portnumber8765AnkiConnect HTTP 服务端口
--anki-hoststring"127.0.0.1"AnkiConnect 主机地址
--read-onlybooleanfalse启用只读模式,禁用所有写操作
--timeoutnumber30请求超时时间(秒)
--log-levelstring"info"日志级别 (trace, debug, info, warn, error)
--verbosebooleanfalse启用详细日志输出

完整示例

# 标准启动
anki-mcp --stdio

# 自定义 AnkiConnect 连接
anki-mcp --stdio --anki-port 8765 --anki-host 127.0.0.1

# 只读模式(社区功能请求 - Issue #18)
anki-mcp --stdio --read-only

# 启用调试日志
anki-mcp --stdio --log-level debug --verbose

Claude Desktop 配置

claude_desktop_config.json 中配置:

{
  "mcpServers": {
    "anki": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
      "env": {}
    }
  }
}

HTTP 隧道模式

HTTP 隧道模式通过 Ngrok 创建公共 URL,支持远程访问 Anki MCP Server。

基本语法

anki-mcp --tunnel

隧道模式选项

参数类型默认值说明
--tunnelbooleanfalse启用 Ngrok 隧道模式
--tunnel-portnumber8080本地 HTTP 服务端口
--auth-tokenstring-Ngrok 认证令牌
--domainstring-Ngrok 自定义域名

Ngrok 认证配置

首次使用隧道模式需要配置 Ngrok 认证:

  1. 注册 Ngrok 账号
  2. 获取 Authtoken
  3. 配置 Ngrok:
ngrok config add-authtoken <YOUR_AUTH_TOKEN>

完整示例

# 基本隧道启动
anki-mcp --tunnel

# 自定义本地端口
anki-mcp --tunnel --tunnel-port 9090

# 使用 Ngrok authtoken
anki-mcp --tunnel --auth-token <YOUR_TOKEN>

注意: Ngrok 模式曾报告启动问题(见 Issue #9),如遇 "failed to start ngrok" 错误,建议检查 Ngrok 版本。

只读模式

只读模式是社区请求的功能(Issue #18),用于限制 MCP 服务器的操作权限,防止意外修改 Anki 集合。

启用方式

anki-mcp --stdio --read-only

只读模式的限制

启用后,以下操作将被阻止:

操作类型受影响工具
创建笔记addNote, addNotes
更新笔记updateNoteFields
删除笔记deleteNotes
管理牌组createDeck, deleteDeck
管理模板createModel, updateModelStyling
复习操作rateCard
媒体操作storeMediaFile

允许的操作(只读)

  • get_due_cards - 获取到期卡片
  • get_cards - 获取卡片信息
  • present_card - 展示卡片
  • modelNames - 列出模板
  • modelFieldNames - 获取字段名
  • getTags - 获取标签列表
  • guiBrowse - 浏览窗口
  • 统计工具

环境变量

除命令行参数外,部分配置也可通过环境变量设置:

变量名说明对应参数
ANKI_PORTAnkiConnect 端口--anki-port
ANKI_HOSTAnkiConnect 主机--anki-host
ANKI_TIMEOUT请求超时(秒)--timeout
LOG_LEVEL日志级别--log-level
READ_ONLY只读模式--read-only

连接架构

graph TD
    subgraph "MCP 客户端"
        A[Claude Desktop / VS Code]
    end
    
    subgraph "Anki MCP Server"
        B[CLI 解析层]
        C[传输层]
        D[业务逻辑层]
    end
    
    subgraph "AnkiConnect"
        E[HTTP 服务]
        F[Anki 应用]
    end
    
    A -->|MCP 协议| B
    B --> C
    C -->|STDIO 或 HTTP| D
    D -->|JSON-RPC| E
    E -->|API| F
    
    style A fill:#e1f5fe
    style F fill:#c8e6c9
    style D fill:#fff3e0

常见问题与故障排除

ERR_REQUIRE_ESM 错误

问题: Node.js 21.x 用户遇到启动崩溃(Issue #12Issue #16

原因: 项目依赖的 ky 库是纯 ESM 模块,Node.js 21.x 不支持此加载方式

解决方案:

  • 降级至 Node.js 20.19+ 或升级至 Node.js 22+
  • 或使用 npx 自动获取兼容版本

AnkiConnect 超时

问题: 创建卡片时频繁超时(Issue #22

原因: AnkiConnect 基于 Qt 单线程事件循环,高并发请求会导致排队

解决方案:

  • 使用 addNotes 批量创建而非多次 addNote 调用
  • 增加 --timeout 参数值
  • 检查 Anki 是否正在执行同步操作

Ngrok 启动失败

问题: Ngrok 隧道模式启动失败(Issue #9

解决方案:

  • 验证 Ngrok authtoken 配置正确
  • 检查 Ngrok 版本(建议 3.x)
  • 确认防火墙允许 Ngrok 出站连接

退出码

退出码含义
0正常退出
1一般错误(参数错误、连接失败等)
2AnkiConnect 连接失败
130收到 SIGINT (Ctrl+C) 中断信号

相关文档

来源:https://github.com/ankimcp/anki-mcp-server / 项目说明书

安全特性

Anki MCP Server 实现了多层次的安全机制,用于保护用户数据免受恶意请求、路径遍历攻击、服务器端请求伪造(SSRF)等安全威胁。本页面详细说明服务器的安全架构、实现机制和配置选项。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 概述

继续阅读本节完整说明和来源证据。

章节 MIME 类型白名单

继续阅读本节完整说明和来源证据。

章节 路径遍历防护

继续阅读本节完整说明和来源证据。

架构概览

Anki MCP Server 的安全体系由以下几个核心模块组成:

graph TD
    A[客户端请求] --> B{传输层}
    B --> C[STDIO 传输]
    B --> D[HTTP 传输]
    D --> E[来源验证守卫]
    E --> F[API Key 认证]
    D --> G[媒体文件操作]
    G --> H[媒体安全验证]
    H --> I{MIME 类型检查}
    H --> J{路径规范化检查}
    H --> K{URL 参数验证}
    I --> L[允许列表验证]
    J --> M[禁止遍历序列]
    K --> N[DNS 重绑定防护]
    
    style A fill:#e1f5fe
    style L fill:#c8e6c9
    style M fill:#c8e6c9
    style N fill:#c8e6c9

媒体安全验证

概述

v0.15.1 版本引入了媒体操作的安全加固,针对 storeMediaFile 工具的路径遍历漏洞和 URL 参数的 SSRF 风险实施了多层验证。该安全更新由安全研究员 Hideaki Takahashi 报告。

资料来源:SECURITY.md

MIME 类型白名单

媒体文件上传必须通过 MIME 类型白名单验证。服务器仅允许预定义的安全文件类型:

类型分类允许的 MIME 类型
图片image/jpeg, image/png, image/gif, image/webp, image/svg+xml
音频audio/mpeg, audio/wav, audio/ogg, audio/flac
视频video/mp4, video/webm, video/ogg
文档application/pdf
// src/mcp/utils/media-validation.utils.ts
export const ALLOWED_MIME_TYPES = [
  // Images
  "image/jpeg",
  "image/png",
  "image/gif",
  "image/webp",
  "image/svg+xml",
  // Audio
  "audio/mpeg",
  "audio/wav",
  "audio/ogg",
  "audio/flac",
  // Video
  "video/mp4",
  "video/webm",
  "video/ogg",
  // Documents
  "application/pdf",
] as const;

资料来源:src/mcp/utils/media-validation.utils.ts

路径遍历防护

storeMediaFile 工具实现了路径规范化检查,防止攻击者通过 ../ 等序列访问用户目录之外的敏感文件:

export function isPathSafe(filePath: string): boolean {
  const normalized = path.normalize(filePath);
  return (
    !normalized.includes("..") &&
    path.isAbsolute(filePath) === false &&
    !normalized.startsWith("/")
  );
}

关键检查规则:

  • 禁止路径中包含 .. 遍历序列
  • 不允许绝对路径
  • 禁止以 / 开头的路径

资料来源:src/mcp/utils/media-validation.utils.ts

SSRF 防护

对于通过 URL 参数传入的媒体文件,服务器实施以下防护措施:

  1. URL 协议验证:仅允许 http://https:// 协议
  2. DNS 重绑定保护:验证 Host 头部,防止私有 IP 地址范围访问
  3. 重定向限制:验证最终请求目标,防止重定向到内部网络
// src/mcp/utils/media-validation.utils.ts
export function validateUrlSafety(url: string): boolean {
  try {
    const parsed = new URL(url);
    if (!["http:", "https:"].includes(parsed.protocol)) {
      return false;
    }
    // Additional DNS rebinding protection
    return !isPrivateIpRange(parsed.hostname);
  } catch {
    return false;
  }
}

资料来源:src/mcp/utils/media-validation.utils.ts

HTTP 传输安全

来源验证守卫

HTTP 传输模式使用来源验证守卫(Origin Validation Guard)防止跨站请求攻击:

// src/http/guards/origin-validation.guard.ts
@Injectable()
export class OriginValidationGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const origin = request.headers.origin;
    
    // Validate against allowed origins
    const allowedOrigins = this.configService.getAllowedOrigins();
    if (!allowedOrigins.includes(origin)) {
      throw new ForbiddenException('Invalid origin');
    }
    return true;
  }
}

资料来源:src/http/guards/origin-validation.guard.ts

API Key 认证

HTTP 端点使用 JWT API Key 进行身份验证:

// src/http/strategies/api-key.strategy.ts
@Injectable()
export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') {
  constructor(private configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
      secretOrKey: configService.getApiKeySecret(),
    });
  }
}

资料来源:src/http/strategies/api-key.strategy.ts

只读模式

用户可以通过命令行参数启用只读模式,防止 MCP 服务器执行任何写入操作:

npx @ankimcp/anki-mcp-server --read-only --stdio

资料来源:src/config/anki-config.interface.ts

配置接口

export interface IAnkiConfig {
  readonly?: boolean;
  ankiHost?: string;
  ankiPort?: number;
  // ... other config options
}

只读模式会阻止以下操作:

  • 创建笔记 (addNote, addNotes)
  • 更新笔记字段 (updateNoteFields)
  • 删除笔记 (deleteNotes)
  • 存储媒体文件 (storeMediaFile)
  • 创建卡牌模板 (createModel)

资料来源:src/mcp/clients/anki-connect.client.ts

工具注解与权限控制

每个 MCP 工具都通过注解(annotations)声明其安全属性:

注解类型说明示例
readOnlyHint标识只读操作truefalse
destructiveHint标识破坏性操作truefalse
idempotentHint标识幂等操作truefalse
// 示例:storeMediaFile 工具注解
annotations: {
  readOnlyHint: false,
  destructiveHint: false,
  idempotentHint: false,
},

资料来源:src/mcp/clients/anki-connect.client.ts

安全报告

Anki MCP Server 遵循负责任的安全披露原则。如需报告安全漏洞,请参考 SECURITY.md

已知限制

问题编号描述当前状态
#18缺少细粒度工具权限配置(per-tool control)功能请求中
#22批量创建卡片时可能触发 AnkiConnect 超时建议使用 addNotes 批量工具

资料来源:SECURITY.md

开发指南

本指南面向希望为 anki-mcp-server 项目贡献代码、扩展功能或深入了解项目架构的开发者。anki-mcp-server 是一个基于 Model Context Protocol (MCP) 的 Anki 间隔重复记忆应用服务器,使 AI 助手能够与 Anki 进行自然语言交互。

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 Node.js 版本要求

继续阅读本节完整说明和来源证据。

章节 核心依赖

继续阅读本节完整说明和来源证据。

章节 开发脚本

继续阅读本节完整说明和来源证据。

环境要求与项目设置

Node.js 版本要求

项目明确要求 Node.js >= 20.19.0< 21.0.0。Node 21.x 由于缺少 require(esm) 特性支持会导致 ERR_REQUIRE_ESM 错误。

"engines": {
  "node": ">=20.19.0 <21.0.0"
}

资料来源:package.json:7-9

核心依赖

依赖包版本用途
@modelcontextprotocol/sdk精确版本 1.29.0MCP 协议实现
zod^4.3.6数据验证(注意:使用 v4 而非 v3)
ky^1.14.3HTTP 客户端(ESM 模块)
@rekog/mcp-nest-MCP-Nest 框架
@nestjs/common-NestJS 核心

资料来源:package.json:31-62

开发脚本

# 构建项目
npm run build

# STDIO 模式开发(热重载)
npm run start:dev:stdio

# HTTP 模式开发(热重载)
npm run start:dev:http

# 生产环境启动
npm run start:prod:stdio
npm run start:prod:http

# 代码检查与格式化
npm run lint
npm run format

# 测试
npm run test

资料来源:package.json:17-28

项目架构概览

anki-mcp-server/
├── src/
│   ├── main-stdio.ts           # STDIO 传输入口
│   ├── main-http.ts           # HTTP 传输入口
│   ├── main-tunnel.ts         # Ngrok 隧道入口
│   ├── app.module.ts          # 根模块
│   ├── config/                # 配置相关
│   │   ├── anki-config.interface.ts  # 配置接口
│   │   └── anki-config.loader.ts      # 配置加载器
│   ├── services/              # 服务层
│   │   └── ngrok.service.ts  # Ngrok 隧道管理
│   └── mcp/                   # MCP 核心模块
│       ├── clients/           # AnkiConnect HTTP 客户端
│       ├── config/           # MCP 配置
│       ├── types/            # 共享类型定义
│       ├── utils/            # 工具函数
│       └── primitives/       # 工具、提示词、资源
│           ├── essential/    # 核心工具
│           └── gui/          # GUI 交互工具
├── test/                     # 测试文件
├── scripts/                  # 构建脚本
└── bin/                      # CLI 入口

资料来源:CLAUDE.md:1-22

传输模式架构

项目支持三种传输模式:

graph TD
    A[客户端] --> B{传输模式}
    B -->|stdio| C[main-stdio.ts]
    B -->|http| D[main-http.ts]
    B -->|tunnel| E[main-tunnel.ts + Ngrok]
    
    C --> F[McpModule STDIO]
    D --> G[McpModule STREAMABLE_HTTP]
    E --> G
    E --> H[NgrokService]
    
    F --> I[AnkiConnect Client]
    G --> I
    H --> J[AnkiConnect]
    
    I --> K[Anki 桌面应用]
    J --> K

模块系统

应用模块结构

AppModule.forStdio() / forHttp()
  → McpModule.forRoot()           // STDIO 或 STREAMABLE_HTTP 传输
  → McpPrimitivesAnkiEssentialModule.forRoot()  // 核心工具
  → McpPrimitivesAnkiGuiModule.forRoot()       // GUI 工具

资料来源:CLAUDE.md:24-31

模块发现机制

所有工具、提示词和资源通过 @rekog/mcp-nest 自动发现。MCP-Nest 1.9.0+ 要求工具同时在 AppModule.providers 中声明(参见 ESSENTIAL_MCP_TOOLSGUI_MCP_TOOLS 数组)。

工具开发规范

标准工具结构

每个 MCP 工具应遵循以下模式:

// 1. Zod schema 用于输入验证
// 2. @Injectable() 类注入 AnkiConnectClient
// 3. @Tool 装饰器定义元数据
// 4. execute() 方法调用 AnkiConnectClient.invoke()
// 5. 成功返回匹配 outputSchema 的原始对象
// 6. 错误返回 createErrorResponse()

资料来源:CLAUDE.md:67-75

最小工具示例

import { Injectable, Logger } from "@nestjs/common";
import { Tool } from "@rekog/mcp-nest";
import { z } from "zod";
import { AnkiConnectClient } from "@/mcp/clients/anki-connect.client";
import { createErrorResponse } from "@/mcp/utils/anki.utils";

@Injectable()
export class SyncTool {
  private readonly logger = new Logger(SyncTool.name);

  constructor(private readonly ankiClient: AnkiConnectClient) {}

  @Tool({
    name: "sync",
    description: "Sync with AnkiWeb to get latest data and push changes",
    parameters: z.object({}),
    outputSchema: z.object({
      success: z.boolean(),
      message: z.string(),
    }),
    annotations: {
      title: "Sync Collection",
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
    },
  })
  async execute() {
    try {
      const result = await this.ankiClient.invoke("sync", {});
      return result;
    } catch (error) {
      return createErrorResponse(error, {
        hint: "Make sure Anki is running and logged into AnkiWeb.",
      });
    }
  }
}

资料来源:src/mcp/primitives/essential/tools/sync.tool.ts

@Tool 装饰器参数

参数类型说明
namestring工具唯一名称
descriptionstring工具描述,用于 AI 理解功能
parametersZodSchema输入参数验证 schema
outputSchemaZodSchema输出数据结构 schema
annotationsobject包含 readOnlyHintdestructiveHintidempotentHint

outputSchema 与错误处理

  • 成功路径:返回匹配 outputSchema 的原始对象,MCP-Nest handler 自动验证并包装
  • 错误路径:使用 createErrorResponse() 返回,跳过 outputSchema 验证
// 错误响应示例
return createErrorResponse(error, {
  modelName,
  hint: "Model not found. Use modelNames tool to see available models.",
});

资料来源:CLAUDE.md:53-62

GUI 工具特殊要求

GUI 工具位于 src/mcp/primitives/gui/,必须包含双重警告:

  1. "IMPORTANT: Only use when user explicitly requests..."
  2. "This tool is for note editing/creation workflows, NOT for review sessions"

数据类型定义

核心类型

// 添加笔记参数
interface AddNoteParams {
  deckName: string;                    // 目标牌组
  modelName: string;                   // 笔记类型
  fields: Record<string, string>;      // 字段键值对
  tags?: string[];                     // 可选标签
  options?: NoteOptions;                // 重复检查选项
}

// 笔记类型/模型信息
interface Model {
  name: string;      // 模型名称
  id: number;        // 唯一标识符
  css: string;       // CSS 样式
  fields: string[];  // 字段名称数组
}

// 笔记详细信息
interface NoteInfo {
  noteId: number;
  modelName: string;
  tags: string[];
  fields: Record<string, { value: string; order: number }>;
  cards: number[];
  mod: number;
}

资料来源:src/mcp/types/anki.types.ts

工具函数

错误响应创建

import { createErrorResponse } from "@/mcp/utils/anki.utils";

// 返回 CallToolResult,isError: true,绕过 outputSchema 验证
return createErrorResponse(error, {
  field: "value",
  hint: "Helpful error message",
});

资料来源:src/mcp/utils/anki.utils.ts:1-10

HTML 清理

import { cleanHtml } from "@/mcp/utils/anki.utils";

// 移除 HTML 标签并解码 HTML 实体
const cleanText = cleanHtml(html);

Markdown 解析

import { parseMarkdownSections } from "@/mcp/utils/markdown.utils";

// 按 H1 标题分割 Markdown 内容
const sections = parseMarkdownSections(markdown);
// 返回: { "Description": "...", "Content": "..." }

路径别名配置

项目配置了 TypeScript 路径别名:

别名指向
@/*src/*
@test/*test/*
// 示例导入
import { AnkiConnectClient } from "@/mcp/clients/anki-connect.client";
import { Something } from "@test/helpers";

资料来源:CLAUDE.md:88-91

测试策略

项目采用三层测试策略,根据变更类型选择合适的测试级别:

graph LR
    A[变更类型] --> B{选择测试}
    B -->|工具逻辑| C[单元测试]
    B -->|集成流程| D[集成测试]
    B -->|端到端| E[E2E 测试]

测试目录结构

test/
├── unit/           # 单元测试
├── integration/    # 集成测试
└── e2e/           # 端到端测试

常见陷阱与限制

AnkiConnect 上游行为

项目中标注了以下上游行为,开发时需要注意:

行为说明处理方式
updateNoteFields 静默失败目标笔记在浏览窗口打开时不保存在工具描述中警告用户
Model CSS 是按笔记类型而非按笔记获取 CSS 用 modelStyling,判断模型用 notesInfo更新笔记时保留内联样式
sync 依赖桌面应用登录状态无 API 路径进行身份验证返回提示性错误信息
deleteNotes 不可逆且级联删除所有相关卡片一并删除要求 confirmDeletion: true

资料来源:CLAUDE.md:40-50

Zod 版本注意

项目使用 Zod v4zod@^4.x),不是 v3。Zod 4 有不同的 API:

  • 使用 z.interface() 而非 z.object()(在某些场景)
  • 错误处理方式不同
// Zod v4 正确用法
const schema = z.object({
  name: z.string(),
  age: z.number(),
});

Claude Desktop 集成

安装配置

在 Claude Desktop 配置文件 (~/.config/Claude/claude_desktop_config.json) 中添加:

{
  "mcpServers": {
    "anki-mcp-server": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server"],
      "env": {
        "ANKI_HOST": "127.0.0.1",
        "ANKI_PORT": "8765"
      }
    }
  }
}

环境变量

变量默认值说明
ANKI_HOST127.0.0.1AnkiConnect 主机地址
ANKI_PORT8765AnkiConnect 端口
ANKI_READ_ONLYfalse只读模式标志

社区已知问题

开发时需注意以下社区反馈的问题:

Issue状态说明
#22: 创建卡片超时已知AnkiConnect 单线程 Qt 事件循环在高并发下超时
#21: 批量创建性能功能请求addNotes 批量工具已提供,建议优先使用
#20: 空字段处理已知当前对空字段有检查,可选字段场景受限
#16: ERR_REQUIRE_ESM已修复Node 21.x 不支持,已排除在 engines 范围外

资料来源:community_context

代码规范

ESLint 配置

项目使用 ESLint 进行代码检查,配置文件位于 eslint.config.mjs

Prettier 格式化

# 格式化所有源码
npm run format

TypeScript 配置

  • strict: true - 严格类型检查
  • module: "nodenext" - Node.js ESM 支持
  • target: "ES2023" - 编译目标

发布流程

项目使用语义化版本控制,当前处于 0.x.x beta 阶段,允许破坏性变更。

发布通过 GitHub Actions 自动完成,发布说明由合并的 PR 自动生成。

# 构建并发布
npm run build
npm publish

资料来源:CHANGELOG.md

扩展开发清单

新增工具时的检查清单:

  • [ ] 创建 *.tool.ts 文件于 src/mcp/primitives/essential/src/mcp/primitives/gui/
  • [ ] 定义 Zod 输入/输出 schema
  • [ ] 使用 @Injectable()@Tool() 装饰器
  • [ ] 在 ESSENTIAL_MCP_TOOLSGUI_MCP_TOOLS 数组中注册
  • [ ] 添加单元测试
  • [ ] 更新 manifest.json 工具列表(如需要)
  • [ ] 更新本开发指南文档

资料来源:package.json:7-9

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 来源证据:Anki mcp for mcp clients fails with 'ERR_REQUIRE_ESM'

可能增加新用户试用和生产接入成本。

medium 来源证据:Crash on startup: ERR_REQUIRE_ESM when requiring 'ky'

可能阻塞安装或首次运行。

medium 来源证据:Feature Request: Deck and Collection Level Statistics

可能增加新用户试用和生产接入成本。

medium 来源证据:Not possible to install Anki MCP 0.8.4 to latest Claude Desktop Claude 1.0.1307 (1ed883)

可能增加新用户试用和生产接入成本。

Pitfall Log / 踩坑日志

项目:ankimcp/anki-mcp-server

摘要:发现 14 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:安装坑 - 来源证据:Anki mcp for mcp clients fails with 'ERR_REQUIRE_ESM'。

1. 安装坑 · 来源证据:Anki mcp for mcp clients fails with 'ERR_REQUIRE_ESM'

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Anki mcp for mcp clients fails with 'ERR_REQUIRE_ESM'
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_7f29acec242e48c9b9a28ff2585734d3 | https://github.com/ankimcp/anki-mcp-server/issues/12 | 来源讨论提到 node 相关条件,需在安装/试用前复核。

2. 安装坑 · 来源证据:Crash on startup: ERR_REQUIRE_ESM when requiring 'ky'

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Crash on startup: ERR_REQUIRE_ESM when requiring 'ky'
  • 对用户的影响:可能阻塞安装或首次运行。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_66dcd7ebe4a842228360620571d902f5 | https://github.com/ankimcp/anki-mcp-server/issues/16 | 来源讨论提到 node 相关条件,需在安装/试用前复核。

3. 安装坑 · 来源证据:Feature Request: Deck and Collection Level Statistics

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Feature Request: Deck and Collection Level Statistics
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_e49f272712124771bc55365bbe3ad1cc | https://github.com/ankimcp/anki-mcp-server/issues/14 | 来源讨论提到 npm 相关条件,需在安装/试用前复核。

4. 安装坑 · 来源证据:Not possible to install Anki MCP 0.8.4 to latest Claude Desktop Claude 1.0.1307 (1ed883)

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Not possible to install Anki MCP 0.8.4 to latest Claude Desktop Claude 1.0.1307 (1ed883)
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_82a572d18c7b4eac9facb5ff06652bc5 | https://github.com/ankimcp/anki-mcp-server/issues/10 | 来源类型 github_issue 暴露的待验证使用条件。

5. 安装坑 · 来源证据:ngrok fails to start with latest version

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:ngrok fails to start with latest version
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_bd4f26c6db6b4db8adc1436a457ff69a | https://github.com/ankimcp/anki-mcp-server/issues/9 | 来源讨论提到 npm 相关条件,需在安装/试用前复核。

6. 配置坑 · 来源证据:Explicitly exclude Node 21.x in engines field

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个配置相关的待验证问题:Explicitly exclude Node 21.x in engines field
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_0a42c043dbad4d93a4731734d006fa08 | https://github.com/ankimcp/anki-mcp-server/issues/17 | 来源讨论提到 node 相关条件,需在安装/试用前复核。

7. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 建议检查:将假设转成下游验证清单。
  • 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
  • 证据:capability.assumptions | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | README/documentation is current enough for a first validation pass.

8. 运行坑 · 来源证据:getting lots of timeouts creating cards

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个运行相关的待验证问题:getting lots of timeouts creating cards
  • 对用户的影响:可能增加新用户试用和生产接入成本。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_92310c7e5cea46d48a7643da19e2d5a6 | https://github.com/ankimcp/anki-mcp-server/issues/22 | 来源类型 github_issue 暴露的待验证使用条件。

9. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
  • 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
  • 证据:evidence.maintainer_signals | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | last_activity_observed missing

10. 安全/权限坑 · 下游验证发现风险项

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:下游已经要求复核,不能在页面中弱化。
  • 建议检查:进入安全/权限治理复核队列。
  • 防护动作:下游风险存在时必须保持 review/recommendation 降级。
  • 证据:downstream_validation.risk_items | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | no_demo; severity=medium

11. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 建议检查:把风险写入边界卡,并确认是否需要人工复核。
  • 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
  • 证据:risks.scoring_risks | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | no_demo; severity=medium

12. 安全/权限坑 · 来源证据:Feature: Configurable tool permissions (read-only mode)

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:Feature: Configurable tool permissions (read-only mode)
  • 对用户的影响:可能阻塞安装或首次运行。
  • 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
  • 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
  • 证据:community_evidence:github | cevd_65de282533484baf95eaa214c669167b | https://github.com/ankimcp/anki-mcp-server/issues/18 | 来源类型 github_issue 暴露的待验证使用条件。

13. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
  • 防护动作:issue/PR 响应未知时,必须提示维护风险。
  • 证据:evidence.maintainer_signals | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | issue_or_pr_quality=unknown

14. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
  • 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
  • 证据:evidence.maintainer_signals | mcp_registry:ai.ankimcp/anki-mcp-server:0.18.5 | https://registry.modelcontextprotocol.io/v0.1/servers/ai.ankimcp%2Fanki-mcp-server/versions/0.18.5 | release_recency=unknown

来源:Doramagic 发现、验证与编译记录