anki-mcp-http 0.19.2 → 0.20.1
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.
- package/README.md +7 -1
- package/dist/mcp/clients/anki-connect.client.d.ts +1 -0
- package/dist/mcp/clients/anki-connect.client.js +36 -11
- package/dist/mcp/clients/anki-connect.client.js.map +1 -1
- package/dist/mcp/primitives/essential/index.d.ts +13 -1
- package/dist/mcp/primitives/essential/index.js +25 -1
- package/dist/mcp/primitives/essential/index.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/add-model-field.tool.d.ts +113 -0
- package/dist/mcp/primitives/essential/tools/add-model-field.tool.js +150 -0
- package/dist/mcp/primitives/essential/tools/add-model-field.tool.js.map +1 -0
- package/dist/mcp/primitives/essential/tools/add-note.tool.js +1 -1
- package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/add-notes.tool.js +1 -1
- package/dist/mcp/primitives/essential/tools/add-notes.tool.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/model-templates.tool.d.ts +116 -0
- package/dist/mcp/primitives/essential/tools/model-templates.tool.js +95 -0
- package/dist/mcp/primitives/essential/tools/model-templates.tool.js.map +1 -0
- package/dist/mcp/primitives/essential/tools/remove-model-field.tool.d.ts +112 -0
- package/dist/mcp/primitives/essential/tools/remove-model-field.tool.js +107 -0
- package/dist/mcp/primitives/essential/tools/remove-model-field.tool.js.map +1 -0
- package/dist/mcp/primitives/essential/tools/rename-model-field.tool.d.ts +114 -0
- package/dist/mcp/primitives/essential/tools/rename-model-field.tool.js +156 -0
- package/dist/mcp/primitives/essential/tools/rename-model-field.tool.js.map +1 -0
- package/dist/mcp/primitives/essential/tools/reposition-model-field.tool.d.ts +113 -0
- package/dist/mcp/primitives/essential/tools/reposition-model-field.tool.js +137 -0
- package/dist/mcp/primitives/essential/tools/reposition-model-field.tool.js.map +1 -0
- package/dist/mcp/primitives/essential/tools/update-model-templates.tool.d.ts +115 -0
- package/dist/mcp/primitives/essential/tools/update-model-templates.tool.js +140 -0
- package/dist/mcp/primitives/essential/tools/update-model-templates.tool.js.map +1 -0
- package/package.json +12 -11
|
@@ -0,0 +1,140 @@
|
|
|
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 UpdateModelTemplatesTool_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.UpdateModelTemplatesTool = 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 UpdateModelTemplatesTool = UpdateModelTemplatesTool_1 = class UpdateModelTemplatesTool {
|
|
20
|
+
ankiClient;
|
|
21
|
+
logger = new common_1.Logger(UpdateModelTemplatesTool_1.name);
|
|
22
|
+
constructor(ankiClient) {
|
|
23
|
+
this.ankiClient = ankiClient;
|
|
24
|
+
}
|
|
25
|
+
async updateModelTemplates({ modelName, templates, }) {
|
|
26
|
+
try {
|
|
27
|
+
this.logger.log(`Updating templates for model: ${modelName}`);
|
|
28
|
+
const existingTemplates = await this.ankiClient.invoke("modelTemplates", {
|
|
29
|
+
modelName,
|
|
30
|
+
});
|
|
31
|
+
if (!existingTemplates || Object.keys(existingTemplates).length === 0) {
|
|
32
|
+
return (0, anki_utils_1.createErrorResponse)(new Error(`Model "${modelName}" has no templates or does not exist`), {
|
|
33
|
+
modelName,
|
|
34
|
+
hint: "Model not found. Use modelNames tool to see available models.",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const existingNames = new Set(Object.keys(existingTemplates));
|
|
38
|
+
const unknownNames = Object.keys(templates).filter((name) => !existingNames.has(name));
|
|
39
|
+
if (unknownNames.length > 0) {
|
|
40
|
+
const offending = unknownNames.map((name) => `"${name}"`).join(", ");
|
|
41
|
+
const validNames = Object.keys(existingTemplates)
|
|
42
|
+
.map((name) => `"${name}"`)
|
|
43
|
+
.join(", ");
|
|
44
|
+
return (0, anki_utils_1.createErrorResponse)(new Error(`Card template(s) not found in model "${modelName}": ${offending}. ` +
|
|
45
|
+
`Valid templates: ${validNames}. ` +
|
|
46
|
+
"Use modelTemplates to see current names."), {
|
|
47
|
+
modelName,
|
|
48
|
+
hint: `Card template names are case-sensitive and must match exactly. Valid templates: ${validNames}.`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const templateCount = Object.keys(templates).length;
|
|
52
|
+
await this.ankiClient.invoke("updateModelTemplates", {
|
|
53
|
+
model: {
|
|
54
|
+
name: modelName,
|
|
55
|
+
templates,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
this.logger.log(`Successfully updated ${templateCount} templates for model: ${modelName}`);
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
modelName,
|
|
62
|
+
templateCount,
|
|
63
|
+
message: `Successfully updated ${templateCount} card template(s) for model "${modelName}"`,
|
|
64
|
+
hint: "Template changes apply to all cards using this model. Use guiBrowse to preview changes.",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
this.logger.error(`Failed to update templates for model ${modelName}`, error);
|
|
69
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
70
|
+
if (errorMessage.includes("not found") ||
|
|
71
|
+
errorMessage.includes("does not exist") ||
|
|
72
|
+
errorMessage.includes("model not found")) {
|
|
73
|
+
return (0, anki_utils_1.createErrorResponse)(error, {
|
|
74
|
+
modelName,
|
|
75
|
+
hint: "Model not found. Use modelNames tool to see available models.",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return (0, anki_utils_1.createErrorResponse)(error, {
|
|
79
|
+
modelName,
|
|
80
|
+
hint: "Make sure Anki is running and the model name is correct.",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
exports.UpdateModelTemplatesTool = UpdateModelTemplatesTool;
|
|
86
|
+
__decorate([
|
|
87
|
+
(0, mcp_nest_1.Tool)({
|
|
88
|
+
name: "updateModelTemplates",
|
|
89
|
+
description: "Update the card templates (Front and Back HTML) for an existing note type (model). " +
|
|
90
|
+
"Each card template defines how the card's front and back sides are rendered. " +
|
|
91
|
+
"Use modelTemplates first to see current templates, then modify and pass back the templates object. " +
|
|
92
|
+
"Changes apply to all cards using this model. " +
|
|
93
|
+
"WARNING: Invalid HTML or missing required fields may break card rendering. " +
|
|
94
|
+
"Card template names are validated against the model's existing templates (case-sensitive) — unknown or mis-cased names are rejected before any update. " +
|
|
95
|
+
"An empty string cannot be used to blank a side.",
|
|
96
|
+
parameters: zod_1.z.object({
|
|
97
|
+
modelName: zod_1.z
|
|
98
|
+
.string()
|
|
99
|
+
.min(1)
|
|
100
|
+
.describe('Name of the model to update (e.g., "Basic", "Cloze")'),
|
|
101
|
+
templates: zod_1.z
|
|
102
|
+
.record(zod_1.z.string(), zod_1.z.object({
|
|
103
|
+
Front: zod_1.z
|
|
104
|
+
.string()
|
|
105
|
+
.min(1)
|
|
106
|
+
.describe("HTML template for the front/question side"),
|
|
107
|
+
Back: zod_1.z
|
|
108
|
+
.string()
|
|
109
|
+
.min(1)
|
|
110
|
+
.describe("HTML template for the back/answer side"),
|
|
111
|
+
}))
|
|
112
|
+
.refine((t) => Object.keys(t).length > 0, {
|
|
113
|
+
message: "At least one card template is required",
|
|
114
|
+
})
|
|
115
|
+
.describe('Card templates keyed by card name (e.g., { "Card 1": { Front: "...", Back: "..." } }). ' +
|
|
116
|
+
"Use modelTemplates first to get the current structure, then modify the Front/Back HTML as needed."),
|
|
117
|
+
}),
|
|
118
|
+
outputSchema: zod_1.z.object({
|
|
119
|
+
success: zod_1.z.boolean(),
|
|
120
|
+
modelName: zod_1.z.string(),
|
|
121
|
+
templateCount: zod_1.z.number(),
|
|
122
|
+
message: zod_1.z.string(),
|
|
123
|
+
hint: zod_1.z.string(),
|
|
124
|
+
}),
|
|
125
|
+
annotations: {
|
|
126
|
+
title: "Update Note Type Templates",
|
|
127
|
+
readOnlyHint: false,
|
|
128
|
+
destructiveHint: false,
|
|
129
|
+
idempotentHint: true,
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
__metadata("design:type", Function),
|
|
133
|
+
__metadata("design:paramtypes", [Object]),
|
|
134
|
+
__metadata("design:returntype", Promise)
|
|
135
|
+
], UpdateModelTemplatesTool.prototype, "updateModelTemplates", null);
|
|
136
|
+
exports.UpdateModelTemplatesTool = UpdateModelTemplatesTool = UpdateModelTemplatesTool_1 = __decorate([
|
|
137
|
+
(0, common_1.Injectable)(),
|
|
138
|
+
__metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
|
|
139
|
+
], UpdateModelTemplatesTool);
|
|
140
|
+
//# sourceMappingURL=update-model-templates.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-model-templates.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/update-model-templates.tool.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anki-mcp-http",
|
|
3
3
|
"mcpName": "ai.ankimcp/anki-mcp-server",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.20.1",
|
|
5
5
|
"description": "Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards",
|
|
6
6
|
"author": "Anatoly Tarnavsky",
|
|
7
7
|
"private": false,
|
|
@@ -57,13 +57,14 @@
|
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
60
|
-
"@nestjs/common": "^11.1.
|
|
60
|
+
"@nestjs/common": "^11.1.26",
|
|
61
61
|
"@nestjs/config": "^4.0.4",
|
|
62
|
-
"@nestjs/core": "11.1.
|
|
62
|
+
"@nestjs/core": "11.1.26",
|
|
63
63
|
"@nestjs/jwt": "^11.0.2",
|
|
64
64
|
"@nestjs/passport": "^11.0.5",
|
|
65
|
-
"@nestjs/platform-express": "^11.1.
|
|
65
|
+
"@nestjs/platform-express": "^11.1.26",
|
|
66
66
|
"@rekog/mcp-nest": "^1.9.10",
|
|
67
|
+
"async-mutex": "^0.5.0",
|
|
67
68
|
"commander": "^15.0.0",
|
|
68
69
|
"ipaddr.js": "^2.4.0",
|
|
69
70
|
"jsonwebtoken": "^9.0.3",
|
|
@@ -87,15 +88,15 @@
|
|
|
87
88
|
"@anthropic-ai/mcpb": "^2.1.2",
|
|
88
89
|
"@eslint/eslintrc": "^3.3.5",
|
|
89
90
|
"@eslint/js": "^10.0.1",
|
|
90
|
-
"@modelcontextprotocol/inspector": "^0.
|
|
91
|
-
"@nestjs/cli": "^11.0.
|
|
91
|
+
"@modelcontextprotocol/inspector": "^0.22.0",
|
|
92
|
+
"@nestjs/cli": "^11.0.23",
|
|
92
93
|
"@nestjs/schematics": "^11.1.0",
|
|
93
|
-
"@nestjs/testing": "^11.1.
|
|
94
|
+
"@nestjs/testing": "^11.1.26",
|
|
94
95
|
"@types/express": "^5.0.6",
|
|
95
96
|
"@types/jest": "^30.0.0",
|
|
96
97
|
"@types/jsonwebtoken": "^9.0.10",
|
|
97
98
|
"@types/mdast": "^4.0.4",
|
|
98
|
-
"@types/node": "^25.9.
|
|
99
|
+
"@types/node": "^25.9.3",
|
|
99
100
|
"@types/supertest": "^7.2.0",
|
|
100
101
|
"@types/update-notifier": "^6.0.8",
|
|
101
102
|
"@types/ws": "^8.18.1",
|
|
@@ -105,8 +106,8 @@
|
|
|
105
106
|
"globals": "^17.6.0",
|
|
106
107
|
"husky": "^9.1.7",
|
|
107
108
|
"jest": "^30.4.2",
|
|
108
|
-
"prettier": "^3.8.
|
|
109
|
-
"sharp": "^0.
|
|
109
|
+
"prettier": "^3.8.4",
|
|
110
|
+
"sharp": "^0.35.0",
|
|
110
111
|
"source-map-support": "^0.5.21",
|
|
111
112
|
"supertest": "^7.2.2",
|
|
112
113
|
"ts-jest": "^29.4.11",
|
|
@@ -114,7 +115,7 @@
|
|
|
114
115
|
"ts-node": "^10.9.2",
|
|
115
116
|
"tsconfig-paths": "^4.2.0",
|
|
116
117
|
"typescript": "^6.0.3",
|
|
117
|
-
"typescript-eslint": "^8.
|
|
118
|
+
"typescript-eslint": "^8.61.0"
|
|
118
119
|
},
|
|
119
120
|
"jest": {
|
|
120
121
|
"moduleFileExtensions": [
|