@dizzlkheinz/ynab-mcpb 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +33 -33
- package/.github/workflows/ci-tests.yml +45 -45
- package/.github/workflows/claude-code-review.yml +57 -57
- package/.github/workflows/claude.yml +50 -50
- package/.github/workflows/full-integration.yml +22 -22
- package/.github/workflows/publish.yml +12 -3
- package/.github/workflows/release.yml +2 -2
- package/CHANGELOG.md +10 -1
- package/CLAUDE.md +16 -12
- package/README.md +6 -1
- package/dist/bundle/index.cjs +49 -49
- package/dist/server/YNABMCPServer.d.ts +125 -54
- package/dist/server/YNABMCPServer.js +42 -11
- package/dist/server/cacheManager.js +6 -5
- package/dist/server/completions.d.ts +25 -0
- package/dist/server/completions.js +160 -0
- package/dist/server/config.d.ts +2 -2
- package/dist/server/errorHandler.js +1 -0
- package/dist/server/rateLimiter.js +3 -1
- package/dist/server/resources.d.ts +1 -0
- package/dist/server/resources.js +33 -16
- package/dist/server/securityMiddleware.d.ts +38 -8
- package/dist/server/securityMiddleware.js +1 -0
- package/dist/server/toolRegistry.d.ts +9 -0
- package/dist/server/toolRegistry.js +11 -0
- package/dist/tools/adapters.d.ts +3 -1
- package/dist/tools/adapters.js +1 -0
- package/dist/tools/reconciliation/executor.d.ts +2 -0
- package/dist/tools/reconciliation/executor.js +26 -1
- package/dist/tools/reconciliation/index.d.ts +3 -2
- package/dist/tools/reconciliation/index.js +4 -3
- package/dist/tools/schemas/outputs/index.d.ts +2 -2
- package/dist/tools/schemas/outputs/index.js +2 -2
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +0 -15
- package/dist/tools/schemas/outputs/utilityOutputs.js +0 -9
- package/dist/tools/utilityTools.d.ts +0 -7
- package/dist/tools/utilityTools.js +1 -50
- package/docs/maintainers/npm-publishing.md +27 -0
- package/docs/reference/API.md +83 -97
- package/docs/technical/reconciliation-system-architecture.md +2251 -2251
- package/package.json +6 -6
- package/scripts/analyze-bundle.mjs +41 -41
- package/scripts/generate-mcpb.ps1 +95 -95
- package/scripts/watch-and-restart.ps1 +49 -49
- package/src/__tests__/comprehensive.integration.test.ts +4 -32
- package/src/__tests__/performance.test.ts +5 -14
- package/src/__tests__/setup.ts +45 -14
- package/src/__tests__/smoke.e2e.test.ts +70 -0
- package/src/__tests__/testUtils.ts +2 -113
- package/src/server/YNABMCPServer.ts +64 -10
- package/src/server/__tests__/YNABMCPServer.test.ts +0 -1
- package/src/server/__tests__/completions.integration.test.ts +117 -0
- package/src/server/__tests__/completions.test.ts +319 -0
- package/src/server/__tests__/resources.template.test.ts +3 -3
- package/src/server/__tests__/resources.test.ts +3 -3
- package/src/server/__tests__/toolRegistration.test.ts +3 -3
- package/src/server/cacheManager.ts +7 -6
- package/src/server/completions.ts +279 -0
- package/src/server/errorHandler.ts +1 -0
- package/src/server/rateLimiter.ts +4 -1
- package/src/server/resources.ts +49 -13
- package/src/server/securityMiddleware.ts +1 -0
- package/src/server/toolRegistry.ts +42 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +63 -3
- package/src/tools/__tests__/utilityTools.integration.test.ts +1 -85
- package/src/tools/__tests__/utilityTools.test.ts +1 -123
- package/src/tools/adapters.ts +22 -1
- package/src/tools/reconciliation/__tests__/executor.progress.test.ts +462 -0
- package/src/tools/reconciliation/executor.ts +55 -1
- package/src/tools/reconciliation/index.ts +7 -3
- package/src/tools/schemas/outputs/index.ts +0 -3
- package/src/tools/schemas/outputs/utilityOutputs.ts +2 -43
- package/src/tools/toolCategories.ts +0 -1
- package/src/tools/utilityTools.ts +5 -76
- package/vitest.config.ts +4 -1
- package/.chunkhound.json +0 -11
- package/.code/agents/0098661e-0fa3-4990-beb9-c0cbf3f123aa/status.txt +0 -1
- package/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +0 -3
- package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +0 -3
- package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +0 -1
- package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +0 -5
- package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +0 -1569
- package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +0 -3
- package/.code/agents/1324/exec-call_tIpx9uV1TpARbAMZonRQm8AO.txt +0 -757
- package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +0 -2832
- package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +0 -2709
- package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +0 -2832
- package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +0 -2832
- package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +0 -2709
- package/.code/agents/1572/exec-call_GjVFBFOWcY7lE0idc5nWlLNh.txt +0 -781
- package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +0 -1
- package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +0 -5217
- package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +0 -2594
- package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +0 -2594
- package/.code/agents/1846/exec-call_1YNAVD18RjrMN7JnfkkQhUP3.txt +0 -766
- package/.code/agents/1846/exec-call_lh3lDzE4WJAh1lFiomiiZ73D.txt +0 -766
- package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +0 -231
- package/.code/agents/2038/exec-call_DYwOukaYsL8VCONWmV2rUW5u.txt +0 -766
- package/.code/agents/2038/exec-call_c7fOQ7UrpVcTtvdfGBRM146V.txt +0 -652
- package/.code/agents/2038/exec-call_ySNyq9Mm55jWE480s54r5QcA.txt +0 -766
- package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +0 -2590
- package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +0 -5195
- package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +0 -286
- package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +0 -218
- package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +0 -180
- package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +0 -3
- package/.code/agents/2256/exec-call_AtPcRWPmFPMcmX6qOFm1fCEY.txt +0 -766
- package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +0 -1
- package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +0 -747
- package/.code/agents/2454/exec-call_aFJpupwjfZeOBm7ixI5Vc8z2.txt +0 -766
- package/.code/agents/2454/exec-call_wogZ4HfXTodTEXvdgXlVUBpv.txt +0 -766
- package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +0 -1
- package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +0 -2594
- package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +0 -2594
- package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +0 -144
- package/.code/agents/2e905864-aa07-4314-bcf9-c5b32277e4ac/result.txt +0 -36
- package/.code/agents/3073/exec-call_Peeagc9DxGYLgE6pNdMZhqIE.txt +0 -766
- package/.code/agents/3073/exec-call_d2YSE3hXF08KRSoUM3qd8Z3x.txt +0 -766
- package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +0 -416
- package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +0 -2590
- package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +0 -2590
- package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +0 -2590
- package/.code/agents/335aa031-466d-4fb7-925f-3cd864e264d0/result.txt +0 -191
- package/.code/agents/3364/exec-call_NbhIrsM5HhyDZDmJZG5CuCYL.txt +0 -766
- package/.code/agents/3364/exec-call_cKtJg0NrXiwXEFwlsE3uPZRA.txt +0 -766
- package/.code/agents/36d98414-5cde-4d9d-9a67-a240a18c1f07/result.txt +0 -189
- package/.code/agents/4604e866-b7b8-44f5-992f-2f683b0a523b/status.txt +0 -1
- package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +0 -790
- package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +0 -766
- package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +0 -790
- package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +0 -2594
- package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +0 -1000
- package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +0 -3489
- package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +0 -766
- package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +0 -2594
- package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +0 -2456
- package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +0 -2594
- package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +0 -18
- package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +0 -48
- package/.code/agents/5f8dc01c-47b3-4163-b0b3-aa31be89fcdc/status.txt +0 -1
- package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +0 -1
- package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +0 -1
- package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +0 -1
- package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +0 -1
- package/.code/agents/7/exec-call_HltHpkDox0Zm1vGEjdksUgpE.txt +0 -1120
- package/.code/agents/7/exec-call_LCATrOPPAgbxW9Q1z0XaVi2E.txt +0 -2646
- package/.code/agents/7/exec-call_W8DeRfNG9hvbgVFvf0clBf6R.txt +0 -2646
- package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +0 -1271
- package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +0 -1570
- package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +0 -2590
- package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +0 -3
- package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +0 -3299
- package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +0 -3299
- package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +0 -1882
- package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +0 -2594
- package/.code/agents/94a0ddf3-a304-4ec3-913e-3cceef509948/error.txt +0 -1
- package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +0 -1
- package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +0 -170
- package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +0 -1
- package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +0 -3
- package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +0 -1
- package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +0 -1
- package/.code/agents/e2c752b7-711d-423a-af57-f53c809deb84/result.txt +0 -160
- package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +0 -3
- package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +0 -1
- package/.code/agents/e6601719-c31f-4a0e-8c71-d70787d0ab71/status.txt +0 -1
- package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +0 -1
- package/.code/agents/f250b7ed-5bd5-4036-aa8c-ce63caee7d61/result.txt +0 -20
- package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +0 -5
- package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +0 -1
- package/AGENTS.md +0 -1
- package/NUL +0 -0
- package/package.json.tmp +0 -105
- package/src/__tests__/delta.performance.test.ts +0 -80
- package/src/__tests__/workflows.e2e.test.ts +0 -1702
- package/temp-recon.ts +0 -126
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +0 -23
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +0 -23
- package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +0 -44
- package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +0 -58
- package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +0 -3662
- package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +0 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dizzlkheinz/ynab-mcpb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Model Context Protocol server for YNAB (You Need A Budget) integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"verify-build": "node scripts/verify-build.js",
|
|
24
24
|
"lint": "npm run lint:eslint && npm run format:check",
|
|
25
25
|
"lint:eslint": "eslint src --ext .ts",
|
|
26
|
-
"lint:fix": "eslint src --ext .ts --fix && prettier --write .",
|
|
27
|
-
"format": "prettier --write .",
|
|
28
|
-
"format:check": "prettier --check .",
|
|
26
|
+
"lint:fix": "eslint src --ext .ts --fix && prettier --log-level silent --write .",
|
|
27
|
+
"format": "prettier --log-level silent --write .",
|
|
28
|
+
"format:check": "prettier --log-level silent --check .",
|
|
29
29
|
"type-check": "tsc --noEmit",
|
|
30
30
|
"test": "vitest run --project unit && npm run filter-test-results",
|
|
31
31
|
"test:watch": "vitest",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"author": "",
|
|
67
67
|
"license": "AGPL-3.0",
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
70
70
|
"chrono-node": "^2.9.0",
|
|
71
71
|
"csv-parse": "^6.1.0",
|
|
72
72
|
"d3-array": "^3.2.4",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"eslint": "^9.35.0",
|
|
91
91
|
"eslint-config-prettier": "^10.1.8",
|
|
92
92
|
"prettier": "^3.3.3",
|
|
93
|
-
"rimraf": "^6.
|
|
93
|
+
"rimraf": "^6.1.2",
|
|
94
94
|
"tsx": "^4.20.6",
|
|
95
95
|
"typescript": "^5.9.2",
|
|
96
96
|
"typescript-eslint": "^8.42.0",
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
|
|
3
|
-
let meta;
|
|
4
|
-
try {
|
|
5
|
-
meta = JSON.parse(fs.readFileSync('meta.json', 'utf-8'));
|
|
6
|
-
} catch (error) {
|
|
7
|
-
console.error('❌ Error reading meta.json:', error.message);
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
if (!meta.inputs || typeof meta.inputs !== 'object') {
|
|
11
|
-
console.error('❌ Error: meta.inputs is missing or invalid in meta.json');
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const inputs = Object.entries(meta.inputs)
|
|
16
|
-
.map(([path, data]) => ({
|
|
17
|
-
path,
|
|
18
|
-
bytes: data.bytes,
|
|
19
|
-
}))
|
|
20
|
-
.sort((a, b) => b.bytes - a.bytes)
|
|
21
|
-
.slice(0, 20);
|
|
22
|
-
|
|
23
|
-
const totalBytes = Object.values(meta.inputs).reduce((sum, item) => sum + item.bytes, 0);
|
|
24
|
-
console.log(`\n📦 Total input size: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
25
|
-
const outputKey = 'dist/bundle/index.cjs';
|
|
26
|
-
if (!meta.outputs || !meta.outputs[outputKey]) {
|
|
27
|
-
console.error(`❌ Error: meta.outputs['${outputKey}'] is missing in meta.json`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
console.log(`📦 Output size: ${(meta.outputs[outputKey].bytes / 1024 / 1024).toFixed(2)} MB`);
|
|
31
|
-
console.log('\n📊 Top 20 largest inputs in bundle:\n');
|
|
32
|
-
inputs.forEach((item) => {
|
|
33
|
-
const kb = (item.bytes / 1024).toFixed(1).padStart(8);
|
|
34
|
-
console.log(`${kb} KB ${item.path}`);
|
|
35
|
-
}); const kb = (item.bytes / 1024).toFixed(1).padStart(8);
|
|
36
|
-
console.log(`${kb} KB ${item.path}`);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const totalBytes = Object.values(meta.inputs).reduce((sum, item) => sum + item.bytes, 0);
|
|
40
|
-
console.log(`\n📦 Total input size: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
41
|
-
console.log(`📦 Output size: ${(meta.outputs['dist/bundle/index.cjs'].bytes / 1024 / 1024).toFixed(2)} MB`);
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
|
|
3
|
+
let meta;
|
|
4
|
+
try {
|
|
5
|
+
meta = JSON.parse(fs.readFileSync('meta.json', 'utf-8'));
|
|
6
|
+
} catch (error) {
|
|
7
|
+
console.error('❌ Error reading meta.json:', error.message);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
if (!meta.inputs || typeof meta.inputs !== 'object') {
|
|
11
|
+
console.error('❌ Error: meta.inputs is missing or invalid in meta.json');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const inputs = Object.entries(meta.inputs)
|
|
16
|
+
.map(([path, data]) => ({
|
|
17
|
+
path,
|
|
18
|
+
bytes: data.bytes,
|
|
19
|
+
}))
|
|
20
|
+
.sort((a, b) => b.bytes - a.bytes)
|
|
21
|
+
.slice(0, 20);
|
|
22
|
+
|
|
23
|
+
const totalBytes = Object.values(meta.inputs).reduce((sum, item) => sum + item.bytes, 0);
|
|
24
|
+
console.log(`\n📦 Total input size: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
25
|
+
const outputKey = 'dist/bundle/index.cjs';
|
|
26
|
+
if (!meta.outputs || !meta.outputs[outputKey]) {
|
|
27
|
+
console.error(`❌ Error: meta.outputs['${outputKey}'] is missing in meta.json`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
console.log(`📦 Output size: ${(meta.outputs[outputKey].bytes / 1024 / 1024).toFixed(2)} MB`);
|
|
31
|
+
console.log('\n📊 Top 20 largest inputs in bundle:\n');
|
|
32
|
+
inputs.forEach((item) => {
|
|
33
|
+
const kb = (item.bytes / 1024).toFixed(1).padStart(8);
|
|
34
|
+
console.log(`${kb} KB ${item.path}`);
|
|
35
|
+
}); const kb = (item.bytes / 1024).toFixed(1).padStart(8);
|
|
36
|
+
console.log(`${kb} KB ${item.path}`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const totalBytes = Object.values(meta.inputs).reduce((sum, item) => sum + item.bytes, 0);
|
|
40
|
+
console.log(`\n📦 Total input size: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
41
|
+
console.log(`📦 Output size: ${(meta.outputs['dist/bundle/index.cjs'].bytes / 1024 / 1024).toFixed(2)} MB`);
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
# PowerShell script to generate a .mcpb file using the official Anthropic MCPB CLI
|
|
2
|
-
|
|
3
|
-
param(
|
|
4
|
-
[string]$OutputDir = "dist"
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
Write-Host "Generating YNAB MCP Server .mcpb package using official CLI..." -ForegroundColor Green
|
|
8
|
-
|
|
9
|
-
# Configuration
|
|
10
|
-
$PackageJson = Get-Content "package.json" | ConvertFrom-Json
|
|
11
|
-
$PackageName = $PackageJson.name
|
|
12
|
-
$Version = $PackageJson.version
|
|
13
|
-
|
|
14
|
-
# Ensure we have a built version
|
|
15
|
-
if (-not (Test-Path "dist/index.js")) {
|
|
16
|
-
Write-Host "Build not found. Running build first..." -ForegroundColor Red
|
|
17
|
-
npm run build
|
|
18
|
-
if ($LASTEXITCODE -ne 0) {
|
|
19
|
-
Write-Host "Build failed!" -ForegroundColor Red
|
|
20
|
-
exit 1
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# Check if official MCPB CLI is installed
|
|
25
|
-
try {
|
|
26
|
-
$mcpbVersion = & mcpb --version
|
|
27
|
-
Write-Host "Using MCPB CLI version: $mcpbVersion" -ForegroundColor Green
|
|
28
|
-
} catch {
|
|
29
|
-
Write-Host "MCPB CLI not found. Installing..." -ForegroundColor Yellow
|
|
30
|
-
npm install -g @anthropic-ai/mcpb
|
|
31
|
-
if ($LASTEXITCODE -ne 0) {
|
|
32
|
-
Write-Host "Failed to install MCPB CLI!" -ForegroundColor Red
|
|
33
|
-
exit 1
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# Ensure manifest.json exists and is valid
|
|
38
|
-
if (-not (Test-Path "manifest.json")) {
|
|
39
|
-
Write-Host "manifest.json not found. Creating one..." -ForegroundColor Yellow
|
|
40
|
-
& mcpb init -y
|
|
41
|
-
if ($LASTEXITCODE -ne 0) {
|
|
42
|
-
Write-Host "Failed to create manifest!" -ForegroundColor Red
|
|
43
|
-
exit 1
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
# Sync version from package.json to manifest.json
|
|
48
|
-
Write-Host "Syncing version from package.json to manifest.json..." -ForegroundColor Yellow
|
|
49
|
-
$ManifestPath = "manifest.json"
|
|
50
|
-
$ManifestContent = Get-Content $ManifestPath -Raw
|
|
51
|
-
$Manifest = $ManifestContent | ConvertFrom-Json
|
|
52
|
-
|
|
53
|
-
if ($Manifest.version -ne $Version) {
|
|
54
|
-
Write-Host "Updating manifest version from $($Manifest.version) to $Version" -ForegroundColor Cyan
|
|
55
|
-
# Use regex to update version while preserving formatting
|
|
56
|
-
$UpdatedContent = $ManifestContent -replace '("version"\s*:\s*)"[^"]*"', "`$1`"$Version`""
|
|
57
|
-
$UpdatedContent | Set-Content $ManifestPath -NoNewline
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
# Validate the manifest
|
|
61
|
-
Write-Host "Validating manifest..." -ForegroundColor Yellow
|
|
62
|
-
& mcpb validate manifest.json
|
|
63
|
-
if ($LASTEXITCODE -ne 0) {
|
|
64
|
-
Write-Host "Manifest validation failed!" -ForegroundColor Red
|
|
65
|
-
exit 1
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
# Pack the MCPB using official CLI
|
|
69
|
-
Write-Host "Packing MCPB file..." -ForegroundColor Yellow
|
|
70
|
-
$DxtFile = "$PackageName-$Version.mcpb"
|
|
71
|
-
$OutputPath = Join-Path $OutputDir $DxtFile
|
|
72
|
-
|
|
73
|
-
& mcpb pack . $OutputPath
|
|
74
|
-
if ($LASTEXITCODE -ne 0) {
|
|
75
|
-
Write-Host "MCPB packing failed!" -ForegroundColor Red
|
|
76
|
-
exit 1
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
# Get file size
|
|
80
|
-
if (Test-Path $OutputPath) {
|
|
81
|
-
$FileSize = (Get-Item $OutputPath).Length
|
|
82
|
-
$FileSizeKB = [math]::Round($FileSize / 1KB, 1)
|
|
83
|
-
$FileSizeMB = [math]::Round($FileSize / 1MB, 1)
|
|
84
|
-
|
|
85
|
-
Write-Host "Created $OutputPath" -ForegroundColor Green
|
|
86
|
-
Write-Host "Size: $FileSizeKB KB ($FileSizeMB MB)" -ForegroundColor Cyan
|
|
87
|
-
} else {
|
|
88
|
-
Write-Host "MCPB file was not created!" -ForegroundColor Red
|
|
89
|
-
exit 1
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
Write-Host ""
|
|
93
|
-
Write-Host "Installation Instructions:" -ForegroundColor Yellow
|
|
94
|
-
Write-Host "1. Drag and drop the .mcpb file into Claude Desktop" -ForegroundColor White
|
|
95
|
-
Write-Host "2. Set YNAB_ACCESS_TOKEN environment variable" -ForegroundColor White
|
|
1
|
+
# PowerShell script to generate a .mcpb file using the official Anthropic MCPB CLI
|
|
2
|
+
|
|
3
|
+
param(
|
|
4
|
+
[string]$OutputDir = "dist"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
Write-Host "Generating YNAB MCP Server .mcpb package using official CLI..." -ForegroundColor Green
|
|
8
|
+
|
|
9
|
+
# Configuration
|
|
10
|
+
$PackageJson = Get-Content "package.json" | ConvertFrom-Json
|
|
11
|
+
$PackageName = $PackageJson.name
|
|
12
|
+
$Version = $PackageJson.version
|
|
13
|
+
|
|
14
|
+
# Ensure we have a built version
|
|
15
|
+
if (-not (Test-Path "dist/index.js")) {
|
|
16
|
+
Write-Host "Build not found. Running build first..." -ForegroundColor Red
|
|
17
|
+
npm run build
|
|
18
|
+
if ($LASTEXITCODE -ne 0) {
|
|
19
|
+
Write-Host "Build failed!" -ForegroundColor Red
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Check if official MCPB CLI is installed
|
|
25
|
+
try {
|
|
26
|
+
$mcpbVersion = & mcpb --version
|
|
27
|
+
Write-Host "Using MCPB CLI version: $mcpbVersion" -ForegroundColor Green
|
|
28
|
+
} catch {
|
|
29
|
+
Write-Host "MCPB CLI not found. Installing..." -ForegroundColor Yellow
|
|
30
|
+
npm install -g @anthropic-ai/mcpb
|
|
31
|
+
if ($LASTEXITCODE -ne 0) {
|
|
32
|
+
Write-Host "Failed to install MCPB CLI!" -ForegroundColor Red
|
|
33
|
+
exit 1
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Ensure manifest.json exists and is valid
|
|
38
|
+
if (-not (Test-Path "manifest.json")) {
|
|
39
|
+
Write-Host "manifest.json not found. Creating one..." -ForegroundColor Yellow
|
|
40
|
+
& mcpb init -y
|
|
41
|
+
if ($LASTEXITCODE -ne 0) {
|
|
42
|
+
Write-Host "Failed to create manifest!" -ForegroundColor Red
|
|
43
|
+
exit 1
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Sync version from package.json to manifest.json
|
|
48
|
+
Write-Host "Syncing version from package.json to manifest.json..." -ForegroundColor Yellow
|
|
49
|
+
$ManifestPath = "manifest.json"
|
|
50
|
+
$ManifestContent = Get-Content $ManifestPath -Raw
|
|
51
|
+
$Manifest = $ManifestContent | ConvertFrom-Json
|
|
52
|
+
|
|
53
|
+
if ($Manifest.version -ne $Version) {
|
|
54
|
+
Write-Host "Updating manifest version from $($Manifest.version) to $Version" -ForegroundColor Cyan
|
|
55
|
+
# Use regex to update version while preserving formatting
|
|
56
|
+
$UpdatedContent = $ManifestContent -replace '("version"\s*:\s*)"[^"]*"', "`$1`"$Version`""
|
|
57
|
+
$UpdatedContent | Set-Content $ManifestPath -NoNewline
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Validate the manifest
|
|
61
|
+
Write-Host "Validating manifest..." -ForegroundColor Yellow
|
|
62
|
+
& mcpb validate manifest.json
|
|
63
|
+
if ($LASTEXITCODE -ne 0) {
|
|
64
|
+
Write-Host "Manifest validation failed!" -ForegroundColor Red
|
|
65
|
+
exit 1
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Pack the MCPB using official CLI
|
|
69
|
+
Write-Host "Packing MCPB file..." -ForegroundColor Yellow
|
|
70
|
+
$DxtFile = "$PackageName-$Version.mcpb"
|
|
71
|
+
$OutputPath = Join-Path $OutputDir $DxtFile
|
|
72
|
+
|
|
73
|
+
& mcpb pack . $OutputPath
|
|
74
|
+
if ($LASTEXITCODE -ne 0) {
|
|
75
|
+
Write-Host "MCPB packing failed!" -ForegroundColor Red
|
|
76
|
+
exit 1
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Get file size
|
|
80
|
+
if (Test-Path $OutputPath) {
|
|
81
|
+
$FileSize = (Get-Item $OutputPath).Length
|
|
82
|
+
$FileSizeKB = [math]::Round($FileSize / 1KB, 1)
|
|
83
|
+
$FileSizeMB = [math]::Round($FileSize / 1MB, 1)
|
|
84
|
+
|
|
85
|
+
Write-Host "Created $OutputPath" -ForegroundColor Green
|
|
86
|
+
Write-Host "Size: $FileSizeKB KB ($FileSizeMB MB)" -ForegroundColor Cyan
|
|
87
|
+
} else {
|
|
88
|
+
Write-Host "MCPB file was not created!" -ForegroundColor Red
|
|
89
|
+
exit 1
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Write-Host ""
|
|
93
|
+
Write-Host "Installation Instructions:" -ForegroundColor Yellow
|
|
94
|
+
Write-Host "1. Drag and drop the .mcpb file into Claude Desktop" -ForegroundColor White
|
|
95
|
+
Write-Host "2. Set YNAB_ACCESS_TOKEN environment variable" -ForegroundColor White
|
|
96
96
|
Write-Host "3. Restart Claude Desktop" -ForegroundColor White
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
# PowerShell script to watch for file changes and restart MCP
|
|
2
|
-
param(
|
|
3
|
-
[string]$Path = ".\src",
|
|
4
|
-
[string]$Filter = "*.ts",
|
|
5
|
-
[int]$RestartDelay = 3
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
Write-Host "🔍 Watching for changes in: $Path"
|
|
9
|
-
Write-Host "📁 Filter: $Filter"
|
|
10
|
-
|
|
11
|
-
$watcher = New-Object System.IO.FileSystemWatcher
|
|
12
|
-
$watcher.Path = Resolve-Path $Path
|
|
13
|
-
$watcher.Filter = $Filter
|
|
14
|
-
$watcher.EnableRaisingEvents = $true
|
|
15
|
-
$watcher.IncludeSubdirectories = $true
|
|
16
|
-
|
|
17
|
-
$action = {
|
|
18
|
-
$path = $Event.SourceEventArgs.FullPath
|
|
19
|
-
$changeType = $Event.SourceEventArgs.ChangeType
|
|
20
|
-
Write-Host "🔄 File $changeType`: $path"
|
|
21
|
-
|
|
22
|
-
# Build the project
|
|
23
|
-
Write-Host "🏗️ Building project..."
|
|
24
|
-
npm run build
|
|
25
|
-
|
|
26
|
-
if ($LASTEXITCODE -eq 0) {
|
|
27
|
-
Write-Host "✅ Build successful"
|
|
28
|
-
Start-Sleep -Seconds $RestartDelay
|
|
29
|
-
|
|
30
|
-
Write-Host "🔄 Reconnecting to YNAB MCP server..."
|
|
31
|
-
/mcp reconnect ynab-mcp-server
|
|
32
|
-
Start-Sleep -Seconds 1
|
|
33
|
-
/mcp reconnect ynab-mcp-server
|
|
34
|
-
Write-Host "✅ MCP server reconnected"
|
|
35
|
-
} else {
|
|
36
|
-
Write-Host "❌ Build failed, skipping MCP restart"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
Register-ObjectEvent -InputObject $watcher -EventName "Changed" -Action $action
|
|
41
|
-
Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action $action
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
Write-Host "✅ File watcher started. Press Ctrl+C to stop."
|
|
45
|
-
while ($true) { Start-Sleep 1 }
|
|
46
|
-
}
|
|
47
|
-
finally {
|
|
48
|
-
$watcher.Dispose()
|
|
49
|
-
Write-Host "👋 File watcher stopped"
|
|
1
|
+
# PowerShell script to watch for file changes and restart MCP
|
|
2
|
+
param(
|
|
3
|
+
[string]$Path = ".\src",
|
|
4
|
+
[string]$Filter = "*.ts",
|
|
5
|
+
[int]$RestartDelay = 3
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
Write-Host "🔍 Watching for changes in: $Path"
|
|
9
|
+
Write-Host "📁 Filter: $Filter"
|
|
10
|
+
|
|
11
|
+
$watcher = New-Object System.IO.FileSystemWatcher
|
|
12
|
+
$watcher.Path = Resolve-Path $Path
|
|
13
|
+
$watcher.Filter = $Filter
|
|
14
|
+
$watcher.EnableRaisingEvents = $true
|
|
15
|
+
$watcher.IncludeSubdirectories = $true
|
|
16
|
+
|
|
17
|
+
$action = {
|
|
18
|
+
$path = $Event.SourceEventArgs.FullPath
|
|
19
|
+
$changeType = $Event.SourceEventArgs.ChangeType
|
|
20
|
+
Write-Host "🔄 File $changeType`: $path"
|
|
21
|
+
|
|
22
|
+
# Build the project
|
|
23
|
+
Write-Host "🏗️ Building project..."
|
|
24
|
+
npm run build
|
|
25
|
+
|
|
26
|
+
if ($LASTEXITCODE -eq 0) {
|
|
27
|
+
Write-Host "✅ Build successful"
|
|
28
|
+
Start-Sleep -Seconds $RestartDelay
|
|
29
|
+
|
|
30
|
+
Write-Host "🔄 Reconnecting to YNAB MCP server..."
|
|
31
|
+
/mcp reconnect ynab-mcp-server
|
|
32
|
+
Start-Sleep -Seconds 1
|
|
33
|
+
/mcp reconnect ynab-mcp-server
|
|
34
|
+
Write-Host "✅ MCP server reconnected"
|
|
35
|
+
} else {
|
|
36
|
+
Write-Host "❌ Build failed, skipping MCP restart"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Register-ObjectEvent -InputObject $watcher -EventName "Changed" -Action $action
|
|
41
|
+
Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action $action
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
Write-Host "✅ File watcher started. Press Ctrl+C to stop."
|
|
45
|
+
while ($true) { Start-Sleep 1 }
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
$watcher.Dispose()
|
|
49
|
+
Write-Host "👋 File watcher stopped"
|
|
50
50
|
}
|
|
@@ -351,7 +351,7 @@ describe('YNAB MCP Server - Comprehensive Integration Tests', () => {
|
|
|
351
351
|
});
|
|
352
352
|
|
|
353
353
|
describe('Complete Transaction Management Integration', () => {
|
|
354
|
-
// TODO: Re-enable after DeltaFetcher cache integration alignment
|
|
354
|
+
// TODO: Re-enable after DeltaFetcher cache integration alignment.
|
|
355
355
|
it.skip(
|
|
356
356
|
'should handle complete transaction workflow',
|
|
357
357
|
{ meta: { tier: 'domain', domain: 'workflows' } },
|
|
@@ -748,34 +748,6 @@ describe('YNAB MCP Server - Comprehensive Integration Tests', () => {
|
|
|
748
748
|
expect(mockYnabAPI.user.getUser).toHaveBeenCalledTimes(1);
|
|
749
749
|
},
|
|
750
750
|
);
|
|
751
|
-
|
|
752
|
-
it(
|
|
753
|
-
'should handle amount conversion',
|
|
754
|
-
{ meta: { tier: 'domain', domain: 'workflows' } },
|
|
755
|
-
async () => {
|
|
756
|
-
// Test dollar to milliunits conversion
|
|
757
|
-
const toMilliunitsResult = await executeToolCall(server, 'ynab:convert_amount', {
|
|
758
|
-
amount: 25.75,
|
|
759
|
-
to_milliunits: true,
|
|
760
|
-
});
|
|
761
|
-
validateToolResult(toMilliunitsResult);
|
|
762
|
-
|
|
763
|
-
const toMilli = parseToolResult(toMilliunitsResult);
|
|
764
|
-
expect(toMilli.data.conversion.converted_amount).toBe(25750);
|
|
765
|
-
expect(toMilli.data.conversion.description).toBe('$25.75 = 25750 milliunits');
|
|
766
|
-
|
|
767
|
-
// Test milliunits to dollar conversion
|
|
768
|
-
const toDollarsResult = await executeToolCall(server, 'ynab:convert_amount', {
|
|
769
|
-
amount: 25750,
|
|
770
|
-
to_milliunits: false,
|
|
771
|
-
});
|
|
772
|
-
validateToolResult(toDollarsResult);
|
|
773
|
-
|
|
774
|
-
const dollars = parseToolResult(toDollarsResult);
|
|
775
|
-
expect(dollars.data.conversion.converted_amount).toBe(25.75);
|
|
776
|
-
expect(dollars.data.conversion.description).toBe('25750 milliunits = $25.75');
|
|
777
|
-
},
|
|
778
|
-
);
|
|
779
751
|
});
|
|
780
752
|
|
|
781
753
|
describe('Error Handling Integration', () => {
|
|
@@ -879,7 +851,7 @@ describe('YNAB MCP Server - Comprehensive Integration Tests', () => {
|
|
|
879
851
|
}
|
|
880
852
|
});
|
|
881
853
|
|
|
882
|
-
// TODO: Re-enable after DeltaFetcher cache integration alignment
|
|
854
|
+
// TODO: Re-enable after DeltaFetcher cache integration alignment.
|
|
883
855
|
it.skip(
|
|
884
856
|
'should cache budget list requests and improve performance on subsequent calls',
|
|
885
857
|
{ meta: { tier: 'domain', domain: 'workflows' } },
|
|
@@ -1010,7 +982,7 @@ describe('YNAB MCP Server - Comprehensive Integration Tests', () => {
|
|
|
1010
982
|
},
|
|
1011
983
|
);
|
|
1012
984
|
|
|
1013
|
-
// TODO: Re-enable after DeltaFetcher cache integration alignment
|
|
985
|
+
// TODO: Re-enable after DeltaFetcher cache integration alignment.
|
|
1014
986
|
it.skip(
|
|
1015
987
|
'should not cache filtered transaction requests',
|
|
1016
988
|
{ meta: { tier: 'domain', domain: 'workflows' } },
|
|
@@ -1143,7 +1115,7 @@ describe('YNAB MCP Server - Comprehensive Integration Tests', () => {
|
|
|
1143
1115
|
},
|
|
1144
1116
|
);
|
|
1145
1117
|
|
|
1146
|
-
// TODO: Re-enable after DeltaFetcher cache integration alignment
|
|
1118
|
+
// TODO: Re-enable after DeltaFetcher cache integration alignment.
|
|
1147
1119
|
it.skip(
|
|
1148
1120
|
'should respect cache TTL and return fresh data after expiration',
|
|
1149
1121
|
{ meta: { tier: 'domain', domain: 'workflows' } },
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
6
|
-
import { YNABMCPServer } from '../server/YNABMCPServer.js';
|
|
7
6
|
import { executeToolCall, parseToolResult } from './testUtils.js';
|
|
8
7
|
import { executeReconciliation, type AccountSnapshot } from '../tools/reconciliation/executor.js';
|
|
9
8
|
import type { ReconciliationAnalysis } from '../tools/reconciliation/types.js';
|
|
@@ -373,7 +372,7 @@ async function measurePerformanceScenario(options: {
|
|
|
373
372
|
}
|
|
374
373
|
|
|
375
374
|
describe('YNAB MCP Server - Performance Tests', () => {
|
|
376
|
-
let server: YNABMCPServer
|
|
375
|
+
let server: InstanceType<typeof import('../server/YNABMCPServer.js').YNABMCPServer>;
|
|
377
376
|
let mockYnabAPI: any;
|
|
378
377
|
|
|
379
378
|
beforeEach(async () => {
|
|
@@ -623,12 +622,6 @@ describe('YNAB MCP Server - Performance Tests', () => {
|
|
|
623
622
|
|
|
624
623
|
// Test multiple validation scenarios
|
|
625
624
|
const validationTests = [
|
|
626
|
-
// Valid parameters
|
|
627
|
-
executeToolCall(server, 'ynab:convert_amount', {
|
|
628
|
-
amount: 25.5,
|
|
629
|
-
to_milliunits: true,
|
|
630
|
-
}),
|
|
631
|
-
|
|
632
625
|
// Invalid parameters (should fail quickly)
|
|
633
626
|
executeToolCall(server, 'ynab:get_budget', {
|
|
634
627
|
budget_id: '', // Empty string should fail validation
|
|
@@ -648,10 +641,9 @@ describe('YNAB MCP Server - Performance Tests', () => {
|
|
|
648
641
|
|
|
649
642
|
const totalTime = endTime - startTime;
|
|
650
643
|
|
|
651
|
-
expect(parsed).toHaveLength(
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
const secondError = parsed[2].error ?? parsed[2].data?.error;
|
|
644
|
+
expect(parsed).toHaveLength(2);
|
|
645
|
+
const firstError = parsed[0].error ?? parsed[0].data?.error;
|
|
646
|
+
const secondError = parsed[1].error ?? parsed[1].data?.error;
|
|
655
647
|
expect(firstError?.code).toBe(SecurityErrorCode.VALIDATION_ERROR); // Invalid calls should fail
|
|
656
648
|
expect(secondError?.code).toBe(SecurityErrorCode.VALIDATION_ERROR);
|
|
657
649
|
expect(totalTime).toBeLessThan(1000); // Validation should be fast
|
|
@@ -715,7 +707,6 @@ describe('YNAB MCP Server - Performance Tests', () => {
|
|
|
715
707
|
executeToolCall(server, 'ynab:list_accounts', { budget_id: 'test' }),
|
|
716
708
|
executeToolCall(server, 'ynab:list_transactions', { budget_id: 'test' }),
|
|
717
709
|
executeToolCall(server, 'ynab:list_categories', { budget_id: 'test' }),
|
|
718
|
-
executeToolCall(server, 'ynab:convert_amount', { amount: i * 10, to_milliunits: true }),
|
|
719
710
|
);
|
|
720
711
|
}
|
|
721
712
|
|
|
@@ -724,7 +715,7 @@ describe('YNAB MCP Server - Performance Tests', () => {
|
|
|
724
715
|
|
|
725
716
|
const totalTime = endTime - startTime;
|
|
726
717
|
|
|
727
|
-
expect(results).toHaveLength(
|
|
718
|
+
expect(results).toHaveLength(80); // 20 iterations × 4 tools
|
|
728
719
|
results.forEach((result) => expect(result).toBeDefined());
|
|
729
720
|
expect(totalTime).toBeLessThan(10000); // Should complete within 10 seconds
|
|
730
721
|
});
|
package/src/__tests__/setup.ts
CHANGED
|
@@ -12,6 +12,49 @@ const hasAccessToken = !!process.env['YNAB_ACCESS_TOKEN'];
|
|
|
12
12
|
if (!process.env['SKIP_E2E_TESTS']) {
|
|
13
13
|
process.env['SKIP_E2E_TESTS'] = hasAccessToken ? 'false' : 'true';
|
|
14
14
|
}
|
|
15
|
+
if (!process.env['YNAB_ACCESS_TOKEN']) {
|
|
16
|
+
process.env['YNAB_ACCESS_TOKEN'] = 'test-token-for-mocked-tests';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Set test environment variables immediately
|
|
20
|
+
process.env['NODE_ENV'] = 'test';
|
|
21
|
+
if (!process.env['LOG_LEVEL']) {
|
|
22
|
+
process.env['LOG_LEVEL'] = 'error';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Disable console output for cleaner test output unless VERBOSE_TESTS is set
|
|
26
|
+
if (!process.env['VERBOSE_TESTS']) {
|
|
27
|
+
const originalConsoleError = console.error;
|
|
28
|
+
|
|
29
|
+
console.error = (...args: any[]) => {
|
|
30
|
+
const firstArg = args[0];
|
|
31
|
+
const isString = typeof firstArg === 'string';
|
|
32
|
+
// Only show errors that are part of test assertions, actual errors, or explicitly marked [ERROR]
|
|
33
|
+
if (
|
|
34
|
+
(isString &&
|
|
35
|
+
(firstArg.includes('❌') || firstArg.includes('Test') || firstArg.includes('[ERROR]'))) ||
|
|
36
|
+
firstArg instanceof Error
|
|
37
|
+
) {
|
|
38
|
+
originalConsoleError(...args);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
console.warn = () => {
|
|
43
|
+
// Suppress warnings by default
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
console.log = () => {
|
|
47
|
+
// Suppress logs by default
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
console.info = () => {
|
|
51
|
+
// Suppress info logs by default
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
console.debug = () => {
|
|
55
|
+
// Suppress debug logs by default
|
|
56
|
+
};
|
|
57
|
+
}
|
|
15
58
|
|
|
16
59
|
type TierFilter = 'core' | 'domain' | 'full';
|
|
17
60
|
interface TestMeta {
|
|
@@ -47,26 +90,14 @@ const shouldRunDomain = (domain?: string): boolean => {
|
|
|
47
90
|
* Global test setup
|
|
48
91
|
*/
|
|
49
92
|
beforeAll(async () => {
|
|
50
|
-
// Set test environment variables
|
|
51
|
-
process.env['NODE_ENV'] = 'test';
|
|
52
|
-
|
|
53
93
|
// Set default test token if not provided
|
|
54
94
|
if (!process.env['YNAB_ACCESS_TOKEN']) {
|
|
55
95
|
process.env['YNAB_ACCESS_TOKEN'] = 'test-token-for-mocked-tests';
|
|
56
96
|
}
|
|
57
97
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const originalConsoleError = console.error;
|
|
61
|
-
console.error = (...args: any[]) => {
|
|
62
|
-
// Only show errors that are part of test assertions
|
|
63
|
-
if (args[0]?.includes?.('❌') || args[0]?.includes?.('Test')) {
|
|
64
|
-
originalConsoleError(...args);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
98
|
+
if (process.env['VERBOSE_TESTS']) {
|
|
99
|
+
console.warn('🧪 Test environment initialized');
|
|
67
100
|
}
|
|
68
|
-
|
|
69
|
-
console.warn('🧪 Test environment initialized');
|
|
70
101
|
});
|
|
71
102
|
|
|
72
103
|
/**
|