@ankimcp/anki-mcp-server 0.8.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 (171) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +756 -0
  3. package/bin/ankimcp.js +12 -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 +84 -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 +9 -0
  14. package/dist/cli.js +114 -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 +42 -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 +32 -0
  35. package/dist/mcp/primitives/essential/index.js +130 -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/prompts/twenty-rules.prompt/content.md +195 -0
  41. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.d.ts +12 -0
  42. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.js +89 -0
  43. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.js.map +1 -0
  44. package/dist/mcp/primitives/essential/resources/system-info.resource.d.ts +21 -0
  45. package/dist/mcp/primitives/essential/resources/system-info.resource.js +115 -0
  46. package/dist/mcp/primitives/essential/resources/system-info.resource.js.map +1 -0
  47. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +93 -0
  48. package/dist/mcp/primitives/essential/tools/add-note.tool.js +185 -0
  49. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -0
  50. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +83 -0
  51. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +121 -0
  52. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +1 -0
  53. package/dist/mcp/primitives/essential/tools/create-model.tool.d.ts +88 -0
  54. package/dist/mcp/primitives/essential/tools/create-model.tool.js +144 -0
  55. package/dist/mcp/primitives/essential/tools/create-model.tool.js.map +1 -0
  56. package/dist/mcp/primitives/essential/tools/delete-notes.tool.d.ts +84 -0
  57. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js +120 -0
  58. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js.map +1 -0
  59. package/dist/mcp/primitives/essential/tools/find-notes.tool.d.ts +83 -0
  60. package/dist/mcp/primitives/essential/tools/find-notes.tool.js +106 -0
  61. package/dist/mcp/primitives/essential/tools/find-notes.tool.js.map +1 -0
  62. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.d.ts +84 -0
  63. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js +108 -0
  64. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js.map +1 -0
  65. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +83 -0
  66. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +117 -0
  67. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +1 -0
  68. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.d.ts +10 -0
  69. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.js +18 -0
  70. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.js.map +1 -0
  71. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.d.ts +12 -0
  72. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.js +22 -0
  73. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.js.map +1 -0
  74. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.d.ts +12 -0
  75. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.js +29 -0
  76. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.js.map +1 -0
  77. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.d.ts +15 -0
  78. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.js +41 -0
  79. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.js.map +1 -0
  80. package/dist/mcp/primitives/essential/tools/mediaActions/index.d.ts +5 -0
  81. package/dist/mcp/primitives/essential/tools/mediaActions/index.js +6 -0
  82. package/dist/mcp/primitives/essential/tools/mediaActions/index.js.map +1 -0
  83. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.d.ts +89 -0
  84. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.js +141 -0
  85. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.js.map +1 -0
  86. package/dist/mcp/primitives/essential/tools/model-field-names.tool.d.ts +83 -0
  87. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +119 -0
  88. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -0
  89. package/dist/mcp/primitives/essential/tools/model-names.tool.d.ts +81 -0
  90. package/dist/mcp/primitives/essential/tools/model-names.tool.js +80 -0
  91. package/dist/mcp/primitives/essential/tools/model-names.tool.js.map +1 -0
  92. package/dist/mcp/primitives/essential/tools/model-styling.tool.d.ts +83 -0
  93. package/dist/mcp/primitives/essential/tools/model-styling.tool.js +93 -0
  94. package/dist/mcp/primitives/essential/tools/model-styling.tool.js.map +1 -0
  95. package/dist/mcp/primitives/essential/tools/notes-info.tool.d.ts +83 -0
  96. package/dist/mcp/primitives/essential/tools/notes-info.tool.js +111 -0
  97. package/dist/mcp/primitives/essential/tools/notes-info.tool.js.map +1 -0
  98. package/dist/mcp/primitives/essential/tools/present-card.tool.d.ts +84 -0
  99. package/dist/mcp/primitives/essential/tools/present-card.tool.js +100 -0
  100. package/dist/mcp/primitives/essential/tools/present-card.tool.js.map +1 -0
  101. package/dist/mcp/primitives/essential/tools/rate-card.tool.d.ts +84 -0
  102. package/dist/mcp/primitives/essential/tools/rate-card.tool.js +101 -0
  103. package/dist/mcp/primitives/essential/tools/rate-card.tool.js.map +1 -0
  104. package/dist/mcp/primitives/essential/tools/sync.tool.d.ts +81 -0
  105. package/dist/mcp/primitives/essential/tools/sync.tool.js +61 -0
  106. package/dist/mcp/primitives/essential/tools/sync.tool.js.map +1 -0
  107. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.d.ts +84 -0
  108. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js +119 -0
  109. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js.map +1 -0
  110. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.d.ts +96 -0
  111. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js +154 -0
  112. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js.map +1 -0
  113. package/dist/mcp/primitives/gui/index.d.ts +23 -0
  114. package/dist/mcp/primitives/gui/index.js +94 -0
  115. package/dist/mcp/primitives/gui/index.js.map +1 -0
  116. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.d.ts +88 -0
  117. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js +111 -0
  118. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js.map +1 -0
  119. package/dist/mcp/primitives/gui/tools/gui-browse.tool.d.ts +87 -0
  120. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js +99 -0
  121. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js.map +1 -0
  122. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.d.ts +81 -0
  123. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js +76 -0
  124. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js.map +1 -0
  125. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.d.ts +81 -0
  126. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js +64 -0
  127. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js.map +1 -0
  128. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.d.ts +83 -0
  129. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js +88 -0
  130. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js.map +1 -0
  131. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.d.ts +83 -0
  132. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js +80 -0
  133. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js.map +1 -0
  134. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.d.ts +83 -0
  135. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js +90 -0
  136. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js.map +1 -0
  137. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.d.ts +81 -0
  138. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js +83 -0
  139. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js.map +1 -0
  140. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.d.ts +81 -0
  141. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js +74 -0
  142. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js.map +1 -0
  143. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.d.ts +81 -0
  144. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js +74 -0
  145. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js.map +1 -0
  146. package/dist/mcp/primitives/gui/tools/gui-undo.tool.d.ts +81 -0
  147. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js +74 -0
  148. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js.map +1 -0
  149. package/dist/mcp/types/anki.types.d.ts +180 -0
  150. package/dist/mcp/types/anki.types.js +18 -0
  151. package/dist/mcp/types/anki.types.js.map +1 -0
  152. package/dist/mcp/utils/anki.utils.d.ts +19 -0
  153. package/dist/mcp/utils/anki.utils.js +157 -0
  154. package/dist/mcp/utils/anki.utils.js.map +1 -0
  155. package/dist/mcp/utils/markdown.utils.d.ts +4 -0
  156. package/dist/mcp/utils/markdown.utils.js +60 -0
  157. package/dist/mcp/utils/markdown.utils.js.map +1 -0
  158. package/dist/mcp/utils/mcpb-workarounds.d.ts +1 -0
  159. package/dist/mcp/utils/mcpb-workarounds.js +13 -0
  160. package/dist/mcp/utils/mcpb-workarounds.js.map +1 -0
  161. package/dist/services/ngrok.service.d.ts +15 -0
  162. package/dist/services/ngrok.service.js +120 -0
  163. package/dist/services/ngrok.service.js.map +1 -0
  164. package/dist/test-fixtures/mock-data.d.ts +126 -0
  165. package/dist/test-fixtures/mock-data.js +112 -0
  166. package/dist/test-fixtures/mock-data.js.map +1 -0
  167. package/dist/test-fixtures/test-helpers.d.ts +12 -0
  168. package/dist/test-fixtures/test-helpers.js +24 -0
  169. package/dist/test-fixtures/test-helpers.js.map +1 -0
  170. package/dist/tsconfig.build.tsbuildinfo +1 -0
  171. package/package.json +168 -0
