@ankimcp/anki-mcp-server 0.18.0 → 0.18.4-tunnel
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/bin/ankimcp.js +10 -1
- package/dist/app-config.service.d.ts +22 -0
- package/dist/app-config.service.js +79 -0
- package/dist/app-config.service.js.map +1 -0
- package/dist/app.module.d.ts +4 -2
- package/dist/app.module.js +99 -11
- package/dist/app.module.js.map +1 -1
- package/dist/bootstrap.d.ts +6 -1
- package/dist/bootstrap.js +7 -2
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli/__tests__/cli-output.manual.d.ts +2 -0
- package/dist/cli/__tests__/cli-output.manual.js +13 -0
- package/dist/cli/__tests__/cli-output.manual.js.map +1 -0
- package/dist/cli/cli-output.d.ts +20 -0
- package/dist/cli/cli-output.js +69 -0
- package/dist/cli/cli-output.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +20 -6
- package/dist/cli.js.map +1 -1
- package/dist/config/config.factory.d.ts +13 -0
- package/dist/config/config.factory.js +32 -0
- package/dist/config/config.factory.js.map +1 -0
- package/dist/config/config.schema.d.ts +33 -0
- package/dist/config/config.schema.js +58 -0
- package/dist/config/config.schema.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +11 -0
- package/dist/config/index.js.map +1 -0
- package/dist/http/guards/origin-validation.guard.d.ts +1 -0
- package/dist/http/guards/origin-validation.guard.js +5 -3
- package/dist/http/guards/origin-validation.guard.js.map +1 -1
- package/dist/main-http.js +20 -10
- package/dist/main-http.js.map +1 -1
- package/dist/main-stdio.js +9 -9
- package/dist/main-stdio.js.map +1 -1
- package/dist/main-tunnel.d.ts +1 -0
- package/dist/main-tunnel.js +26 -0
- package/dist/main-tunnel.js.map +1 -0
- package/dist/mcp/primitives/essential/index.d.ts +1 -0
- package/dist/mcp/primitives/essential/index.js +8 -1
- package/dist/mcp/primitives/essential/index.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +1 -1
- package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js +66 -36
- package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/deck-stats.tool.js +25 -8
- package/dist/mcp/primitives/essential/tools/deck-stats.tool.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js +14 -7
- package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js.map +1 -1
- package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +1 -1
- package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -1
- package/dist/mcp/primitives/gui/index.d.ts +1 -0
- package/dist/mcp/primitives/gui/index.js +8 -1
- package/dist/mcp/primitives/gui/index.js.map +1 -1
- package/dist/mcp/utils/deck-hierarchy.utils.d.ts +3 -0
- package/dist/mcp/utils/deck-hierarchy.utils.js +21 -0
- package/dist/mcp/utils/deck-hierarchy.utils.js.map +1 -0
- package/dist/services/ngrok.service.d.ts +1 -0
- package/dist/services/ngrok.service.js +5 -3
- package/dist/services/ngrok.service.js.map +1 -1
- package/dist/test-fixtures/mock-data.d.ts +8 -0
- package/dist/test-fixtures/mock-data.js +8 -0
- package/dist/test-fixtures/mock-data.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/tunnel/commands/index.d.ts +3 -0
- package/dist/tunnel/commands/index.js +10 -0
- package/dist/tunnel/commands/index.js.map +1 -0
- package/dist/tunnel/commands/login.command.d.ts +1 -0
- package/dist/tunnel/commands/login.command.js +108 -0
- package/dist/tunnel/commands/login.command.js.map +1 -0
- package/dist/tunnel/commands/logout.command.d.ts +1 -0
- package/dist/tunnel/commands/logout.command.js +26 -0
- package/dist/tunnel/commands/logout.command.js.map +1 -0
- package/dist/tunnel/commands/tunnel.command.d.ts +1 -0
- package/dist/tunnel/commands/tunnel.command.js +185 -0
- package/dist/tunnel/commands/tunnel.command.js.map +1 -0
- package/dist/tunnel/credentials.service.d.ts +23 -0
- package/dist/tunnel/credentials.service.js +152 -0
- package/dist/tunnel/credentials.service.js.map +1 -0
- package/dist/tunnel/device-flow.service.d.ts +46 -0
- package/dist/tunnel/device-flow.service.js +237 -0
- package/dist/tunnel/device-flow.service.js.map +1 -0
- package/dist/tunnel/in-memory.transport.d.ts +14 -0
- package/dist/tunnel/in-memory.transport.js +63 -0
- package/dist/tunnel/in-memory.transport.js.map +1 -0
- package/dist/tunnel/index.d.ts +6 -0
- package/dist/tunnel/index.js +31 -0
- package/dist/tunnel/index.js.map +1 -0
- package/dist/tunnel/tunnel-mcp.service.d.ts +15 -0
- package/dist/tunnel/tunnel-mcp.service.js +100 -0
- package/dist/tunnel/tunnel-mcp.service.js.map +1 -0
- package/dist/tunnel/tunnel.client.d.ts +60 -0
- package/dist/tunnel/tunnel.client.js +386 -0
- package/dist/tunnel/tunnel.client.js.map +1 -0
- package/dist/tunnel/tunnel.protocol.d.ts +68 -0
- package/dist/tunnel/tunnel.protocol.js +26 -0
- package/dist/tunnel/tunnel.protocol.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +21 -0
- package/dist/version.js.map +1 -0
- package/package.json +7 -2
- package/dist/anki-config.service.d.ts +0 -11
- package/dist/anki-config.service.js +0 -46
- package/dist/anki-config.service.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildConfigInput = buildConfigInput;
|
|
4
|
+
exports.loadValidatedConfig = loadValidatedConfig;
|
|
5
|
+
const config_schema_1 = require("./config.schema");
|
|
6
|
+
function buildConfigInput(cliOverrides = {}) {
|
|
7
|
+
const input = { ...process.env };
|
|
8
|
+
if (cliOverrides.port !== undefined) {
|
|
9
|
+
input.PORT = String(cliOverrides.port);
|
|
10
|
+
}
|
|
11
|
+
if (cliOverrides.host !== undefined) {
|
|
12
|
+
input.HOST = cliOverrides.host;
|
|
13
|
+
}
|
|
14
|
+
if (cliOverrides.ankiConnect !== undefined) {
|
|
15
|
+
input.ANKI_CONNECT_URL = cliOverrides.ankiConnect;
|
|
16
|
+
}
|
|
17
|
+
if (cliOverrides.readOnly !== undefined) {
|
|
18
|
+
input.READ_ONLY = cliOverrides.readOnly ? "true" : "false";
|
|
19
|
+
}
|
|
20
|
+
if (typeof cliOverrides.tunnel === "string") {
|
|
21
|
+
input.TUNNEL_SERVER_URL = cliOverrides.tunnel;
|
|
22
|
+
}
|
|
23
|
+
if (cliOverrides.debug) {
|
|
24
|
+
input.LOG_LEVEL = "debug";
|
|
25
|
+
}
|
|
26
|
+
return input;
|
|
27
|
+
}
|
|
28
|
+
function loadValidatedConfig(cliOverrides = {}) {
|
|
29
|
+
const input = buildConfigInput(cliOverrides);
|
|
30
|
+
return config_schema_1.configSchema.parse((0, config_schema_1.transformEnvToConfig)(input));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=config.factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.factory.js","sourceRoot":"","sources":["../../src/config/config.factory.ts"],"names":[],"mappings":";;AA8BA,4CAwBC;AAMD,kDAKC;AAjED,mDAAgF;AA8BhF,SAAgB,gBAAgB,CAAC,eAA6B,EAAE;IAE9D,MAAM,KAAK,GAAgB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE9C,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC3C,KAAK,CAAC,gBAAgB,GAAG,YAAY,CAAC,WAAW,CAAC;IACpD,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACxC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC5C,KAAK,CAAC,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC;IAChD,CAAC;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAMD,SAAgB,mBAAmB,CACjC,eAA6B,EAAE;IAE/B,MAAM,KAAK,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,4BAAY,CAAC,KAAK,CAAC,IAAA,oCAAoB,EAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const configSchema: z.ZodObject<{
|
|
3
|
+
port: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
4
|
+
host: z.ZodDefault<z.ZodString>;
|
|
5
|
+
nodeEnv: z.ZodDefault<z.ZodEnum<{
|
|
6
|
+
development: "development";
|
|
7
|
+
production: "production";
|
|
8
|
+
test: "test";
|
|
9
|
+
}>>;
|
|
10
|
+
ankiConnect: z.ZodObject<{
|
|
11
|
+
url: z.ZodDefault<z.ZodString>;
|
|
12
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
13
|
+
apiVersion: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
14
|
+
timeout: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
auth: z.ZodObject<{
|
|
17
|
+
url: z.ZodDefault<z.ZodString>;
|
|
18
|
+
realm: z.ZodDefault<z.ZodString>;
|
|
19
|
+
clientId: z.ZodDefault<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
tunnel: z.ZodObject<{
|
|
22
|
+
serverUrl: z.ZodDefault<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
readOnly: z.ZodDefault<z.ZodPipe<z.ZodTransform<{} | null, unknown>, z.ZodBoolean>>;
|
|
25
|
+
logLevel: z.ZodDefault<z.ZodEnum<{
|
|
26
|
+
error: "error";
|
|
27
|
+
debug: "debug";
|
|
28
|
+
info: "info";
|
|
29
|
+
warn: "warn";
|
|
30
|
+
}>>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type AppConfig = z.infer<typeof configSchema>;
|
|
33
|
+
export declare function transformEnvToConfig(env: Record<string, any>): any;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configSchema = void 0;
|
|
4
|
+
exports.transformEnvToConfig = transformEnvToConfig;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
exports.configSchema = zod_1.z.object({
|
|
7
|
+
port: zod_1.z.coerce.number().int().positive().default(3000),
|
|
8
|
+
host: zod_1.z.string().default("127.0.0.1"),
|
|
9
|
+
nodeEnv: zod_1.z.enum(["development", "production", "test"]).default("development"),
|
|
10
|
+
ankiConnect: zod_1.z.object({
|
|
11
|
+
url: zod_1.z.string().url().default("http://localhost:8765"),
|
|
12
|
+
apiKey: zod_1.z.string().optional(),
|
|
13
|
+
apiVersion: zod_1.z.coerce.number().int().positive().default(6),
|
|
14
|
+
timeout: zod_1.z.coerce.number().int().positive().default(5000),
|
|
15
|
+
}),
|
|
16
|
+
auth: zod_1.z.object({
|
|
17
|
+
url: zod_1.z.string().url().default("https://keycloak.anatoly.dev"),
|
|
18
|
+
realm: zod_1.z.string().default("ankimcp-dev"),
|
|
19
|
+
clientId: zod_1.z.string().default("ankimcp-cli"),
|
|
20
|
+
}),
|
|
21
|
+
tunnel: zod_1.z.object({
|
|
22
|
+
serverUrl: zod_1.z.string().url().default("wss://tunnel.ankimcp.ai"),
|
|
23
|
+
}),
|
|
24
|
+
readOnly: zod_1.z
|
|
25
|
+
.preprocess((val) => {
|
|
26
|
+
if (val === "true" || val === "1")
|
|
27
|
+
return true;
|
|
28
|
+
if (val === "false" || val === "0" || val === undefined || val === "")
|
|
29
|
+
return false;
|
|
30
|
+
return val;
|
|
31
|
+
}, zod_1.z.boolean())
|
|
32
|
+
.default(false),
|
|
33
|
+
logLevel: zod_1.z.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
34
|
+
});
|
|
35
|
+
function transformEnvToConfig(env) {
|
|
36
|
+
return {
|
|
37
|
+
port: env.PORT,
|
|
38
|
+
host: env.HOST,
|
|
39
|
+
nodeEnv: env.NODE_ENV,
|
|
40
|
+
ankiConnect: {
|
|
41
|
+
url: env.ANKI_CONNECT_URL,
|
|
42
|
+
apiKey: env.ANKI_CONNECT_API_KEY,
|
|
43
|
+
apiVersion: env.ANKI_CONNECT_API_VERSION,
|
|
44
|
+
timeout: env.ANKI_CONNECT_TIMEOUT,
|
|
45
|
+
},
|
|
46
|
+
auth: {
|
|
47
|
+
url: env.TUNNEL_AUTH_URL,
|
|
48
|
+
realm: env.TUNNEL_AUTH_REALM,
|
|
49
|
+
clientId: env.TUNNEL_AUTH_CLIENT_ID,
|
|
50
|
+
},
|
|
51
|
+
tunnel: {
|
|
52
|
+
serverUrl: env.TUNNEL_SERVER_URL,
|
|
53
|
+
},
|
|
54
|
+
readOnly: env.READ_ONLY,
|
|
55
|
+
logLevel: env.LOG_LEVEL,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=config.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.schema.js","sourceRoot":"","sources":["../../src/config/config.schema.ts"],"names":[],"mappings":";;;AAuDA,oDAsBC;AA7ED,6BAAwB;AAMX,QAAA,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IAEnC,IAAI,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACtD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;IACrC,OAAO,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAG7E,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC;QACpB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;QACtD,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACzD,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KAC1D,CAAC;IAGF,IAAI,EAAE,OAAC,CAAC,MAAM,CAAC;QACb,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC;QAC7D,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;QACxC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;KAC5C,CAAC;IAGF,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,yBAAyB,CAAC;KAC/D,CAAC;IAGF,QAAQ,EAAE,OAAC;SACR,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;QAClB,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAC/C,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;YACnE,OAAO,KAAK,CAAC;QACf,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC;SACd,OAAO,CAAC,KAAK,CAAC;IAGjB,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;CACrE,CAAC,CAAC;AAWH,SAAgB,oBAAoB,CAAC,GAAwB;IAC3D,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,WAAW,EAAE;YACX,GAAG,EAAE,GAAG,CAAC,gBAAgB;YACzB,MAAM,EAAE,GAAG,CAAC,oBAAoB;YAChC,UAAU,EAAE,GAAG,CAAC,wBAAwB;YACxC,OAAO,EAAE,GAAG,CAAC,oBAAoB;SAClC;QACD,IAAI,EAAE;YACJ,GAAG,EAAE,GAAG,CAAC,eAAe;YACxB,KAAK,EAAE,GAAG,CAAC,iBAAiB;YAC5B,QAAQ,EAAE,GAAG,CAAC,qBAAqB;SACpC;QACD,MAAM,EAAE;YACN,SAAS,EAAE,GAAG,CAAC,iBAAiB;SACjC;QACD,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,QAAQ,EAAE,GAAG,CAAC,SAAS;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APP_CONFIG = exports.loadValidatedConfig = exports.buildConfigInput = exports.transformEnvToConfig = exports.configSchema = void 0;
|
|
4
|
+
var config_schema_1 = require("./config.schema");
|
|
5
|
+
Object.defineProperty(exports, "configSchema", { enumerable: true, get: function () { return config_schema_1.configSchema; } });
|
|
6
|
+
Object.defineProperty(exports, "transformEnvToConfig", { enumerable: true, get: function () { return config_schema_1.transformEnvToConfig; } });
|
|
7
|
+
var config_factory_1 = require("./config.factory");
|
|
8
|
+
Object.defineProperty(exports, "buildConfigInput", { enumerable: true, get: function () { return config_factory_1.buildConfigInput; } });
|
|
9
|
+
Object.defineProperty(exports, "loadValidatedConfig", { enumerable: true, get: function () { return config_factory_1.loadValidatedConfig; } });
|
|
10
|
+
exports.APP_CONFIG = Symbol("APP_CONFIG");
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":";;;AAIA,iDAIyB;AAHvB,6GAAA,YAAY,OAAA;AACZ,qHAAA,oBAAoB,OAAA;AAGtB,mDAK0B;AAJxB,kHAAA,gBAAgB,OAAA;AAChB,qHAAA,mBAAmB,OAAA;AASR,QAAA,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -8,10 +8,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var OriginValidationGuard_1;
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
13
|
exports.OriginValidationGuard = void 0;
|
|
13
14
|
const common_1 = require("@nestjs/common");
|
|
14
|
-
let OriginValidationGuard = class OriginValidationGuard {
|
|
15
|
+
let OriginValidationGuard = OriginValidationGuard_1 = class OriginValidationGuard {
|
|
16
|
+
logger = new common_1.Logger(OriginValidationGuard_1.name);
|
|
15
17
|
allowedOrigins;
|
|
16
18
|
constructor() {
|
|
17
19
|
const defaultOrigins = "http://localhost:*,http://127.0.0.1:*,https://localhost:*,https://127.0.0.1:*";
|
|
@@ -26,7 +28,7 @@ let OriginValidationGuard = class OriginValidationGuard {
|
|
|
26
28
|
}
|
|
27
29
|
const isAllowed = this.allowedOrigins.some((allowedOrigin) => this.matchesPattern(origin, allowedOrigin));
|
|
28
30
|
if (!isAllowed) {
|
|
29
|
-
|
|
31
|
+
this.logger.warn(`Rejected request from unauthorized origin: ${origin}`);
|
|
30
32
|
}
|
|
31
33
|
return isAllowed;
|
|
32
34
|
}
|
|
@@ -45,7 +47,7 @@ let OriginValidationGuard = class OriginValidationGuard {
|
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
49
|
exports.OriginValidationGuard = OriginValidationGuard;
|
|
48
|
-
exports.OriginValidationGuard = OriginValidationGuard = __decorate([
|
|
50
|
+
exports.OriginValidationGuard = OriginValidationGuard = OriginValidationGuard_1 = __decorate([
|
|
49
51
|
(0, common_1.Injectable)(),
|
|
50
52
|
__metadata("design:paramtypes", [])
|
|
51
53
|
], OriginValidationGuard);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"origin-validation.guard.js","sourceRoot":"","sources":["../../../src/http/guards/origin-validation.guard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"origin-validation.guard.js","sourceRoot":"","sources":["../../../src/http/guards/origin-validation.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAKwB;AAiBjB,IAAM,qBAAqB,6BAA3B,MAAM,qBAAqB;IACf,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAqB,CAAC,IAAI,CAAC,CAAC;IAChD,cAAc,CAAW;IAE1C;QACE,MAAM,cAAc,GAClB,+EAA+E,CAAC;QAClF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,cAAc,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAGjE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE,CAC3D,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAC3C,CAAC;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IASO,cAAc,CAAC,MAAc,EAAE,OAAe;QAEpD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,OAAO;iBACzB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;iBACrB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACxB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC;YAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAxDY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;;GACA,qBAAqB,CAwDjC"}
|
package/dist/main-http.js
CHANGED
|
@@ -5,17 +5,25 @@ const app_module_1 = require("./app.module");
|
|
|
5
5
|
const bootstrap_1 = require("./bootstrap");
|
|
6
6
|
const origin_validation_guard_1 = require("./http/guards/origin-validation.guard");
|
|
7
7
|
const cli_1 = require("./cli");
|
|
8
|
+
const cli_output_1 = require("./cli/cli-output");
|
|
8
9
|
const ngrok_service_1 = require("./services/ngrok.service");
|
|
10
|
+
const config_1 = require("./config");
|
|
9
11
|
async function bootstrap() {
|
|
10
12
|
(0, cli_1.checkForUpdates)();
|
|
11
13
|
const options = (0, cli_1.parseCliArgs)();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
(0, cli_output_1.setDebugMode)(options.debug);
|
|
15
|
+
const configInput = (0, config_1.buildConfigInput)({
|
|
16
|
+
port: options.port,
|
|
17
|
+
host: options.host,
|
|
18
|
+
ankiConnect: options.ankiConnect,
|
|
19
|
+
readOnly: options.readOnly,
|
|
20
|
+
tunnel: options.tunnel,
|
|
21
|
+
ngrok: options.ngrok,
|
|
22
|
+
debug: options.debug,
|
|
23
|
+
});
|
|
24
|
+
const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDOUT, configInput.LOG_LEVEL || "info");
|
|
17
25
|
const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
|
|
18
|
-
const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(), {
|
|
26
|
+
const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(configInput), {
|
|
19
27
|
logger: loggerService,
|
|
20
28
|
bufferLogs: true,
|
|
21
29
|
});
|
|
@@ -29,15 +37,17 @@ async function bootstrap() {
|
|
|
29
37
|
ngrokUrl = tunnelInfo.publicUrl;
|
|
30
38
|
}
|
|
31
39
|
catch (err) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
cli_output_1.cli.blank();
|
|
41
|
+
cli_output_1.cli.error(`Failed to start ngrok: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
|
|
42
|
+
cli_output_1.cli.blank();
|
|
43
|
+
cli_output_1.cli.info("Server is still running locally without tunnel.");
|
|
44
|
+
cli_output_1.cli.blank();
|
|
35
45
|
}
|
|
36
46
|
}
|
|
37
47
|
(0, cli_1.displayStartupBanner)(options, ngrokUrl);
|
|
38
48
|
}
|
|
39
49
|
bootstrap().catch((err) => {
|
|
40
|
-
|
|
50
|
+
cli_output_1.cli.error(`Failed to start MCP HTTP server: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
|
|
41
51
|
process.exit(1);
|
|
42
52
|
});
|
|
43
53
|
//# sourceMappingURL=main-http.js.map
|
package/dist/main-http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,
|
|
1
|
+
{"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAIqB;AACrB,mFAA8E;AAC9E,+BAA4E;AAC5E,iDAAqD;AACrD,4DAAwD;AACxD,qCAA4C;AAE5C,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,IAAA,yBAAY,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAG5B,MAAM,WAAW,GAAG,IAAA,yBAAgB,EAAC;QACnC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAIH,MAAM,UAAU,GAAG,IAAA,4BAAgB,EACjC,2BAAe,CAAC,MAAM,EACtB,WAAW,CAAC,SAAS,IAAI,MAAM,CAChC,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;QACnE,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,IAAI,+CAAqB,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7C,IAAI,QAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gBAAG,CAAC,KAAK,EAAE,CAAC;YACZ,gBAAG,CAAC,KAAK,CACP,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC5E,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;YACF,gBAAG,CAAC,KAAK,EAAE,CAAC;YACZ,gBAAG,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC5D,gBAAG,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAGD,IAAA,0BAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,oCAAoC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACtF,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/main-stdio.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@nestjs/core");
|
|
4
4
|
const app_module_1 = require("./app.module");
|
|
5
5
|
const bootstrap_1 = require("./bootstrap");
|
|
6
|
+
const cli_output_1 = require("./cli/cli-output");
|
|
7
|
+
const config_1 = require("./config");
|
|
6
8
|
function parseStdioArgs() {
|
|
7
9
|
const args = process.argv.slice(2);
|
|
8
10
|
let readOnly = false;
|
|
@@ -20,15 +22,13 @@ function parseStdioArgs() {
|
|
|
20
22
|
}
|
|
21
23
|
async function bootstrap() {
|
|
22
24
|
const cliOptions = parseStdioArgs();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
const pinoLogger = (0, bootstrap_1.createPinoLogger)(2);
|
|
25
|
+
const configInput = (0, config_1.buildConfigInput)({
|
|
26
|
+
ankiConnect: cliOptions.ankiConnect,
|
|
27
|
+
readOnly: cliOptions.readOnly,
|
|
28
|
+
});
|
|
29
|
+
const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDERR, configInput.LOG_LEVEL || "info");
|
|
30
30
|
const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
|
|
31
|
-
await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forStdio(), {
|
|
31
|
+
await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forStdio(configInput), {
|
|
32
32
|
logger: loggerService,
|
|
33
33
|
bufferLogs: true,
|
|
34
34
|
});
|
|
@@ -41,7 +41,7 @@ async function bootstrap() {
|
|
|
41
41
|
await new Promise(() => { });
|
|
42
42
|
}
|
|
43
43
|
bootstrap().catch((err) => {
|
|
44
|
-
|
|
44
|
+
cli_output_1.cli.error(`Failed to start MCP STDIO server: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
|
|
45
45
|
process.exit(1);
|
|
46
46
|
});
|
|
47
47
|
//# sourceMappingURL=main-stdio.js.map
|
package/dist/main-stdio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,
|
|
1
|
+
{"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAIqB;AACrB,iDAAuC;AACvC,qCAA4C;AAM5C,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAA+B,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC9B,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,SAAS;IAEtB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IAGpC,MAAM,WAAW,GAAG,IAAA,yBAAgB,EAAC;QACnC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAC,CAAC;IAIH,MAAM,UAAU,GAAG,IAAA,4BAAgB,EACjC,2BAAe,CAAC,MAAM,EACtB,WAAW,CAAC,SAAS,IAAI,MAAM,CAChC,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,kBAAW,CAAC,wBAAwB,CAAC,sBAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;QAC1E,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAGD,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,qCAAqC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACvF,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const cli_1 = require("./cli");
|
|
4
|
+
const cli_output_1 = require("./cli/cli-output");
|
|
5
|
+
const tunnel_1 = require("./tunnel");
|
|
6
|
+
async function bootstrap() {
|
|
7
|
+
(0, cli_1.checkForUpdates)();
|
|
8
|
+
const options = (0, cli_1.parseCliArgs)();
|
|
9
|
+
(0, cli_output_1.setDebugMode)(options.debug);
|
|
10
|
+
if (options.login) {
|
|
11
|
+
const loginUrl = typeof options.login === "string" ? options.login : undefined;
|
|
12
|
+
await (0, tunnel_1.handleLogin)(loginUrl);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
if (options.logout) {
|
|
16
|
+
await (0, tunnel_1.handleLogout)();
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
const tunnelUrl = typeof options.tunnel === "string" ? options.tunnel : undefined;
|
|
20
|
+
await (0, tunnel_1.handleTunnel)(tunnelUrl, options.debug, options.readOnly);
|
|
21
|
+
}
|
|
22
|
+
bootstrap().catch((err) => {
|
|
23
|
+
cli_output_1.cli.error(`Failed to start tunnel: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=main-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-tunnel.js","sourceRoot":"","sources":["../src/main-tunnel.ts"],"names":[],"mappings":";;AAAA,+BAAsD;AACtD,iDAAqD;AACrD,qCAAmE;AAEnE,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,IAAA,yBAAY,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAG5B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,MAAM,IAAA,oBAAW,EAAC,QAAQ,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAA,qBAAY,GAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAID,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,MAAM,IAAA,qBAAY,EAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC7E,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -75,6 +75,7 @@ import { SystemInfoResource } from "./resources/system-info.resource";
|
|
|
75
75
|
export declare const ESSENTIAL_MCP_TOOLS: (typeof SyncTool | typeof GetDueCardsTool | typeof GetCardsTool | typeof PresentCardTool | typeof RateCardTool | typeof ModelNamesTool | typeof ModelFieldNamesTool | typeof ModelStylingTool | typeof CreateModelTool | typeof UpdateModelStylingTool | typeof AddNoteTool | typeof AddNotesTool | typeof FindNotesTool | typeof NotesInfoTool | typeof UpdateNoteFieldsTool | typeof DeleteNotesTool | typeof GetTagsTool | typeof ListDecksTool | typeof DeckStatsTool | typeof CreateDeckTool | typeof ChangeDeckTool | typeof RetrieveMediaFileTool | typeof GetMediaFilesNamesTool | typeof StoreMediaFileTool | typeof DeleteMediaFileTool | typeof AddTagsTool | typeof RemoveTagsTool | typeof ReplaceTagsTool | typeof ClearUnusedTagsTool | typeof CollectionStatsTool | typeof ReviewStatsTool | typeof ReviewSessionPrompt | typeof TwentyRulesPrompt | typeof SystemInfoResource)[];
|
|
76
76
|
export interface McpPrimitivesAnkiEssentialModuleOptions {
|
|
77
77
|
ankiConfigProvider: Provider;
|
|
78
|
+
appConfigProvider?: Provider;
|
|
78
79
|
}
|
|
79
80
|
export declare class McpPrimitivesAnkiEssentialModule {
|
|
80
81
|
static forRoot(options: McpPrimitivesAnkiEssentialModuleOptions): DynamicModule;
|
|
@@ -173,9 +173,16 @@ exports.ESSENTIAL_MCP_TOOLS = [
|
|
|
173
173
|
const ESSENTIAL_MCP_PRIMITIVES = [anki_connect_client_2.AnkiConnectClient, ...exports.ESSENTIAL_MCP_TOOLS];
|
|
174
174
|
let McpPrimitivesAnkiEssentialModule = McpPrimitivesAnkiEssentialModule_1 = class McpPrimitivesAnkiEssentialModule {
|
|
175
175
|
static forRoot(options) {
|
|
176
|
+
const providers = [
|
|
177
|
+
options.ankiConfigProvider,
|
|
178
|
+
...ESSENTIAL_MCP_PRIMITIVES,
|
|
179
|
+
];
|
|
180
|
+
if (options.appConfigProvider) {
|
|
181
|
+
providers.push(options.appConfigProvider);
|
|
182
|
+
}
|
|
176
183
|
return {
|
|
177
184
|
module: McpPrimitivesAnkiEssentialModule_1,
|
|
178
|
-
providers
|
|
185
|
+
providers,
|
|
179
186
|
exports: ESSENTIAL_MCP_PRIMITIVES,
|
|
180
187
|
};
|
|
181
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -121,7 +121,7 @@ export declare class AddNoteTool {
|
|
|
121
121
|
details: {
|
|
122
122
|
fieldsAdded: number;
|
|
123
123
|
tagsAdded: number;
|
|
124
|
-
duplicateCheckScope: "
|
|
124
|
+
duplicateCheckScope: "default" | "deck" | "collection" | "none";
|
|
125
125
|
};
|
|
126
126
|
}>;
|
|
127
127
|
}
|
|
@@ -16,6 +16,7 @@ const mcp_nest_1 = require("@rekog/mcp-nest");
|
|
|
16
16
|
const zod_1 = require("zod");
|
|
17
17
|
const anki_connect_client_1 = require("../../../../clients/anki-connect.client");
|
|
18
18
|
const anki_utils_1 = require("../../../../utils/anki.utils");
|
|
19
|
+
const deck_hierarchy_utils_1 = require("../../../../utils/deck-hierarchy.utils");
|
|
19
20
|
const stats_utils_1 = require("../../../../utils/stats.utils");
|
|
20
21
|
let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
|
|
21
22
|
ankiClient;
|
|
@@ -61,34 +62,27 @@ let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
|
|
|
61
62
|
if (!deckStatsResponse || typeof deckStatsResponse !== "object") {
|
|
62
63
|
throw new Error("Invalid getDeckStats response");
|
|
63
64
|
}
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
total: 0,
|
|
67
|
-
new: 0,
|
|
68
|
-
learning: 0,
|
|
69
|
-
review: 0,
|
|
70
|
-
other: 0,
|
|
71
|
-
};
|
|
65
|
+
const perDeckOwnTotal = new Map();
|
|
66
|
+
const perDeckStats = new Map();
|
|
72
67
|
const missingDecks = [];
|
|
73
68
|
for (const deckName of deckNames) {
|
|
74
69
|
const deckId = deckNamesAndIds[deckName];
|
|
75
70
|
const deckStats = deckId != null ? deckStatsResponse[String(deckId)] : undefined;
|
|
76
71
|
if (!deckStats) {
|
|
77
72
|
missingDecks.push(deckName);
|
|
78
|
-
|
|
79
|
-
deck: deckName,
|
|
80
|
-
total: 0,
|
|
81
|
-
new: 0,
|
|
82
|
-
learning: 0,
|
|
83
|
-
review: 0,
|
|
84
|
-
other: 0,
|
|
85
|
-
});
|
|
73
|
+
perDeckOwnTotal.set(deckName, 0);
|
|
86
74
|
continue;
|
|
87
75
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
76
|
+
perDeckOwnTotal.set(deckName, deckStats.total_in_deck ?? 0);
|
|
77
|
+
perDeckStats.set(deckName, deckStats);
|
|
78
|
+
}
|
|
79
|
+
const per_deck = [];
|
|
80
|
+
for (const deckName of deckNames) {
|
|
81
|
+
const stats = perDeckStats.get(deckName);
|
|
82
|
+
const newCount = stats?.new_count ?? 0;
|
|
83
|
+
const learning = stats?.learn_count ?? 0;
|
|
84
|
+
const review = stats?.review_count ?? 0;
|
|
85
|
+
const total = (0, deck_hierarchy_utils_1.rollupDeckTotal)(deckName, perDeckOwnTotal);
|
|
92
86
|
const other = Math.max(0, total - newCount - learning - review);
|
|
93
87
|
per_deck.push({
|
|
94
88
|
deck: deckName,
|
|
@@ -98,17 +92,30 @@ let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
|
|
|
98
92
|
review,
|
|
99
93
|
other,
|
|
100
94
|
});
|
|
101
|
-
counts.total += total;
|
|
102
|
-
counts.new += newCount;
|
|
103
|
-
counts.learning += learning;
|
|
104
|
-
counts.review += review;
|
|
105
|
-
counts.other += other;
|
|
106
95
|
}
|
|
107
96
|
if (missingDecks.length > 0) {
|
|
108
97
|
this.logger.warn(`getDeckStats did not return stats for ${missingDecks.length} deck(s): ` +
|
|
109
98
|
`${missingDecks.join(", ")}. Filled with zeros.`);
|
|
110
99
|
}
|
|
111
|
-
|
|
100
|
+
const rootDeckNames = new Set((0, deck_hierarchy_utils_1.getRootDeckNames)(deckNames));
|
|
101
|
+
const counts = {
|
|
102
|
+
total: 0,
|
|
103
|
+
new: 0,
|
|
104
|
+
learning: 0,
|
|
105
|
+
review: 0,
|
|
106
|
+
other: 0,
|
|
107
|
+
};
|
|
108
|
+
for (const entry of per_deck) {
|
|
109
|
+
if (!rootDeckNames.has(entry.deck))
|
|
110
|
+
continue;
|
|
111
|
+
counts.total += entry.total;
|
|
112
|
+
counts.new += entry.new;
|
|
113
|
+
counts.learning += entry.learning;
|
|
114
|
+
counts.review += entry.review;
|
|
115
|
+
counts.other += entry.other;
|
|
116
|
+
}
|
|
117
|
+
this.logger.log(`Aggregated counts: ${counts.total} total cards across ${rootDeckNames.size} root deck(s) ` +
|
|
118
|
+
`(${deckNames.length} total decks including children)`);
|
|
112
119
|
await context.reportProgress({ progress: 40, total: 100 });
|
|
113
120
|
if (counts.total === 0) {
|
|
114
121
|
this.logger.log("Collection is empty (no cards)");
|
|
@@ -202,7 +209,9 @@ __decorate([
|
|
|
202
209
|
(0, mcp_nest_1.Tool)({
|
|
203
210
|
name: "collection_stats",
|
|
204
211
|
description: "Get aggregated statistics across all decks in the collection including card counts, ease factor distribution, and interval distribution. " +
|
|
205
|
-
"
|
|
212
|
+
"Per-deck counts are rolled up over descendants (a parent deck includes its children), matching Anki's deck browser. " +
|
|
213
|
+
"Collection-level `counts` sum the ROOT decks only to avoid double-counting children. " +
|
|
214
|
+
"Invariant: for every deck and for the collection, total === new + learning + review + other. " +
|
|
206
215
|
"Use this to analyze overall collection health and compare deck statistics. " +
|
|
207
216
|
"Ease buckets and interval buckets can be customized to focus on specific ranges.",
|
|
208
217
|
parameters: zod_1.z.object({
|
|
@@ -229,16 +238,32 @@ __decorate([
|
|
|
229
238
|
}),
|
|
230
239
|
outputSchema: zod_1.z.object({
|
|
231
240
|
total_decks: zod_1.z.number(),
|
|
232
|
-
counts: zod_1.z
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
241
|
+
counts: zod_1.z
|
|
242
|
+
.object({
|
|
243
|
+
total: zod_1.z
|
|
244
|
+
.number()
|
|
245
|
+
.describe("Total cards in the collection. Computed as the sum of " +
|
|
246
|
+
"ROOT-deck rolled-up totals (decks without `::` in the name), " +
|
|
247
|
+
"which prevents double-counting children. Invariant: " +
|
|
248
|
+
"total === new + learning + review + other."),
|
|
249
|
+
new: zod_1.z
|
|
250
|
+
.number()
|
|
251
|
+
.describe("New cards (never studied), summed over root decks' rolled-up counts."),
|
|
252
|
+
learning: zod_1.z
|
|
253
|
+
.number()
|
|
254
|
+
.describe("Learning/relearning cards, summed over root decks' rolled-up counts."),
|
|
255
|
+
review: zod_1.z
|
|
256
|
+
.number()
|
|
257
|
+
.describe("Review cards (mature), summed over root decks' rolled-up counts."),
|
|
237
258
|
other: zod_1.z
|
|
238
259
|
.number()
|
|
239
|
-
.describe("Cards not in new/learning/review (typically suspended or buried)
|
|
260
|
+
.describe("Cards not in new/learning/review (typically suspended or buried), " +
|
|
261
|
+
"summed over root decks' rolled-up counts. " +
|
|
240
262
|
"Computed as total - new - learning - review."),
|
|
241
|
-
})
|
|
263
|
+
})
|
|
264
|
+
.describe("Aggregated card counts across the collection. Summed over ROOT " +
|
|
265
|
+
"decks only (names without `::`) so that a parent's rollup is not " +
|
|
266
|
+
"added on top of its children."),
|
|
242
267
|
ease: zod_1.z.object({
|
|
243
268
|
mean: zod_1.z.number(),
|
|
244
269
|
median: zod_1.z.number(),
|
|
@@ -255,14 +280,19 @@ __decorate([
|
|
|
255
280
|
count: zod_1.z.number(),
|
|
256
281
|
buckets: zod_1.z.record(zod_1.z.string(), zod_1.z.number()),
|
|
257
282
|
}),
|
|
258
|
-
per_deck: zod_1.z
|
|
283
|
+
per_deck: zod_1.z
|
|
284
|
+
.array(zod_1.z.object({
|
|
259
285
|
deck: zod_1.z.string(),
|
|
260
286
|
total: zod_1.z.number(),
|
|
261
287
|
new: zod_1.z.number(),
|
|
262
288
|
learning: zod_1.z.number(),
|
|
263
289
|
review: zod_1.z.number(),
|
|
264
290
|
other: zod_1.z.number(),
|
|
265
|
-
}))
|
|
291
|
+
}))
|
|
292
|
+
.describe("Per-deck breakdown with one entry per deck. Each entry's counts " +
|
|
293
|
+
'are rolled up over that deck\'s descendants (entry for "German" ' +
|
|
294
|
+
'includes cards from "German::Verbs"). Invariant per row: ' +
|
|
295
|
+
"total === new + learning + review + other."),
|
|
266
296
|
}),
|
|
267
297
|
annotations: {
|
|
268
298
|
title: "Collection Statistics",
|