anki-mcp-http 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +591 -0
  3. package/bin/ankimcp.js +2 -0
  4. package/dist/anki-config.service.d.ts +10 -0
  5. package/dist/anki-config.service.js +42 -0
  6. package/dist/anki-config.service.js.map +1 -0
  7. package/dist/app.module.d.ts +5 -0
  8. package/dist/app.module.js +74 -0
  9. package/dist/app.module.js.map +1 -0
  10. package/dist/bootstrap.d.ts +3 -0
  11. package/dist/bootstrap.js +39 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/cli.d.ts +7 -0
  14. package/dist/cli.js +68 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/http/guards/origin-validation.guard.d.ts +7 -0
  17. package/dist/http/guards/origin-validation.guard.js +52 -0
  18. package/dist/http/guards/origin-validation.guard.js.map +1 -0
  19. package/dist/main-http.d.ts +1 -0
  20. package/dist/main-http.js +27 -0
  21. package/dist/main-http.js.map +1 -0
  22. package/dist/main-stdio.d.ts +1 -0
  23. package/dist/main-stdio.js +20 -0
  24. package/dist/main-stdio.js.map +1 -0
  25. package/dist/mcp/clients/__mocks__/anki-connect.client.d.ts +6 -0
  26. package/dist/mcp/clients/__mocks__/anki-connect.client.js +18 -0
  27. package/dist/mcp/clients/__mocks__/anki-connect.client.js.map +1 -0
  28. package/dist/mcp/clients/anki-connect.client.d.ts +15 -0
  29. package/dist/mcp/clients/anki-connect.client.js +145 -0
  30. package/dist/mcp/clients/anki-connect.client.js.map +1 -0
  31. package/dist/mcp/config/anki-config.interface.d.ts +7 -0
  32. package/dist/mcp/config/anki-config.interface.js +5 -0
  33. package/dist/mcp/config/anki-config.interface.js.map +1 -0
  34. package/dist/mcp/primitives/essential/index.d.ts +30 -0
  35. package/dist/mcp/primitives/essential/index.js +125 -0
  36. package/dist/mcp/primitives/essential/index.js.map +1 -0
  37. package/dist/mcp/primitives/essential/prompts/review-session.prompt.d.ts +12 -0
  38. package/dist/mcp/primitives/essential/prompts/review-session.prompt.js +113 -0
  39. package/dist/mcp/primitives/essential/prompts/review-session.prompt.js.map +1 -0
  40. package/dist/mcp/primitives/essential/resources/system-info.resource.d.ts +21 -0
  41. package/dist/mcp/primitives/essential/resources/system-info.resource.js +115 -0
  42. package/dist/mcp/primitives/essential/resources/system-info.resource.js.map +1 -0
  43. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +93 -0
  44. package/dist/mcp/primitives/essential/tools/add-note.tool.js +188 -0
  45. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -0
  46. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +83 -0
  47. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +120 -0
  48. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +1 -0
  49. package/dist/mcp/primitives/essential/tools/create-model.tool.d.ts +88 -0
  50. package/dist/mcp/primitives/essential/tools/create-model.tool.js +142 -0
  51. package/dist/mcp/primitives/essential/tools/create-model.tool.js.map +1 -0
  52. package/dist/mcp/primitives/essential/tools/delete-notes.tool.d.ts +84 -0
  53. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js +120 -0
  54. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js.map +1 -0
  55. package/dist/mcp/primitives/essential/tools/find-notes.tool.d.ts +83 -0
  56. package/dist/mcp/primitives/essential/tools/find-notes.tool.js +106 -0
  57. package/dist/mcp/primitives/essential/tools/find-notes.tool.js.map +1 -0
  58. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.d.ts +84 -0
  59. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js +106 -0
  60. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js.map +1 -0
  61. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +83 -0
  62. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +117 -0
  63. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +1 -0
  64. package/dist/mcp/primitives/essential/tools/model-field-names.tool.d.ts +83 -0
  65. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +116 -0
  66. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -0
  67. package/dist/mcp/primitives/essential/tools/model-names.tool.d.ts +81 -0
  68. package/dist/mcp/primitives/essential/tools/model-names.tool.js +78 -0
  69. package/dist/mcp/primitives/essential/tools/model-names.tool.js.map +1 -0
  70. package/dist/mcp/primitives/essential/tools/model-styling.tool.d.ts +83 -0
  71. package/dist/mcp/primitives/essential/tools/model-styling.tool.js +93 -0
  72. package/dist/mcp/primitives/essential/tools/model-styling.tool.js.map +1 -0
  73. package/dist/mcp/primitives/essential/tools/notes-info.tool.d.ts +83 -0
  74. package/dist/mcp/primitives/essential/tools/notes-info.tool.js +111 -0
  75. package/dist/mcp/primitives/essential/tools/notes-info.tool.js.map +1 -0
  76. package/dist/mcp/primitives/essential/tools/present-card.tool.d.ts +84 -0
  77. package/dist/mcp/primitives/essential/tools/present-card.tool.js +100 -0
  78. package/dist/mcp/primitives/essential/tools/present-card.tool.js.map +1 -0
  79. package/dist/mcp/primitives/essential/tools/rate-card.tool.d.ts +84 -0
  80. package/dist/mcp/primitives/essential/tools/rate-card.tool.js +96 -0
  81. package/dist/mcp/primitives/essential/tools/rate-card.tool.js.map +1 -0
  82. package/dist/mcp/primitives/essential/tools/sync.tool.d.ts +81 -0
  83. package/dist/mcp/primitives/essential/tools/sync.tool.js +61 -0
  84. package/dist/mcp/primitives/essential/tools/sync.tool.js.map +1 -0
  85. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.d.ts +84 -0
  86. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js +119 -0
  87. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js.map +1 -0
  88. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.d.ts +96 -0
  89. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js +154 -0
  90. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js.map +1 -0
  91. package/dist/mcp/primitives/gui/index.d.ts +4 -0
  92. package/dist/mcp/primitives/gui/index.js +26 -0
  93. package/dist/mcp/primitives/gui/index.js.map +1 -0
  94. package/dist/mcp/types/anki.types.d.ts +152 -0
  95. package/dist/mcp/types/anki.types.js +18 -0
  96. package/dist/mcp/types/anki.types.js.map +1 -0
  97. package/dist/mcp/utils/anki.utils.d.ts +19 -0
  98. package/dist/mcp/utils/anki.utils.js +153 -0
  99. package/dist/mcp/utils/anki.utils.js.map +1 -0
  100. package/dist/mcp/utils/mcpb-workarounds.d.ts +1 -0
  101. package/dist/mcp/utils/mcpb-workarounds.js +13 -0
  102. package/dist/mcp/utils/mcpb-workarounds.js.map +1 -0
  103. package/dist/test-fixtures/mock-data.d.ts +126 -0
  104. package/dist/test-fixtures/mock-data.js +112 -0
  105. package/dist/test-fixtures/mock-data.js.map +1 -0
  106. package/dist/test-fixtures/test-helpers.d.ts +12 -0
  107. package/dist/test-fixtures/test-helpers.js +24 -0
  108. package/dist/test-fixtures/test-helpers.js.map +1 -0
  109. package/dist/tsconfig.build.tsbuildinfo +1 -0
  110. package/package.json +153 -0
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var RateCardTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.RateCardTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let RateCardTool = RateCardTool_1 = class RateCardTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(RateCardTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async rateCard({ card_id, rating }, context) {
26
+ try {
27
+ if (!Number.isInteger(rating) || rating < 1 || rating > 4) {
28
+ return (0, anki_utils_1.createErrorResponse)(new Error('Invalid rating. Must be 1 (Again), 2 (Hard), 3 (Good), or 4 (Easy)'), { cardId: card_id, attemptedRating: rating });
29
+ }
30
+ this.logger.log(`Rating card ${card_id} with rating ${rating}`);
31
+ await context.reportProgress({ progress: 25, total: 100 });
32
+ const answers = [{
33
+ cardId: card_id,
34
+ ease: rating
35
+ }];
36
+ const result = await this.ankiClient.invoke('answerCards', { answers });
37
+ const ratingDesc = (0, anki_utils_1.getRatingDescription)(rating);
38
+ this.logger.log(`Card ${card_id} rated as ${ratingDesc}`);
39
+ await context.reportProgress({ progress: 75, total: 100 });
40
+ const cardsInfo = await this.ankiClient.invoke('cardsInfo', {
41
+ cards: [card_id]
42
+ });
43
+ let nextReview = null;
44
+ if (cardsInfo && cardsInfo.length > 0) {
45
+ const card = cardsInfo[0];
46
+ nextReview = {
47
+ interval: card.interval || 0,
48
+ due: card.due || 0,
49
+ factor: card.factor || 2500,
50
+ };
51
+ }
52
+ await context.reportProgress({ progress: 100, total: 100 });
53
+ return (0, anki_utils_1.createSuccessResponse)({
54
+ success: true,
55
+ cardId: card_id,
56
+ rating: rating,
57
+ ratingDescription: ratingDesc,
58
+ message: `Card successfully rated as ${ratingDesc}`,
59
+ nextReview,
60
+ });
61
+ }
62
+ catch (error) {
63
+ this.logger.error(`Failed to rate card ${card_id}`, error);
64
+ return (0, anki_utils_1.createErrorResponse)(error, {
65
+ cardId: card_id,
66
+ attemptedRating: rating,
67
+ hint: 'Make sure Anki is running and the card exists',
68
+ });
69
+ }
70
+ }
71
+ };
72
+ exports.RateCardTool = RateCardTool;
73
+ __decorate([
74
+ (0, mcp_nest_1.Tool)({
75
+ name: 'rate_card',
76
+ description: 'Submit a rating for a card to update Anki\'s spaced repetition scheduling. Use this ONLY after the user confirms or modifies your suggested rating. Do not rate automatically without user input.',
77
+ parameters: zod_1.z.object({
78
+ card_id: zod_1.z
79
+ .number()
80
+ .describe('The ID of the card to rate'),
81
+ rating: zod_1.z
82
+ .number()
83
+ .min(1)
84
+ .max(4)
85
+ .describe('The rating for the card (use the user\'s choice, not your suggestion): 1=Again (failed), 2=Hard, 3=Good, 4=Easy'),
86
+ }),
87
+ }),
88
+ __metadata("design:type", Function),
89
+ __metadata("design:paramtypes", [Object, Object]),
90
+ __metadata("design:returntype", Promise)
91
+ ], RateCardTool.prototype, "rateCard", null);
92
+ exports.RateCardTool = RateCardTool = RateCardTool_1 = __decorate([
93
+ (0, common_1.Injectable)(),
94
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
95
+ ], RateCardTool);
96
+ //# sourceMappingURL=rate-card.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-card.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/rate-card.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,8CAAuC;AAEvC,6BAAwB;AACxB,8EAAyE;AACzE,0DAA6G;AAMtG,IAAM,YAAY,oBAAlB,MAAM,YAAY;IAGM;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,cAAY,CAAC,IAAI,CAAC,CAAC;IAExD,YAA6B,UAA6B;QAA7B,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;IAiBxD,AAAN,KAAK,CAAC,QAAQ,CACZ,EAAE,OAAO,EAAE,MAAM,EAAuC,EACxD,OAAgB;QAEhB,IAAI,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1D,OAAO,IAAA,gCAAmB,EACxB,IAAI,KAAK,CAAC,oEAAoE,CAAC,EAC/E,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,CAC7C,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,OAAO,gBAAgB,MAAM,EAAE,CAAC,CAAC;YAChE,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAI3D,MAAM,OAAO,GAAG,CAAC;oBACf,MAAM,EAAE,OAAO;oBACf,IAAI,EAAE,MAAM;iBACb,CAAC,CAAC;YAGH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAU,aAAa,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YAEjF,MAAM,UAAU,GAAG,IAAA,iCAAoB,EAAC,MAAM,CAAC,CAAC;YAEhD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,OAAO,aAAa,UAAU,EAAE,CAAC,CAAC;YAC1D,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG3D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAQ,WAAW,EAAE;gBACjE,KAAK,EAAE,CAAC,OAAO,CAAC;aACjB,CAAC,CAAC;YAEH,IAAI,UAAU,GAAG,IAAI,CAAC;YACtB,IAAI,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC1B,UAAU,GAAG;oBACX,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC;oBAC5B,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC;oBAClB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;iBAC5B,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAE5D,OAAO,IAAA,kCAAqB,EAAC;gBAC3B,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,MAAM;gBACd,iBAAiB,EAAE,UAAU;gBAC7B,OAAO,EAAE,8BAA8B,UAAU,EAAE;gBACnD,UAAU;aACX,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;YAE3D,OAAO,IAAA,gCAAmB,EAAC,KAAK,EAAE;gBAChC,MAAM,EAAE,OAAO;gBACf,eAAe,EAAE,MAAM;gBACvB,IAAI,EAAE,+CAA+C;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AAtFY,oCAAY;AAoBjB;IAfL,IAAA,eAAI,EAAC;QACJ,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,mMAAmM;QACrM,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,OAAO,EAAE,OAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,4BAA4B,CAAC;YACzC,MAAM,EAAE,OAAC;iBACN,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,iHAAiH,CAAC;SAC/H,CAAC;KACH,CAAC;;;;4CAkED;uBArFU,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAI8B,uCAAiB;GAH/C,YAAY,CAsFxB"}
@@ -0,0 +1,81 @@
1
+ import type { Context } from '@rekog/mcp-nest';
2
+ import { AnkiConnectClient } from '../../../clients/anki-connect.client';
3
+ export declare class SyncTool {
4
+ private readonly ankiClient;
5
+ private readonly logger;
6
+ constructor(ankiClient: AnkiConnectClient);
7
+ sync(_args: {}, context: Context): Promise<{
8
+ [x: string]: unknown;
9
+ content: ({
10
+ [x: string]: unknown;
11
+ type: "text";
12
+ text: string;
13
+ _meta?: {
14
+ [x: string]: unknown;
15
+ } | undefined;
16
+ } | {
17
+ [x: string]: unknown;
18
+ type: "image";
19
+ data: string;
20
+ mimeType: string;
21
+ _meta?: {
22
+ [x: string]: unknown;
23
+ } | undefined;
24
+ } | {
25
+ [x: string]: unknown;
26
+ type: "audio";
27
+ data: string;
28
+ mimeType: string;
29
+ _meta?: {
30
+ [x: string]: unknown;
31
+ } | undefined;
32
+ } | {
33
+ [x: string]: unknown;
34
+ type: "resource_link";
35
+ name: string;
36
+ uri: string;
37
+ _meta?: {
38
+ [x: string]: unknown;
39
+ } | undefined;
40
+ mimeType?: string | undefined;
41
+ title?: string | undefined;
42
+ description?: string | undefined;
43
+ icons?: {
44
+ [x: string]: unknown;
45
+ src: string;
46
+ mimeType?: string | undefined;
47
+ sizes?: string | undefined;
48
+ }[] | undefined;
49
+ } | {
50
+ [x: string]: unknown;
51
+ type: "resource";
52
+ resource: {
53
+ [x: string]: unknown;
54
+ text: string;
55
+ uri: string;
56
+ _meta?: {
57
+ [x: string]: unknown;
58
+ } | undefined;
59
+ mimeType?: string | undefined;
60
+ } | {
61
+ [x: string]: unknown;
62
+ uri: string;
63
+ blob: string;
64
+ _meta?: {
65
+ [x: string]: unknown;
66
+ } | undefined;
67
+ mimeType?: string | undefined;
68
+ };
69
+ _meta?: {
70
+ [x: string]: unknown;
71
+ } | undefined;
72
+ })[];
73
+ _meta?: {
74
+ [x: string]: unknown;
75
+ } | undefined;
76
+ structuredContent?: {
77
+ [x: string]: unknown;
78
+ } | undefined;
79
+ isError?: boolean | undefined;
80
+ }>;
81
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var SyncTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.SyncTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let SyncTool = SyncTool_1 = class SyncTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(SyncTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async sync(_args, context) {
26
+ try {
27
+ this.logger.log('Synchronizing Anki collection with AnkiWeb');
28
+ await context.reportProgress({ progress: 25, total: 100 });
29
+ await this.ankiClient.invoke('sync');
30
+ this.logger.log('Anki sync completed successfully');
31
+ await context.reportProgress({ progress: 100, total: 100 });
32
+ return (0, anki_utils_1.createSuccessResponse)({
33
+ success: true,
34
+ message: 'Successfully synchronized with AnkiWeb',
35
+ timestamp: new Date().toISOString(),
36
+ });
37
+ }
38
+ catch (error) {
39
+ this.logger.error('Failed to sync with AnkiWeb', error);
40
+ return (0, anki_utils_1.createErrorResponse)(error, {
41
+ hint: 'Make sure Anki is running and you are logged into AnkiWeb',
42
+ });
43
+ }
44
+ }
45
+ };
46
+ exports.SyncTool = SyncTool;
47
+ __decorate([
48
+ (0, mcp_nest_1.Tool)({
49
+ name: 'sync',
50
+ description: 'Synchronize local Anki collection with AnkiWeb. IMPORTANT: Always sync at the START of a review session (before getting cards) and at the END when user indicates they are done. This ensures data consistency across devices.',
51
+ parameters: zod_1.z.object({}),
52
+ }),
53
+ __metadata("design:type", Function),
54
+ __metadata("design:paramtypes", [Object, Object]),
55
+ __metadata("design:returntype", Promise)
56
+ ], SyncTool.prototype, "sync", null);
57
+ exports.SyncTool = SyncTool = SyncTool_1 = __decorate([
58
+ (0, common_1.Injectable)(),
59
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
60
+ ], SyncTool);
61
+ //# sourceMappingURL=sync.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/sync.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,8CAAuC;AAEvC,6BAAwB;AACxB,8EAAyE;AACzE,0DAAuF;AAMhF,IAAM,QAAQ,gBAAd,MAAM,QAAQ;IAGU;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,UAAQ,CAAC,IAAI,CAAC,CAAC;IAEpD,YAA6B,UAA6B;QAA7B,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;IAQxD,AAAN,KAAK,CAAC,IAAI,CAAC,KAAS,EAAE,OAAgB;QACpC,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;YAC9D,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG3D,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAErC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;YACpD,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAE5D,OAAO,IAAA,kCAAqB,EAAC;gBAC3B,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,wCAAwC;gBACjD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YAExD,OAAO,IAAA,gCAAmB,EAAC,KAAK,EAAE;gBAChC,IAAI,EAAE,2DAA2D;aAClE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AAnCY,4BAAQ;AAWb;IANL,IAAA,eAAI,EAAC;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,gOAAgO;QAClO,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC;KACzB,CAAC;;;;oCAwBD;mBAlCU,QAAQ;IADpB,IAAA,mBAAU,GAAE;qCAI8B,uCAAiB;GAH/C,QAAQ,CAmCpB"}
@@ -0,0 +1,84 @@
1
+ import type { Context } from '@rekog/mcp-nest';
2
+ import { AnkiConnectClient } from '../../../clients/anki-connect.client';
3
+ export declare class UpdateModelStylingTool {
4
+ private readonly ankiClient;
5
+ private readonly logger;
6
+ constructor(ankiClient: AnkiConnectClient);
7
+ updateModelStyling({ modelName, css }: {
8
+ modelName: string;
9
+ css: string;
10
+ }, context: Context): Promise<{
11
+ [x: string]: unknown;
12
+ content: ({
13
+ [x: string]: unknown;
14
+ type: "text";
15
+ text: string;
16
+ _meta?: {
17
+ [x: string]: unknown;
18
+ } | undefined;
19
+ } | {
20
+ [x: string]: unknown;
21
+ type: "image";
22
+ data: string;
23
+ mimeType: string;
24
+ _meta?: {
25
+ [x: string]: unknown;
26
+ } | undefined;
27
+ } | {
28
+ [x: string]: unknown;
29
+ type: "audio";
30
+ data: string;
31
+ mimeType: string;
32
+ _meta?: {
33
+ [x: string]: unknown;
34
+ } | undefined;
35
+ } | {
36
+ [x: string]: unknown;
37
+ type: "resource_link";
38
+ name: string;
39
+ uri: string;
40
+ _meta?: {
41
+ [x: string]: unknown;
42
+ } | undefined;
43
+ mimeType?: string | undefined;
44
+ title?: string | undefined;
45
+ description?: string | undefined;
46
+ icons?: {
47
+ [x: string]: unknown;
48
+ src: string;
49
+ mimeType?: string | undefined;
50
+ sizes?: string | undefined;
51
+ }[] | undefined;
52
+ } | {
53
+ [x: string]: unknown;
54
+ type: "resource";
55
+ resource: {
56
+ [x: string]: unknown;
57
+ text: string;
58
+ uri: string;
59
+ _meta?: {
60
+ [x: string]: unknown;
61
+ } | undefined;
62
+ mimeType?: string | undefined;
63
+ } | {
64
+ [x: string]: unknown;
65
+ uri: string;
66
+ blob: string;
67
+ _meta?: {
68
+ [x: string]: unknown;
69
+ } | undefined;
70
+ mimeType?: string | undefined;
71
+ };
72
+ _meta?: {
73
+ [x: string]: unknown;
74
+ } | undefined;
75
+ })[];
76
+ _meta?: {
77
+ [x: string]: unknown;
78
+ } | undefined;
79
+ structuredContent?: {
80
+ [x: string]: unknown;
81
+ } | undefined;
82
+ isError?: boolean | undefined;
83
+ }>;
84
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var UpdateModelStylingTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.UpdateModelStylingTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let UpdateModelStylingTool = UpdateModelStylingTool_1 = class UpdateModelStylingTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(UpdateModelStylingTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async updateModelStyling({ modelName, css }, context) {
26
+ try {
27
+ this.logger.log(`Updating styling for model: ${modelName}`);
28
+ await context.reportProgress({ progress: 10, total: 100 });
29
+ let oldStyling = null;
30
+ try {
31
+ oldStyling = await this.ankiClient.invoke('modelStyling', {
32
+ modelName,
33
+ });
34
+ }
35
+ catch (error) {
36
+ this.logger.warn(`Could not fetch old styling for ${modelName}`);
37
+ }
38
+ await context.reportProgress({ progress: 40, total: 100 });
39
+ await this.ankiClient.invoke('updateModelStyling', {
40
+ model: {
41
+ name: modelName,
42
+ css,
43
+ },
44
+ });
45
+ await context.reportProgress({ progress: 80, total: 100 });
46
+ this.logger.log(`Successfully updated styling for model: ${modelName}`);
47
+ await context.reportProgress({ progress: 100, total: 100 });
48
+ const cssLength = css.length;
49
+ const hasRtl = css.includes('direction: rtl') || css.includes('direction:rtl');
50
+ const hasCardClass = css.includes('.card');
51
+ const hasFrontClass = css.includes('.front');
52
+ const hasBackClass = css.includes('.back');
53
+ const hasClozeClass = css.includes('.cloze');
54
+ const response = {
55
+ success: true,
56
+ modelName,
57
+ cssLength,
58
+ cssInfo: {
59
+ hasRtlSupport: hasRtl,
60
+ hasCardStyling: hasCardClass,
61
+ hasFrontStyling: hasFrontClass,
62
+ hasBackStyling: hasBackClass,
63
+ hasClozeStyling: hasClozeClass,
64
+ },
65
+ message: `Successfully updated CSS styling for model "${modelName}"`,
66
+ };
67
+ if (oldStyling) {
68
+ response.oldCssLength = oldStyling.css.length;
69
+ response.cssLengthChange = cssLength - oldStyling.css.length;
70
+ }
71
+ return (0, anki_utils_1.createSuccessResponse)(response);
72
+ }
73
+ catch (error) {
74
+ this.logger.error(`Failed to update styling for model ${modelName}`, error);
75
+ const errorMessage = error instanceof Error ? error.message : String(error);
76
+ if (errorMessage.includes('not found') ||
77
+ errorMessage.includes('does not exist') ||
78
+ errorMessage.includes('model not found')) {
79
+ return (0, anki_utils_1.createErrorResponse)(error, {
80
+ modelName,
81
+ hint: 'Model not found. Use modelNames tool to see available models.',
82
+ });
83
+ }
84
+ return (0, anki_utils_1.createErrorResponse)(error, {
85
+ modelName,
86
+ hint: 'Make sure Anki is running and the model name is correct.',
87
+ });
88
+ }
89
+ }
90
+ };
91
+ exports.UpdateModelStylingTool = UpdateModelStylingTool;
92
+ __decorate([
93
+ (0, mcp_nest_1.Tool)({
94
+ name: 'updateModelStyling',
95
+ description: 'Update the CSS styling for an existing note type (model). ' +
96
+ 'This changes how cards of this type are rendered in Anki. ' +
97
+ 'Useful for adding RTL (Right-to-Left) support, changing fonts, colors, or layout. ' +
98
+ 'Changes apply to all cards using this model.',
99
+ parameters: zod_1.z.object({
100
+ modelName: zod_1.z
101
+ .string()
102
+ .min(1)
103
+ .describe('Name of the model to update (e.g., "Basic", "Basic RTL")'),
104
+ css: zod_1.z
105
+ .string()
106
+ .min(1)
107
+ .describe('New CSS styling content. For RTL languages, include "direction: rtl;" in .card class. ' +
108
+ 'This will completely replace the existing CSS.'),
109
+ }),
110
+ }),
111
+ __metadata("design:type", Function),
112
+ __metadata("design:paramtypes", [Object, Object]),
113
+ __metadata("design:returntype", Promise)
114
+ ], UpdateModelStylingTool.prototype, "updateModelStyling", null);
115
+ exports.UpdateModelStylingTool = UpdateModelStylingTool = UpdateModelStylingTool_1 = __decorate([
116
+ (0, common_1.Injectable)(),
117
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
118
+ ], UpdateModelStylingTool);
119
+ //# sourceMappingURL=update-model-styling.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-model-styling.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/update-model-styling.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,8CAAuC;AAEvC,6BAAwB;AACxB,8EAAyE;AACzE,0DAAuF;AAMhF,IAAM,sBAAsB,8BAA5B,MAAM,sBAAsB;IAGJ;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,wBAAsB,CAAC,IAAI,CAAC,CAAC;IAElE,YAA6B,UAA6B;QAA7B,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;IAuBxD,AAAN,KAAK,CAAC,kBAAkB,CACtB,EAAE,SAAS,EAAE,GAAG,EAAsC,EACtD,OAAgB;QAEhB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC;YAC5D,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG3D,IAAI,UAAU,GAA2B,IAAI,CAAC;YAC9C,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAkB,cAAc,EAAE;oBACzE,SAAS;iBACV,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAEf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG3D,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,oBAAoB,EAAE;gBACjD,KAAK,EAAE;oBACL,IAAI,EAAE,SAAS;oBACf,GAAG;iBACJ;aACF,CAAC,CAAC;YAEH,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAE3D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;YAExE,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG5D,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC;YAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;YAC/E,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAE7C,MAAM,QAAQ,GAAQ;gBACpB,OAAO,EAAE,IAAI;gBACb,SAAS;gBACT,SAAS;gBACT,OAAO,EAAE;oBACP,aAAa,EAAE,MAAM;oBACrB,cAAc,EAAE,YAAY;oBAC5B,eAAe,EAAE,aAAa;oBAC9B,cAAc,EAAE,YAAY;oBAC5B,eAAe,EAAE,aAAa;iBAC/B;gBACD,OAAO,EAAE,+CAA+C,SAAS,GAAG;aACrE,CAAC;YAEF,IAAI,UAAU,EAAE,CAAC;gBACf,QAAQ,CAAC,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC9C,QAAQ,CAAC,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;YAC/D,CAAC;YAED,OAAO,IAAA,kCAAqB,EAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;YAG5E,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,IACE,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAClC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBACvC,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EACxC,CAAC;gBACD,OAAO,IAAA,gCAAmB,EAAC,KAAK,EAAE;oBAChC,SAAS;oBACT,IAAI,EAAE,+DAA+D;iBACtE,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAA,gCAAmB,EAAC,KAAK,EAAE;gBAChC,SAAS;gBACT,IAAI,EAAE,0DAA0D;aACjE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AA/GY,wDAAsB;AA0B3B;IArBL,IAAA,eAAI,EAAC;QACJ,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,4DAA4D;YAC5D,4DAA4D;YAC5D,oFAAoF;YACpF,8CAA8C;QAChD,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,SAAS,EAAE,OAAC;iBACT,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,0DAA0D,CAAC;YACvE,GAAG,EAAE,OAAC;iBACH,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CACP,wFAAwF;gBACxF,gDAAgD,CACjD;SACJ,CAAC;KACH,CAAC;;;;gEAqFD;iCA9GU,sBAAsB;IADlC,IAAA,mBAAU,GAAE;qCAI8B,uCAAiB;GAH/C,sBAAsB,CA+GlC"}
@@ -0,0 +1,96 @@
1
+ import type { Context } from '@rekog/mcp-nest';
2
+ import { AnkiConnectClient } from '../../../clients/anki-connect.client';
3
+ export declare class UpdateNoteFieldsTool {
4
+ private readonly ankiClient;
5
+ private readonly logger;
6
+ constructor(ankiClient: AnkiConnectClient);
7
+ updateNoteFields({ note }: {
8
+ note: {
9
+ id: number;
10
+ fields: Record<string, string>;
11
+ audio?: Array<{
12
+ url: string;
13
+ filename: string;
14
+ fields: string[];
15
+ }>;
16
+ picture?: Array<{
17
+ url: string;
18
+ filename: string;
19
+ fields: string[];
20
+ }>;
21
+ };
22
+ }, context: Context): Promise<{
23
+ [x: string]: unknown;
24
+ content: ({
25
+ [x: string]: unknown;
26
+ type: "text";
27
+ text: string;
28
+ _meta?: {
29
+ [x: string]: unknown;
30
+ } | undefined;
31
+ } | {
32
+ [x: string]: unknown;
33
+ type: "image";
34
+ data: string;
35
+ mimeType: string;
36
+ _meta?: {
37
+ [x: string]: unknown;
38
+ } | undefined;
39
+ } | {
40
+ [x: string]: unknown;
41
+ type: "audio";
42
+ data: string;
43
+ mimeType: string;
44
+ _meta?: {
45
+ [x: string]: unknown;
46
+ } | undefined;
47
+ } | {
48
+ [x: string]: unknown;
49
+ type: "resource_link";
50
+ name: string;
51
+ uri: string;
52
+ _meta?: {
53
+ [x: string]: unknown;
54
+ } | undefined;
55
+ mimeType?: string | undefined;
56
+ title?: string | undefined;
57
+ description?: string | undefined;
58
+ icons?: {
59
+ [x: string]: unknown;
60
+ src: string;
61
+ mimeType?: string | undefined;
62
+ sizes?: string | undefined;
63
+ }[] | undefined;
64
+ } | {
65
+ [x: string]: unknown;
66
+ type: "resource";
67
+ resource: {
68
+ [x: string]: unknown;
69
+ text: string;
70
+ uri: string;
71
+ _meta?: {
72
+ [x: string]: unknown;
73
+ } | undefined;
74
+ mimeType?: string | undefined;
75
+ } | {
76
+ [x: string]: unknown;
77
+ uri: string;
78
+ blob: string;
79
+ _meta?: {
80
+ [x: string]: unknown;
81
+ } | undefined;
82
+ mimeType?: string | undefined;
83
+ };
84
+ _meta?: {
85
+ [x: string]: unknown;
86
+ } | undefined;
87
+ })[];
88
+ _meta?: {
89
+ [x: string]: unknown;
90
+ } | undefined;
91
+ structuredContent?: {
92
+ [x: string]: unknown;
93
+ } | undefined;
94
+ isError?: boolean | undefined;
95
+ }>;
96
+ }