From 04f139fdc569f2c7beac9cb2ca04ba1f0eae21f2 Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:13:13 +0200 Subject: [PATCH 1/9] feat: add MCP server and client implementation, integrate tool registration, and update workspace configuration --- bun.lock | 172 +++++++++++++++++++++++++++++++++++++++++ mcp/package.json | 19 +++++ mcp/src/client.ts | 99 ++++++++++++++++++++++++ mcp/src/index.ts | 9 +++ mcp/src/tools/decks.ts | 59 ++++++++++++++ mcp/src/tools/index.ts | 10 +++ mcp/src/tools/notes.ts | 117 ++++++++++++++++++++++++++++ mcp/tsconfig.json | 14 ++++ package.json | 2 +- 9 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 mcp/package.json create mode 100644 mcp/src/client.ts create mode 100644 mcp/src/index.ts create mode 100644 mcp/src/tools/decks.ts create mode 100644 mcp/src/tools/index.ts create mode 100644 mcp/src/tools/notes.ts create mode 100644 mcp/tsconfig.json diff --git a/bun.lock b/bun.lock index 84a74df..48f1adf 100644 --- a/bun.lock +++ b/bun.lock @@ -38,12 +38,26 @@ "typescript": "^5.8.3", }, }, + "mcp": { + "name": "@anki-cloud/mcp", + "version": "0.1.0", + "dependencies": { + "@modelcontextprotocol/sdk": "1.10.2", + "zod": "^3.24.2", + }, + "devDependencies": { + "@types/bun": "^1.2.10", + "typescript": "^5.8.3", + }, + }, }, "packages": { "@anki-cloud/api": ["@anki-cloud/api@workspace:api"], "@anki-cloud/db": ["@anki-cloud/db@workspace:db"], + "@anki-cloud/mcp": ["@anki-cloud/mcp@workspace:mcp"], + "@asteasolutions/zod-to-openapi": ["@asteasolutions/zod-to-openapi@7.3.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@asteasolutions/zod-to-openapi/-/zod-to-openapi-7.3.4.tgz", { "dependencies": { "openapi3-ts": "^4.1.2" }, "peerDependencies": { "zod": "^3.20.2" } }, "sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@babel/code-frame/-/code-frame-7.29.0.tgz", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], @@ -164,6 +178,8 @@ "@hono/zod-validator": ["@hono/zod-validator@0.7.6", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@hono/zod-validator/-/zod-validator-0.7.6.tgz", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.10.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.3", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA=="], + "@noble/ciphers": ["@noble/ciphers@2.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@noble/ciphers/-/ciphers-2.2.0.tgz", {}, "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA=="], "@noble/hashes": ["@noble/hashes@2.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/@noble/hashes/-/hashes-2.2.0.tgz", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="], @@ -192,6 +208,8 @@ "JSONStream": ["JSONStream@1.3.5", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/JSONStream/-/JSONStream-1.3.5.tgz", { "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" }, "bin": { "JSONStream": "./bin.js" } }, "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ=="], + "accepts": ["accepts@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/accepts/-/accepts-2.0.0.tgz", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + "ajv": ["ajv@8.18.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ajv/-/ajv-8.18.0.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], "ansi-regex": ["ansi-regex@5.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -208,10 +226,18 @@ "better-call": ["better-call@1.3.5", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/better-call/-/better-call-1.3.5.tgz", { "dependencies": { "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-kOFJkBP7utAQLEYrobZm3vkTH8mXq5GNgvjc5/XEST1ilVHaxXUXfeDeFlqoETMtyqS4+3/h4ONX2i++ebZrvA=="], + "body-parser": ["body-parser@2.2.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/body-parser/-/body-parser-2.2.2.tgz", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + "buffer-from": ["buffer-from@1.1.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/buffer-from/-/buffer-from-1.1.2.tgz", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bun-types": ["bun-types@1.3.12", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/bun-types/-/bun-types-1.3.12.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], + "bytes": ["bytes@3.1.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/bytes/-/bytes-3.1.2.tgz", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/call-bound/-/call-bound-1.0.4.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "callsites": ["callsites@3.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/callsites/-/callsites-3.1.0.tgz", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "chalk": ["chalk@5.6.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/chalk/-/chalk-5.6.2.tgz", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], @@ -224,68 +250,138 @@ "compare-func": ["compare-func@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/compare-func/-/compare-func-2.0.0.tgz", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], + "content-disposition": ["content-disposition@1.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/content-disposition/-/content-disposition-1.1.0.tgz", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], + + "content-type": ["content-type@1.0.5", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/content-type/-/content-type-1.0.5.tgz", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + "conventional-changelog-angular": ["conventional-changelog-angular@7.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ=="], "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@7.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w=="], "conventional-commits-parser": ["conventional-commits-parser@5.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", { "dependencies": { "JSONStream": "^1.3.5", "is-text-path": "^2.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "conventional-commits-parser": "cli.mjs" } }, "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA=="], + "cookie": ["cookie@0.7.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cookie/-/cookie-0.7.2.tgz", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cookie-signature/-/cookie-signature-1.2.2.tgz", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "cors": ["cors@2.8.6", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cors/-/cors-2.8.6.tgz", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + "cosmiconfig": ["cosmiconfig@9.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cosmiconfig/-/cosmiconfig-9.0.1.tgz", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ=="], "cosmiconfig-typescript-loader": ["cosmiconfig-typescript-loader@6.3.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", { "dependencies": { "jiti": "2.6.1" }, "peerDependencies": { "@types/node": "*", "cosmiconfig": ">=9", "typescript": ">=5" } }, "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA=="], + "cross-spawn": ["cross-spawn@7.0.6", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/cross-spawn/-/cross-spawn-7.0.6.tgz", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "dargs": ["dargs@8.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/dargs/-/dargs-8.1.0.tgz", {}, "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw=="], + "debug": ["debug@4.4.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/debug/-/debug-4.4.3.tgz", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "defu": ["defu@6.1.7", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/defu/-/defu-6.1.7.tgz", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + "depd": ["depd@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/depd/-/depd-2.0.0.tgz", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "dot-prop": ["dot-prop@5.3.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/dot-prop/-/dot-prop-5.3.0.tgz", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], "drizzle-kit": ["drizzle-kit@0.31.10", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/drizzle-kit/-/drizzle-kit-0.31.10.tgz", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "tsx": "^4.21.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw=="], "drizzle-orm": ["drizzle-orm@0.43.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/drizzle-orm/-/drizzle-orm-0.43.1.tgz", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-dUcDaZtE/zN4RV/xqGrVSMpnEczxd5cIaoDeor7Zst9wOe/HzC/7eAaulywWGYXdDEc9oBPMjayVEDg0ziTLJA=="], + "dunder-proto": ["dunder-proto@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/dunder-proto/-/dunder-proto-1.0.1.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ee-first/-/ee-first-1.1.1.tgz", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + "emoji-regex": ["emoji-regex@8.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "encodeurl": ["encodeurl@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/encodeurl/-/encodeurl-2.0.0.tgz", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "env-paths": ["env-paths@2.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/env-paths/-/env-paths-2.2.1.tgz", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], "error-ex": ["error-ex@1.3.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/error-ex/-/error-ex-1.3.4.tgz", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + "es-define-property": ["es-define-property@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/es-define-property/-/es-define-property-1.0.1.tgz", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/es-errors/-/es-errors-1.3.0.tgz", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "esbuild": ["esbuild@0.25.12", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/esbuild/-/esbuild-0.25.12.tgz", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/escalade/-/escalade-3.2.0.tgz", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-html": ["escape-html@1.0.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/escape-html/-/escape-html-1.0.3.tgz", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "etag": ["etag@1.8.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/etag/-/etag-1.8.1.tgz", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventsource": ["eventsource@3.0.7", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/eventsource/-/eventsource-3.0.7.tgz", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.8", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/eventsource-parser/-/eventsource-parser-3.0.8.tgz", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + + "express": ["express@5.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/express/-/express-5.2.1.tgz", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "express-rate-limit": ["express-rate-limit@7.5.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/express-rate-limit/-/express-rate-limit-7.5.1.tgz", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-uri": ["fast-uri@3.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/fast-uri/-/fast-uri-3.1.0.tgz", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + "finalhandler": ["finalhandler@2.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/finalhandler/-/finalhandler-2.1.1.tgz", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + "find-up": ["find-up@7.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/find-up/-/find-up-7.0.0.tgz", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="], + "forwarded": ["forwarded@0.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/forwarded/-/forwarded-0.2.0.tgz", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/fresh/-/fresh-2.0.0.tgz", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "fsevents": ["fsevents@2.3.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "function-bind": ["function-bind@1.1.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/function-bind/-/function-bind-1.1.2.tgz", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "get-caller-file": ["get-caller-file@2.0.5", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/get-caller-file/-/get-caller-file-2.0.5.tgz", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/get-proto/-/get-proto-1.0.1.tgz", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-tsconfig": ["get-tsconfig@4.14.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/get-tsconfig/-/get-tsconfig-4.14.0.tgz", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], "git-raw-commits": ["git-raw-commits@4.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/git-raw-commits/-/git-raw-commits-4.0.0.tgz", { "dependencies": { "dargs": "^8.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "git-raw-commits": "cli.mjs" } }, "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ=="], "global-directory": ["global-directory@4.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/global-directory/-/global-directory-4.0.1.tgz", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="], + "gopd": ["gopd@1.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/gopd/-/gopd-1.2.0.tgz", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-symbols": ["has-symbols@1.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/has-symbols/-/has-symbols-1.1.0.tgz", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/hasown/-/hasown-2.0.3.tgz", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], + "hono": ["hono@4.12.14", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/hono/-/hono-4.12.14.tgz", {}, "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w=="], + "http-errors": ["http-errors@2.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/http-errors/-/http-errors-2.0.1.tgz", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "iconv-lite": ["iconv-lite@0.7.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/iconv-lite/-/iconv-lite-0.7.2.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + "import-fresh": ["import-fresh@3.3.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/import-fresh/-/import-fresh-3.3.1.tgz", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], "import-meta-resolve": ["import-meta-resolve@4.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "inherits": ["inherits@2.0.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/inherits/-/inherits-2.0.4.tgz", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "ini": ["ini@4.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ini/-/ini-4.1.1.tgz", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + "is-arrayish": ["is-arrayish@0.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/is-arrayish/-/is-arrayish-0.2.1.tgz", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], "is-obj": ["is-obj@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/is-obj/-/is-obj-2.0.0.tgz", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + "is-promise": ["is-promise@4.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/is-promise/-/is-promise-4.0.0.tgz", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "is-text-path": ["is-text-path@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/is-text-path/-/is-text-path-2.0.0.tgz", { "dependencies": { "text-extensions": "^2.0.0" } }, "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw=="], + "isexe": ["isexe@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/isexe/-/isexe-2.0.0.tgz", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "jiti": ["jiti@2.6.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/jiti/-/jiti-2.6.1.tgz", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jose": ["jose@6.2.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/jose/-/jose-6.2.2.tgz", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], @@ -324,12 +420,34 @@ "lodash.upperfirst": ["lodash.upperfirst@4.3.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", {}, "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "media-typer": ["media-typer@1.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/media-typer/-/media-typer-1.1.0.tgz", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "meow": ["meow@12.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/meow/-/meow-12.1.1.tgz", {}, "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw=="], + "merge-descriptors": ["merge-descriptors@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "mime-db": ["mime-db@1.54.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/mime-types/-/mime-types-3.0.2.tgz", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "minimist": ["minimist@1.2.8", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "ms": ["ms@2.1.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/ms/-/ms-2.1.3.tgz", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "nanostores": ["nanostores@1.3.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/nanostores/-/nanostores-1.3.0.tgz", {}, "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA=="], + "negotiator": ["negotiator@1.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/negotiator/-/negotiator-1.0.0.tgz", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "object-assign": ["object-assign@4.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/object-assign/-/object-assign-4.1.1.tgz", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/object-inspect/-/object-inspect-1.13.4.tgz", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "on-finished": ["on-finished@2.4.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/on-finished/-/on-finished-2.4.1.tgz", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/once/-/once-1.4.0.tgz", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "openapi3-ts": ["openapi3-ts@4.5.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/openapi3-ts/-/openapi3-ts-4.5.0.tgz", { "dependencies": { "yaml": "^2.8.0" } }, "sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ=="], "p-limit": ["p-limit@4.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/p-limit/-/p-limit-4.0.0.tgz", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], @@ -340,10 +458,26 @@ "parse-json": ["parse-json@5.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/parse-json/-/parse-json-5.2.0.tgz", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + "parseurl": ["parseurl@1.3.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/parseurl/-/parseurl-1.3.3.tgz", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + "path-exists": ["path-exists@5.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/path-exists/-/path-exists-5.0.0.tgz", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], + "path-key": ["path-key@3.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/path-key/-/path-key-3.1.1.tgz", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-to-regexp": ["path-to-regexp@8.4.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "picocolors": ["picocolors@1.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + "pkce-challenge": ["pkce-challenge@5.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/pkce-challenge/-/pkce-challenge-5.0.1.tgz", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + + "proxy-addr": ["proxy-addr@2.0.7", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/proxy-addr/-/proxy-addr-2.0.7.tgz", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "qs": ["qs@6.15.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/qs/-/qs-6.15.1.tgz", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg=="], + + "range-parser": ["range-parser@1.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/range-parser/-/range-parser-1.2.1.tgz", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/raw-body/-/raw-body-3.0.2.tgz", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + "require-directory": ["require-directory@2.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/require-directory/-/require-directory-2.1.1.tgz", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-from-string": ["require-from-string@2.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/require-from-string/-/require-from-string-2.0.2.tgz", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], @@ -354,16 +488,40 @@ "rou3": ["rou3@0.7.12", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/rou3/-/rou3-0.7.12.tgz", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="], + "router": ["router@2.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/router/-/router-2.2.0.tgz", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/safer-buffer/-/safer-buffer-2.1.2.tgz", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "semver": ["semver@7.7.4", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/semver/-/semver-7.7.4.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "send": ["send@1.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/send/-/send-1.2.1.tgz", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "serve-static": ["serve-static@2.2.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/serve-static/-/serve-static-2.2.1.tgz", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + "set-cookie-parser": ["set-cookie-parser@3.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="], + "setprototypeof": ["setprototypeof@1.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/setprototypeof/-/setprototypeof-1.2.0.tgz", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shebang-command": ["shebang-command@2.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/shebang-command/-/shebang-command-2.0.0.tgz", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/shebang-regex/-/shebang-regex-3.0.0.tgz", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/side-channel/-/side-channel-1.1.0.tgz", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/side-channel-list/-/side-channel-list-1.0.1.tgz", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], + + "side-channel-map": ["side-channel-map@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/side-channel-map/-/side-channel-map-1.0.1.tgz", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + "source-map": ["source-map@0.6.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/source-map/-/source-map-0.6.1.tgz", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-support": ["source-map-support@0.5.21", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/source-map-support/-/source-map-support-0.5.21.tgz", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], "split2": ["split2@4.2.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/split2/-/split2-4.2.0.tgz", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + "statuses": ["statuses@2.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/statuses/-/statuses-2.0.2.tgz", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "string-width": ["string-width@4.2.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "strip-ansi": ["strip-ansi@6.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -374,16 +532,28 @@ "tinyexec": ["tinyexec@1.1.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/tinyexec/-/tinyexec-1.1.1.tgz", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "toidentifier": ["toidentifier@1.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/toidentifier/-/toidentifier-1.0.1.tgz", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + "tsx": ["tsx@4.21.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/tsx/-/tsx-4.21.0.tgz", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], + "type-is": ["type-is@2.0.1", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/type-is/-/type-is-2.0.1.tgz", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "typescript": ["typescript@5.9.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "undici-types": ["undici-types@7.19.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/undici-types/-/undici-types-7.19.2.tgz", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], "unicorn-magic": ["unicorn-magic@0.1.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/unicorn-magic/-/unicorn-magic-0.1.0.tgz", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + "unpipe": ["unpipe@1.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/unpipe/-/unpipe-1.0.0.tgz", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "vary": ["vary@1.1.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/vary/-/vary-1.1.2.tgz", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "which": ["which@2.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/which/-/which-2.0.2.tgz", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrappy": ["wrappy@1.0.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/wrappy/-/wrappy-1.0.2.tgz", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "y18n": ["y18n@5.0.8", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/y18n/-/y18n-5.0.8.tgz", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], "yaml": ["yaml@2.8.3", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/yaml/-/yaml-2.8.3.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], @@ -396,6 +566,8 @@ "zod": ["zod@3.25.76", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], + "@better-auth/core/zod": ["zod@4.3.6", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/zod/-/zod-4.3.6.tgz", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "https://cplace.jfrog.io/artifactory/api/npm/cplace-npm/esbuild/-/esbuild-0.18.20.tgz", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], diff --git a/mcp/package.json b/mcp/package.json new file mode 100644 index 0000000..64e416e --- /dev/null +++ b/mcp/package.json @@ -0,0 +1,19 @@ +{ + "name": "@anki-cloud/mcp", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "bun run --watch src/index.ts", + "start": "bun run src/index.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "1.10.2", + "zod": "^3.24.2" + }, + "devDependencies": { + "@types/bun": "^1.2.10", + "typescript": "^5.8.3" + } +} diff --git a/mcp/src/client.ts b/mcp/src/client.ts new file mode 100644 index 0000000..dfac570 --- /dev/null +++ b/mcp/src/client.ts @@ -0,0 +1,99 @@ +// Copyright 2026 Archont Soft Daniel Klimuntowski +// Licensed under the Elastic License 2.0 — see LICENSE in the repository root. + +const API_URL = process.env["API_URL"] ?? "http://localhost:3000"; +const API_KEY = process.env["API_KEY"] ?? ""; + +async function apiRequest(path: string, options?: RequestInit): Promise { + const res = await fetch(`${API_URL}${path}`, { + ...options, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${API_KEY}`, + ...((options?.headers as Record | undefined) ?? {}), + }, + }); + if (!res.ok) { + const body = await res.json().catch(() => ({ error: "api error" })); + throw new Error((body as { error?: string }).error ?? `HTTP ${res.status}`); + } + return res.json() as Promise; +} + +export interface Deck { + id: string; + name: string; +} + +export interface Note { + id: string; + noteTypeId: string; + tags: string[]; + fields: Record; +} + +export interface Paginated { + items: T[]; + nextCursor: string | null; +} + +type Pagination = { limit?: number; cursor?: string }; + +function buildQs(params: Record): string { + const p = new URLSearchParams(); + for (const [k, v] of Object.entries(params)) { + if (v !== undefined) p.set(k, String(v)); + } + const s = p.toString(); + return s ? `?${s}` : ""; +} + +export const listDecks = (opts?: Pagination) => + apiRequest<{ decks: Deck[]; nextCursor: string | null }>( + `/v1/decks${buildQs({ limit: opts?.limit, cursor: opts?.cursor })}` + ); + +export const getDeck = (id: string) => apiRequest(`/v1/decks/${id}`); + +export const createDeck = (name: string) => + apiRequest("/v1/decks", { method: "POST", body: JSON.stringify({ name }) }); + +export const listNotes = (deckId: string, opts?: Pagination) => + apiRequest<{ notes: Note[]; nextCursor: string | null }>( + `/v1/decks/${deckId}/notes${buildQs({ limit: opts?.limit, cursor: opts?.cursor })}` + ); + +export const createNote = ( + deckId: string, + body: { fields: Record; tags?: string[]; noteTypeId?: string } +) => + apiRequest<{ id: string }>(`/v1/decks/${deckId}/notes`, { + method: "POST", + body: JSON.stringify(body), + }); + +export const createNotesBulk = ( + deckId: string, + notes: { fields: Record; tags?: string[]; noteTypeId?: string }[] +) => + apiRequest<{ ids: string[] }>("/v1/cards/bulk", { + method: "POST", + body: JSON.stringify({ deckId, notes }), + }); + +export const searchNotes = (q: string, opts?: Pagination) => + apiRequest<{ notes: Note[]; nextCursor: string | null }>( + `/v1/notes/search${buildQs({ q, limit: opts?.limit, cursor: opts?.cursor })}` + ); + +export const updateNote = ( + id: string, + body: { fields: Record; tags?: string[] } +) => + apiRequest<{ ok: boolean }>(`/v1/notes/${id}`, { + method: "PUT", + body: JSON.stringify(body), + }); + +export const deleteNote = (id: string) => + apiRequest<{ ok: boolean }>(`/v1/notes/${id}`, { method: "DELETE" }); diff --git a/mcp/src/index.ts b/mcp/src/index.ts new file mode 100644 index 0000000..a98cced --- /dev/null +++ b/mcp/src/index.ts @@ -0,0 +1,9 @@ +// Copyright 2026 Archont Soft Daniel Klimuntowski +// Licensed under the Elastic License 2.0 — see LICENSE in the repository root. +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { registerTools } from "./tools/index.js"; + +const server = new McpServer({ name: "anki-cloud", version: "0.1.0" }); +registerTools(server); +await server.connect(new StdioServerTransport()); diff --git a/mcp/src/tools/decks.ts b/mcp/src/tools/decks.ts new file mode 100644 index 0000000..c736101 --- /dev/null +++ b/mcp/src/tools/decks.ts @@ -0,0 +1,59 @@ +// Copyright 2026 Archont Soft Daniel Klimuntowski +// Licensed under the Elastic License 2.0 — see LICENSE in the repository root. +import { z } from "zod"; +import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import * as api from "../client.js"; + +export function registerDeckTools(server: McpServer): void { + server.tool( + "list_decks", + "List all Anki decks in the user's collection. Returns deck IDs and names. " + + "Use this to discover available decks before creating notes.", + { + limit: z + .number() + .int() + .min(1) + .max(1000) + .optional() + .describe("Maximum number of decks to return (default 100)"), + cursor: z + .string() + .optional() + .describe("Pagination cursor from a previous list_decks response"), + }, + async ({ limit, cursor }) => { + const data = await api.listDecks({ limit, cursor }); + return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; + } + ); + + server.tool( + "get_deck", + "Get details of a specific Anki deck by its ID.", + { + id: z.string().describe("The deck ID (e.g. from list_decks)"), + }, + async ({ id }) => { + const deck = await api.getDeck(id); + return { content: [{ type: "text", text: JSON.stringify(deck, null, 2) }] }; + } + ); + + server.tool( + "create_deck", + "Create a new Anki deck. Returns the new deck's ID and name.", + { + name: z + .string() + .min(1) + .describe( + "Name for the new deck, e.g. 'Spanish Vocabulary' or 'Physics::Optics' (use :: for subdecks)" + ), + }, + async ({ name }) => { + const deck = await api.createDeck(name); + return { content: [{ type: "text", text: JSON.stringify(deck, null, 2) }] }; + } + ); +} diff --git a/mcp/src/tools/index.ts b/mcp/src/tools/index.ts new file mode 100644 index 0000000..be485ef --- /dev/null +++ b/mcp/src/tools/index.ts @@ -0,0 +1,10 @@ +// Copyright 2026 Archont Soft Daniel Klimuntowski +// Licensed under the Elastic License 2.0 — see LICENSE in the repository root. +import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { registerDeckTools } from "./decks.js"; +import { registerNoteTools } from "./notes.js"; + +export function registerTools(server: McpServer): void { + registerDeckTools(server); + registerNoteTools(server); +} diff --git a/mcp/src/tools/notes.ts b/mcp/src/tools/notes.ts new file mode 100644 index 0000000..dc08429 --- /dev/null +++ b/mcp/src/tools/notes.ts @@ -0,0 +1,117 @@ +// Copyright 2026 Archont Soft Daniel Klimuntowski +// Licensed under the Elastic License 2.0 — see LICENSE in the repository root. +import { z } from "zod"; +import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import * as api from "../client.js"; + +const NoteFieldsSchema = z.record(z.string()).describe( + "Map of field name to value. The default Anki note type uses 'Front' and 'Back'. " + + "Use search_notes to inspect existing notes and discover field names." +); + +export function registerNoteTools(server: McpServer): void { + server.tool( + "create_note", + "Add a single flashcard to an Anki deck. " + + "The fields map must match the note type's field names — the default type uses 'Front' and 'Back'. " + + "Returns the new note ID.", + { + deckId: z.string().describe("ID of the deck to add the note to"), + fields: NoteFieldsSchema, + tags: z + .array(z.string()) + .optional() + .describe("Optional list of tags, e.g. ['python', 'chapter3']"), + noteTypeId: z + .string() + .optional() + .describe("Note type ID — omit to use the deck's default note type"), + }, + async ({ deckId, fields, tags, noteTypeId }) => { + const result = await api.createNote(deckId, { fields, tags, noteTypeId }); + return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; + } + ); + + server.tool( + "create_notes_bulk", + "Add multiple flashcards to an Anki deck in a single request. " + + "More efficient than calling create_note repeatedly when adding many cards. " + + "Returns an array of created note IDs in the same order as the input.", + { + deckId: z.string().describe("ID of the deck to add the notes to"), + notes: z + .array( + z.object({ + fields: NoteFieldsSchema, + tags: z.array(z.string()).optional(), + noteTypeId: z.string().optional(), + }) + ) + .min(1) + .describe("Array of notes to create"), + }, + async ({ deckId, notes }) => { + const result = await api.createNotesBulk(deckId, notes); + return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; + } + ); + + server.tool( + "search_notes", + "Search for notes using Anki's search syntax. " + + "Examples: 'tag:python', 'deck:Spanish front:hola', 'added:7' (added in last 7 days). " + + "Returns matching notes with their fields and tags.", + { + query: z + .string() + .min(1) + .describe("Anki search query string, e.g. 'tag:python' or 'deck:MyDeck'"), + limit: z + .number() + .int() + .min(1) + .max(1000) + .optional() + .describe("Maximum number of notes to return (default 100)"), + cursor: z + .string() + .optional() + .describe("Pagination cursor from a previous search_notes response"), + }, + async ({ query, limit, cursor }) => { + const data = await api.searchNotes(query, { limit, cursor }); + return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; + } + ); + + server.tool( + "update_note", + "Edit an existing note's fields and/or tags. All fields are replaced, not merged. " + + "Use search_notes to find the note ID and its current fields first.", + { + id: z.string().describe("The note ID to update"), + fields: NoteFieldsSchema, + tags: z + .array(z.string()) + .optional() + .describe("New tag list — replaces existing tags entirely"), + }, + async ({ id, fields, tags }) => { + const result = await api.updateNote(id, { fields, tags }); + return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; + } + ); + + server.tool( + "delete_note", + "Permanently delete a note and all cards generated from it. This cannot be undone.", + { + id: z.string().describe("The note ID to delete"), + }, + async ({ id }) => { + const result = await api.deleteNote(id); + return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; + } + ); +} diff --git a/mcp/tsconfig.json b/mcp/tsconfig.json new file mode 100644 index 0000000..6e1ccf2 --- /dev/null +++ b/mcp/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "noUncheckedIndexedAccess": true, + "lib": ["ES2022"], + "types": ["bun"], + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index fc795d4..c0ac111 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "anki-cloud", "version": "0.1.0", "private": true, - "workspaces": ["api", "db"], + "workspaces": ["api", "db", "mcp"], "devDependencies": { "@commitlint/cli": "^19.8.0", "@commitlint/config-conventional": "^19.8.0" From c07e7b341ca6264fee2594d9c547c2e7bc0d3d4a Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:13:31 +0200 Subject: [PATCH 2/9] ci: add Docker support for MCP service with new Dockerfile and compose configuration --- docker-compose.yml | 12 ++++++++++++ mcp/Dockerfile | 15 +++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 mcp/Dockerfile diff --git a/docker-compose.yml b/docker-compose.yml index f94d3ff..196826c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,5 +39,17 @@ services: depends_on: - anki-sync-server + mcp: + build: + context: . + dockerfile: mcp/Dockerfile + ports: + - "3001:3001" + environment: + API_URL: http://api:3000 + API_KEY: ${MCP_API_KEY} + depends_on: + - api + volumes: app-data: diff --git a/mcp/Dockerfile b/mcp/Dockerfile new file mode 100644 index 0000000..ec70bb8 --- /dev/null +++ b/mcp/Dockerfile @@ -0,0 +1,15 @@ +FROM oven/bun:1 AS base +WORKDIR /app + +# Copy workspace manifests first for layer caching +COPY package.json ./ +COPY mcp/package.json ./mcp/ +COPY bun.lock ./ + +RUN bun install --frozen-lockfile + +# Copy source +COPY mcp/src ./mcp/src +COPY mcp/tsconfig.json ./mcp/ + +CMD ["bun", "run", "mcp/src/index.ts"] From c528442bfae4e0f877ef8032c5fb30993d1bf3ae Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:13:35 +0200 Subject: [PATCH 3/9] docs: add MCP integration guide, setup instructions, and example --- README.md | 35 +++++++++++++- docs/mcp-integration.md | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 docs/mcp-integration.md diff --git a/README.md b/README.md index 6500105..b008532 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,38 @@ Account management endpoints (`/v1/me/*`) use the session cookie set by [Better --- +## MCP integration (LLM → Anki) + +The MCP server lets any LLM (Claude Desktop, API clients) manage your decks and notes directly: + +``` +User: "Create flashcards from this discussion" +LLM: " → cards appear in Anki instantly" +``` + +**Claude Desktop setup** — add to `~/Library/Application Support/Claude/claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "anki-cloud": { + "command": "bun", + "args": ["run", "/path/to/anki-cloud/mcp/src/index.ts"], + "env": { + "API_URL": "http://localhost:3000", + "API_KEY": "ak_your_key_here" + } + } + } +} +``` + +Generate an API key in the web UI under **Account → API Keys**, replace the path and key, then restart Claude Desktop. + +Full setup guide, available tools, and Docker deployment: [docs/mcp-integration.md](docs/mcp-integration.md) + +--- + ## Connecting Anki Desktop In Anki: **Preferences → Syncing → Self-hosted sync server**, set the URL to: @@ -151,8 +183,9 @@ cd e2e && bun test ## Project structure ``` -api/ REST API — TypeScript / Hono on Bun (shared workspace with db/) +api/ REST API — TypeScript / Hono on Bun (shared workspace with db/ and mcp/) db/ Drizzle ORM + SQLite schema (@anki-cloud/db) +mcp/ MCP server — wraps REST API, 8 tools for LLM integration web/ Account management UI (Vite + React) (standalone — cd web && bun install) e2e/ End-to-end tests (standalone — cd e2e && bun install) docs/ Architecture decisions (ADRs) + narrative docs diff --git a/docs/mcp-integration.md b/docs/mcp-integration.md new file mode 100644 index 0000000..8ab4efb --- /dev/null +++ b/docs/mcp-integration.md @@ -0,0 +1,100 @@ +# MCP Integration + +The anki-cloud MCP server exposes 8 tools to LLMs, allowing them to manage your Anki decks and notes directly. + +## Tools + +| Tool | Description | +|---------------------|----------------------------------------| +| `list_decks` | List all decks with IDs and names | +| `get_deck` | Get a specific deck by ID | +| `create_deck` | Create a new deck | +| `create_note` | Add a single flashcard to a deck | +| `create_notes_bulk` | Add multiple flashcards in one request | +| `search_notes` | Search notes using Anki search syntax | +| `update_note` | Edit a note's fields and tags | +| `delete_note` | Permanently delete a note | + +## Prerequisites + +1. A running anki-cloud instance (local or hosted) +2. An API key — generate one in the web UI under **Account → API Keys** +3. [Bun](https://bun.sh) installed locally (for Claude Desktop stdio mode) + +## Claude Desktop Setup + +Claude Desktop connects to the MCP server via stdio. Add the following to your Claude Desktop config: + +**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json` + +**Windows:** `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "anki-cloud": { + "command": "bun", + "args": [ + "run", + "/path/to/anki-cloud/mcp/src/index.ts" + ], + "env": { + "API_URL": "http://localhost:3000", + "API_KEY": "ak_your_key_here" + } + } + } +} +``` + +Replace `/path/to/anki-cloud` with the absolute path to your clone, and `ak_your_key_here` with your API key. + +For a hosted instance: + +```json +{ + "mcpServers": { + "anki-cloud": { + "command": "bun", + "args": [ + "run", + "/path/to/anki-cloud/mcp/src/index.ts" + ], + "env": { + "API_URL": "https://your-anki-cloud-instance.com", + "API_KEY": "ak_your_key_here" + } + } + } +} +``` + +Restart Claude Desktop after saving the config. You should see "anki-cloud" appear in the MCP tools panel. + +## Verifying the Connection + +Ask Claude: _"List my Anki decks"_ — it will call `list_decks` and show the results. + +## Example Prompts + +- _"Create a deck called 'Python' and add 5 flashcards covering list comprehensions"_ +- _"Search my notes for tag:python and update the ones about decorators"_ +- _"Add these flashcards to my Spanish deck: [paste content]"_ + +## Docker Deployment (HTTP mode) + +To run the MCP server as a networked service alongside the full stack: + +```bash +MCP_API_KEY=ak_your_key docker compose up mcp +``` + +The server listens on port 3001. Note: in Docker mode the server uses stdio transport inside the container — you'd need to adapt `src/index.ts` to use `StreamableHTTPServerTransport` from the MCP SDK for true network +exposure. + +## Environment Variables + +| Variable | Default | Description | +|-----------|-------------------------|-------------------------------------| +| `API_URL` | `http://localhost:3000` | Base URL of the anki-cloud REST API | +| `API_KEY` | _(required)_ | API key with `ak_` prefix | From 1329d957684c554c59530066be58167a6d49608f Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:15:40 +0200 Subject: [PATCH 4/9] docs: update .env.example with MCP API key configuration and usage details --- .env.example | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.env.example b/.env.example index cb3ed46..375c2c5 100644 --- a/.env.example +++ b/.env.example @@ -57,3 +57,9 @@ FRONTEND_URL=http://localhost:5173 # If unset, falls back to FRONTEND_URL. # Local dev: http://localhost:5173 Prod: https://app.your-domain.com,https://staging.your-domain.com TRUSTED_ORIGINS= + +# ── MCP SERVER ──────────────────────────────────────────────────────────── + +# API key used by the MCP server to authenticate against the REST API (ak_ prefix) +# Generate one in the web UI under Account → API Keys +MCP_API_KEY= From 5a517445bee2d5c5fa05ca272c9f0dbd595a72f0 Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:18:52 +0200 Subject: [PATCH 5/9] ci: update Dockerfiles to include package.json files for all services to improve caching efficiency --- api/Dockerfile | 1 + mcp/Dockerfile | 2 ++ 2 files changed, 3 insertions(+) diff --git a/api/Dockerfile b/api/Dockerfile index e175e2f..cee5632 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -5,6 +5,7 @@ WORKDIR /app COPY package.json ./ COPY api/package.json ./api/ COPY db/package.json ./db/ +COPY mcp/package.json ./mcp/ COPY bun.lock ./ RUN bun install --frozen-lockfile diff --git a/mcp/Dockerfile b/mcp/Dockerfile index ec70bb8..266a07b 100644 --- a/mcp/Dockerfile +++ b/mcp/Dockerfile @@ -3,6 +3,8 @@ WORKDIR /app # Copy workspace manifests first for layer caching COPY package.json ./ +COPY api/package.json ./api/ +COPY db/package.json ./db/ COPY mcp/package.json ./mcp/ COPY bun.lock ./ From e4f32c0e2a355d813af7b2a6c2a05cf9818a111f Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:34:36 +0200 Subject: [PATCH 6/9] docs: rewrite and expand MCP integration guide with detailed tool references, setup updates, and troubleshooting --- docs/mcp-integration.md | 331 ++++++++++++++++++++++++++++++++++------ 1 file changed, 281 insertions(+), 50 deletions(-) diff --git a/docs/mcp-integration.md b/docs/mcp-integration.md index 8ab4efb..37c78b7 100644 --- a/docs/mcp-integration.md +++ b/docs/mcp-integration.md @@ -1,32 +1,23 @@ # MCP Integration -The anki-cloud MCP server exposes 8 tools to LLMs, allowing them to manage your Anki decks and notes directly. - -## Tools - -| Tool | Description | -|---------------------|----------------------------------------| -| `list_decks` | List all decks with IDs and names | -| `get_deck` | Get a specific deck by ID | -| `create_deck` | Create a new deck | -| `create_note` | Add a single flashcard to a deck | -| `create_notes_bulk` | Add multiple flashcards in one request | -| `search_notes` | Search notes using Anki search syntax | -| `update_note` | Edit a note's fields and tags | -| `delete_note` | Permanently delete a note | +The anki-cloud MCP server exposes 8 tools to LLMs, enabling seamless LLM-to-Anki workflows. +Any MCP-compatible client (Claude Desktop, API clients) can create decks, add flashcards, +search notes, and more — without the user having Anki open. ## Prerequisites -1. A running anki-cloud instance (local or hosted) -2. An API key — generate one in the web UI under **Account → API Keys** -3. [Bun](https://bun.sh) installed locally (for Claude Desktop stdio mode) +1. A running anki-cloud instance (local or hosted) — see [SELF_HOSTING.md](SELF_HOSTING.md) +2. [Bun](https://bun.sh) installed locally +3. An API key — generate one in the web UI under **Account → API Keys** ## Claude Desktop Setup -Claude Desktop connects to the MCP server via stdio. Add the following to your Claude Desktop config: +Claude Desktop spawns the MCP server as a child process over stdio. Each user configures +their own key — the server runs locally on their machine. -**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json` +Add the following to your Claude Desktop config file: +**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json` **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` ```json @@ -36,7 +27,7 @@ Claude Desktop connects to the MCP server via stdio. Add the following to your C "command": "bun", "args": [ "run", - "/path/to/anki-cloud/mcp/src/index.ts" + "/absolute/path/to/anki-cloud/mcp/src/index.ts" ], "env": { "API_URL": "http://localhost:3000", @@ -47,54 +38,294 @@ Claude Desktop connects to the MCP server via stdio. Add the following to your C } ``` -Replace `/path/to/anki-cloud` with the absolute path to your clone, and `ak_your_key_here` with your API key. +Replace `/absolute/path/to/anki-cloud` with the actual path to your clone and +`ak_your_key_here` with your API key. For a hosted instance, set `API_URL` to +`https://your-anki-cloud-instance.com`. + +Restart Claude Desktop after saving. The "anki-cloud" server should appear in the +tools panel (hammer icon). + +**Verify:** Ask Claude _"List my Anki decks"_ — it calls `list_decks` and shows results. + +## Environment Variables + +| Variable | Default | Description | +|-----------|-------------------------|-------------------------------------| +| `API_URL` | `http://localhost:3000` | Base URL of the anki-cloud REST API | +| `API_KEY` | _(required)_ | API key with `ak_` prefix | + +--- + +## Tools Reference + +### `list_decks` -For a hosted instance: +List all decks in the user's collection. + +**Inputs** + +| Parameter | Type | Required | Description | +|-----------|--------|----------|------------------------------------------| +| `limit` | number | no | Max results (1–1000, default 100) | +| `cursor` | string | no | Pagination cursor from previous response | + +**Example prompt** +> "List all my Anki decks." + +**Example response** ```json { - "mcpServers": { - "anki-cloud": { - "command": "bun", - "args": [ - "run", - "/path/to/anki-cloud/mcp/src/index.ts" + "decks": [ + { + "id": "1", + "name": "Default" + }, + { + "id": "1700000000001", + "name": "Spanish Vocabulary" + } + ], + "nextCursor": null +} +``` + +--- + +### `get_deck` + +Get details of a specific deck by ID. + +**Inputs** + +| Parameter | Type | Required | Description | +|-----------|--------|----------|-----------------------------| +| `id` | string | yes | Deck ID (from `list_decks`) | + +**Example prompt** +> "Get details of deck 1700000000001." + +**Example response** + +```json +{ + "id": "1700000000001", + "name": "Spanish Vocabulary" +} +``` + +--- + +### `create_deck` + +Create a new deck. Use `::` for subdecks (e.g. `Languages::Spanish`). + +**Inputs** + +| Parameter | Type | Required | Description | +|-----------|--------|----------|----------------------------------------------| +| `name` | string | yes | Deck name, e.g. `Python` or `CS::Algorithms` | + +**Example prompt** +> "Create a deck called 'Python'." + +**Example response** + +```json +{ + "id": "1700000000042", + "name": "Python" +} +``` + +--- + +### `create_note` + +Add a single flashcard to a deck. The default Anki note type uses `Front` and `Back` fields. + +**Inputs** + +| Parameter | Type | Required | Description | +|--------------|------------------|----------|--------------------------------------| +| `deckId` | string | yes | Target deck ID | +| `fields` | object | yes | Map of field name → value | +| `tags` | array of strings | no | Tags to apply | +| `noteTypeId` | string | no | Note type ID (omit for deck default) | + +**Example prompt** +> "Add a flashcard to my Python deck: Front = 'What is a list comprehension?', Back = 'A concise way to create lists: [expr for item in iterable]'." + +**Example response** + +```json +{ + "id": "1700000000123" +} +``` + +--- + +### `create_notes_bulk` + +Add multiple flashcards in a single request. Prefer this over repeated `create_note` calls. + +**Inputs** + +| Parameter | Type | Required | Description | +|----------------------|--------|----------|-------------------------------| +| `deckId` | string | yes | Target deck ID | +| `notes` | array | yes | Array of note objects (min 1) | +| `notes[].fields` | object | yes | Field map for each note | +| `notes[].tags` | array | no | Tags for each note | +| `notes[].noteTypeId` | string | no | Note type for each note | + +**Example prompt** +> "Add 3 flashcards about the water cycle to my Science deck." + +**Example response** + +```json +{ + "ids": [ + "1700000000124", + "1700000000125", + "1700000000126" + ] +} +``` + +--- + +### `search_notes` + +Search notes using [Anki search syntax](https://docs.ankiweb.net/searching.html). + +**Inputs** + +| Parameter | Type | Required | Description | +|-----------|--------|----------|-----------------------------------| +| `query` | string | yes | Anki search query | +| `limit` | number | no | Max results (1–1000, default 100) | +| `cursor` | string | no | Pagination cursor | + +**Common query examples** + +| Query | Finds | +|----------------|--------------------------------------| +| `tag:python` | Notes tagged "python" | +| `deck:Spanish` | Notes in the Spanish deck | +| `added:7` | Notes added in the last 7 days | +| `front:hola` | Notes with "hola" in the Front field | + +**Example prompt** +> "Search my notes for tag:python." + +**Example response** + +```json +{ + "notes": [ + { + "id": "1700000000123", + "noteTypeId": "1", + "tags": [ + "python" ], - "env": { - "API_URL": "https://your-anki-cloud-instance.com", - "API_KEY": "ak_your_key_here" + "fields": { + "Front": "What is a decorator?", + "Back": "A function that wraps another function." } } - } + ], + "nextCursor": null } ``` -Restart Claude Desktop after saving the config. You should see "anki-cloud" appear in the MCP tools panel. +--- -## Verifying the Connection +### `update_note` -Ask Claude: _"List my Anki decks"_ — it will call `list_decks` and show the results. +Edit a note's fields and/or tags. **All fields are replaced** — include all fields, not just changed ones. -## Example Prompts +**Inputs** -- _"Create a deck called 'Python' and add 5 flashcards covering list comprehensions"_ -- _"Search my notes for tag:python and update the ones about decorators"_ -- _"Add these flashcards to my Spanish deck: [paste content]"_ +| Parameter | Type | Required | Description | +|-----------|------------------|----------|----------------------------------------------| +| `id` | string | yes | Note ID to update | +| `fields` | object | yes | Complete new field map (replaces all fields) | +| `tags` | array of strings | no | New tag list (replaces all existing tags) | -## Docker Deployment (HTTP mode) +**Example prompt** +> "Update note 1700000000123: change the Back field to 'A function that modifies another function, often using @syntax'." -To run the MCP server as a networked service alongside the full stack: +**Example response** -```bash -MCP_API_KEY=ak_your_key docker compose up mcp +```json +{ + "ok": true +} ``` -The server listens on port 3001. Note: in Docker mode the server uses stdio transport inside the container — you'd need to adapt `src/index.ts` to use `StreamableHTTPServerTransport` from the MCP SDK for true network -exposure. +--- -## Environment Variables +### `delete_note` -| Variable | Default | Description | -|-----------|-------------------------|-------------------------------------| -| `API_URL` | `http://localhost:3000` | Base URL of the anki-cloud REST API | -| `API_KEY` | _(required)_ | API key with `ak_` prefix | +Permanently delete a note and all cards generated from it. Cannot be undone. + +**Inputs** + +| Parameter | Type | Required | Description | +|-----------|--------|----------|-------------------| +| `id` | string | yes | Note ID to delete | + +**Example prompt** +> "Delete note 1700000000123." + +**Example response** + +```json +{ + "ok": true +} +``` + +--- + +## Example Workflows + +**Create a deck and populate it from a conversation:** +> "We just discussed Python decorators. Create a deck called 'Python' and add 5 flashcards +> covering the key concepts from our discussion." + +**Bulk import from structured content:** +> "Here's a vocabulary list. Add all of these to my Spanish deck as Front/Back flashcards: ..." + +**Review and update existing notes:** +> "Search my notes for tag:python and show me the ones about decorators. Update the Back field +> of each one to include a code example." + +--- + +## Troubleshooting + +**"Server disconnected" in Claude Desktop** + +- Check the `args` path is absolute and correct: `ls /your/path/to/anki-cloud/mcp/src/index.ts` +- Check `bun` is on PATH: `which bun` in a terminal +- Check the API is running: `curl http://localhost:3000/health` + +**"INVALID_API_KEY" errors** + +- Verify the key starts with `ak_` and was copied in full +- Keys are shown only once on creation — generate a new one if lost + +**Tool calls succeed but no notes appear in Anki** + +- Sync Anki Desktop against the server: **Sync** button in Anki +- Verify Google Drive is connected in the web UI under **Account → Storage** + +**Claude doesn't show the anki-cloud tools** + +- Fully quit and relaunch Claude Desktop (menu bar → Quit, not just close window) +- Check the config file is valid JSON: `cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python3 -m json.tool` From 561296711aadf24d24ddd3e59fc4cdcd3d090913 Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:35:26 +0200 Subject: [PATCH 7/9] docs: rewrite and expand MCP integration guide with detailed tool references, setup updates, and troubleshooting --- docs/mcp-integration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mcp-integration.md b/docs/mcp-integration.md index 37c78b7..2cbf9db 100644 --- a/docs/mcp-integration.md +++ b/docs/mcp-integration.md @@ -17,8 +17,8 @@ their own key — the server runs locally on their machine. Add the following to your Claude Desktop config file: -**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json` -**Windows:** `%APPDATA%\Claude\claude_desktop_config.json` +- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json` +- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` ```json { From 8d9fcf510392a8d5a2a6579d213eecd42816091a Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:37:23 +0200 Subject: [PATCH 8/9] docs: replace JSON response example with an image in MCP integration guide --- ...d-integration-example--list-all-my-decks.png | Bin 0 -> 92333 bytes docs/mcp-integration.md | 16 +--------------- 2 files changed, 1 insertion(+), 15 deletions(-) create mode 100644 docs/images/claude-anki-cloud-integration-example--list-all-my-decks.png diff --git a/docs/images/claude-anki-cloud-integration-example--list-all-my-decks.png b/docs/images/claude-anki-cloud-integration-example--list-all-my-decks.png new file mode 100644 index 0000000000000000000000000000000000000000..eeba8be24f9ec065f1889773891bf25b3bfe5318 GIT binary patch literal 92333 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%0D%=hlLm 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 UF2+CH7Bc{Wr>mdKI;Vst031?lc>n+a literal 0 HcmV?d00001 diff --git a/docs/mcp-integration.md b/docs/mcp-integration.md index 2cbf9db..24b673d 100644 --- a/docs/mcp-integration.md +++ b/docs/mcp-integration.md @@ -74,21 +74,7 @@ List all decks in the user's collection. **Example response** -```json -{ - "decks": [ - { - "id": "1", - "name": "Default" - }, - { - "id": "1700000000001", - "name": "Spanish Vocabulary" - } - ], - "nextCursor": null -} -``` +![](images/claude-anki-cloud-integration-example--list-all-my-decks.png) --- From 74b5856e6382ed37450f6d1ffa61d182598906a1 Mon Sep 17 00:00:00 2001 From: Daniel Klimuntowski Date: Mon, 20 Apr 2026 20:41:15 +0200 Subject: [PATCH 9/9] ci: skip enforcement of 100-character limit on commit headers via commitlint configuration --- .commitlintrc.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.commitlintrc.json b/.commitlintrc.json index c30e5a9..383b5c2 100644 --- a/.commitlintrc.json +++ b/.commitlintrc.json @@ -1,3 +1,6 @@ { - "extends": ["@commitlint/config-conventional"] + "extends": ["@commitlint/config-conventional"], + "rules": { + "header-max-length": [0, "always", 100] + } }