@dizzlkheinz/ynab-mcpb 0.18.3 → 0.19.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/CHANGELOG.md +17 -0
- package/CLAUDE.md +87 -8
- package/bin/ynab-mcp-server.cjs +2 -2
- package/bin/ynab-mcp-server.js +3 -3
- package/biome.json +39 -0
- package/dist/bundle/index.cjs +67 -67
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -27
- package/dist/server/YNABMCPServer.d.ts +3 -4
- package/dist/server/YNABMCPServer.js +111 -116
- package/dist/server/budgetResolver.d.ts +6 -5
- package/dist/server/budgetResolver.js +46 -36
- package/dist/server/cacheKeys.js +6 -6
- package/dist/server/cacheManager.js +14 -11
- package/dist/server/completions.d.ts +2 -2
- package/dist/server/completions.js +20 -15
- package/dist/server/config.d.ts +10 -5
- package/dist/server/config.js +24 -7
- package/dist/server/deltaCache.d.ts +2 -2
- package/dist/server/deltaCache.js +22 -16
- package/dist/server/deltaCache.merge.d.ts +2 -2
- package/dist/server/diagnostics.d.ts +4 -4
- package/dist/server/diagnostics.js +38 -32
- package/dist/server/errorHandler.d.ts +5 -12
- package/dist/server/errorHandler.js +219 -217
- package/dist/server/prompts.d.ts +2 -2
- package/dist/server/prompts.js +45 -45
- package/dist/server/rateLimiter.js +4 -4
- package/dist/server/requestLogger.d.ts +1 -1
- package/dist/server/requestLogger.js +40 -35
- package/dist/server/resources.d.ts +3 -3
- package/dist/server/resources.js +55 -52
- package/dist/server/responseFormatter.js +6 -6
- package/dist/server/securityMiddleware.d.ts +2 -2
- package/dist/server/securityMiddleware.js +22 -20
- package/dist/server/serverKnowledgeStore.js +1 -1
- package/dist/server/toolRegistry.d.ts +3 -3
- package/dist/server/toolRegistry.js +47 -40
- package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
- package/dist/tools/__tests__/deltaTestUtils.js +2 -2
- package/dist/tools/accountTools.d.ts +9 -8
- package/dist/tools/accountTools.js +47 -47
- package/dist/tools/adapters.d.ts +13 -8
- package/dist/tools/adapters.js +21 -11
- package/dist/tools/budgetTools.d.ts +8 -7
- package/dist/tools/budgetTools.js +22 -22
- package/dist/tools/categoryTools.d.ts +9 -8
- package/dist/tools/categoryTools.js +68 -59
- package/dist/tools/compareTransactions/formatter.d.ts +3 -3
- package/dist/tools/compareTransactions/formatter.js +9 -9
- package/dist/tools/compareTransactions/index.d.ts +6 -6
- package/dist/tools/compareTransactions/index.js +58 -43
- package/dist/tools/compareTransactions/matcher.d.ts +1 -1
- package/dist/tools/compareTransactions/matcher.js +28 -15
- package/dist/tools/compareTransactions/parser.d.ts +2 -2
- package/dist/tools/compareTransactions/parser.js +144 -138
- package/dist/tools/compareTransactions/types.d.ts +4 -4
- package/dist/tools/compareTransactions.d.ts +1 -1
- package/dist/tools/compareTransactions.js +1 -1
- package/dist/tools/deltaFetcher.d.ts +2 -2
- package/dist/tools/deltaFetcher.js +16 -15
- package/dist/tools/deltaSupport.d.ts +4 -4
- package/dist/tools/deltaSupport.js +35 -41
- package/dist/tools/exportTransactions.d.ts +5 -4
- package/dist/tools/exportTransactions.js +61 -59
- package/dist/tools/monthTools.d.ts +7 -6
- package/dist/tools/monthTools.js +31 -29
- package/dist/tools/payeeTools.d.ts +7 -6
- package/dist/tools/payeeTools.js +28 -28
- package/dist/tools/reconcileAdapter.d.ts +2 -2
- package/dist/tools/reconcileAdapter.js +21 -11
- package/dist/tools/reconciliation/analyzer.d.ts +4 -4
- package/dist/tools/reconciliation/analyzer.js +136 -57
- package/dist/tools/reconciliation/csvParser.d.ts +3 -3
- package/dist/tools/reconciliation/csvParser.js +128 -104
- package/dist/tools/reconciliation/executor.d.ts +4 -4
- package/dist/tools/reconciliation/executor.js +148 -109
- package/dist/tools/reconciliation/index.d.ts +10 -10
- package/dist/tools/reconciliation/index.js +96 -83
- package/dist/tools/reconciliation/matcher.d.ts +3 -3
- package/dist/tools/reconciliation/matcher.js +17 -16
- package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
- package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
- package/dist/tools/reconciliation/recommendationEngine.js +40 -40
- package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
- package/dist/tools/reconciliation/reportFormatter.js +79 -54
- package/dist/tools/reconciliation/signDetector.d.ts +1 -1
- package/dist/tools/reconciliation/types.d.ts +19 -16
- package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
- package/dist/tools/schemas/common.d.ts +1 -1
- package/dist/tools/schemas/common.js +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
- package/dist/tools/schemas/outputs/index.d.ts +14 -14
- package/dist/tools/schemas/outputs/index.js +14 -14
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
- package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
- package/dist/tools/schemas/shared/commonOutputs.js +15 -9
- package/dist/tools/transactionReadTools.d.ts +11 -0
- package/dist/tools/transactionReadTools.js +202 -0
- package/dist/tools/transactionSchemas.d.ts +309 -0
- package/dist/tools/transactionSchemas.js +235 -0
- package/dist/tools/transactionTools.d.ts +6 -302
- package/dist/tools/transactionTools.js +7 -2054
- package/dist/tools/transactionUtils.d.ts +31 -0
- package/dist/tools/transactionUtils.js +364 -0
- package/dist/tools/transactionWriteTools.d.ts +20 -0
- package/dist/tools/transactionWriteTools.js +1342 -0
- package/dist/tools/utilityTools.d.ts +5 -4
- package/dist/tools/utilityTools.js +11 -11
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +6 -6
- package/dist/types/reconciliation.d.ts +1 -1
- package/dist/types/toolRegistration.d.ts +14 -12
- package/dist/utils/amountUtils.js +1 -1
- package/dist/utils/dateUtils.js +4 -4
- package/dist/utils/errors.d.ts +3 -3
- package/dist/utils/errors.js +4 -4
- package/dist/utils/money.d.ts +2 -2
- package/dist/utils/money.js +8 -8
- package/dist/utils/validationError.d.ts +1 -1
- package/dist/utils/validationError.js +1 -1
- package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
- package/docs/assets/schemas/reconciliation-v2.json +360 -336
- package/docs/plans/2025-12-25-transaction-tools-refactor-design.md +211 -0
- package/docs/plans/2025-12-25-transaction-tools-refactor.md +905 -0
- package/esbuild.config.mjs +53 -50
- package/meta.json +12548 -12548
- package/package.json +98 -109
- package/scripts/analyze-bundle.mjs +33 -30
- package/scripts/create-pr-description.js +169 -120
- package/scripts/run-all-tests.js +205 -0
- package/scripts/run-domain-integration-tests.js +28 -18
- package/scripts/run-generate-mcpb.js +19 -17
- package/scripts/run-throttled-integration-tests.js +92 -83
- package/scripts/test-delta-params.mjs +149 -120
- package/scripts/test-recommendations.ts +36 -32
- package/scripts/tmpTransaction.ts +80 -43
- package/scripts/validate-env.js +98 -91
- package/scripts/verify-build.js +78 -76
- package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
- package/src/__tests__/performance.test.ts +723 -671
- package/src/__tests__/setup.ts +442 -395
- package/src/__tests__/smoke.e2e.test.ts +41 -39
- package/src/__tests__/testRunner.ts +314 -295
- package/src/__tests__/testUtils.ts +456 -364
- package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
- package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
- package/src/index.ts +68 -59
- package/src/server/CLAUDE.md +480 -0
- package/src/server/YNABMCPServer.ts +821 -794
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
- package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
- package/src/server/__tests__/budgetResolver.test.ts +466 -423
- package/src/server/__tests__/cacheManager.test.ts +891 -874
- package/src/server/__tests__/completions.integration.test.ts +115 -106
- package/src/server/__tests__/completions.test.ts +334 -313
- package/src/server/__tests__/config.test.ts +98 -86
- package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
- package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
- package/src/server/__tests__/deltaCache.test.ts +946 -759
- package/src/server/__tests__/diagnostics.test.ts +825 -792
- package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
- package/src/server/__tests__/errorHandler.test.ts +402 -397
- package/src/server/__tests__/prompts.test.ts +424 -347
- package/src/server/__tests__/rateLimiter.test.ts +313 -309
- package/src/server/__tests__/requestLogger.test.ts +443 -403
- package/src/server/__tests__/resources.template.test.ts +196 -185
- package/src/server/__tests__/resources.test.ts +294 -288
- package/src/server/__tests__/security.integration.test.ts +487 -421
- package/src/server/__tests__/securityMiddleware.test.ts +519 -444
- package/src/server/__tests__/server-startup.integration.test.ts +509 -490
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
- package/src/server/__tests__/toolRegistration.test.ts +239 -210
- package/src/server/__tests__/toolRegistry.test.ts +907 -845
- package/src/server/budgetResolver.ts +221 -181
- package/src/server/cacheKeys.ts +6 -6
- package/src/server/cacheManager.ts +498 -484
- package/src/server/completions.ts +267 -243
- package/src/server/config.ts +35 -14
- package/src/server/deltaCache.merge.ts +146 -128
- package/src/server/deltaCache.ts +352 -309
- package/src/server/diagnostics.ts +257 -242
- package/src/server/errorHandler.ts +747 -744
- package/src/server/prompts.ts +181 -176
- package/src/server/rateLimiter.ts +131 -129
- package/src/server/requestLogger.ts +350 -322
- package/src/server/resources.ts +442 -374
- package/src/server/responseFormatter.ts +41 -37
- package/src/server/securityMiddleware.ts +223 -205
- package/src/server/serverKnowledgeStore.ts +67 -67
- package/src/server/toolRegistry.ts +508 -474
- package/src/tools/CLAUDE.md +604 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
- package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
- package/src/tools/__tests__/accountTools.test.ts +685 -638
- package/src/tools/__tests__/adapters.test.ts +142 -108
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
- package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
- package/src/tools/__tests__/budgetTools.test.ts +442 -413
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
- package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
- package/src/tools/__tests__/categoryTools.test.ts +656 -625
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
- package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
- package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
- package/src/tools/__tests__/compareTransactions.test.ts +352 -332
- package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
- package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
- package/src/tools/__tests__/deltaSupport.test.ts +211 -184
- package/src/tools/__tests__/deltaTestUtils.ts +37 -33
- package/src/tools/__tests__/exportTransactions.test.ts +205 -200
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
- package/src/tools/__tests__/monthTools.test.ts +561 -512
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
- package/src/tools/__tests__/payeeTools.test.ts +486 -434
- package/src/tools/__tests__/transactionSchemas.test.ts +1204 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
- package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
- package/src/tools/__tests__/transactionUtils.test.ts +1016 -0
- package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
- package/src/tools/__tests__/utilityTools.test.ts +68 -58
- package/src/tools/accountTools.ts +293 -271
- package/src/tools/adapters.ts +120 -63
- package/src/tools/budgetTools.ts +121 -116
- package/src/tools/categoryTools.ts +379 -339
- package/src/tools/compareTransactions/formatter.ts +131 -119
- package/src/tools/compareTransactions/index.ts +249 -214
- package/src/tools/compareTransactions/matcher.ts +259 -209
- package/src/tools/compareTransactions/parser.ts +517 -487
- package/src/tools/compareTransactions/types.ts +38 -38
- package/src/tools/compareTransactions.ts +1 -1
- package/src/tools/deltaFetcher.ts +281 -260
- package/src/tools/deltaSupport.ts +264 -259
- package/src/tools/exportTransactions.ts +230 -218
- package/src/tools/monthTools.ts +180 -165
- package/src/tools/payeeTools.ts +152 -140
- package/src/tools/reconcileAdapter.ts +297 -246
- package/src/tools/reconciliation/CLAUDE.md +506 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +135 -112
- package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -227
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -335
- package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
- package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
- package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
- package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -986
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -530
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -71
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -58
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +58 -43
- package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
- package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
- package/src/tools/reconciliation/analyzer.ts +582 -406
- package/src/tools/reconciliation/csvParser.ts +656 -609
- package/src/tools/reconciliation/executor.ts +1290 -1128
- package/src/tools/reconciliation/index.ts +580 -528
- package/src/tools/reconciliation/matcher.ts +256 -240
- package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
- package/src/tools/reconciliation/recommendationEngine.ts +357 -345
- package/src/tools/reconciliation/reportFormatter.ts +349 -276
- package/src/tools/reconciliation/signDetector.ts +89 -83
- package/src/tools/reconciliation/types.ts +164 -153
- package/src/tools/reconciliation/ynabAdapter.ts +17 -15
- package/src/tools/schemas/CLAUDE.md +546 -0
- package/src/tools/schemas/common.ts +1 -1
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
- package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
- package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
- package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
- package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
- package/src/tools/schemas/outputs/index.ts +163 -163
- package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
- package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
- package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
- package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
- package/src/tools/schemas/shared/commonOutputs.ts +27 -19
- package/src/tools/toolCategories.ts +114 -114
- package/src/tools/transactionReadTools.ts +327 -0
- package/src/tools/transactionSchemas.ts +484 -0
- package/src/tools/transactionTools.ts +107 -2990
- package/src/tools/transactionUtils.ts +621 -0
- package/src/tools/transactionWriteTools.ts +2110 -0
- package/src/tools/utilityTools.ts +46 -41
- package/src/types/CLAUDE.md +477 -0
- package/src/types/__tests__/index.test.ts +51 -51
- package/src/types/index.ts +43 -39
- package/src/types/integration-tests.d.ts +26 -26
- package/src/types/reconciliation.ts +29 -29
- package/src/types/toolAnnotations.ts +30 -30
- package/src/types/toolRegistration.ts +43 -32
- package/src/utils/CLAUDE.md +508 -0
- package/src/utils/__tests__/dateUtils.test.ts +174 -168
- package/src/utils/__tests__/money.test.ts +193 -187
- package/src/utils/amountUtils.ts +5 -5
- package/src/utils/baseError.ts +5 -5
- package/src/utils/dateUtils.ts +29 -26
- package/src/utils/errors.ts +14 -14
- package/src/utils/money.ts +66 -52
- package/src/utils/validationError.ts +1 -1
- package/tsconfig.json +29 -29
- package/tsconfig.prod.json +16 -16
- package/vitest-reporters/split-json-reporter.ts +247 -204
- package/vitest.config.ts +99 -95
- package/.prettierignore +0 -10
- package/.prettierrc.json +0 -10
- package/eslint.config.js +0 -49
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import "dotenv/config";
|
package/dist/index.js
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import { YNABMCPServer } from
|
|
4
|
-
import { AuthenticationError, ConfigurationError, ValidationError } from
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
import { YNABMCPServer } from "./server/YNABMCPServer.js";
|
|
4
|
+
import { AuthenticationError, ConfigurationError, ValidationError, } from "./utils/errors.js";
|
|
5
5
|
let serverInstance = null;
|
|
6
6
|
async function gracefulShutdown(signal) {
|
|
7
7
|
console.error(`Received ${signal}, initiating graceful shutdown...`);
|
|
8
8
|
try {
|
|
9
9
|
if (serverInstance) {
|
|
10
|
-
console.error(
|
|
10
|
+
console.error("Cleaning up server resources...");
|
|
11
11
|
serverInstance = null;
|
|
12
12
|
}
|
|
13
|
-
console.error(
|
|
13
|
+
console.error("Shutdown complete");
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
16
|
catch (error) {
|
|
17
|
-
console.error(
|
|
17
|
+
console.error("Error during shutdown:", error);
|
|
18
18
|
process.exit(1);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
function reportError(error) {
|
|
22
22
|
if (error instanceof ValidationError) {
|
|
23
|
-
console.error(
|
|
24
|
-
console.error(
|
|
23
|
+
console.error("❌ Validation Error:", error.message);
|
|
24
|
+
console.error("Please check your inputs and try again.");
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
else if (error instanceof AuthenticationError) {
|
|
28
|
-
console.error(
|
|
29
|
-
console.error(
|
|
28
|
+
console.error("❌ Authentication Error:", error.message);
|
|
29
|
+
console.error("Please verify your YNAB access token and try again.");
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
else if (error instanceof ConfigurationError) {
|
|
33
|
-
console.error(
|
|
34
|
-
console.error(
|
|
33
|
+
console.error("❌ Configuration Error:", error.message);
|
|
34
|
+
console.error("Please check your environment variables and try again.");
|
|
35
35
|
process.exit(1);
|
|
36
36
|
}
|
|
37
37
|
else if (error instanceof Error) {
|
|
38
|
-
console.error(
|
|
39
|
-
if (process.env[
|
|
40
|
-
console.error(
|
|
38
|
+
console.error("❌ Server Error:", error.message);
|
|
39
|
+
if (process.env["NODE_ENV"] === "development") {
|
|
40
|
+
console.error("Stack trace:", error.stack);
|
|
41
41
|
}
|
|
42
42
|
process.exit(1);
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
45
|
-
console.error(
|
|
45
|
+
console.error("❌ Unknown error:", error);
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
async function main() {
|
|
50
50
|
try {
|
|
51
|
-
console.error(
|
|
51
|
+
console.error("🚀 Starting YNAB MCP Server...");
|
|
52
52
|
serverInstance = new YNABMCPServer();
|
|
53
|
-
console.error(
|
|
53
|
+
console.error("✅ Server instance created successfully");
|
|
54
54
|
await serverInstance.run();
|
|
55
|
-
console.error(
|
|
55
|
+
console.error("✅ YNAB MCP Server started successfully");
|
|
56
56
|
}
|
|
57
57
|
catch (error) {
|
|
58
58
|
reportError(error);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
process.on(
|
|
62
|
-
process.on(
|
|
63
|
-
process.on(
|
|
64
|
-
console.error(
|
|
65
|
-
if (process.env[
|
|
66
|
-
console.error(
|
|
61
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
62
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
63
|
+
process.on("uncaughtException", (error) => {
|
|
64
|
+
console.error("❌ Uncaught Exception:", error);
|
|
65
|
+
if (process.env["NODE_ENV"] === "development") {
|
|
66
|
+
console.error("Stack trace:", error.stack);
|
|
67
67
|
}
|
|
68
68
|
process.exit(1);
|
|
69
69
|
});
|
|
70
|
-
process.on(
|
|
71
|
-
console.error(
|
|
70
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
71
|
+
console.error("❌ Unhandled Promise Rejection at:", promise, "reason:", reason);
|
|
72
72
|
process.exit(1);
|
|
73
73
|
});
|
|
74
74
|
main().catch(reportError);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Server } from
|
|
2
|
-
import * as ynab from
|
|
3
|
-
import { ToolRegistry } from
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import * as ynab from "ynab";
|
|
3
|
+
import { ToolRegistry } from "./toolRegistry.js";
|
|
4
4
|
export declare class YNABMCPServer {
|
|
5
5
|
private server;
|
|
6
6
|
private ynabAPI;
|
|
@@ -30,7 +30,6 @@ export declare class YNABMCPServer {
|
|
|
30
30
|
getDefaultBudget(): string | undefined;
|
|
31
31
|
clearDefaultBudget(): void;
|
|
32
32
|
getToolRegistry(): ToolRegistry;
|
|
33
|
-
getBudgetId(providedBudgetId?: string): string;
|
|
34
33
|
private warmCacheForBudget;
|
|
35
34
|
handleListTools(): Promise<{
|
|
36
35
|
tools: {
|
|
@@ -1,45 +1,44 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { PromptManager } from
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import { CompletionsManager } from './completions.js';
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { CallToolRequestSchema, CompleteRequestSchema, ErrorCode, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import * as ynab from "ynab";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { registerAccountTools } from "../tools/accountTools.js";
|
|
9
|
+
import { registerBudgetTools } from "../tools/budgetTools.js";
|
|
10
|
+
import { registerCategoryTools } from "../tools/categoryTools.js";
|
|
11
|
+
import { DeltaFetcher } from "../tools/deltaFetcher.js";
|
|
12
|
+
import { registerMonthTools } from "../tools/monthTools.js";
|
|
13
|
+
import { registerPayeeTools } from "../tools/payeeTools.js";
|
|
14
|
+
import { registerReconciliationTools } from "../tools/reconciliation/index.js";
|
|
15
|
+
import { emptyObjectSchema } from "../tools/schemas/common.js";
|
|
16
|
+
import { ToolAnnotationPresets } from "../tools/toolCategories.js";
|
|
17
|
+
import { registerTransactionTools } from "../tools/transactionTools.js";
|
|
18
|
+
import { registerUtilityTools } from "../tools/utilityTools.js";
|
|
19
|
+
import { ValidationError, YNABErrorCode } from "../types/index.js";
|
|
20
|
+
import { AuthenticationError, ValidationError as ConfigValidationError, ConfigurationError, } from "../utils/errors.js";
|
|
21
|
+
import { CacheManager, cacheManager } from "./cacheManager.js";
|
|
22
|
+
import { CompletionsManager } from "./completions.js";
|
|
23
|
+
import { loadConfig } from "./config.js";
|
|
24
|
+
import { DeltaCache } from "./deltaCache.js";
|
|
25
|
+
import { DiagnosticManager } from "./diagnostics.js";
|
|
26
|
+
import { createErrorHandler } from "./errorHandler.js";
|
|
27
|
+
import { PromptManager } from "./prompts.js";
|
|
28
|
+
import { ResourceManager } from "./resources.js";
|
|
29
|
+
import { responseFormatter } from "./responseFormatter.js";
|
|
30
|
+
import { SecurityMiddleware, withSecurityWrapper, } from "./securityMiddleware.js";
|
|
31
|
+
import { ServerKnowledgeStore } from "./serverKnowledgeStore.js";
|
|
32
|
+
import { ToolRegistry, } from "./toolRegistry.js";
|
|
34
33
|
export class YNABMCPServer {
|
|
35
34
|
constructor(exitOnError = true) {
|
|
36
35
|
this.exitOnError = exitOnError;
|
|
37
36
|
this.configInstance = loadConfig();
|
|
38
37
|
this.defaultBudgetId = this.configInstance.YNAB_DEFAULT_BUDGET_ID;
|
|
39
38
|
this.ynabAPI = new ynab.API(this.configInstance.YNAB_ACCESS_TOKEN);
|
|
40
|
-
this.serverVersion = this.readPackageVersion() ??
|
|
39
|
+
this.serverVersion = this.readPackageVersion() ?? "0.0.0";
|
|
41
40
|
this.server = new Server({
|
|
42
|
-
name:
|
|
41
|
+
name: "ynab-mcp-server",
|
|
43
42
|
version: this.serverVersion,
|
|
44
43
|
}, {
|
|
45
44
|
capabilities: {
|
|
@@ -53,7 +52,6 @@ export class YNABMCPServer {
|
|
|
53
52
|
},
|
|
54
53
|
});
|
|
55
54
|
this.errorHandler = createErrorHandler(responseFormatter);
|
|
56
|
-
ErrorHandler.setFormatter(responseFormatter);
|
|
57
55
|
this.toolRegistry = new ToolRegistry({
|
|
58
56
|
withSecurityWrapper,
|
|
59
57
|
errorHandler: this.errorHandler,
|
|
@@ -61,15 +59,15 @@ export class YNABMCPServer {
|
|
|
61
59
|
cacheHelpers: {
|
|
62
60
|
generateKey: (...segments) => {
|
|
63
61
|
const normalized = segments.map((segment) => {
|
|
64
|
-
if (typeof segment ===
|
|
65
|
-
typeof segment ===
|
|
66
|
-
typeof segment ===
|
|
62
|
+
if (typeof segment === "string" ||
|
|
63
|
+
typeof segment === "number" ||
|
|
64
|
+
typeof segment === "boolean" ||
|
|
67
65
|
segment === undefined) {
|
|
68
66
|
return segment;
|
|
69
67
|
}
|
|
70
68
|
return JSON.stringify(segment);
|
|
71
69
|
});
|
|
72
|
-
return CacheManager.generateKey(
|
|
70
|
+
return CacheManager.generateKey("tool", ...normalized);
|
|
73
71
|
},
|
|
74
72
|
invalidate: (key) => {
|
|
75
73
|
try {
|
|
@@ -84,18 +82,18 @@ export class YNABMCPServer {
|
|
|
84
82
|
cacheManager.clear();
|
|
85
83
|
}
|
|
86
84
|
catch (error) {
|
|
87
|
-
console.error(
|
|
85
|
+
console.error("Failed to clear cache:", error);
|
|
88
86
|
}
|
|
89
87
|
},
|
|
90
88
|
},
|
|
91
89
|
validateAccessToken: (token) => {
|
|
92
90
|
const expected = this.configInstance.YNAB_ACCESS_TOKEN.trim();
|
|
93
|
-
const provided = typeof token ===
|
|
91
|
+
const provided = typeof token === "string" ? token.trim() : "";
|
|
94
92
|
if (!provided) {
|
|
95
|
-
throw this.errorHandler.createYNABError(
|
|
93
|
+
throw this.errorHandler.createYNABError(YNABErrorCode.UNAUTHORIZED, "validating access token", new Error("Missing access token"));
|
|
96
94
|
}
|
|
97
95
|
if (provided !== expected) {
|
|
98
|
-
throw this.errorHandler.createYNABError(
|
|
96
|
+
throw this.errorHandler.createYNABError(YNABErrorCode.UNAUTHORIZED, "validating access token", new Error("Access token mismatch"));
|
|
99
97
|
}
|
|
100
98
|
},
|
|
101
99
|
});
|
|
@@ -127,14 +125,16 @@ export class YNABMCPServer {
|
|
|
127
125
|
}
|
|
128
126
|
catch (error) {
|
|
129
127
|
if (this.isMalformedTokenResponse(error)) {
|
|
130
|
-
throw new AuthenticationError(
|
|
128
|
+
throw new AuthenticationError("Unexpected response from YNAB during token validation");
|
|
131
129
|
}
|
|
132
130
|
if (error instanceof Error) {
|
|
133
|
-
if (error.message.includes(
|
|
134
|
-
|
|
131
|
+
if (error.message.includes("401") ||
|
|
132
|
+
error.message.includes("Unauthorized")) {
|
|
133
|
+
throw new AuthenticationError("Invalid or expired YNAB access token");
|
|
135
134
|
}
|
|
136
|
-
if (error.message.includes(
|
|
137
|
-
|
|
135
|
+
if (error.message.includes("403") ||
|
|
136
|
+
error.message.includes("Forbidden")) {
|
|
137
|
+
throw new AuthenticationError("YNAB access token has insufficient permissions");
|
|
138
138
|
}
|
|
139
139
|
const reason = error.message || String(error);
|
|
140
140
|
throw new AuthenticationError(`Token validation failed: ${reason}`);
|
|
@@ -146,18 +146,18 @@ export class YNABMCPServer {
|
|
|
146
146
|
if (error instanceof SyntaxError) {
|
|
147
147
|
return true;
|
|
148
148
|
}
|
|
149
|
-
const message = typeof error ===
|
|
149
|
+
const message = typeof error === "string"
|
|
150
150
|
? error
|
|
151
|
-
: typeof error?.message ===
|
|
151
|
+
: typeof error?.message === "string"
|
|
152
152
|
? String(error.message)
|
|
153
153
|
: null;
|
|
154
154
|
if (!message) {
|
|
155
155
|
return false;
|
|
156
156
|
}
|
|
157
157
|
const normalized = message.toLowerCase();
|
|
158
|
-
return (normalized.includes(
|
|
159
|
-
normalized.includes(
|
|
160
|
-
normalized.includes(
|
|
158
|
+
return (normalized.includes("unexpected token") ||
|
|
159
|
+
normalized.includes("unexpected end of json") ||
|
|
160
|
+
normalized.includes("<html"));
|
|
161
161
|
}
|
|
162
162
|
setupHandlers() {
|
|
163
163
|
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
@@ -192,9 +192,9 @@ export class YNABMCPServer {
|
|
|
192
192
|
const sanitizedArgs = rawArgs
|
|
193
193
|
? (() => {
|
|
194
194
|
const clone = { ...rawArgs };
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
clone["minify"] = undefined;
|
|
196
|
+
clone["_minify"] = undefined;
|
|
197
|
+
clone["__minify"] = undefined;
|
|
198
198
|
return clone;
|
|
199
199
|
})()
|
|
200
200
|
: undefined;
|
|
@@ -206,18 +206,19 @@ export class YNABMCPServer {
|
|
|
206
206
|
if (minifyOverride !== undefined) {
|
|
207
207
|
executionOptions.minifyOverride = minifyOverride;
|
|
208
208
|
}
|
|
209
|
-
const progressToken = request.params
|
|
210
|
-
._meta?.progressToken;
|
|
209
|
+
const progressToken = request.params._meta?.progressToken;
|
|
211
210
|
if (progressToken !== undefined && extra.sendNotification) {
|
|
212
211
|
executionOptions.sendProgress = async (params) => {
|
|
213
212
|
try {
|
|
214
213
|
await extra.sendNotification({
|
|
215
|
-
method:
|
|
214
|
+
method: "notifications/progress",
|
|
216
215
|
params: {
|
|
217
216
|
progressToken,
|
|
218
217
|
progress: params.progress,
|
|
219
218
|
...(params.total !== undefined && { total: params.total }),
|
|
220
|
-
...(params.message !== undefined && {
|
|
219
|
+
...(params.message !== undefined && {
|
|
220
|
+
message: params.message,
|
|
221
|
+
}),
|
|
221
222
|
},
|
|
222
223
|
});
|
|
223
224
|
}
|
|
@@ -229,7 +230,9 @@ export class YNABMCPServer {
|
|
|
229
230
|
});
|
|
230
231
|
this.server.setRequestHandler(CompleteRequestSchema, async (request) => {
|
|
231
232
|
const { argument, context } = request.params;
|
|
232
|
-
const completionContext = context?.arguments
|
|
233
|
+
const completionContext = context?.arguments
|
|
234
|
+
? { arguments: context.arguments }
|
|
235
|
+
: undefined;
|
|
233
236
|
const result = await this.completionsManager.getCompletions(argument.name, argument.value, completionContext);
|
|
234
237
|
return {
|
|
235
238
|
completion: result.completion,
|
|
@@ -248,9 +251,12 @@ export class YNABMCPServer {
|
|
|
248
251
|
getDefaultBudgetId: () => this.defaultBudgetId,
|
|
249
252
|
setDefaultBudget: (budgetId) => this.setDefaultBudget(budgetId),
|
|
250
253
|
cacheManager,
|
|
254
|
+
errorHandler: this.errorHandler,
|
|
251
255
|
diagnosticManager: this.diagnosticManager,
|
|
252
256
|
};
|
|
253
|
-
const setDefaultBudgetSchema = z
|
|
257
|
+
const setDefaultBudgetSchema = z
|
|
258
|
+
.object({ budget_id: z.string().min(1) })
|
|
259
|
+
.strict();
|
|
254
260
|
const diagnosticInfoSchema = z
|
|
255
261
|
.object({
|
|
256
262
|
include_memory: z.boolean().default(true),
|
|
@@ -276,8 +282,8 @@ export class YNABMCPServer {
|
|
|
276
282
|
registerReconciliationTools(this.toolRegistry, toolContext);
|
|
277
283
|
registerUtilityTools(this.toolRegistry, toolContext);
|
|
278
284
|
register({
|
|
279
|
-
name:
|
|
280
|
-
description:
|
|
285
|
+
name: "set_default_budget",
|
|
286
|
+
description: "Set the default budget for subsequent operations",
|
|
281
287
|
inputSchema: setDefaultBudgetSchema,
|
|
282
288
|
handler: async ({ input }) => {
|
|
283
289
|
const { budget_id } = input;
|
|
@@ -288,7 +294,7 @@ export class YNABMCPServer {
|
|
|
288
294
|
return {
|
|
289
295
|
content: [
|
|
290
296
|
{
|
|
291
|
-
type:
|
|
297
|
+
type: "text",
|
|
292
298
|
text: responseFormatter.format({
|
|
293
299
|
success: true,
|
|
294
300
|
message: `Default budget set to: ${budget_id}`,
|
|
@@ -302,13 +308,13 @@ export class YNABMCPServer {
|
|
|
302
308
|
metadata: {
|
|
303
309
|
annotations: {
|
|
304
310
|
...ToolAnnotationPresets.WRITE_EXTERNAL_UPDATE,
|
|
305
|
-
title:
|
|
311
|
+
title: "YNAB: Set Default Budget",
|
|
306
312
|
},
|
|
307
313
|
},
|
|
308
314
|
});
|
|
309
315
|
register({
|
|
310
|
-
name:
|
|
311
|
-
description:
|
|
316
|
+
name: "get_default_budget",
|
|
317
|
+
description: "Get the currently set default budget",
|
|
312
318
|
inputSchema: emptyObjectSchema,
|
|
313
319
|
handler: async () => {
|
|
314
320
|
try {
|
|
@@ -316,32 +322,32 @@ export class YNABMCPServer {
|
|
|
316
322
|
return {
|
|
317
323
|
content: [
|
|
318
324
|
{
|
|
319
|
-
type:
|
|
325
|
+
type: "text",
|
|
320
326
|
text: responseFormatter.format({
|
|
321
327
|
default_budget_id: defaultBudget ?? null,
|
|
322
328
|
has_default: !!defaultBudget,
|
|
323
329
|
message: defaultBudget
|
|
324
330
|
? `Default budget is set to: ${defaultBudget}`
|
|
325
|
-
:
|
|
331
|
+
: "No default budget is currently set",
|
|
326
332
|
}),
|
|
327
333
|
},
|
|
328
334
|
],
|
|
329
335
|
};
|
|
330
336
|
}
|
|
331
337
|
catch (error) {
|
|
332
|
-
return this.errorHandler.createValidationError(
|
|
338
|
+
return this.errorHandler.createValidationError("Error getting default budget", error instanceof Error ? error.message : "Unknown error");
|
|
333
339
|
}
|
|
334
340
|
},
|
|
335
341
|
metadata: {
|
|
336
342
|
annotations: {
|
|
337
343
|
...ToolAnnotationPresets.UTILITY_LOCAL,
|
|
338
|
-
title:
|
|
344
|
+
title: "YNAB: Get Default Budget",
|
|
339
345
|
},
|
|
340
346
|
},
|
|
341
347
|
});
|
|
342
348
|
register({
|
|
343
|
-
name:
|
|
344
|
-
description:
|
|
349
|
+
name: "diagnostic_info",
|
|
350
|
+
description: "Get comprehensive diagnostic information about the MCP server",
|
|
345
351
|
inputSchema: diagnosticInfoSchema,
|
|
346
352
|
handler: async ({ input }) => {
|
|
347
353
|
return this.diagnosticManager.collectDiagnostics(input);
|
|
@@ -349,37 +355,39 @@ export class YNABMCPServer {
|
|
|
349
355
|
metadata: {
|
|
350
356
|
annotations: {
|
|
351
357
|
...ToolAnnotationPresets.UTILITY_LOCAL,
|
|
352
|
-
title:
|
|
358
|
+
title: "YNAB: Diagnostic Information",
|
|
353
359
|
},
|
|
354
360
|
},
|
|
355
361
|
});
|
|
356
362
|
register({
|
|
357
|
-
name:
|
|
358
|
-
description:
|
|
363
|
+
name: "clear_cache",
|
|
364
|
+
description: "Clear the in-memory cache (safe, no YNAB data is modified)",
|
|
359
365
|
inputSchema: emptyObjectSchema,
|
|
360
366
|
handler: async () => {
|
|
361
367
|
cacheManager.clear();
|
|
362
368
|
return {
|
|
363
|
-
content: [
|
|
369
|
+
content: [
|
|
370
|
+
{ type: "text", text: responseFormatter.format({ success: true }) },
|
|
371
|
+
],
|
|
364
372
|
};
|
|
365
373
|
},
|
|
366
374
|
metadata: {
|
|
367
375
|
annotations: {
|
|
368
376
|
...ToolAnnotationPresets.UTILITY_LOCAL,
|
|
369
|
-
title:
|
|
377
|
+
title: "YNAB: Clear Cache",
|
|
370
378
|
},
|
|
371
379
|
},
|
|
372
380
|
});
|
|
373
381
|
register({
|
|
374
|
-
name:
|
|
375
|
-
description:
|
|
382
|
+
name: "set_output_format",
|
|
383
|
+
description: "Configure default JSON output formatting (minify or pretty spaces)",
|
|
376
384
|
inputSchema: setOutputFormatSchema,
|
|
377
385
|
handler: async ({ input }) => {
|
|
378
386
|
const options = {};
|
|
379
|
-
if (typeof input.default_minify ===
|
|
387
|
+
if (typeof input.default_minify === "boolean") {
|
|
380
388
|
options.defaultMinify = input.default_minify;
|
|
381
389
|
}
|
|
382
|
-
if (typeof input.pretty_spaces ===
|
|
390
|
+
if (typeof input.pretty_spaces === "number") {
|
|
383
391
|
options.prettySpaces = Math.max(0, Math.min(10, Math.floor(input.pretty_spaces)));
|
|
384
392
|
}
|
|
385
393
|
responseFormatter.configure(options);
|
|
@@ -391,13 +399,17 @@ export class YNABMCPServer {
|
|
|
391
399
|
parts.push(`spaces=${options.prettySpaces}`);
|
|
392
400
|
}
|
|
393
401
|
const message = parts.length > 0
|
|
394
|
-
? `Output format configured: ${parts.join(
|
|
395
|
-
:
|
|
402
|
+
? `Output format configured: ${parts.join(", ")}`
|
|
403
|
+
: "Output format configured";
|
|
396
404
|
return {
|
|
397
405
|
content: [
|
|
398
406
|
{
|
|
399
|
-
type:
|
|
400
|
-
text: responseFormatter.format({
|
|
407
|
+
type: "text",
|
|
408
|
+
text: responseFormatter.format({
|
|
409
|
+
success: true,
|
|
410
|
+
message,
|
|
411
|
+
options,
|
|
412
|
+
}),
|
|
401
413
|
},
|
|
402
414
|
],
|
|
403
415
|
};
|
|
@@ -405,7 +417,7 @@ export class YNABMCPServer {
|
|
|
405
417
|
metadata: {
|
|
406
418
|
annotations: {
|
|
407
419
|
...ToolAnnotationPresets.UTILITY_LOCAL,
|
|
408
|
-
title:
|
|
420
|
+
title: "YNAB: Set Output Format",
|
|
409
421
|
},
|
|
410
422
|
},
|
|
411
423
|
});
|
|
@@ -414,9 +426,9 @@ export class YNABMCPServer {
|
|
|
414
426
|
if (!args) {
|
|
415
427
|
return undefined;
|
|
416
428
|
}
|
|
417
|
-
for (const key of [
|
|
429
|
+
for (const key of ["minify", "_minify", "__minify"]) {
|
|
418
430
|
const value = args[key];
|
|
419
|
-
if (typeof value ===
|
|
431
|
+
if (typeof value === "boolean") {
|
|
420
432
|
return value;
|
|
421
433
|
}
|
|
422
434
|
}
|
|
@@ -427,14 +439,14 @@ export class YNABMCPServer {
|
|
|
427
439
|
await this.validateToken();
|
|
428
440
|
const transport = new StdioServerTransport();
|
|
429
441
|
await this.server.connect(transport);
|
|
430
|
-
console.error(
|
|
442
|
+
console.error("YNAB MCP Server started successfully");
|
|
431
443
|
}
|
|
432
444
|
catch (error) {
|
|
433
445
|
if (error instanceof AuthenticationError ||
|
|
434
446
|
error instanceof ConfigurationError ||
|
|
435
447
|
error instanceof ConfigValidationError ||
|
|
436
448
|
error instanceof ValidationError ||
|
|
437
|
-
error?.name ===
|
|
449
|
+
error?.name === "ValidationError") {
|
|
438
450
|
console.error(`Server startup failed: ${error instanceof Error ? error.message : error}`);
|
|
439
451
|
if (this.exitOnError) {
|
|
440
452
|
process.exit(1);
|
|
@@ -464,23 +476,6 @@ export class YNABMCPServer {
|
|
|
464
476
|
getToolRegistry() {
|
|
465
477
|
return this.toolRegistry;
|
|
466
478
|
}
|
|
467
|
-
getBudgetId(providedBudgetId) {
|
|
468
|
-
const result = BudgetResolver.resolveBudgetId(providedBudgetId, this.defaultBudgetId);
|
|
469
|
-
if (typeof result === 'string') {
|
|
470
|
-
return result;
|
|
471
|
-
}
|
|
472
|
-
const errorText = result.content?.[0]?.type === 'text' ? result.content[0].text : 'Budget resolution failed';
|
|
473
|
-
const parsedError = (() => {
|
|
474
|
-
try {
|
|
475
|
-
return JSON.parse(errorText);
|
|
476
|
-
}
|
|
477
|
-
catch {
|
|
478
|
-
return { error: { message: errorText } };
|
|
479
|
-
}
|
|
480
|
-
})();
|
|
481
|
-
const message = parsedError.error?.message || 'Budget resolution failed';
|
|
482
|
-
throw new ValidationError(message);
|
|
483
|
-
}
|
|
484
479
|
async warmCacheForBudget(budgetId) {
|
|
485
480
|
try {
|
|
486
481
|
await Promise.all([
|
|
@@ -526,20 +521,20 @@ export class YNABMCPServer {
|
|
|
526
521
|
}
|
|
527
522
|
}
|
|
528
523
|
readPackageVersion() {
|
|
529
|
-
const candidates = [path.resolve(process.cwd(),
|
|
524
|
+
const candidates = [path.resolve(process.cwd(), "package.json")];
|
|
530
525
|
try {
|
|
531
526
|
const metaUrl = import.meta?.url;
|
|
532
527
|
if (metaUrl) {
|
|
533
|
-
const maybe = path.resolve(path.dirname(new URL(metaUrl).pathname),
|
|
528
|
+
const maybe = path.resolve(path.dirname(new URL(metaUrl).pathname), "../../package.json");
|
|
534
529
|
candidates.push(maybe);
|
|
535
530
|
}
|
|
536
531
|
}
|
|
537
532
|
catch {
|
|
538
533
|
}
|
|
539
534
|
try {
|
|
540
|
-
const dir = typeof __dirname ===
|
|
535
|
+
const dir = typeof __dirname === "string" ? __dirname : undefined;
|
|
541
536
|
if (dir) {
|
|
542
|
-
candidates.push(path.resolve(dir,
|
|
537
|
+
candidates.push(path.resolve(dir, "../../package.json"), path.resolve(dir, "../package.json"), path.resolve(dir, "package.json"));
|
|
543
538
|
}
|
|
544
539
|
}
|
|
545
540
|
catch {
|
|
@@ -547,9 +542,9 @@ export class YNABMCPServer {
|
|
|
547
542
|
for (const p of candidates) {
|
|
548
543
|
try {
|
|
549
544
|
if (fs.existsSync(p)) {
|
|
550
|
-
const raw = fs.readFileSync(p,
|
|
545
|
+
const raw = fs.readFileSync(p, "utf8");
|
|
551
546
|
const pkg = JSON.parse(raw);
|
|
552
|
-
if (pkg.version && typeof pkg.version ===
|
|
547
|
+
if (pkg.version && typeof pkg.version === "string")
|
|
553
548
|
return pkg.version;
|
|
554
549
|
}
|
|
555
550
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { CallToolResult } from
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { type ErrorHandler } from "./errorHandler.js";
|
|
2
3
|
export declare class BudgetResolver {
|
|
3
4
|
private static readonly UUID_REGEX;
|
|
4
5
|
private static readonly ALLOWED_KEYWORDS;
|
|
5
|
-
static resolveBudgetId(providedId?: string, defaultId?: string): string | CallToolResult;
|
|
6
|
-
static validateBudgetId(budgetId: string): string | CallToolResult;
|
|
7
|
-
static createMissingBudgetError(): CallToolResult;
|
|
8
|
-
static createInvalidBudgetError(details: string): CallToolResult;
|
|
6
|
+
static resolveBudgetId(providedId?: string, defaultId?: string, errorHandler?: ErrorHandler): string | CallToolResult;
|
|
7
|
+
static validateBudgetId(budgetId: string, errorHandler?: ErrorHandler): string | CallToolResult;
|
|
8
|
+
static createMissingBudgetError(errorHandler?: ErrorHandler): CallToolResult;
|
|
9
|
+
static createInvalidBudgetError(details: string, errorHandler?: ErrorHandler): CallToolResult;
|
|
9
10
|
static resolveBudgetIdOrThrow(providedId?: string, defaultId?: string): string;
|
|
10
11
|
static validateBudgetIdOrThrow(budgetId: string): string;
|
|
11
12
|
}
|