@@ -0,0 +1,180 @@
1
+ export declare enum CardType {
2
+ New = 0,
3
+ Learning = 1,
4
+ Review = 2,
5
+ Relearning = 3
6
+ }
7
+ export interface AnkiCard {
8
+ cardId: number;
9
+ fields: Record<string, {
10
+ value: string;
11
+ order: number;
12
+ }>;
13
+ fieldOrder: number;
14
+ question: string;
15
+ answer: string;
16
+ modelName: string;
17
+ ord: number;
18
+ deckName: string;
19
+ css: string;
20
+ factor?: number;
21
+ interval?: number;
22
+ note: number;
23
+ type: number;
24
+ queue: number;
25
+ due?: number;
26
+ reps?: number;
27
+ lapses?: number;
28
+ left?: number;
29
+ mod?: number;
30
+ flags?: number;
31
+ tags?: string[];
32
+ }
33
+ export interface SimplifiedCard {
34
+ cardId: number;
35
+ front: string;
36
+ back: string;
37
+ deckName: string;
38
+ modelName: string;
39
+ due: number;
40
+ interval: number;
41
+ factor: number;
42
+ }
43
+ export interface CardPresentation {
44
+ cardId: number;
45
+ front: string;
46
+ back?: string;
47
+ deckName: string;
48
+ modelName: string;
49
+ tags: string[];
50
+ currentInterval: number;
51
+ easeFactor: number;
52
+ reviews: number;
53
+ lapses: number;
54
+ cardType: string;
55
+ noteId: number;
56
+ }
57
+ export interface DeckInfo {
58
+ name: string;
59
+ stats?: DeckStats;
60
+ }
61
+ export interface DeckStats {
62
+ deck_id: number;
63
+ name: string;
64
+ new_count: number;
65
+ learn_count: number;
66
+ review_count: number;
67
+ total_new: number;
68
+ total_cards: number;
69
+ }
70
+ export declare enum CardRating {
71
+ Again = 1,
72
+ Hard = 2,
73
+ Good = 3,
74
+ Easy = 4
75
+ }
76
+ export interface AnkiConnectRequest {
77
+ action: string;
78
+ version: number;
79
+ params?: Record<string, any>;
80
+ key?: string;
81
+ }
82
+ export interface AnkiConnectResponse<T = any> {
83
+ result: T;
84
+ error: string | null;
85
+ }
86
+ export interface NoteOptions {
87
+ allowDuplicate?: boolean;
88
+ duplicateScope?: "deck" | "collection";
89
+ duplicateScopeOptions?: {
90
+ deckName?: string;
91
+ checkChildren?: boolean;
92
+ checkAllModels?: boolean;
93
+ };
94
+ }
95
+ export interface AddNoteParams {
96
+ deckName: string;
97
+ modelName: string;
98
+ fields: Record<string, string>;
99
+ tags?: string[];
100
+ options?: NoteOptions;
101
+ }
102
+ export interface Model {
103
+ name: string;
104
+ id: number;
105
+ css: string;
106
+ fields: string[];
107
+ }
108
+ export interface NoteInfo {
109
+ noteId: number;
110
+ modelName: string;
111
+ tags: string[];
112
+ fields: Record<string, {
113
+ value: string;
114
+ order: number;
115
+ }>;
116
+ cards: number[];
117
+ mod: number;
118
+ }
119
+ export interface UpdateNoteFieldsParams {
120
+ note: {
121
+ id: number;
122
+ fields: Record<string, string>;
123
+ audio?: Array<{
124
+ url: string;
125
+ filename: string;
126
+ fields: string[];
127
+ }>;
128
+ picture?: Array<{
129
+ url: string;
130
+ filename: string;
131
+ fields: string[];
132
+ }>;
133
+ };
134
+ }
135
+ export interface CardTemplate {
136
+ Name: string;
137
+ Front: string;
138
+ Back: string;
139
+ }
140
+ export interface CreateModelParams {
141
+ modelName: string;
142
+ inOrderFields: string[];
143
+ cardTemplates: CardTemplate[];
144
+ css?: string;
145
+ isCloze?: boolean;
146
+ }
147
+ export interface UpdateModelStylingParams {
148
+ model: {
149
+ name: string;
150
+ css: string;
151
+ };
152
+ }
153
+ export interface GuiCurrentCardInfo {
154
+ answer: string;
155
+ question: string;
156
+ deckName: string;
157
+ modelName: string;
158
+ cardId: number;
159
+ buttons: number[];
160
+ nextReviews: string[];
161
+ fields?: Record<string, {
162
+ value: string;
163
+ order: number;
164
+ }>;
165
+ }
166
+ export interface GuiBrowseParams {
167
+ query: string;
168
+ reorderCards?: {
169
+ order: "ascending" | "descending";
170
+ columnId: string;
171
+ };
172
+ }
173
+ export interface GuiAddCardsParams {
174
+ note: {
175
+ deckName: string;
176
+ modelName: string;
177
+ fields: Record<string, string>;
178
+ tags?: string[];
179
+ };
180
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CardRating = exports.CardType = void 0;
4
+ var CardType;
5
+ (function (CardType) {
6
+ CardType[CardType["New"] = 0] = "New";
7
+ CardType[CardType["Learning"] = 1] = "Learning";
8
+ CardType[CardType["Review"] = 2] = "Review";
9
+ CardType[CardType["Relearning"] = 3] = "Relearning";
10
+ })(CardType || (exports.CardType = CardType = {}));
11
+ var CardRating;
12
+ (function (CardRating) {
13
+ CardRating[CardRating["Again"] = 1] = "Again";
14
+ CardRating[CardRating["Hard"] = 2] = "Hard";
15
+ CardRating[CardRating["Good"] = 3] = "Good";
16
+ CardRating[CardRating["Easy"] = 4] = "Easy";
17
+ })(CardRating || (exports.CardRating = CardRating = {}));
18
+ //# sourceMappingURL=anki.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anki.types.js","sourceRoot":"","sources":["../../../src/mcp/types/anki.types.ts"],"names":[],"mappings":";;;AAOA,IAAY,QAKX;AALD,WAAY,QAAQ;IAClB,qCAAO,CAAA;IACP,+CAAY,CAAA;IACZ,2CAAU,CAAA;IACV,mDAAc,CAAA;AAChB,CAAC,EALW,QAAQ,wBAAR,QAAQ,QAKnB;AAqFD,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,6CAAS,CAAA;IACT,2CAAQ,CAAA;IACR,2CAAQ,CAAA;IACR,2CAAQ,CAAA;AACV,CAAC,EALW,UAAU,0BAAV,UAAU,QAKrB"}
@@ -0,0 +1,19 @@
1
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ import { AnkiCard } from "../types/anki.types";
3
+ export declare function cleanHtml(html: string): string;
4
+ export declare function extractCardContent(fields: AnkiCard["fields"]): {
5
+ front: string;
6
+ back: string;
7
+ };
8
+ export declare function getCardType(type: number): string;
9
+ export declare function getNoteType(modelName: string): string;
10
+ export declare function getRatingDescription(rating: number): string;
11
+ export declare function createSuccessResponse(data: any): CallToolResult;
12
+ export declare function createErrorResponse(error: unknown, context?: Record<string, any>): CallToolResult;
13
+ export declare function formatInterval(days: number): string;
14
+ export declare function parseDeckStats(stats: any): {
15
+ new_count: number;
16
+ learn_count: number;
17
+ review_count: number;
18
+ total_cards: number;
19
+ };
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cleanHtml = cleanHtml;
4
+ exports.extractCardContent = extractCardContent;
5
+ exports.getCardType = getCardType;
6
+ exports.getNoteType = getNoteType;
7
+ exports.getRatingDescription = getRatingDescription;
8
+ exports.createSuccessResponse = createSuccessResponse;
9
+ exports.createErrorResponse = createErrorResponse;
10
+ exports.formatInterval = formatInterval;
11
+ exports.parseDeckStats = parseDeckStats;
12
+ const anki_types_1 = require("../types/anki.types");
13
+ const anki_connect_client_1 = require("../clients/anki-connect.client");
14
+ function cleanHtml(html) {
15
+ return html
16
+ .replace(/<[^>]*>/g, "")
17
+ .replace(/&nbsp;/g, " ")
18
+ .replace(/&amp;/g, "&")
19
+ .replace(/&lt;/g, "<")
20
+ .replace(/&gt;/g, ">")
21
+ .replace(/&quot;/g, '"')
22
+ .replace(/&#39;/g, "'")
23
+ .replace(/\n\s*\n/g, "\n")
24
+ .trim();
25
+ }
26
+ function extractCardContent(fields) {
27
+ let front = "";
28
+ let back = "";
29
+ if (!fields) {
30
+ return { front, back };
31
+ }
32
+ const frontFieldNames = ["Front", "正面", "Question", "Text"];
33
+ const backFieldNames = ["Back", "背面", "Answer", "Extra", "Back Extra"];
34
+ for (const fieldName of frontFieldNames) {
35
+ if (fields[fieldName]) {
36
+ front = fields[fieldName].value;
37
+ break;
38
+ }
39
+ }
40
+ for (const fieldName of backFieldNames) {
41
+ if (fields[fieldName]) {
42
+ back = fields[fieldName].value;
43
+ break;
44
+ }
45
+ }
46
+ if (!front && !back) {
47
+ const fieldEntries = Object.entries(fields).sort((a, b) => a[1].order - b[1].order);
48
+ if (fieldEntries.length > 0) {
49
+ front = fieldEntries[0][1].value;
50
+ }
51
+ if (fieldEntries.length > 1) {
52
+ back = fieldEntries[1][1].value;
53
+ }
54
+ }
55
+ return {
56
+ front: cleanHtml(front),
57
+ back: cleanHtml(back),
58
+ };
59
+ }
60
+ function getCardType(type) {
61
+ switch (type) {
62
+ case anki_types_1.CardType.New:
63
+ return "new";
64
+ case anki_types_1.CardType.Learning:
65
+ return "learning";
66
+ case anki_types_1.CardType.Review:
67
+ return "review";
68
+ case anki_types_1.CardType.Relearning:
69
+ return "relearning";
70
+ default:
71
+ return "unknown";
72
+ }
73
+ }
74
+ function getNoteType(modelName) {
75
+ const lowerName = modelName.toLowerCase();
76
+ if (lowerName.includes("basic")) {
77
+ if (lowerName.includes("reverse")) {
78
+ return "Basic (and reversed card)";
79
+ }
80
+ return "Basic";
81
+ }
82
+ if (lowerName.includes("cloze")) {
83
+ return "Cloze";
84
+ }
85
+ return "Custom";
86
+ }
87
+ function getRatingDescription(rating) {
88
+ switch (rating) {
89
+ case anki_types_1.CardRating.Again:
90
+ return "Again (failed to recall)";
91
+ case anki_types_1.CardRating.Hard:
92
+ return "Hard (recalled with difficulty)";
93
+ case anki_types_1.CardRating.Good:
94
+ return "Good (recalled with some effort)";
95
+ case anki_types_1.CardRating.Easy:
96
+ return "Easy (recalled instantly)";
97
+ default:
98
+ return "Unknown";
99
+ }
100
+ }
101
+ function createSuccessResponse(data) {
102
+ return {
103
+ content: [
104
+ {
105
+ type: "text",
106
+ text: JSON.stringify(data, null, 2),
107
+ },
108
+ ],
109
+ };
110
+ }
111
+ function createErrorResponse(error, context) {
112
+ const errorData = {
113
+ success: false,
114
+ error: error instanceof Error ? error.message : "Unknown error occurred",
115
+ };
116
+ if (error instanceof anki_connect_client_1.AnkiConnectError) {
117
+ if (error.action) {
118
+ errorData.action = error.action;
119
+ }
120
+ }
121
+ if (context) {
122
+ Object.assign(errorData, context);
123
+ }
124
+ return {
125
+ content: [
126
+ {
127
+ type: "text",
128
+ text: JSON.stringify(errorData, null, 2),
129
+ },
130
+ ],
131
+ isError: true,
132
+ };
133
+ }
134
+ function formatInterval(days) {
135
+ if (days < 1) {
136
+ const hours = Math.round(days * 24);
137
+ return `${hours} hour${hours !== 1 ? "s" : ""}`;
138
+ }
139
+ if (days < 30) {
140
+ return `${Math.round(days)} day${days !== 1 ? "s" : ""}`;
141
+ }
142
+ if (days < 365) {
143
+ const months = Math.round(days / 30);
144
+ return `${months} month${months !== 1 ? "s" : ""}`;
145
+ }
146
+ const years = Math.round((days / 365) * 10) / 10;
147
+ return `${years} year${years !== 1 ? "s" : ""}`;
148
+ }
149
+ function parseDeckStats(stats) {
150
+ return {
151
+ new_count: stats.new_count || 0,
152
+ learn_count: stats.lrn_count || 0,
153
+ review_count: stats.rev_count || 0,
154
+ total_cards: stats.total || 0,
155
+ };
156
+ }
157
+ //# sourceMappingURL=anki.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anki.utils.js","sourceRoot":"","sources":["../../../src/mcp/utils/anki.utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export interface MarkdownSections {
2
+ [heading: string]: string;
3
+ }
4
+ export declare function parseMarkdownSections(markdown: string): MarkdownSections;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseMarkdownSections = parseMarkdownSections;
7
+ const unified_1 = require("unified");
8
+ const remark_parse_1 = __importDefault(require("remark-parse"));
9
+ const unist_util_visit_1 = require("unist-util-visit");
10
+ function nodeToString(node) {
11
+ if (node.type === "text") {
12
+ return node.value;
13
+ }
14
+ if (node.type === "inlineCode") {
15
+ return `\`${node.value}\``;
16
+ }
17
+ if ("children" in node && Array.isArray(node.children)) {
18
+ return node.children
19
+ .map((child) => nodeToString(child))
20
+ .join("");
21
+ }
22
+ if ("value" in node && typeof node.value === "string") {
23
+ return node.value;
24
+ }
25
+ return "";
26
+ }
27
+ function extractHeadingText(node) {
28
+ if ("children" in node && Array.isArray(node.children)) {
29
+ return node.children
30
+ .map((child) => nodeToString(child))
31
+ .join("");
32
+ }
33
+ return "";
34
+ }
35
+ function parseMarkdownSections(markdown) {
36
+ const tree = (0, unified_1.unified)().use(remark_parse_1.default).parse(markdown);
37
+ const sections = {};
38
+ let currentHeading = null;
39
+ let currentContent = [];
40
+ (0, unist_util_visit_1.visit)(tree, (node) => {
41
+ if (node.type === "heading" && node.depth === 1) {
42
+ if (currentHeading) {
43
+ sections[currentHeading] = currentContent.join("\n").trim();
44
+ }
45
+ currentHeading = extractHeadingText(node);
46
+ currentContent = [];
47
+ }
48
+ else if (currentHeading) {
49
+ const content = nodeToString(node);
50
+ if (content.trim()) {
51
+ currentContent.push(content.trim());
52
+ }
53
+ }
54
+ });
55
+ if (currentHeading) {
56
+ sections[currentHeading] = currentContent.join("\n").trim();
57
+ }
58
+ return sections;
59
+ }
60
+ //# sourceMappingURL=markdown.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.utils.js","sourceRoot":"","sources":["../../../src/mcp/utils/markdown.utils.ts"],"names":[],"mappings":";;;;;AAsEA,sDAgCC;AAtGD,qCAAkC;AAClC,gEAAuC;AACvC,uDAAyC;AAezC,SAAS,YAAY,CAAC,IAAiB;IACrC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC/B,OAAO,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC;IAC7B,CAAC;IACD,IAAI,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,QAAQ;aACjB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAoB,CAAC,CAAC;aAClD,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IACD,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAKD,SAAS,kBAAkB,CAAC,IAAiB;IAC3C,IAAI,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,QAAQ;aACjB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAoB,CAAC,CAAC;aAClD,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAyBD,SAAgB,qBAAqB,CAAC,QAAgB;IACpD,MAAM,IAAI,GAAG,IAAA,iBAAO,GAAE,CAAC,GAAG,CAAC,sBAAW,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAS,CAAC;IAChE,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,IAAI,cAAc,GAAa,EAAE,CAAC;IAElC,IAAA,wBAAK,EAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;QACnB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YAEhD,IAAI,cAAc,EAAE,CAAC;gBACnB,QAAQ,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9D,CAAC;YAGD,cAAc,GAAG,kBAAkB,CAAC,IAAmB,CAAC,CAAC;YACzD,cAAc,GAAG,EAAE,CAAC;QACtB,CAAC;aAAM,IAAI,cAAc,EAAE,CAAC;YAE1B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAmB,CAAC,CAAC;YAClD,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAGH,IAAI,cAAc,EAAE,CAAC;QACnB,QAAQ,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function sanitizeMcpbConfigValue(value: string | undefined): string | undefined;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeMcpbConfigValue = sanitizeMcpbConfigValue;
4
+ function sanitizeMcpbConfigValue(value) {
5
+ if (!value || value.trim() === "") {
6
+ return undefined;
7
+ }
8
+ if (value.startsWith("${") && value.endsWith("}")) {
9
+ return undefined;
10
+ }
11
+ return value;
12
+ }
13
+ //# sourceMappingURL=mcpb-workarounds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpb-workarounds.js","sourceRoot":"","sources":["../../../src/mcp/utils/mcpb-workarounds.ts"],"names":[],"mappings":";;AA0BA,0DAaC;AAbD,SAAgB,uBAAuB,CACrC,KAAyB;IAEzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IACnB,CAAC;IAGD,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface NgrokTunnelInfo {
2
+ publicUrl: string;
3
+ apiUrl: string;
4
+ }
5
+ export declare class NgrokService {
6
+ private process;
7
+ private cleanupHandlersRegistered;
8
+ start(port: number): Promise<NgrokTunnelInfo>;
9
+ private isNgrokInstalled;
10
+ private waitForNgrok;
11
+ private getTunnelUrl;
12
+ private registerCleanupHandlers;
13
+ private cleanup;
14
+ getWebInterfaceUrl(): string;
15
+ }
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NgrokService = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const http_1 = __importDefault(require("http"));
9
+ class NgrokService {
10
+ process = null;
11
+ cleanupHandlersRegistered = false;
12
+ async start(port) {
13
+ if (!(await this.isNgrokInstalled())) {
14
+ throw new Error("ngrok is not installed.\n" +
15
+ "Install it with: npm install -g ngrok\n" +
16
+ "Or download from: https://ngrok.com/download\n" +
17
+ "Then setup auth: ngrok config add-authtoken <your-token>");
18
+ }
19
+ this.process = (0, child_process_1.spawn)("ngrok", ["http", port.toString()], {
20
+ stdio: "pipe",
21
+ });
22
+ if (!this.cleanupHandlersRegistered) {
23
+ this.registerCleanupHandlers();
24
+ this.cleanupHandlersRegistered = true;
25
+ }
26
+ this.process.on("error", (err) => {
27
+ throw new Error(`Failed to start ngrok: ${err.message}`);
28
+ });
29
+ this.process.on("exit", (code, _signal) => {
30
+ if (code !== 0 && code !== null) {
31
+ console.error(`ngrok exited with code ${code}`);
32
+ }
33
+ });
34
+ await this.waitForNgrok();
35
+ const publicUrl = await this.getTunnelUrl();
36
+ return {
37
+ publicUrl,
38
+ apiUrl: "http://localhost:4040",
39
+ };
40
+ }
41
+ async isNgrokInstalled() {
42
+ return new Promise((resolve) => {
43
+ const check = (0, child_process_1.spawn)("which", ["ngrok"]);
44
+ check.on("close", (code) => resolve(code === 0));
45
+ check.on("error", () => resolve(false));
46
+ });
47
+ }
48
+ async waitForNgrok(maxAttempts = 20, delayMs = 500) {
49
+ for (let i = 0; i < maxAttempts; i++) {
50
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
51
+ try {
52
+ await this.getTunnelUrl();
53
+ return;
54
+ }
55
+ catch {
56
+ }
57
+ }
58
+ throw new Error("ngrok failed to start in time.\n" +
59
+ "Make sure you have configured your auth token:\n" +
60
+ "ngrok config add-authtoken <your-token>");
61
+ }
62
+ async getTunnelUrl() {
63
+ return new Promise((resolve, reject) => {
64
+ http_1.default
65
+ .get("http://localhost:4040/api/tunnels", (res) => {
66
+ let data = "";
67
+ res.on("data", (chunk) => (data += chunk));
68
+ res.on("end", () => {
69
+ try {
70
+ const response = JSON.parse(data);
71
+ const tunnel = response.tunnels?.find((t) => t.proto === "https");
72
+ const publicUrl = tunnel?.public_url;
73
+ if (publicUrl) {
74
+ resolve(publicUrl);
75
+ }
76
+ else {
77
+ reject(new Error("No HTTPS tunnel found in ngrok API response"));
78
+ }
79
+ }
80
+ catch (err) {
81
+ reject(new Error(`Failed to parse ngrok API response: ${err}`));
82
+ }
83
+ });
84
+ })
85
+ .on("error", (err) => {
86
+ reject(new Error(`Failed to connect to ngrok API: ${err.message}`));
87
+ });
88
+ });
89
+ }
90
+ registerCleanupHandlers() {
91
+ process.on("SIGINT", () => {
92
+ console.log("\n\n🛑 Shutting down ngrok tunnel...");
93
+ this.cleanup();
94
+ process.exit(0);
95
+ });
96
+ process.on("SIGTERM", () => {
97
+ this.cleanup();
98
+ process.exit(0);
99
+ });
100
+ process.on("exit", () => {
101
+ this.cleanup();
102
+ });
103
+ process.on("uncaughtException", (err) => {
104
+ console.error("Uncaught exception:", err);
105
+ this.cleanup();
106
+ process.exit(1);
107
+ });
108
+ }
109
+ cleanup() {
110
+ if (this.process && !this.process.killed) {
111
+ this.process.kill("SIGTERM");
112
+ this.process = null;
113
+ }
114
+ }
115
+ getWebInterfaceUrl() {
116
+ return "http://localhost:4040";
117
+ }
118
+ }
119
+ exports.NgrokService = NgrokService;
120
+ //# sourceMappingURL=ngrok.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngrok.service.js","sourceRoot":"","sources":["../../src/services/ngrok.service.ts"],"names":[],"mappings":"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"}