@dizzlkheinz/ynab-mcpb 0.12.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 (435) hide show
  1. package/.chunkhound.json +11 -0
  2. package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +8 -0
  3. package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +3 -0
  4. package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +3 -0
  5. package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +1 -0
  6. package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +12 -0
  7. package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +1 -0
  8. package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +1 -0
  9. package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +5 -0
  10. package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +1453 -0
  11. package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +8 -0
  12. package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +9 -0
  13. package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +1 -0
  14. package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +5 -0
  15. package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +81 -0
  16. package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +610 -0
  17. package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +1 -0
  18. package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +1 -0
  19. package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +1 -0
  20. package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +3 -0
  21. package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +8 -0
  22. package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +5 -0
  23. package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +1 -0
  24. package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +9 -0
  25. package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +1 -0
  26. package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +13 -0
  27. package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +14 -0
  28. package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +5 -0
  29. package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +5 -0
  30. package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +5 -0
  31. package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +3 -0
  32. package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +1 -0
  33. package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +1 -0
  34. package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +5 -0
  35. package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +5 -0
  36. package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +8 -0
  37. package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +8 -0
  38. package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +5 -0
  39. package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +1 -0
  40. package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +1 -0
  41. package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +1 -0
  42. package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +1 -0
  43. package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +1 -0
  44. package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +5 -0
  45. package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +1 -0
  46. package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +1 -0
  47. package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +1 -0
  48. package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +3 -0
  49. package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +8 -0
  50. package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +1 -0
  51. package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +1 -0
  52. package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +8 -0
  53. package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +3 -0
  54. package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +5 -0
  55. package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +1 -0
  56. package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +1 -0
  57. package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +5 -0
  58. package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +1 -0
  59. package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +14 -0
  60. package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +1 -0
  61. package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +5 -0
  62. package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +5 -0
  63. package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +11 -0
  64. package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +1 -0
  65. package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +8 -0
  66. package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +1 -0
  67. package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +3 -0
  68. package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +3 -0
  69. package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +8 -0
  70. package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +1 -0
  71. package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +5 -0
  72. package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +1 -0
  73. package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +1 -0
  74. package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +1 -0
  75. package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +1 -0
  76. package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +3 -0
  77. package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +8 -0
  78. package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +1 -0
  79. package/.dxtignore +57 -0
  80. package/.env.example +44 -0
  81. package/.gemini/settings.json +8 -0
  82. package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  83. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  84. package/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  85. package/.github/ISSUE_TEMPLATE/release_checklist.md +31 -0
  86. package/.github/pull_request_template.md +41 -0
  87. package/.github/workflows/ci-tests.yml +41 -0
  88. package/.github/workflows/claude-code-review.yml +57 -0
  89. package/.github/workflows/claude.yml +50 -0
  90. package/.github/workflows/full-integration.yml +22 -0
  91. package/.github/workflows/pr-description-check.yml +88 -0
  92. package/.github/workflows/publish.yml +33 -0
  93. package/.github/workflows/release.yml +89 -0
  94. package/.mcpbignore +58 -0
  95. package/.prettierignore +10 -0
  96. package/.prettierrc.json +10 -0
  97. package/ADOS-2-Module-1-Complete-Manual.md +757 -0
  98. package/AGENTS.md +36 -0
  99. package/CHANGELOG.md +187 -0
  100. package/CLAUDE.md +414 -0
  101. package/CODEREVIEW_RESPONSE.md +128 -0
  102. package/LICENSE +17 -0
  103. package/NUL +1 -0
  104. package/README.md +222 -0
  105. package/SCHEMA_IMPROVEMENT_SUMMARY.md +120 -0
  106. package/TESTING_NOTES.md +217 -0
  107. package/WARP.md +245 -0
  108. package/accountactivity-merged.csv +149 -0
  109. package/bin/ynab-mcp-server.cjs +4 -0
  110. package/bin/ynab-mcp-server.js +8 -0
  111. package/bundle-analysis.html +13110 -0
  112. package/dist/bundle/index.cjs +124 -0
  113. package/dist/index.d.ts +2 -0
  114. package/dist/index.js +85 -0
  115. package/dist/server/YNABMCPServer.d.ts +264 -0
  116. package/dist/server/YNABMCPServer.js +845 -0
  117. package/dist/server/budgetResolver.d.ts +15 -0
  118. package/dist/server/budgetResolver.js +99 -0
  119. package/dist/server/cacheManager.d.ts +74 -0
  120. package/dist/server/cacheManager.js +306 -0
  121. package/dist/server/config.d.ts +3 -0
  122. package/dist/server/config.js +19 -0
  123. package/dist/server/deltaCache.d.ts +61 -0
  124. package/dist/server/deltaCache.js +206 -0
  125. package/dist/server/deltaCache.merge.d.ts +9 -0
  126. package/dist/server/deltaCache.merge.js +111 -0
  127. package/dist/server/diagnostics.d.ts +90 -0
  128. package/dist/server/diagnostics.js +163 -0
  129. package/dist/server/errorHandler.d.ts +69 -0
  130. package/dist/server/errorHandler.js +524 -0
  131. package/dist/server/prompts.d.ts +31 -0
  132. package/dist/server/prompts.js +205 -0
  133. package/dist/server/rateLimiter.d.ts +27 -0
  134. package/dist/server/rateLimiter.js +82 -0
  135. package/dist/server/requestLogger.d.ts +62 -0
  136. package/dist/server/requestLogger.js +190 -0
  137. package/dist/server/resources.d.ts +39 -0
  138. package/dist/server/resources.js +85 -0
  139. package/dist/server/responseFormatter.d.ts +14 -0
  140. package/dist/server/responseFormatter.js +42 -0
  141. package/dist/server/securityMiddleware.d.ts +87 -0
  142. package/dist/server/securityMiddleware.js +117 -0
  143. package/dist/server/serverKnowledgeStore.d.ts +11 -0
  144. package/dist/server/serverKnowledgeStore.js +42 -0
  145. package/dist/server/toolRegistry.d.ts +85 -0
  146. package/dist/server/toolRegistry.js +272 -0
  147. package/dist/tools/__tests__/deltaTestUtils.d.ts +18 -0
  148. package/dist/tools/__tests__/deltaTestUtils.js +26 -0
  149. package/dist/tools/accountTools.d.ts +37 -0
  150. package/dist/tools/accountTools.js +175 -0
  151. package/dist/tools/budgetTools.d.ts +10 -0
  152. package/dist/tools/budgetTools.js +68 -0
  153. package/dist/tools/categoryTools.d.ts +27 -0
  154. package/dist/tools/categoryTools.js +232 -0
  155. package/dist/tools/compareTransactions/formatter.d.ts +71 -0
  156. package/dist/tools/compareTransactions/formatter.js +97 -0
  157. package/dist/tools/compareTransactions/index.d.ts +30 -0
  158. package/dist/tools/compareTransactions/index.js +160 -0
  159. package/dist/tools/compareTransactions/matcher.d.ts +12 -0
  160. package/dist/tools/compareTransactions/matcher.js +140 -0
  161. package/dist/tools/compareTransactions/parser.d.ts +14 -0
  162. package/dist/tools/compareTransactions/parser.js +430 -0
  163. package/dist/tools/compareTransactions/types.d.ts +27 -0
  164. package/dist/tools/compareTransactions/types.js +1 -0
  165. package/dist/tools/compareTransactions.d.ts +1 -0
  166. package/dist/tools/compareTransactions.js +1 -0
  167. package/dist/tools/deltaFetcher.d.ts +22 -0
  168. package/dist/tools/deltaFetcher.js +137 -0
  169. package/dist/tools/deltaSupport.d.ts +20 -0
  170. package/dist/tools/deltaSupport.js +176 -0
  171. package/dist/tools/exportTransactions.d.ts +17 -0
  172. package/dist/tools/exportTransactions.js +191 -0
  173. package/dist/tools/monthTools.d.ts +16 -0
  174. package/dist/tools/monthTools.js +107 -0
  175. package/dist/tools/payeeTools.d.ts +17 -0
  176. package/dist/tools/payeeTools.js +82 -0
  177. package/dist/tools/reconcileAdapter.d.ts +25 -0
  178. package/dist/tools/reconcileAdapter.js +167 -0
  179. package/dist/tools/reconciliation/analyzer.d.ts +3 -0
  180. package/dist/tools/reconciliation/analyzer.js +567 -0
  181. package/dist/tools/reconciliation/executor.d.ts +94 -0
  182. package/dist/tools/reconciliation/executor.js +611 -0
  183. package/dist/tools/reconciliation/index.d.ts +54 -0
  184. package/dist/tools/reconciliation/index.js +249 -0
  185. package/dist/tools/reconciliation/matcher.d.ts +3 -0
  186. package/dist/tools/reconciliation/matcher.js +160 -0
  187. package/dist/tools/reconciliation/payeeNormalizer.d.ts +6 -0
  188. package/dist/tools/reconciliation/payeeNormalizer.js +77 -0
  189. package/dist/tools/reconciliation/recommendationEngine.d.ts +2 -0
  190. package/dist/tools/reconciliation/recommendationEngine.js +273 -0
  191. package/dist/tools/reconciliation/reportFormatter.d.ts +13 -0
  192. package/dist/tools/reconciliation/reportFormatter.js +214 -0
  193. package/dist/tools/reconciliation/types.d.ts +172 -0
  194. package/dist/tools/reconciliation/types.js +7 -0
  195. package/dist/tools/schemas/outputs/accountOutputs.d.ts +58 -0
  196. package/dist/tools/schemas/outputs/accountOutputs.js +24 -0
  197. package/dist/tools/schemas/outputs/budgetOutputs.d.ts +48 -0
  198. package/dist/tools/schemas/outputs/budgetOutputs.js +15 -0
  199. package/dist/tools/schemas/outputs/categoryOutputs.d.ts +93 -0
  200. package/dist/tools/schemas/outputs/categoryOutputs.js +37 -0
  201. package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +269 -0
  202. package/dist/tools/schemas/outputs/comparisonOutputs.js +181 -0
  203. package/dist/tools/schemas/outputs/index.d.ts +14 -0
  204. package/dist/tools/schemas/outputs/index.js +14 -0
  205. package/dist/tools/schemas/outputs/monthOutputs.d.ts +122 -0
  206. package/dist/tools/schemas/outputs/monthOutputs.js +51 -0
  207. package/dist/tools/schemas/outputs/payeeOutputs.d.ts +34 -0
  208. package/dist/tools/schemas/outputs/payeeOutputs.js +16 -0
  209. package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +1275 -0
  210. package/dist/tools/schemas/outputs/reconciliationOutputs.js +377 -0
  211. package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +717 -0
  212. package/dist/tools/schemas/outputs/transactionMutationOutputs.js +260 -0
  213. package/dist/tools/schemas/outputs/transactionOutputs.d.ts +98 -0
  214. package/dist/tools/schemas/outputs/transactionOutputs.js +49 -0
  215. package/dist/tools/schemas/outputs/utilityOutputs.d.ts +219 -0
  216. package/dist/tools/schemas/outputs/utilityOutputs.js +120 -0
  217. package/dist/tools/schemas/shared/commonOutputs.d.ts +24 -0
  218. package/dist/tools/schemas/shared/commonOutputs.js +27 -0
  219. package/dist/tools/toolCategories.d.ts +32 -0
  220. package/dist/tools/toolCategories.js +32 -0
  221. package/dist/tools/transactionTools.d.ts +315 -0
  222. package/dist/tools/transactionTools.js +1722 -0
  223. package/dist/tools/utilityTools.d.ts +10 -0
  224. package/dist/tools/utilityTools.js +56 -0
  225. package/dist/types/index.d.ts +20 -0
  226. package/dist/types/index.js +16 -0
  227. package/dist/types/toolAnnotations.d.ts +7 -0
  228. package/dist/types/toolAnnotations.js +1 -0
  229. package/dist/utils/amountUtils.d.ts +3 -0
  230. package/dist/utils/amountUtils.js +10 -0
  231. package/dist/utils/dateUtils.d.ts +9 -0
  232. package/dist/utils/dateUtils.js +43 -0
  233. package/dist/utils/money.d.ts +21 -0
  234. package/dist/utils/money.js +51 -0
  235. package/docs/README.md +72 -0
  236. package/docs/assets/examples/reconciliation-with-recommendations.json +68 -0
  237. package/docs/assets/schemas/reconciliation-v2.json +338 -0
  238. package/docs/getting-started/CONFIGURATION.md +175 -0
  239. package/docs/getting-started/INSTALLATION.md +333 -0
  240. package/docs/getting-started/QUICKSTART.md +282 -0
  241. package/docs/guides/ARCHITECTURE.md +650 -0
  242. package/docs/guides/DEPLOYMENT.md +189 -0
  243. package/docs/guides/INTEGRATION_TESTING.md +730 -0
  244. package/docs/guides/TESTING.md +591 -0
  245. package/docs/reconciliation-flow.md +83 -0
  246. package/docs/reference/API.md +1450 -0
  247. package/docs/reference/EXAMPLES.md +946 -0
  248. package/docs/reference/TOOLS.md +348 -0
  249. package/docs/reference/TROUBLESHOOTING.md +481 -0
  250. package/esbuild.config.mjs +68 -0
  251. package/eslint.config.js +49 -0
  252. package/fix-types.sh +17 -0
  253. package/meta.json +12550 -0
  254. package/package.json +105 -0
  255. package/package.json.tmp +105 -0
  256. package/scripts/analyze-bundle.mjs +41 -0
  257. package/scripts/create-pr-description.js +203 -0
  258. package/scripts/generate-mcpb.ps1 +96 -0
  259. package/scripts/run-domain-integration-tests.js +33 -0
  260. package/scripts/run-generate-mcpb.js +29 -0
  261. package/scripts/run-throttled-integration-tests.js +116 -0
  262. package/scripts/test-delta-params.mjs +140 -0
  263. package/scripts/test-recommendations.ts +53 -0
  264. package/scripts/tmpTransaction.ts +48 -0
  265. package/scripts/validate-env.js +122 -0
  266. package/scripts/verify-build.js +105 -0
  267. package/scripts/watch-and-restart.ps1 +50 -0
  268. package/src/__tests__/comprehensive.integration.test.ts +1196 -0
  269. package/src/__tests__/delta.performance.test.ts +80 -0
  270. package/src/__tests__/performance.test.ts +725 -0
  271. package/src/__tests__/setup.ts +449 -0
  272. package/src/__tests__/testRunner.ts +444 -0
  273. package/src/__tests__/testUtils.ts +563 -0
  274. package/src/__tests__/workflows.e2e.test.ts +1675 -0
  275. package/src/index.ts +124 -0
  276. package/src/server/.gitkeep +1 -0
  277. package/src/server/YNABMCPServer.ts +1188 -0
  278. package/src/server/__tests__/YNABMCPServer.integration.test.ts +903 -0
  279. package/src/server/__tests__/YNABMCPServer.test.ts +894 -0
  280. package/src/server/__tests__/budgetResolver.test.ts +425 -0
  281. package/src/server/__tests__/cacheManager.test.ts +880 -0
  282. package/src/server/__tests__/config.test.ts +166 -0
  283. package/src/server/__tests__/deltaCache.merge.test.ts +724 -0
  284. package/src/server/__tests__/deltaCache.swr.test.ts +168 -0
  285. package/src/server/__tests__/deltaCache.test.ts +774 -0
  286. package/src/server/__tests__/diagnostics.test.ts +823 -0
  287. package/src/server/__tests__/errorHandler.integration.test.ts +466 -0
  288. package/src/server/__tests__/errorHandler.test.ts +416 -0
  289. package/src/server/__tests__/prompts.test.ts +354 -0
  290. package/src/server/__tests__/rateLimiter.test.ts +314 -0
  291. package/src/server/__tests__/requestLogger.test.ts +408 -0
  292. package/src/server/__tests__/resources.test.ts +299 -0
  293. package/src/server/__tests__/security.integration.test.ts +426 -0
  294. package/src/server/__tests__/securityMiddleware.test.ts +449 -0
  295. package/src/server/__tests__/server-startup.integration.test.ts +477 -0
  296. package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -0
  297. package/src/server/__tests__/toolRegistry.test.ts +855 -0
  298. package/src/server/budgetResolver.ts +235 -0
  299. package/src/server/cacheManager.ts +503 -0
  300. package/src/server/config.ts +41 -0
  301. package/src/server/deltaCache.merge.ts +149 -0
  302. package/src/server/deltaCache.ts +341 -0
  303. package/src/server/diagnostics.ts +338 -0
  304. package/src/server/errorHandler.ts +756 -0
  305. package/src/server/prompts.ts +291 -0
  306. package/src/server/rateLimiter.ts +156 -0
  307. package/src/server/requestLogger.ts +344 -0
  308. package/src/server/resources.ts +168 -0
  309. package/src/server/responseFormatter.ts +51 -0
  310. package/src/server/securityMiddleware.ts +236 -0
  311. package/src/server/serverKnowledgeStore.ts +91 -0
  312. package/src/server/toolRegistry.ts +489 -0
  313. package/src/tools/.gitkeep +1 -0
  314. package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -0
  315. package/src/tools/__tests__/accountTools.integration.test.ts +117 -0
  316. package/src/tools/__tests__/accountTools.test.ts +653 -0
  317. package/src/tools/__tests__/budgetTools.delta.integration.test.ts +90 -0
  318. package/src/tools/__tests__/budgetTools.integration.test.ts +134 -0
  319. package/src/tools/__tests__/budgetTools.test.ts +423 -0
  320. package/src/tools/__tests__/categoryTools.delta.integration.test.ts +80 -0
  321. package/src/tools/__tests__/categoryTools.integration.test.ts +295 -0
  322. package/src/tools/__tests__/categoryTools.test.ts +622 -0
  323. package/src/tools/__tests__/compareTransactions/formatter.test.ts +486 -0
  324. package/src/tools/__tests__/compareTransactions/index.test.ts +383 -0
  325. package/src/tools/__tests__/compareTransactions/matcher.test.ts +410 -0
  326. package/src/tools/__tests__/compareTransactions/parser.test.ts +764 -0
  327. package/src/tools/__tests__/compareTransactions.test.ts +342 -0
  328. package/src/tools/__tests__/compareTransactions.window.test.ts +147 -0
  329. package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +76 -0
  330. package/src/tools/__tests__/deltaFetcher.test.ts +270 -0
  331. package/src/tools/__tests__/deltaSupport.test.ts +188 -0
  332. package/src/tools/__tests__/deltaTestUtils.ts +46 -0
  333. package/src/tools/__tests__/exportTransactions.test.ts +213 -0
  334. package/src/tools/__tests__/monthTools.delta.integration.test.ts +80 -0
  335. package/src/tools/__tests__/monthTools.integration.test.ts +174 -0
  336. package/src/tools/__tests__/monthTools.test.ts +523 -0
  337. package/src/tools/__tests__/payeeTools.delta.integration.test.ts +80 -0
  338. package/src/tools/__tests__/payeeTools.integration.test.ts +150 -0
  339. package/src/tools/__tests__/payeeTools.test.ts +445 -0
  340. package/src/tools/__tests__/transactionTools.integration.test.ts +762 -0
  341. package/src/tools/__tests__/transactionTools.test.ts +3521 -0
  342. package/src/tools/__tests__/utilityTools.integration.test.ts +128 -0
  343. package/src/tools/__tests__/utilityTools.test.ts +205 -0
  344. package/src/tools/accountTools.ts +283 -0
  345. package/src/tools/budgetTools.ts +112 -0
  346. package/src/tools/categoryTools.ts +366 -0
  347. package/src/tools/compareTransactions/formatter.ts +163 -0
  348. package/src/tools/compareTransactions/index.ts +228 -0
  349. package/src/tools/compareTransactions/matcher.ts +240 -0
  350. package/src/tools/compareTransactions/parser.ts +557 -0
  351. package/src/tools/compareTransactions/types.ts +60 -0
  352. package/src/tools/compareTransactions.ts +3 -0
  353. package/src/tools/deltaFetcher.ts +278 -0
  354. package/src/tools/deltaSupport.ts +293 -0
  355. package/src/tools/exportTransactions.ts +273 -0
  356. package/src/tools/monthTools.ts +164 -0
  357. package/src/tools/payeeTools.ts +140 -0
  358. package/src/tools/reconcileAdapter.ts +312 -0
  359. package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +122 -0
  360. package/src/tools/reconciliation/__tests__/adapter.test.ts +234 -0
  361. package/src/tools/reconciliation/__tests__/analyzer.test.ts +406 -0
  362. package/src/tools/reconciliation/__tests__/executor.integration.test.ts +366 -0
  363. package/src/tools/reconciliation/__tests__/executor.test.ts +779 -0
  364. package/src/tools/reconciliation/__tests__/matcher.test.ts +650 -0
  365. package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +278 -0
  366. package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +658 -0
  367. package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1000 -0
  368. package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +151 -0
  369. package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +573 -0
  370. package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +78 -0
  371. package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +47 -0
  372. package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +61 -0
  373. package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +49 -0
  374. package/src/tools/reconciliation/analyzer.ts +824 -0
  375. package/src/tools/reconciliation/executor.ts +880 -0
  376. package/src/tools/reconciliation/index.ts +400 -0
  377. package/src/tools/reconciliation/matcher.ts +269 -0
  378. package/src/tools/reconciliation/payeeNormalizer.ts +167 -0
  379. package/src/tools/reconciliation/recommendationEngine.ts +506 -0
  380. package/src/tools/reconciliation/reportFormatter.ts +363 -0
  381. package/src/tools/reconciliation/types.ts +314 -0
  382. package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +424 -0
  383. package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +310 -0
  384. package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +448 -0
  385. package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +519 -0
  386. package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +155 -0
  387. package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +288 -0
  388. package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +478 -0
  389. package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +370 -0
  390. package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +401 -0
  391. package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +213 -0
  392. package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +474 -0
  393. package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +333 -0
  394. package/src/tools/schemas/outputs/accountOutputs.ts +137 -0
  395. package/src/tools/schemas/outputs/budgetOutputs.ts +86 -0
  396. package/src/tools/schemas/outputs/categoryOutputs.ts +194 -0
  397. package/src/tools/schemas/outputs/comparisonOutputs.ts +600 -0
  398. package/src/tools/schemas/outputs/index.ts +270 -0
  399. package/src/tools/schemas/outputs/monthOutputs.ts +243 -0
  400. package/src/tools/schemas/outputs/payeeOutputs.ts +105 -0
  401. package/src/tools/schemas/outputs/reconciliationOutputs.ts +796 -0
  402. package/src/tools/schemas/outputs/transactionMutationOutputs.ts +758 -0
  403. package/src/tools/schemas/outputs/transactionOutputs.ts +243 -0
  404. package/src/tools/schemas/outputs/utilityOutputs.ts +411 -0
  405. package/src/tools/schemas/shared/commonOutputs.ts +140 -0
  406. package/src/tools/toolCategories.ts +140 -0
  407. package/src/tools/transactionTools.ts +2509 -0
  408. package/src/tools/utilityTools.ts +90 -0
  409. package/src/types/.gitkeep +1 -0
  410. package/src/types/__tests__/index.test.ts +52 -0
  411. package/src/types/index.ts +67 -0
  412. package/src/types/integration-tests.d.ts +35 -0
  413. package/src/types/toolAnnotations.ts +44 -0
  414. package/src/utils/__tests__/dateUtils.test.ts +170 -0
  415. package/src/utils/__tests__/money.test.ts +189 -0
  416. package/src/utils/amountUtils.ts +32 -0
  417. package/src/utils/dateUtils.ts +108 -0
  418. package/src/utils/money.ts +123 -0
  419. package/test-csv-sample.csv +28 -0
  420. package/test-exports/sample_bank_statement.csv +7 -0
  421. package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +23 -0
  422. package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +23 -0
  423. package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +44 -0
  424. package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +58 -0
  425. package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +115 -0
  426. package/test-reconcile-autodetect.js +40 -0
  427. package/test-reconcile-tool.js +152 -0
  428. package/test-reconcile-with-csv.cjs +89 -0
  429. package/test-statement.csv +8 -0
  430. package/test_debug.js +47 -0
  431. package/test_simple.mjs +16 -0
  432. package/tsconfig.json +31 -0
  433. package/tsconfig.prod.json +18 -0
  434. package/vitest-reporters/split-json-reporter.ts +211 -0
  435. package/vitest.config.ts +96 -0
