@dizzlkheinz/ynab-mcpb 0.16.1 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/.env.example +33 -33
  2. package/.github/workflows/ci-tests.yml +45 -45
  3. package/.github/workflows/claude-code-review.yml +57 -57
  4. package/.github/workflows/claude.yml +50 -50
  5. package/.github/workflows/full-integration.yml +22 -22
  6. package/.github/workflows/publish.yml +11 -2
  7. package/CLAUDE.md +33 -47
  8. package/README.md +8 -10
  9. package/dist/bundle/index.cjs +54 -54
  10. package/dist/server/YNABMCPServer.d.ts +120 -54
  11. package/dist/server/YNABMCPServer.js +28 -381
  12. package/dist/server/config.d.ts +2 -0
  13. package/dist/server/config.js +1 -0
  14. package/dist/server/securityMiddleware.d.ts +37 -8
  15. package/dist/tools/accountTools.d.ts +2 -0
  16. package/dist/tools/accountTools.js +45 -0
  17. package/dist/tools/adapters.d.ts +12 -0
  18. package/dist/tools/adapters.js +25 -0
  19. package/dist/tools/budgetTools.d.ts +2 -0
  20. package/dist/tools/budgetTools.js +30 -0
  21. package/dist/tools/categoryTools.d.ts +2 -0
  22. package/dist/tools/categoryTools.js +45 -0
  23. package/dist/tools/monthTools.d.ts +2 -0
  24. package/dist/tools/monthTools.js +32 -0
  25. package/dist/tools/payeeTools.d.ts +2 -0
  26. package/dist/tools/payeeTools.js +32 -0
  27. package/dist/tools/reconciliation/index.d.ts +2 -0
  28. package/dist/tools/reconciliation/index.js +33 -0
  29. package/dist/tools/schemas/common.d.ts +3 -0
  30. package/dist/tools/schemas/common.js +3 -0
  31. package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
  32. package/dist/tools/schemas/outputs/index.d.ts +2 -2
  33. package/dist/tools/schemas/outputs/index.js +2 -2
  34. package/dist/tools/schemas/outputs/utilityOutputs.d.ts +0 -15
  35. package/dist/tools/schemas/outputs/utilityOutputs.js +0 -9
  36. package/dist/tools/transactionTools.d.ts +2 -0
  37. package/dist/tools/transactionTools.js +124 -0
  38. package/dist/tools/utilityTools.d.ts +2 -7
  39. package/dist/tools/utilityTools.js +19 -38
  40. package/dist/types/index.d.ts +1 -0
  41. package/dist/types/toolRegistration.d.ts +27 -0
  42. package/dist/types/toolRegistration.js +1 -0
  43. package/docs/maintainers/npm-publishing.md +27 -0
  44. package/docs/reference/API.md +15 -70
  45. package/docs/technical/reconciliation-system-architecture.md +2251 -2251
  46. package/package.json +6 -6
  47. package/scripts/analyze-bundle.mjs +41 -41
  48. package/scripts/generate-mcpb.ps1 +95 -95
  49. package/scripts/run-domain-integration-tests.js +4 -1
  50. package/scripts/watch-and-restart.ps1 +49 -49
  51. package/src/__tests__/comprehensive.integration.test.ts +0 -28
  52. package/src/__tests__/performance.test.ts +4 -12
  53. package/src/__tests__/setup.ts +45 -14
  54. package/src/__tests__/workflows.e2e.test.ts +1 -51
  55. package/src/server/YNABMCPServer.ts +33 -519
  56. package/src/server/__tests__/YNABMCPServer.test.ts +0 -1
  57. package/src/server/__tests__/toolRegistration.test.ts +236 -0
  58. package/src/server/config.ts +1 -0
  59. package/src/tools/__tests__/adapters.test.ts +113 -0
  60. package/src/tools/__tests__/transactionTools.integration.test.ts +63 -3
  61. package/src/tools/__tests__/utilityTools.integration.test.ts +1 -85
  62. package/src/tools/__tests__/utilityTools.test.ts +1 -123
  63. package/src/tools/accountTools.ts +53 -0
  64. package/src/tools/adapters.ts +74 -0
  65. package/src/tools/budgetTools.ts +37 -0
  66. package/src/tools/categoryTools.ts +53 -0
  67. package/src/tools/monthTools.ts +39 -0
  68. package/src/tools/payeeTools.ts +39 -0
  69. package/src/tools/reconciliation/index.ts +45 -0
  70. package/src/tools/schemas/common.ts +18 -0
  71. package/src/tools/schemas/outputs/index.ts +0 -3
  72. package/src/tools/schemas/outputs/utilityOutputs.ts +2 -43
  73. package/src/tools/toolCategories.ts +0 -1
  74. package/src/tools/transactionTools.ts +140 -0
  75. package/src/tools/utilityTools.ts +24 -55
  76. package/src/types/index.ts +3 -0
  77. package/src/types/toolRegistration.ts +88 -0
  78. package/vitest.config.ts +2 -1
  79. package/.chunkhound.json +0 -11
  80. package/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +0 -3
  81. package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +0 -3
  82. package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +0 -1
  83. package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +0 -5
  84. package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +0 -1569
  85. package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +0 -3
  86. package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +0 -2832
  87. package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +0 -2709
  88. package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +0 -2832
  89. package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +0 -2832
  90. package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +0 -2709
  91. package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +0 -1
  92. package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +0 -5217
  93. package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +0 -2594
  94. package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +0 -2594
  95. package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +0 -231
  96. package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +0 -2590
  97. package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +0 -5195
  98. package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +0 -286
  99. package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +0 -218
  100. package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +0 -180
  101. package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +0 -3
  102. package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +0 -1
  103. package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +0 -747
  104. package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +0 -1
  105. package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +0 -2594
  106. package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +0 -2594
  107. package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +0 -144
  108. package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +0 -416
  109. package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +0 -2590
  110. package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +0 -2590
  111. package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +0 -2590
  112. package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +0 -790
  113. package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +0 -766
  114. package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +0 -790
  115. package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +0 -2594
  116. package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +0 -1000
  117. package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +0 -3489
  118. package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +0 -766
  119. package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +0 -2594
  120. package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +0 -2456
  121. package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +0 -2594
  122. package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +0 -18
  123. package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +0 -48
  124. package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +0 -1
  125. package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +0 -1
  126. package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +0 -1
  127. package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +0 -1
  128. package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +0 -1271
  129. package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +0 -1570
  130. package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +0 -2590
  131. package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +0 -3
  132. package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +0 -3299
  133. package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +0 -3299
  134. package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +0 -1882
  135. package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +0 -2594
  136. package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +0 -1
  137. package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +0 -170
  138. package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +0 -1
  139. package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +0 -3
  140. package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +0 -1
  141. package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +0 -1
  142. package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +0 -3
  143. package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +0 -1
  144. package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +0 -1
  145. package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +0 -5
  146. package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +0 -1
  147. package/.github/workflows/pr-description-check.yml +0 -88
  148. package/AGENTS.md +0 -36
  149. package/NUL +0 -1
  150. package/docs/README.md +0 -72
  151. package/docs/getting-started/CONFIGURATION.md +0 -175
  152. package/docs/getting-started/INSTALLATION.md +0 -333
  153. package/docs/getting-started/QUICKSTART.md +0 -282
  154. package/docs/guides/ARCHITECTURE.md +0 -533
  155. package/docs/guides/DEPLOYMENT.md +0 -189
  156. package/docs/guides/INTEGRATION_TESTING.md +0 -730
  157. package/docs/guides/TESTING.md +0 -591
  158. package/docs/reconciliation-flow.md +0 -83
  159. package/docs/reference/EXAMPLES.md +0 -946
  160. package/docs/reference/TOOLS.md +0 -348
  161. package/docs/reference/TROUBLESHOOTING.md +0 -481
  162. package/package.json.tmp +0 -105
  163. package/temp-recon.ts +0 -126
  164. package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +0 -23
  165. package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +0 -23
  166. package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +0 -44
  167. package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +0 -58
  168. package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +0 -3662
  169. package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +0 -115
