UNPKG

@ankimcp/anki-mcp-server

Version:

Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards

137 lines • 7 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var ListDecksTool_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.ListDecksTool = void 0; const common_1 = require("@nestjs/common"); const microservices_1 = require("@nestjs/microservices"); const mcp_nest_1 = require("@rekog/mcp-nest"); const zod_1 = require("zod"); const anki_connect_client_1 = require("../../../clients/anki-connect.client.js"); const anki_utils_1 = require("../../../utils/anki.utils.js"); const listDecks_action_1 = require("./deckActions/actions/listDecks.action"); let ListDecksTool = ListDecksTool_1 = class ListDecksTool { ankiClient; logger = new common_1.Logger(ListDecksTool_1.name); constructor(ankiClient) { this.ankiClient = ankiClient; } async execute(params) { try { this.logger.log("Executing listDecks"); const result = await (0, listDecks_action_1.listDecks)({ includeStats: params.includeStats }, this.ankiClient); return result; } catch (error) { this.logger.error("Failed to execute listDecks", error); return (0, anki_utils_1.createErrorResponse)(error, { action: "listDecks", hint: "This can happen when Anki is not running", }); } } }; exports.ListDecksTool = ListDecksTool; __decorate([ (0, mcp_nest_1.Tool)({ name: "listDecks", description: "List all Anki decks, optionally with per-deck study-queue statistics. " + "Those statistics are Anki's deck-browser numbers — cards DUE TODAY, capped by each deck's daily new/review limits, excluding suspended and buried cards — NOT totals per card state. " + "The `deckStats` tool (its `states` block) and `collection_stats` return true card-state counts. " + "Reads the local collection, which reflects other devices only as of the last AnkiWeb sync.", parameters: zod_1.z.object({ includeStats: zod_1.z .boolean() .optional() .describe("Include card count statistics for each deck"), }), outputSchema: zod_1.z.object({ success: zod_1.z.boolean(), decks: zod_1.z.array(zod_1.z.object({ name: zod_1.z.string(), stats: zod_1.z .object({ deck_id: zod_1.z.number(), name: zod_1.z.string(), new_count: zod_1.z .number() .describe("New cards due today, capped by the daily new-card limit. " + "Subdecks included. Not the total number of new cards."), learn_count: zod_1.z .number() .describe("Learning/relearning cards due now or today. Subdecks included."), review_count: zod_1.z .number() .describe("Review cards DUE TODAY, capped by the daily review limit. " + "Subdecks included. Not 'mature' cards and not all review cards."), total_new: zod_1.z .number() .describe("Misleading legacy name: same value as new_count (new cards " + "due today), NOT the total number of new cards."), total_cards: zod_1.z .number() .describe("Cards stored directly in this deck, subdecks NOT included, " + "suspended and buried included."), }) .optional() .describe("Study-queue counts from Anki's deck browser (due today, capped " + "by daily limits) — not per-state card totals."), })), total: zod_1.z.number(), summary: zod_1.z .object({ total_cards: zod_1.z .number() .describe("Total cards in the collection: sum of every deck's own card " + "count (subdecks are separate rows, so nothing is missed or " + "double-counted)."), new_cards: zod_1.z .number() .describe("New cards due across the collection today, capped by daily " + "limits. Summed over ROOT decks only, because the per-deck " + "counts are already rolled up over subdecks. Not the total " + "number of new cards."), learning_cards: zod_1.z .number() .describe("Learning/relearning cards due now or today across the " + "collection. Summed over ROOT decks only, like new_cards."), review_cards: zod_1.z .number() .describe("Review cards DUE TODAY across the collection, capped by daily " + "limits. Summed over ROOT decks only, like new_cards. Not all " + "review cards."), }) .optional() .describe("Collection-wide totals with study-queue semantics, not card-state " + "totals. Use collection_stats for true per-state counts."), message: zod_1.z.string().optional(), }), annotations: { title: "List Decks", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }), __param(0, (0, microservices_1.Payload)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], ListDecksTool.prototype, "execute", null); exports.ListDecksTool = ListDecksTool = ListDecksTool_1 = __decorate([ (0, mcp_nest_1.McpController)(), __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient]) ], ListDecksTool); //# sourceMappingURL=list-decks.tool.js.map