@@ -0,0 +1,273 @@
1
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import * as ynab from 'ynab';
3
+ import { z } from 'zod/v4';
4
+ import { withToolErrorHandling } from '../types/index.js';
5
+ import { responseFormatter } from '../server/responseFormatter.js';
6
+ import { writeFileSync, mkdirSync } from 'fs';
7
+ import { format } from 'date-fns';
8
+ import { join, resolve } from 'path';
9
+ import { homedir } from 'os';
10
+
11
+ /**
12
+ * Schema for ynab:export_transactions tool parameters
13
+ */
14
+ export const ExportTransactionsSchema = z
15
+ .object({
16
+ budget_id: z.string().min(1, 'Budget ID is required'),
17
+ account_id: z.string().optional(),
18
+ category_id: z.string().optional(),
19
+ since_date: z
20
+ .string()
21
+ .regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in ISO format (YYYY-MM-DD)')
22
+ .optional(),
23
+ type: z.enum(['uncategorized', 'unapproved']).optional(),
24
+ filename: z.string().optional(),
25
+ minimal: z.boolean().optional().default(true),
26
+ })
27
+ .strict();
28
+
29
+ export type ExportTransactionsParams = z.infer<typeof ExportTransactionsSchema>;
30
+
31
+ /**
32
+ * Generate a descriptive filename for transaction export
33
+ */
34
+ function generateExportFilename(
35
+ params: ExportTransactionsParams,
36
+ transactionCount: number,
37
+ ): string {
38
+ if (params.filename) {
39
+ return params.filename.endsWith('.json') ? params.filename : `${params.filename}.json`;
40
+ }
41
+
42
+ const timestamp = format(new Date(), 'yyyy-MM-dd_HH-mm-ss');
43
+ let description = 'transactions';
44
+
45
+ // Add filters to filename for clarity
46
+ const filters = [];
47
+
48
+ if (params.since_date) {
49
+ filters.push(`since_${params.since_date}`);
50
+ }
51
+
52
+ if (params.account_id) {
53
+ filters.push(`account_${params.account_id.substring(0, 8)}`);
54
+ }
55
+
56
+ if (params.category_id) {
57
+ filters.push(`category_${params.category_id.substring(0, 8)}`);
58
+ }
59
+
60
+ if (params.type) {
61
+ filters.push(params.type);
62
+ }
63
+
64
+ if (params.minimal !== false) {
65
+ // Default true, only false if explicitly set
66
+ filters.push('minimal');
67
+ }
68
+
69
+ if (filters.length > 0) {
70
+ description = filters.join('_');
71
+ }
72
+
73
+ return `ynab_${description}_${transactionCount}items_${timestamp}.json`;
74
+ }
75
+
76
+ /**
77
+ * Get platform-specific default export directory
78
+ */
79
+ function getDefaultExportPath(): string {
80
+ const platform = process.platform;
81
+ const home = homedir();
82
+
83
+ switch (platform) {
84
+ case 'win32':
85
+ // Windows: Downloads folder
86
+ return join(home, 'Downloads');
87
+ case 'darwin':
88
+ // macOS: Downloads folder
89
+ return join(home, 'Downloads');
90
+ case 'linux':
91
+ case 'freebsd':
92
+ case 'openbsd':
93
+ case 'sunos':
94
+ case 'aix':
95
+ // Linux/Unix: Documents folder (more common for data files)
96
+ // Try XDG_DOCUMENTS_DIR first, fallback to ~/Documents
97
+ return process.env['XDG_DOCUMENTS_DIR'] || join(home, 'Documents');
98
+ default:
99
+ // Fallback for unknown platforms
100
+ return join(home, 'Downloads');
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Get the export directory path, with platform-specific defaults
106
+ */
107
+ function getExportPath(): string {
108
+ const exportPath = process.env['YNAB_EXPORT_PATH']?.trim();
109
+
110
+ let targetPath: string;
111
+
112
+ if (!exportPath) {
113
+ // Use platform-specific default
114
+ targetPath = getDefaultExportPath();
115
+ } else {
116
+ // Handle ~ expansion manually for cross-platform compatibility
117
+ if (exportPath.startsWith('~/')) {
118
+ targetPath = join(homedir(), exportPath.slice(2));
119
+ } else {
120
+ targetPath = resolve(exportPath);
121
+ }
122
+ }
123
+
124
+ // Ensure directory exists
125
+ try {
126
+ mkdirSync(targetPath, { recursive: true });
127
+ } catch (error) {
128
+ console.warn(`Failed to create export directory ${targetPath}, using platform default:`, error);
129
+ // Fallback to platform-specific default if custom path fails
130
+ const fallbackPath = getDefaultExportPath();
131
+ try {
132
+ mkdirSync(fallbackPath, { recursive: true });
133
+ return fallbackPath;
134
+ } catch (fallbackError) {
135
+ console.warn('Failed to create default folder, using current directory:', fallbackError);
136
+ return process.cwd();
137
+ }
138
+ }
139
+
140
+ return targetPath;
141
+ }
142
+
143
+ /**
144
+ * Handles the ynab:export_transactions tool call
145
+ * Exports all transactions to a JSON file with descriptive filename
146
+ */
147
+ export async function handleExportTransactions(
148
+ ynabAPI: ynab.API,
149
+ params: ExportTransactionsParams,
150
+ ): Promise<CallToolResult> {
151
+ return await withToolErrorHandling(
152
+ async () => {
153
+ let response;
154
+
155
+ // Use conditional API calls based on filter parameters
156
+ if (params.account_id) {
157
+ response = await ynabAPI.transactions.getTransactionsByAccount(
158
+ params.budget_id,
159
+ params.account_id,
160
+ params.since_date,
161
+ );
162
+ } else if (params.category_id) {
163
+ response = await ynabAPI.transactions.getTransactionsByCategory(
164
+ params.budget_id,
165
+ params.category_id,
166
+ params.since_date,
167
+ );
168
+ } else {
169
+ response = await ynabAPI.transactions.getTransactions(
170
+ params.budget_id,
171
+ params.since_date,
172
+ params.type,
173
+ );
174
+ }
175
+
176
+ const transactions = response.data.transactions;
177
+
178
+ // Get export directory and generate full path
179
+ const exportDir = getExportPath();
180
+ const filename = generateExportFilename(params, transactions.length);
181
+ const fullPath = join(exportDir, filename);
182
+
183
+ // Prepare transaction data for export
184
+ const exportData = {
185
+ export_info: {
186
+ exported_at: new Date().toISOString(),
187
+ total_transactions: transactions.length,
188
+ minimal: params.minimal !== false, // Default true, only false if explicitly set
189
+ filters: {
190
+ budget_id: params.budget_id,
191
+ account_id: params.account_id || null,
192
+ category_id: params.category_id || null,
193
+ since_date: params.since_date || null,
194
+ type: params.type || null,
195
+ },
196
+ },
197
+ transactions: transactions.map((transaction) => {
198
+ if (params.minimal !== false) {
199
+ // Default true, only false if explicitly set
200
+ // Minimal export: only essential fields
201
+ return {
202
+ id: transaction.id,
203
+ date: transaction.date,
204
+ amount: transaction.amount,
205
+ payee_name: transaction.payee_name,
206
+ cleared: transaction.cleared,
207
+ };
208
+ } else {
209
+ // Full export: all available fields
210
+ return {
211
+ id: transaction.id,
212
+ date: transaction.date,
213
+ amount: transaction.amount,
214
+ memo: transaction.memo,
215
+ cleared: transaction.cleared,
216
+ approved: transaction.approved,
217
+ flag_color: transaction.flag_color,
218
+ account_id: transaction.account_id,
219
+ payee_id: transaction.payee_id,
220
+ category_id: transaction.category_id,
221
+ transfer_account_id: transaction.transfer_account_id,
222
+ transfer_transaction_id: transaction.transfer_transaction_id,
223
+ matched_transaction_id: transaction.matched_transaction_id,
224
+ import_id: transaction.import_id,
225
+ deleted: transaction.deleted,
226
+ account_name: transaction.account_name,
227
+ payee_name: transaction.payee_name,
228
+ category_name: transaction.category_name,
229
+ };
230
+ }
231
+ }),
232
+ };
233
+
234
+ // Write to file
235
+ writeFileSync(fullPath, JSON.stringify(exportData, null, 2), 'utf-8');
236
+
237
+ // Return first few transactions as preview
238
+ const previewCount = Math.min(10, transactions.length);
239
+ const preview = transactions.slice(0, previewCount);
240
+
241
+ return {
242
+ content: [
243
+ {
244
+ type: 'text',
245
+ text: responseFormatter.format({
246
+ message: `Successfully exported ${transactions.length} transactions${params.minimal !== false ? ' (minimal fields)' : ' (full fields)'}`,
247
+ filename: filename,
248
+ full_path: fullPath,
249
+ export_directory: exportDir,
250
+ export_mode: params.minimal !== false ? 'minimal' : 'full',
251
+ minimal_fields:
252
+ params.minimal !== false ? 'id, date, amount, payee_name, cleared' : null,
253
+ filename_explanation:
254
+ 'Filename format: ynab_{filters}_{count}items_{timestamp}.json - identifies what data was exported, when, and how many transactions',
255
+ preview_count: previewCount,
256
+ total_count: transactions.length,
257
+ preview_transactions: preview.map((transaction) => ({
258
+ id: transaction.id,
259
+ date: transaction.date,
260
+ amount: transaction.amount,
261
+ memo: transaction.memo,
262
+ payee_name: transaction.payee_name,
263
+ category_name: transaction.category_name,
264
+ })),
265
+ }),
266
+ },
267
+ ],
268
+ };
269
+ },
270
+ 'ynab:export_transactions',
271
+ 'exporting transactions',
272
+ );
273
+ }
@@ -0,0 +1,164 @@
1
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import * as ynab from 'ynab';
3
+ import { z } from 'zod/v4';
4
+ import { withToolErrorHandling } from '../types/index.js';
5
+ import { responseFormatter } from '../server/responseFormatter.js';
6
+ import { milliunitsToAmount } from '../utils/amountUtils.js';
7
+ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
8
+ import type { DeltaFetcher } from './deltaFetcher.js';
9
+ import { resolveDeltaFetcherArgs } from './deltaSupport.js';
10
+
11
+ /**
12
+ * Schema for ynab:get_month tool parameters
13
+ */
14
+ export const GetMonthSchema = z
15
+ .object({
16
+ budget_id: z.string().min(1, 'Budget ID is required'),
17
+ month: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Month must be in YYYY-MM-DD format'),
18
+ })
19
+ .strict();
20
+
21
+ export type GetMonthParams = z.infer<typeof GetMonthSchema>;
22
+
23
+ /**
24
+ * Schema for ynab:list_months tool parameters
25
+ */
26
+ export const ListMonthsSchema = z
27
+ .object({
28
+ budget_id: z.string().min(1, 'Budget ID is required'),
29
+ })
30
+ .strict();
31
+
32
+ export type ListMonthsParams = z.infer<typeof ListMonthsSchema>;
33
+
34
+ /**
35
+ * Handles the ynab:get_month tool call
36
+ * Gets budget data for a specific month
37
+ */
38
+ export async function handleGetMonth(
39
+ ynabAPI: ynab.API,
40
+ params: GetMonthParams,
41
+ ): Promise<CallToolResult> {
42
+ return await withToolErrorHandling(
43
+ async () => {
44
+ // Always use cache
45
+ const cacheKey = CacheManager.generateKey('month', 'get', params.budget_id, params.month);
46
+ const wasCached = cacheManager.has(cacheKey);
47
+ const month = await cacheManager.wrap<ynab.MonthDetail>(cacheKey, {
48
+ ttl: CACHE_TTLS.MONTHS,
49
+ loader: async () => {
50
+ const response = await ynabAPI.months.getBudgetMonth(params.budget_id, params.month);
51
+ return response.data.month;
52
+ },
53
+ });
54
+
55
+ return {
56
+ content: [
57
+ {
58
+ type: 'text',
59
+ text: responseFormatter.format({
60
+ month: {
61
+ month: month.month,
62
+ note: month.note,
63
+ income: milliunitsToAmount(month.income),
64
+ budgeted: milliunitsToAmount(month.budgeted),
65
+ activity: milliunitsToAmount(month.activity),
66
+ to_be_budgeted: milliunitsToAmount(month.to_be_budgeted),
67
+ age_of_money: month.age_of_money,
68
+ deleted: month.deleted,
69
+ categories: month.categories?.map((category) => ({
70
+ id: category.id,
71
+ category_group_id: category.category_group_id,
72
+ category_group_name: category.category_group_name,
73
+ name: category.name,
74
+ hidden: category.hidden,
75
+ original_category_group_id: category.original_category_group_id,
76
+ note: category.note,
77
+ budgeted: milliunitsToAmount(category.budgeted),
78
+ activity: milliunitsToAmount(category.activity),
79
+ balance: milliunitsToAmount(category.balance),
80
+ goal_type: category.goal_type,
81
+ goal_creation_month: category.goal_creation_month,
82
+ goal_target: category.goal_target,
83
+ goal_target_month: category.goal_target_month,
84
+ goal_percentage_complete: category.goal_percentage_complete,
85
+ goal_months_to_budget: category.goal_months_to_budget,
86
+ goal_under_funded: category.goal_under_funded,
87
+ goal_overall_funded: category.goal_overall_funded,
88
+ goal_overall_left: category.goal_overall_left,
89
+ deleted: category.deleted,
90
+ })),
91
+ },
92
+ cached: wasCached,
93
+ cache_info: wasCached
94
+ ? 'Data retrieved from cache for improved performance'
95
+ : 'Fresh data retrieved from YNAB API',
96
+ }),
97
+ },
98
+ ],
99
+ };
100
+ },
101
+ 'ynab:get_month',
102
+ 'getting month data',
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Handles the ynab:list_months tool call
108
+ * Lists all months summary data for a budget
109
+ */
110
+ export async function handleListMonths(
111
+ ynabAPI: ynab.API,
112
+ deltaFetcher: DeltaFetcher,
113
+ params: ListMonthsParams,
114
+ ): Promise<CallToolResult>;
115
+ export async function handleListMonths(
116
+ ynabAPI: ynab.API,
117
+ params: ListMonthsParams,
118
+ ): Promise<CallToolResult>;
119
+ export async function handleListMonths(
120
+ ynabAPI: ynab.API,
121
+ deltaFetcherOrParams: DeltaFetcher | ListMonthsParams,
122
+ maybeParams?: ListMonthsParams,
123
+ ): Promise<CallToolResult> {
124
+ const { deltaFetcher, params } = resolveDeltaFetcherArgs(
125
+ ynabAPI,
126
+ deltaFetcherOrParams,
127
+ maybeParams,
128
+ );
129
+ return await withToolErrorHandling(
130
+ async () => {
131
+ // Always use cache
132
+ const result = await deltaFetcher.fetchMonths(params.budget_id);
133
+ const months = result.data;
134
+ const wasCached = result.wasCached;
135
+ const usedDelta = result.usedDelta;
136
+
137
+ return {
138
+ content: [
139
+ {
140
+ type: 'text',
141
+ text: responseFormatter.format({
142
+ months: months.map((month) => ({
143
+ month: month.month,
144
+ note: month.note,
145
+ income: milliunitsToAmount(month.income),
146
+ budgeted: milliunitsToAmount(month.budgeted),
147
+ activity: milliunitsToAmount(month.activity),
148
+ to_be_budgeted: milliunitsToAmount(month.to_be_budgeted),
149
+ age_of_money: month.age_of_money,
150
+ deleted: month.deleted,
151
+ })),
152
+ cached: wasCached,
153
+ cache_info: wasCached
154
+ ? `Data retrieved from cache for improved performance${usedDelta ? ' (delta merge applied)' : ''}`
155
+ : 'Fresh data retrieved from YNAB API',
156
+ }),
157
+ },
158
+ ],
159
+ };
160
+ },
161
+ 'ynab:list_months',
162
+ 'listing months',
163
+ );
164
+ }
@@ -0,0 +1,140 @@
1
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import * as ynab from 'ynab';
3
+ import { z } from 'zod/v4';
4
+ import { withToolErrorHandling } from '../types/index.js';
5
+ import { responseFormatter } from '../server/responseFormatter.js';
6
+ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
7
+ import type { DeltaFetcher } from './deltaFetcher.js';
8
+ import { resolveDeltaFetcherArgs } from './deltaSupport.js';
9
+
10
+ /**
11
+ * Schema for ynab:list_payees tool parameters
12
+ */
13
+ export const ListPayeesSchema = z
14
+ .object({
15
+ budget_id: z.string().min(1, 'Budget ID is required'),
16
+ limit: z.number().int().positive().optional(),
17
+ })
18
+ .strict();
19
+
20
+ export type ListPayeesParams = z.infer<typeof ListPayeesSchema>;
21
+
22
+ /**
23
+ * Schema for ynab:get_payee tool parameters
24
+ */
25
+ export const GetPayeeSchema = z
26
+ .object({
27
+ budget_id: z.string().min(1, 'Budget ID is required'),
28
+ payee_id: z.string().min(1, 'Payee ID is required'),
29
+ })
30
+ .strict();
31
+
32
+ export type GetPayeeParams = z.infer<typeof GetPayeeSchema>;
33
+
34
+ /**
35
+ * Handles the ynab:list_payees tool call
36
+ * Lists all payees for a specific budget
37
+ */
38
+ export async function handleListPayees(
39
+ ynabAPI: ynab.API,
40
+ deltaFetcher: DeltaFetcher,
41
+ params: ListPayeesParams,
42
+ ): Promise<CallToolResult>;
43
+ export async function handleListPayees(
44
+ ynabAPI: ynab.API,
45
+ params: ListPayeesParams,
46
+ ): Promise<CallToolResult>;
47
+ export async function handleListPayees(
48
+ ynabAPI: ynab.API,
49
+ deltaFetcherOrParams: DeltaFetcher | ListPayeesParams,
50
+ maybeParams?: ListPayeesParams,
51
+ ): Promise<CallToolResult> {
52
+ const { deltaFetcher, params } = resolveDeltaFetcherArgs(
53
+ ynabAPI,
54
+ deltaFetcherOrParams,
55
+ maybeParams,
56
+ );
57
+ return await withToolErrorHandling(
58
+ async () => {
59
+ const result = await deltaFetcher.fetchPayees(params.budget_id);
60
+ let payees = result.data;
61
+ const wasCached = result.wasCached;
62
+
63
+ // Apply limit if specified
64
+ const totalCount = payees.length;
65
+ if (params.limit !== undefined) {
66
+ payees = payees.slice(0, params.limit);
67
+ }
68
+
69
+ return {
70
+ content: [
71
+ {
72
+ type: 'text',
73
+ text: responseFormatter.format({
74
+ payees: payees.map((payee) => ({
75
+ id: payee.id,
76
+ name: payee.name,
77
+ transfer_account_id: payee.transfer_account_id,
78
+ deleted: payee.deleted,
79
+ })),
80
+ total_count: totalCount,
81
+ returned_count: payees.length,
82
+ cached: wasCached,
83
+ cache_info: wasCached
84
+ ? `Data retrieved from cache for improved performance${result.usedDelta ? ' (delta merge applied)' : ''}`
85
+ : 'Fresh data retrieved from YNAB API',
86
+ }),
87
+ },
88
+ ],
89
+ };
90
+ },
91
+ 'ynab:list_payees',
92
+ 'listing payees',
93
+ );
94
+ }
95
+
96
+ /**
97
+ * Handles the ynab:get_payee tool call
98
+ * Gets detailed information for a specific payee
99
+ */
100
+ export async function handleGetPayee(
101
+ ynabAPI: ynab.API,
102
+ params: GetPayeeParams,
103
+ ): Promise<CallToolResult> {
104
+ return await withToolErrorHandling(
105
+ async () => {
106
+ // Use enhanced CacheManager wrap method
107
+ const cacheKey = CacheManager.generateKey('payee', 'get', params.budget_id, params.payee_id);
108
+ const wasCached = cacheManager.has(cacheKey);
109
+ const payee = await cacheManager.wrap<ynab.Payee>(cacheKey, {
110
+ ttl: CACHE_TTLS.PAYEES,
111
+ loader: async () => {
112
+ const response = await ynabAPI.payees.getPayeeById(params.budget_id, params.payee_id);
113
+ return response.data.payee;
114
+ },
115
+ });
116
+
117
+ return {
118
+ content: [
119
+ {
120
+ type: 'text',
121
+ text: responseFormatter.format({
122
+ payee: {
123
+ id: payee.id,
124
+ name: payee.name,
125
+ transfer_account_id: payee.transfer_account_id,
126
+ deleted: payee.deleted,
127
+ },
128
+ cached: wasCached,
129
+ cache_info: wasCached
130
+ ? 'Data retrieved from cache for improved performance'
131
+ : 'Fresh data retrieved from YNAB API',
132
+ }),
133
+ },
134
+ ],
135
+ };
136
+ },
137
+ 'ynab:get_payee',
138
+ 'getting payee details',
139
+ );
140
+ }