@@ -11,19 +11,18 @@ import { loadConfig } from './config.js';
11
11
  import { createErrorHandler, ErrorHandler } from './errorHandler.js';
12
12
  import { BudgetResolver } from './budgetResolver.js';
13
13
  import { SecurityMiddleware, withSecurityWrapper } from './securityMiddleware.js';
14
- import { handleListBudgets, handleGetBudget, GetBudgetSchema } from '../tools/budgetTools.js';
15
- import { handleListAccounts, handleGetAccount, handleCreateAccount, ListAccountsSchema, GetAccountSchema, CreateAccountSchema, } from '../tools/accountTools.js';
16
- import { handleListTransactions, handleGetTransaction, handleCreateTransaction, handleCreateTransactions, handleCreateReceiptSplitTransaction, handleUpdateTransaction, handleUpdateTransactions, handleDeleteTransaction, ListTransactionsSchema, GetTransactionSchema, CreateTransactionSchema, CreateTransactionsSchema, CreateReceiptSplitTransactionSchema, UpdateTransactionSchema, UpdateTransactionsSchema, DeleteTransactionSchema, } from '../tools/transactionTools.js';
17
- import { handleExportTransactions, ExportTransactionsSchema } from '../tools/exportTransactions.js';
18
- import { handleCompareTransactions, CompareTransactionsSchema, } from '../tools/compareTransactions/index.js';
19
- import { handleReconcileAccount, ReconcileAccountSchema } from '../tools/reconciliation/index.js';
20
- import { handleListCategories, handleGetCategory, handleUpdateCategory, ListCategoriesSchema, GetCategorySchema, UpdateCategorySchema, } from '../tools/categoryTools.js';
21
- import { handleListPayees, handleGetPayee, ListPayeesSchema, GetPayeeSchema, } from '../tools/payeeTools.js';
22
- import { handleGetMonth, handleListMonths, GetMonthSchema, ListMonthsSchema, } from '../tools/monthTools.js';
23
- import { handleGetUser, handleConvertAmount, ConvertAmountSchema } from '../tools/utilityTools.js';
14
+ import { registerBudgetTools } from '../tools/budgetTools.js';
15
+ import { registerAccountTools } from '../tools/accountTools.js';
16
+ import { registerTransactionTools } from '../tools/transactionTools.js';
17
+ import { registerReconciliationTools } from '../tools/reconciliation/index.js';
18
+ import { registerCategoryTools } from '../tools/categoryTools.js';
19
+ import { registerPayeeTools } from '../tools/payeeTools.js';
20
+ import { registerMonthTools } from '../tools/monthTools.js';
21
+ import { registerUtilityTools } from '../tools/utilityTools.js';
22
+ import { emptyObjectSchema } from '../tools/schemas/common.js';
24
23
  import { cacheManager, CacheManager } from './cacheManager.js';
25
24
  import { responseFormatter } from './responseFormatter.js';
26
- import { ToolRegistry, DefaultArgumentResolutionError, } from './toolRegistry.js';
25
+ import { ToolRegistry } from './toolRegistry.js';
27
26
  import { ResourceManager } from './resources.js';
28
27
  import { PromptManager } from './prompts.js';
29
28
  import { DiagnosticManager } from './diagnostics.js';
@@ -31,12 +30,11 @@ import { ServerKnowledgeStore } from './serverKnowledgeStore.js';
31
30
  import { DeltaCache } from './deltaCache.js';
32
31
  import { DeltaFetcher } from '../tools/deltaFetcher.js';
33
32
  import { ToolAnnotationPresets } from '../tools/toolCategories.js';
34
- import { GetUserOutputSchema, ConvertAmountOutputSchema, GetDefaultBudgetOutputSchema, SetDefaultBudgetOutputSchema, ClearCacheOutputSchema, SetOutputFormatOutputSchema, DiagnosticInfoOutputSchema, GetBudgetOutputSchema, ListBudgetsOutputSchema, ListAccountsOutputSchema, GetAccountOutputSchema, GetTransactionOutputSchema, ExportTransactionsOutputSchema, CompareTransactionsOutputSchema, ListCategoriesOutputSchema, GetCategoryOutputSchema, ListPayeesOutputSchema, GetPayeeOutputSchema, GetMonthOutputSchema, ListMonthsOutputSchema, } from '../tools/schemas/outputs/index.js';
35
33
  export class YNABMCPServer {
36
34
  constructor(exitOnError = true) {
37
35
  this.exitOnError = exitOnError;
38
36
  this.configInstance = loadConfig();
39
- this.defaultBudgetId = process.env['YNAB_DEFAULT_BUDGET_ID'];
37
+ this.defaultBudgetId = this.configInstance.YNAB_DEFAULT_BUDGET_ID;
40
38
  this.ynabAPI = new ynab.API(this.configInstance.YNAB_ACCESS_TOKEN);
41
39
  this.serverVersion = this.readPackageVersion() ?? '0.0.0';
42
40
  this.server = new Server({
@@ -211,23 +209,16 @@ export class YNABMCPServer {
211
209
  const register = (definition) => {
212
210
  this.toolRegistry.register(definition);
213
211
  };
214
- const adapt = (handler) => async ({ input }) => handler(this.ynabAPI, input);
215
- const adaptNoInput = (handler) => async (_payload) => handler(this.ynabAPI);
216
- const adaptWithDelta = (handler) => async ({ input }) => handler(this.ynabAPI, this.deltaFetcher, input);
217
- const adaptWrite = (handler) => async ({ input }) => handler(this.ynabAPI, this.deltaCache, this.serverKnowledgeStore, input);
218
- const resolveBudgetId = () => {
219
- return ({ rawArguments }) => {
220
- const provided = typeof rawArguments['budget_id'] === 'string' && rawArguments['budget_id'].length > 0
221
- ? rawArguments['budget_id']
222
- : undefined;
223
- const result = BudgetResolver.resolveBudgetId(provided, this.defaultBudgetId);
224
- if (typeof result === 'string') {
225
- return { budget_id: result };
226
- }
227
- throw new DefaultArgumentResolutionError(result);
228
- };
212
+ const toolContext = {
213
+ ynabAPI: this.ynabAPI,
214
+ deltaFetcher: this.deltaFetcher,
215
+ deltaCache: this.deltaCache,
216
+ serverKnowledgeStore: this.serverKnowledgeStore,
217
+ getDefaultBudgetId: () => this.defaultBudgetId,
218
+ setDefaultBudget: (budgetId) => this.setDefaultBudget(budgetId),
219
+ cacheManager,
220
+ diagnosticManager: this.diagnosticManager,
229
221
  };
230
- const emptyObjectSchema = z.object({}).strict();
231
222
  const setDefaultBudgetSchema = z.object({ budget_id: z.string().min(1) }).strict();
232
223
  const diagnosticInfoSchema = z
233
224
  .object({
@@ -245,38 +236,18 @@ export class YNABMCPServer {
245
236
  pretty_spaces: z.number().int().min(0).max(10).optional(),
246
237
  })
247
238
  .strict();
248
- const LooseObjectSchema = z.object({}).passthrough();
249
- register({
250
- name: 'list_budgets',
251
- description: "List all budgets associated with the user's account",
252
- inputSchema: emptyObjectSchema,
253
- outputSchema: ListBudgetsOutputSchema,
254
- handler: adaptWithDelta(handleListBudgets),
255
- metadata: {
256
- annotations: {
257
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
258
- title: 'YNAB: List Budgets',
259
- },
260
- },
261
- });
262
- register({
263
- name: 'get_budget',
264
- description: 'Get detailed information for a specific budget',
265
- inputSchema: GetBudgetSchema,
266
- outputSchema: GetBudgetOutputSchema,
267
- handler: adapt(handleGetBudget),
268
- metadata: {
269
- annotations: {
270
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
271
- title: 'YNAB: Get Budget Details',
272
- },
273
- },
274
- });
239
+ registerBudgetTools(this.toolRegistry, toolContext);
240
+ registerPayeeTools(this.toolRegistry, toolContext);
241
+ registerCategoryTools(this.toolRegistry, toolContext);
242
+ registerAccountTools(this.toolRegistry, toolContext);
243
+ registerMonthTools(this.toolRegistry, toolContext);
244
+ registerTransactionTools(this.toolRegistry, toolContext);
245
+ registerReconciliationTools(this.toolRegistry, toolContext);
246
+ registerUtilityTools(this.toolRegistry, toolContext);
275
247
  register({
276
248
  name: 'set_default_budget',
277
249
  description: 'Set the default budget for subsequent operations',
278
250
  inputSchema: setDefaultBudgetSchema,
279
- outputSchema: SetDefaultBudgetOutputSchema,
280
251
  handler: async ({ input }) => {
281
252
  const { budget_id } = input;
282
253
  await this.ynabAPI.budgets.getBudgetById(budget_id);
@@ -308,7 +279,6 @@ export class YNABMCPServer {
308
279
  name: 'get_default_budget',
309
280
  description: 'Get the currently set default budget',
310
281
  inputSchema: emptyObjectSchema,
311
- outputSchema: GetDefaultBudgetOutputSchema,
312
282
  handler: async () => {
313
283
  try {
314
284
  const defaultBudget = this.getDefaultBudget();
@@ -338,331 +308,10 @@ export class YNABMCPServer {
338
308
  },
339
309
  },
340
310
  });
341
- register({
342
- name: 'list_accounts',
343
- description: 'List all accounts for a specific budget (uses default budget if not specified)',
344
- inputSchema: ListAccountsSchema,
345
- outputSchema: ListAccountsOutputSchema,
346
- handler: adaptWithDelta(handleListAccounts),
347
- defaultArgumentResolver: resolveBudgetId(),
348
- metadata: {
349
- annotations: {
350
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
351
- title: 'YNAB: List Accounts',
352
- },
353
- },
354
- });
355
- register({
356
- name: 'get_account',
357
- description: 'Get detailed information for a specific account',
358
- inputSchema: GetAccountSchema,
359
- outputSchema: GetAccountOutputSchema,
360
- handler: adapt(handleGetAccount),
361
- defaultArgumentResolver: resolveBudgetId(),
362
- metadata: {
363
- annotations: {
364
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
365
- title: 'YNAB: Get Account Details',
366
- },
367
- },
368
- });
369
- register({
370
- name: 'create_account',
371
- description: 'Create a new account in the specified budget',
372
- inputSchema: CreateAccountSchema,
373
- outputSchema: LooseObjectSchema,
374
- handler: adaptWrite(handleCreateAccount),
375
- defaultArgumentResolver: resolveBudgetId(),
376
- metadata: {
377
- annotations: {
378
- ...ToolAnnotationPresets.WRITE_EXTERNAL_CREATE,
379
- title: 'YNAB: Create Account',
380
- },
381
- },
382
- });
383
- register({
384
- name: 'list_transactions',
385
- description: 'List transactions for a budget with optional filtering',
386
- inputSchema: ListTransactionsSchema,
387
- outputSchema: LooseObjectSchema,
388
- handler: adaptWithDelta(handleListTransactions),
389
- defaultArgumentResolver: resolveBudgetId(),
390
- metadata: {
391
- annotations: {
392
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
393
- title: 'YNAB: List Transactions',
394
- },
395
- },
396
- });
397
- register({
398
- name: 'export_transactions',
399
- description: 'Export all transactions to a JSON file with descriptive filename',
400
- inputSchema: ExportTransactionsSchema,
401
- outputSchema: ExportTransactionsOutputSchema,
402
- handler: adapt(handleExportTransactions),
403
- defaultArgumentResolver: resolveBudgetId(),
404
- metadata: {
405
- annotations: {
406
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
407
- title: 'YNAB: Export Transactions',
408
- },
409
- },
410
- });
411
- register({
412
- name: 'compare_transactions',
413
- description: 'Compare bank transactions from CSV with YNAB transactions to find missing entries',
414
- inputSchema: CompareTransactionsSchema,
415
- outputSchema: CompareTransactionsOutputSchema,
416
- handler: adapt(handleCompareTransactions),
417
- defaultArgumentResolver: resolveBudgetId(),
418
- metadata: {
419
- annotations: {
420
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
421
- title: 'YNAB: Compare Transactions',
422
- },
423
- },
424
- });
425
- register({
426
- name: 'reconcile_account',
427
- description: 'Guided reconciliation workflow with human narrative, insight detection, and optional execution (create/update/unclear). Set include_structured_data=true to also get full JSON output (large).',
428
- inputSchema: ReconcileAccountSchema,
429
- outputSchema: LooseObjectSchema,
430
- handler: adaptWithDelta(handleReconcileAccount),
431
- defaultArgumentResolver: resolveBudgetId(),
432
- metadata: {
433
- annotations: {
434
- ...ToolAnnotationPresets.WRITE_EXTERNAL_UPDATE,
435
- title: 'YNAB: Reconcile Account',
436
- },
437
- },
438
- });
439
- register({
440
- name: 'get_transaction',
441
- description: 'Get detailed information for a specific transaction',
442
- inputSchema: GetTransactionSchema,
443
- outputSchema: GetTransactionOutputSchema,
444
- handler: adapt(handleGetTransaction),
445
- defaultArgumentResolver: resolveBudgetId(),
446
- metadata: {
447
- annotations: {
448
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
449
- title: 'YNAB: Get Transaction Details',
450
- },
451
- },
452
- });
453
- register({
454
- name: 'create_transaction',
455
- description: 'Create a new transaction in the specified budget and account',
456
- inputSchema: CreateTransactionSchema,
457
- outputSchema: LooseObjectSchema,
458
- handler: adaptWrite(handleCreateTransaction),
459
- defaultArgumentResolver: resolveBudgetId(),
460
- metadata: {
461
- annotations: {
462
- ...ToolAnnotationPresets.WRITE_EXTERNAL_CREATE,
463
- title: 'YNAB: Create Transaction',
464
- },
465
- },
466
- });
467
- register({
468
- name: 'create_transactions',
469
- description: 'Create multiple transactions in a single batch (1-100 items) with duplicate detection, dry-run validation, and automatic response size management with correlation metadata.',
470
- inputSchema: CreateTransactionsSchema,
471
- outputSchema: LooseObjectSchema,
472
- handler: adaptWrite(handleCreateTransactions),
473
- defaultArgumentResolver: resolveBudgetId(),
474
- metadata: {
475
- annotations: {
476
- ...ToolAnnotationPresets.WRITE_EXTERNAL_CREATE,
477
- title: 'YNAB: Create Multiple Transactions',
478
- },
479
- },
480
- });
481
- register({
482
- name: 'update_transactions',
483
- description: 'Update multiple transactions in a single batch (1-100 items) with dry-run validation, automatic cache invalidation, and response size management. Supports optional original_account_id and original_date metadata for efficient cache invalidation.',
484
- inputSchema: UpdateTransactionsSchema,
485
- outputSchema: LooseObjectSchema,
486
- handler: adaptWrite(handleUpdateTransactions),
487
- defaultArgumentResolver: resolveBudgetId(),
488
- metadata: {
489
- annotations: {
490
- ...ToolAnnotationPresets.WRITE_EXTERNAL_UPDATE,
491
- title: 'YNAB: Update Multiple Transactions',
492
- },
493
- },
494
- });
495
- register({
496
- name: 'create_receipt_split_transaction',
497
- description: 'Create a split transaction from receipt items with proportional tax allocation',
498
- inputSchema: CreateReceiptSplitTransactionSchema,
499
- outputSchema: LooseObjectSchema,
500
- handler: adaptWrite(handleCreateReceiptSplitTransaction),
501
- defaultArgumentResolver: resolveBudgetId(),
502
- metadata: {
503
- annotations: {
504
- ...ToolAnnotationPresets.WRITE_EXTERNAL_CREATE,
505
- title: 'YNAB: Create Split Transaction from Receipt',
506
- },
507
- },
508
- });
509
- register({
510
- name: 'update_transaction',
511
- description: 'Update an existing transaction',
512
- inputSchema: UpdateTransactionSchema,
513
- outputSchema: LooseObjectSchema,
514
- handler: adaptWrite(handleUpdateTransaction),
515
- defaultArgumentResolver: resolveBudgetId(),
516
- metadata: {
517
- annotations: {
518
- ...ToolAnnotationPresets.WRITE_EXTERNAL_UPDATE,
519
- title: 'YNAB: Update Transaction',
520
- },
521
- },
522
- });
523
- register({
524
- name: 'delete_transaction',
525
- description: 'Delete a transaction from the specified budget',
526
- inputSchema: DeleteTransactionSchema,
527
- outputSchema: LooseObjectSchema,
528
- handler: adaptWrite(handleDeleteTransaction),
529
- defaultArgumentResolver: resolveBudgetId(),
530
- metadata: {
531
- annotations: {
532
- ...ToolAnnotationPresets.WRITE_EXTERNAL_DELETE,
533
- title: 'YNAB: Delete Transaction',
534
- },
535
- },
536
- });
537
- register({
538
- name: 'list_categories',
539
- description: 'List all categories for a specific budget',
540
- inputSchema: ListCategoriesSchema,
541
- outputSchema: ListCategoriesOutputSchema,
542
- handler: adaptWithDelta(handleListCategories),
543
- defaultArgumentResolver: resolveBudgetId(),
544
- metadata: {
545
- annotations: {
546
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
547
- title: 'YNAB: List Categories',
548
- },
549
- },
550
- });
551
- register({
552
- name: 'get_category',
553
- description: 'Get detailed information for a specific category',
554
- inputSchema: GetCategorySchema,
555
- outputSchema: GetCategoryOutputSchema,
556
- handler: adapt(handleGetCategory),
557
- defaultArgumentResolver: resolveBudgetId(),
558
- metadata: {
559
- annotations: {
560
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
561
- title: 'YNAB: Get Category Details',
562
- },
563
- },
564
- });
565
- register({
566
- name: 'update_category',
567
- description: 'Update the budgeted amount for a category in the current month',
568
- inputSchema: UpdateCategorySchema,
569
- outputSchema: LooseObjectSchema,
570
- handler: adaptWrite(handleUpdateCategory),
571
- defaultArgumentResolver: resolveBudgetId(),
572
- metadata: {
573
- annotations: {
574
- ...ToolAnnotationPresets.WRITE_EXTERNAL_UPDATE,
575
- title: 'YNAB: Update Category Budget',
576
- },
577
- },
578
- });
579
- register({
580
- name: 'list_payees',
581
- description: 'List all payees for a specific budget',
582
- inputSchema: ListPayeesSchema,
583
- outputSchema: ListPayeesOutputSchema,
584
- handler: adaptWithDelta(handleListPayees),
585
- defaultArgumentResolver: resolveBudgetId(),
586
- metadata: {
587
- annotations: {
588
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
589
- title: 'YNAB: List Payees',
590
- },
591
- },
592
- });
593
- register({
594
- name: 'get_payee',
595
- description: 'Get detailed information for a specific payee',
596
- inputSchema: GetPayeeSchema,
597
- outputSchema: GetPayeeOutputSchema,
598
- handler: adapt(handleGetPayee),
599
- defaultArgumentResolver: resolveBudgetId(),
600
- metadata: {
601
- annotations: {
602
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
603
- title: 'YNAB: Get Payee Details',
604
- },
605
- },
606
- });
607
- register({
608
- name: 'get_month',
609
- description: 'Get budget data for a specific month',
610
- inputSchema: GetMonthSchema,
611
- outputSchema: GetMonthOutputSchema,
612
- handler: adapt(handleGetMonth),
613
- defaultArgumentResolver: resolveBudgetId(),
614
- metadata: {
615
- annotations: {
616
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
617
- title: 'YNAB: Get Month Budget Data',
618
- },
619
- },
620
- });
621
- register({
622
- name: 'list_months',
623
- description: 'List all months summary data for a budget',
624
- inputSchema: ListMonthsSchema,
625
- outputSchema: ListMonthsOutputSchema,
626
- handler: adaptWithDelta(handleListMonths),
627
- defaultArgumentResolver: resolveBudgetId(),
628
- metadata: {
629
- annotations: {
630
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
631
- title: 'YNAB: List Months',
632
- },
633
- },
634
- });
635
- register({
636
- name: 'get_user',
637
- description: 'Get information about the authenticated user',
638
- inputSchema: emptyObjectSchema,
639
- outputSchema: GetUserOutputSchema,
640
- handler: adaptNoInput(handleGetUser),
641
- metadata: {
642
- annotations: {
643
- ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
644
- title: 'YNAB: Get User Information',
645
- },
646
- },
647
- });
648
- register({
649
- name: 'convert_amount',
650
- description: 'Convert between dollars and milliunits with integer arithmetic for precision',
651
- inputSchema: ConvertAmountSchema,
652
- outputSchema: ConvertAmountOutputSchema,
653
- handler: async ({ input }) => handleConvertAmount(input),
654
- metadata: {
655
- annotations: {
656
- ...ToolAnnotationPresets.UTILITY_LOCAL,
657
- title: 'YNAB: Convert Amount',
658
- },
659
- },
660
- });
661
311
  register({
662
312
  name: 'diagnostic_info',
663
313
  description: 'Get comprehensive diagnostic information about the MCP server',
664
314
  inputSchema: diagnosticInfoSchema,
665
- outputSchema: DiagnosticInfoOutputSchema,
666
315
  handler: async ({ input }) => {
667
316
  return this.diagnosticManager.collectDiagnostics(input);
668
317
  },
@@ -677,7 +326,6 @@ export class YNABMCPServer {
677
326
  name: 'clear_cache',
678
327
  description: 'Clear the in-memory cache (safe, no YNAB data is modified)',
679
328
  inputSchema: emptyObjectSchema,
680
- outputSchema: ClearCacheOutputSchema,
681
329
  handler: async () => {
682
330
  cacheManager.clear();
683
331
  return {
@@ -695,7 +343,6 @@ export class YNABMCPServer {
695
343
  name: 'set_output_format',
696
344
  description: 'Configure default JSON output formatting (minify or pretty spaces)',
697
345
  inputSchema: setOutputFormatSchema,
698
- outputSchema: SetOutputFormatOutputSchema,
699
346
  handler: async ({ input }) => {
700
347
  const options = {};
701
348
  if (typeof input.default_minify === 'boolean') {
@@ -2,6 +2,7 @@ import 'dotenv/config';
2
2
  import { z } from 'zod';
3
3
  declare const envSchema: z.ZodObject<{
4
4
  YNAB_ACCESS_TOKEN: z.ZodString;
5
+ YNAB_DEFAULT_BUDGET_ID: z.ZodOptional<z.ZodString>;
5
6
  MCP_PORT: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
6
7
  LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
7
8
  error: "error";
@@ -17,6 +18,7 @@ export declare function loadConfig(env?: NodeJS.ProcessEnv): AppConfig;
17
18
  export declare const config: {
18
19
  YNAB_ACCESS_TOKEN: string;
19
20
  LOG_LEVEL: "error" | "warn" | "info" | "debug" | "trace" | "fatal";
21
+ YNAB_DEFAULT_BUDGET_ID?: string | undefined;
20
22
  MCP_PORT?: number | undefined;
21
23
  };
22
24
  export {};
@@ -4,6 +4,7 @@ import { fromZodError } from 'zod-validation-error';
4
4
  import { ValidationError } from '../utils/errors.js';
5
5
  const envSchema = z.object({
6
6
  YNAB_ACCESS_TOKEN: z.string().trim().min(1, 'YNAB_ACCESS_TOKEN must be a non-empty string'),
7
+ YNAB_DEFAULT_BUDGET_ID: z.string().uuid('YNAB_DEFAULT_BUDGET_ID must be a valid UUID').optional(),
7
8
  MCP_PORT: z.coerce.number().int().positive().optional(),
8
9
  LOG_LEVEL: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'),
9
10
  });
@@ -24,6 +24,11 @@ export declare function withSecurityWrapper<T extends Record<string, unknown>>(t
24
24
  content: ({
25
25
  type: "text";
26
26
  text: string;
27
+ annotations?: {
28
+ audience?: ("user" | "assistant")[] | undefined;
29
+ priority?: number | undefined;
30
+ lastModified?: string | undefined;
31
+ } | undefined;
27
32
  _meta?: {
28
33
  [x: string]: unknown;
29
34
  } | undefined;
@@ -31,6 +36,11 @@ export declare function withSecurityWrapper<T extends Record<string, unknown>>(t
31
36
  type: "image";
32
37
  data: string;
33
38
  mimeType: string;
39
+ annotations?: {
40
+ audience?: ("user" | "assistant")[] | undefined;
41
+ priority?: number | undefined;
42
+ lastModified?: string | undefined;
43
+ } | undefined;
34
44
  _meta?: {
35
45
  [x: string]: unknown;
36
46
  } | undefined;
@@ -38,47 +48,66 @@ export declare function withSecurityWrapper<T extends Record<string, unknown>>(t
38
48
  type: "audio";
39
49
  data: string;
40
50
  mimeType: string;
51
+ annotations?: {
52
+ audience?: ("user" | "assistant")[] | undefined;
53
+ priority?: number | undefined;
54
+ lastModified?: string | undefined;
55
+ } | undefined;
41
56
  _meta?: {
42
57
  [x: string]: unknown;
43
58
  } | undefined;
44
59
  } | {
45
- type: "resource_link";
46
- name: string;
47
60
  uri: string;
61
+ name: string;
62
+ type: "resource_link";
63
+ description?: string | undefined;
64
+ mimeType?: string | undefined;
65
+ annotations?: {
66
+ audience?: ("user" | "assistant")[] | undefined;
67
+ priority?: number | undefined;
68
+ lastModified?: string | undefined;
69
+ } | undefined;
48
70
  _meta?: {
49
71
  [x: string]: unknown;
50
72
  } | undefined;
51
- mimeType?: string | undefined | undefined;
52
73
  icons?: {
53
74
  src: string;
54
- mimeType?: string | undefined | undefined;
75
+ mimeType?: string | undefined;
55
76
  sizes?: string[] | undefined;
56
77
  }[] | undefined;
57
- title?: string | undefined | undefined;
58
- description?: string | undefined | undefined;
78
+ title?: string | undefined;
59
79
  } | {
60
80
  type: "resource";
61
81
  resource: {
62
82
  uri: string;
63
83
  text: string;
84
+ mimeType?: string | undefined;
64
85
  _meta?: {
65
86
  [x: string]: unknown;
66
87
  } | undefined;
67
- mimeType?: string | undefined | undefined;
68
88
  } | {
69
89
  uri: string;
70
90
  blob: string;
91
+ mimeType?: string | undefined;
71
92
  _meta?: {
72
93
  [x: string]: unknown;
73
94
  } | undefined;
74
- mimeType?: string | undefined | undefined;
75
95
  };
96
+ annotations?: {
97
+ audience?: ("user" | "assistant")[] | undefined;
98
+ priority?: number | undefined;
99
+ lastModified?: string | undefined;
100
+ } | undefined;
76
101
  _meta?: {
77
102
  [x: string]: unknown;
78
103
  } | undefined;
79
104
  })[];
80
105
  _meta?: {
81
106
  [x: string]: unknown;
107
+ "io.modelcontextprotocol/related-task"?: {
108
+ [x: string]: unknown;
109
+ taskId: string;
110
+ } | undefined;
82
111
  } | undefined;
83
112
  structuredContent?: {
84
113
  [x: string]: unknown;
@@ -4,6 +4,7 @@ import { z } from 'zod/v4';
4
4
  import type { DeltaFetcher } from './deltaFetcher.js';
5
5
  import type { DeltaCache } from '../server/deltaCache.js';
6
6
  import type { ServerKnowledgeStore } from '../server/serverKnowledgeStore.js';
7
+ import type { ToolFactory } from '../types/toolRegistration.js';
7
8
  export declare const ListAccountsSchema: z.ZodObject<{
8
9
  budget_id: z.ZodString;
9
10
  limit: z.ZodOptional<z.ZodNumber>;
@@ -35,3 +36,4 @@ export declare function handleListAccounts(ynabAPI: ynab.API, params: ListAccoun
35
36
  export declare function handleGetAccount(ynabAPI: ynab.API, params: GetAccountParams): Promise<CallToolResult>;
36
37
  export declare function handleCreateAccount(ynabAPI: ynab.API, deltaCache: DeltaCache, knowledgeStore: ServerKnowledgeStore, params: CreateAccountParams): Promise<CallToolResult>;
37
38
  export declare function handleCreateAccount(ynabAPI: ynab.API, params: CreateAccountParams): Promise<CallToolResult>;
39
+ export declare const registerAccountTools: ToolFactory;
@@ -5,6 +5,8 @@ import { milliunitsToAmount } from '../utils/amountUtils.js';
5
5
  import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
6
6
  import { CacheKeys } from '../server/cacheKeys.js';
7
7
  import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from './deltaSupport.js';
8
+ import { createAdapters, createBudgetResolver } from './adapters.js';
9
+ import { ToolAnnotationPresets } from './toolCategories.js';
8
10
  export const ListAccountsSchema = z
9
11
  .object({
10
12
  budget_id: z.string().min(1, 'Budget ID is required'),
@@ -174,3 +176,46 @@ export async function handleCreateAccount(ynabAPI, deltaCacheOrParams, knowledge
174
176
  };
175
177
  }, 'ynab:create_account', 'creating account');
176
178
  }
179
+ export const registerAccountTools = (registry, context) => {
180
+ const { adapt, adaptWithDelta, adaptWrite } = createAdapters(context);
181
+ const budgetResolver = createBudgetResolver(context);
182
+ registry.register({
183
+ name: 'list_accounts',
184
+ description: 'List all accounts for a specific budget',
185
+ inputSchema: ListAccountsSchema,
186
+ handler: adaptWithDelta(handleListAccounts),
187
+ defaultArgumentResolver: budgetResolver(),
188
+ metadata: {
189
+ annotations: {
190
+ ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
191
+ title: 'YNAB: List Accounts',
192
+ },
193
+ },
194
+ });
195
+ registry.register({
196
+ name: 'get_account',
197
+ description: 'Get detailed information for a specific account',
198
+ inputSchema: GetAccountSchema,
199
+ handler: adapt(handleGetAccount),
200
+ defaultArgumentResolver: budgetResolver(),
201
+ metadata: {
202
+ annotations: {
203
+ ...ToolAnnotationPresets.READ_ONLY_EXTERNAL,
204
+ title: 'YNAB: Get Account Details',
205
+ },
206
+ },
207
+ });
208
+ registry.register({
209
+ name: 'create_account',
210
+ description: 'Create a new account in the specified budget',
211
+ inputSchema: CreateAccountSchema,
212
+ handler: adaptWrite(handleCreateAccount),
213
+ defaultArgumentResolver: budgetResolver(),
214
+ metadata: {
215
+ annotations: {
216
+ ...ToolAnnotationPresets.WRITE_EXTERNAL_CREATE,
217
+ title: 'YNAB: Create Account',
218
+ },
219
+ },
220
+ });
221
+ };