@bank-mcp/server 0.1.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +564 -0
  3. package/dist/config.d.ts +11 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +79 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/index.d.ts +11 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +33 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/init.d.ts +6 -0
  12. package/dist/init.d.ts.map +1 -0
  13. package/dist/init.js +96 -0
  14. package/dist/init.js.map +1 -0
  15. package/dist/providers/base.d.ts +22 -0
  16. package/dist/providers/base.d.ts.map +1 -0
  17. package/dist/providers/base.js +9 -0
  18. package/dist/providers/base.js.map +1 -0
  19. package/dist/providers/enable-banking/auth.d.ts +9 -0
  20. package/dist/providers/enable-banking/auth.d.ts.map +1 -0
  21. package/dist/providers/enable-banking/auth.js +30 -0
  22. package/dist/providers/enable-banking/auth.js.map +1 -0
  23. package/dist/providers/enable-banking/index.d.ts +12 -0
  24. package/dist/providers/enable-banking/index.d.ts.map +1 -0
  25. package/dist/providers/enable-banking/index.js +171 -0
  26. package/dist/providers/enable-banking/index.js.map +1 -0
  27. package/dist/providers/mock/index.d.ts +18 -0
  28. package/dist/providers/mock/index.d.ts.map +1 -0
  29. package/dist/providers/mock/index.js +151 -0
  30. package/dist/providers/mock/index.js.map +1 -0
  31. package/dist/providers/plaid/index.d.ts +12 -0
  32. package/dist/providers/plaid/index.d.ts.map +1 -0
  33. package/dist/providers/plaid/index.js +213 -0
  34. package/dist/providers/plaid/index.js.map +1 -0
  35. package/dist/providers/registry.d.ts +4 -0
  36. package/dist/providers/registry.d.ts.map +1 -0
  37. package/dist/providers/registry.js +26 -0
  38. package/dist/providers/registry.js.map +1 -0
  39. package/dist/providers/teller/index.d.ts +12 -0
  40. package/dist/providers/teller/index.d.ts.map +1 -0
  41. package/dist/providers/teller/index.js +215 -0
  42. package/dist/providers/teller/index.js.map +1 -0
  43. package/dist/providers/tink/index.d.ts +12 -0
  44. package/dist/providers/tink/index.d.ts.map +1 -0
  45. package/dist/providers/tink/index.js +169 -0
  46. package/dist/providers/tink/index.js.map +1 -0
  47. package/dist/server.d.ts +2 -0
  48. package/dist/server.d.ts.map +1 -0
  49. package/dist/server.js +90 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/tools/get-balance.d.ts +8 -0
  52. package/dist/tools/get-balance.d.ts.map +1 -0
  53. package/dist/tools/get-balance.js +39 -0
  54. package/dist/tools/get-balance.js.map +1 -0
  55. package/dist/tools/list-accounts.d.ts +7 -0
  56. package/dist/tools/list-accounts.d.ts.map +1 -0
  57. package/dist/tools/list-accounts.js +33 -0
  58. package/dist/tools/list-accounts.js.map +1 -0
  59. package/dist/tools/list-transactions.d.ts +17 -0
  60. package/dist/tools/list-transactions.d.ts.map +1 -0
  61. package/dist/tools/list-transactions.js +104 -0
  62. package/dist/tools/list-transactions.js.map +1 -0
  63. package/dist/tools/search-transactions.d.ts +10 -0
  64. package/dist/tools/search-transactions.d.ts.map +1 -0
  65. package/dist/tools/search-transactions.js +27 -0
  66. package/dist/tools/search-transactions.js.map +1 -0
  67. package/dist/tools/spending-summary.d.ts +25 -0
  68. package/dist/tools/spending-summary.d.ts.map +1 -0
  69. package/dist/tools/spending-summary.js +65 -0
  70. package/dist/tools/spending-summary.js.map +1 -0
  71. package/dist/types.d.ts +65 -0
  72. package/dist/types.d.ts.map +1 -0
  73. package/dist/types.js +21 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/utils/cache.d.ts +19 -0
  76. package/dist/utils/cache.d.ts.map +1 -0
  77. package/dist/utils/cache.js +33 -0
  78. package/dist/utils/cache.js.map +1 -0
  79. package/dist/utils/http.d.ts +12 -0
  80. package/dist/utils/http.d.ts.map +1 -0
  81. package/dist/utils/http.js +34 -0
  82. package/dist/utils/http.js.map +1 -0
  83. package/dist/utils/zod-to-json.d.ts +9 -0
  84. package/dist/utils/zod-to-json.d.ts.map +1 -0
  85. package/dist/utils/zod-to-json.js +62 -0
  86. package/dist/utils/zod-to-json.js.map +1 -0
  87. package/package.json +58 -0
@@ -0,0 +1,169 @@
1
+ import { BankProvider } from "../base.js";
2
+ import { httpFetch } from "../../utils/http.js";
3
+ const BASE_URL = "https://api.tink.com";
4
+ function parseConfig(raw) {
5
+ const accessToken = raw.accessToken;
6
+ if (!accessToken) {
7
+ throw new Error("Tink config requires: accessToken");
8
+ }
9
+ return { accessToken };
10
+ }
11
+ /**
12
+ * GET request to Tink API with Bearer token auth.
13
+ */
14
+ async function tinkGet(config, path, params) {
15
+ let url = `${BASE_URL}${path}`;
16
+ if (params) {
17
+ const qs = new URLSearchParams(params).toString();
18
+ if (qs)
19
+ url += `?${qs}`;
20
+ }
21
+ return httpFetch(url, {
22
+ method: "GET",
23
+ headers: {
24
+ Authorization: `Bearer ${config.accessToken}`,
25
+ },
26
+ timeoutMs: 30000,
27
+ retries: 2,
28
+ });
29
+ }
30
+ /**
31
+ * Parse Tink's fixed-point decimal amount.
32
+ *
33
+ * Tink represents amounts as { unscaledValue, scale } where
34
+ * actual = unscaledValue * 10^(-scale).
35
+ *
36
+ * Example: { unscaledValue: "15099", scale: 2 } → 150.99
37
+ */
38
+ function parseAmount(amount) {
39
+ const unscaled = parseFloat(amount.unscaledValue);
40
+ return unscaled * Math.pow(10, -(amount.scale ?? 0));
41
+ }
42
+ export class TinkProvider extends BankProvider {
43
+ name = "tink";
44
+ displayName = "Tink (EU Open Banking)";
45
+ validateConfig(config) {
46
+ parseConfig(config);
47
+ }
48
+ getConfigSchema() {
49
+ return [
50
+ {
51
+ name: "accessToken",
52
+ label: "Access token (from Tink Console)",
53
+ type: "string",
54
+ required: true,
55
+ secret: true,
56
+ },
57
+ ];
58
+ }
59
+ async listAccounts(config) {
60
+ const tc = parseConfig(config);
61
+ const data = (await tinkGet(tc, "/data/v2/accounts"));
62
+ return data.accounts.map((a) => ({
63
+ uid: a.id,
64
+ iban: a.identifiers?.iban?.iban || a.id,
65
+ name: a.name,
66
+ currency: a.balances?.booked?.amount?.currencyCode || "EUR",
67
+ connectionId: "",
68
+ }));
69
+ }
70
+ async listTransactions(config, accountId, filter) {
71
+ const tc = parseConfig(config);
72
+ const allTx = [];
73
+ let pageToken;
74
+ // nextPageToken cursor pagination
75
+ do {
76
+ const params = {
77
+ accountIdIn: accountId,
78
+ pageSize: "100",
79
+ };
80
+ if (filter?.dateFrom)
81
+ params.bookedDateGte = filter.dateFrom;
82
+ if (filter?.dateTo)
83
+ params.bookedDateLte = filter.dateTo;
84
+ if (pageToken)
85
+ params.pageToken = pageToken;
86
+ const data = (await tinkGet(tc, "/data/v2/transactions", params));
87
+ for (const raw of data.transactions) {
88
+ allTx.push(normalizeTransaction(raw));
89
+ }
90
+ pageToken = data.nextPageToken || undefined;
91
+ } while (pageToken);
92
+ // Apply local filters
93
+ let filtered = allTx;
94
+ if (filter?.amountMin !== undefined) {
95
+ filtered = filtered.filter((t) => Math.abs(t.amount) >= filter.amountMin);
96
+ }
97
+ if (filter?.amountMax !== undefined) {
98
+ filtered = filtered.filter((t) => Math.abs(t.amount) <= filter.amountMax);
99
+ }
100
+ if (filter?.type) {
101
+ filtered = filtered.filter((t) => t.type === filter.type);
102
+ }
103
+ if (filter?.limit) {
104
+ filtered = filtered.slice(0, filter.limit);
105
+ }
106
+ return filtered;
107
+ }
108
+ async getBalance(config, accountId) {
109
+ const tc = parseConfig(config);
110
+ const data = (await tinkGet(tc, `/data/v2/accounts/${accountId}/balances`));
111
+ const balances = [];
112
+ if (data.balances?.bookedBalance) {
113
+ const amt = data.balances.bookedBalance.amount;
114
+ balances.push({
115
+ accountId,
116
+ amount: parseAmount(amt),
117
+ currency: amt.currencyCode,
118
+ type: "booked",
119
+ });
120
+ }
121
+ if (data.balances?.availableBalance) {
122
+ const amt = data.balances.availableBalance.amount;
123
+ balances.push({
124
+ accountId,
125
+ amount: parseAmount(amt),
126
+ currency: amt.currencyCode,
127
+ type: "available",
128
+ });
129
+ }
130
+ return balances;
131
+ }
132
+ }
133
+ /**
134
+ * Normalize a Tink transaction to our standard format.
135
+ *
136
+ * Amount: Tink uses fixed-point { unscaledValue, scale }.
137
+ * Sign: Tink amounts are always positive; the `types.type` field
138
+ * indicates DEBIT (money out) vs CREDIT (money in).
139
+ * We negate DEBIT amounts to match our convention (negative = expense).
140
+ *
141
+ * Descriptions: Tink provides three levels:
142
+ * display (cleanest) > original (raw) > detailed.unstructured
143
+ */
144
+ function normalizeTransaction(raw) {
145
+ const absAmount = parseAmount(raw.amount);
146
+ const isDebit = raw.types?.type === "DEBIT";
147
+ const amount = isDebit ? -absAmount : absAmount;
148
+ const merchantName = raw.merchantInformation?.merchantName || undefined;
149
+ const category = raw.categories?.pfm?.name || undefined;
150
+ // Best description: display > original > detailed
151
+ const description = raw.descriptions.display ||
152
+ raw.descriptions.original ||
153
+ raw.descriptions.detailed?.unstructured ||
154
+ "Unknown";
155
+ return {
156
+ id: raw.id,
157
+ accountId: raw.accountId,
158
+ date: raw.dates.booked,
159
+ amount,
160
+ currency: raw.amount.currencyCode,
161
+ description: merchantName || description,
162
+ merchantName,
163
+ category,
164
+ type: isDebit ? "debit" : "credit",
165
+ reference: raw.reference || description,
166
+ rawData: raw,
167
+ };
168
+ }
169
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/tink/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function startServer(): Promise<void>;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAqEA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAqDjD"}
package/dist/server.js ADDED
@@ -0,0 +1,90 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { z } from "zod";
5
+ import { listAccountsSchema, listAccounts } from "./tools/list-accounts.js";
6
+ import { listTransactionsSchema, listTransactions, } from "./tools/list-transactions.js";
7
+ import { searchTransactionsSchema, searchTransactions, } from "./tools/search-transactions.js";
8
+ import { getBalanceSchema, getBalance } from "./tools/get-balance.js";
9
+ import { spendingSummarySchema, spendingSummary, } from "./tools/spending-summary.js";
10
+ const TOOLS = [
11
+ {
12
+ name: "list_accounts",
13
+ description: "List all bank accounts across configured connections. Returns account UIDs, IBANs, names, and currencies.",
14
+ inputSchema: z.toJSONSchema(listAccountsSchema),
15
+ },
16
+ {
17
+ name: "list_transactions",
18
+ description: "List bank transactions with optional filters. Defaults to last 90 days. Supports date range, amount range, and debit/credit type filtering.",
19
+ inputSchema: z.toJSONSchema(listTransactionsSchema),
20
+ },
21
+ {
22
+ name: "search_transactions",
23
+ description: "Full-text search across transaction descriptions, merchant names, and references. Use for finding specific payments or payees.",
24
+ inputSchema: z.toJSONSchema(searchTransactionsSchema),
25
+ },
26
+ {
27
+ name: "get_balance",
28
+ description: "Get current account balance(s). Returns closing booked balance and expected balance when available.",
29
+ inputSchema: z.toJSONSchema(getBalanceSchema),
30
+ },
31
+ {
32
+ name: "spending_summary",
33
+ description: 'Group expenses by merchant or category with totals. Shows where money is being spent. Use groupBy "merchant" for vendor breakdown, "category" for category breakdown.',
34
+ inputSchema: z.toJSONSchema(spendingSummarySchema),
35
+ },
36
+ ];
37
+ const handlers = {
38
+ list_accounts: (args) => listAccounts(listAccountsSchema.parse(args)),
39
+ list_transactions: (args) => listTransactions(listTransactionsSchema.parse(args)),
40
+ search_transactions: (args) => searchTransactions(searchTransactionsSchema.parse(args)),
41
+ get_balance: (args) => getBalance(getBalanceSchema.parse(args)),
42
+ spending_summary: (args) => spendingSummary(spendingSummarySchema.parse(args)),
43
+ };
44
+ export async function startServer() {
45
+ const server = new Server({ name: "bank-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
46
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
47
+ tools: TOOLS,
48
+ }));
49
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
50
+ const { name, arguments: args } = request.params;
51
+ const handler = handlers[name];
52
+ if (!handler) {
53
+ return {
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: JSON.stringify({ error: true, code: "unknown_tool", message: `Unknown tool: ${name}` }),
58
+ },
59
+ ],
60
+ isError: true,
61
+ };
62
+ }
63
+ try {
64
+ const result = await handler(args || {});
65
+ return {
66
+ content: [
67
+ { type: "text", text: JSON.stringify(result, null, 2) },
68
+ ],
69
+ };
70
+ }
71
+ catch (err) {
72
+ const message = err instanceof Error ? err.message : String(err);
73
+ // Return structured error as text so LLMs can explain it
74
+ return {
75
+ content: [
76
+ {
77
+ type: "text",
78
+ text: JSON.stringify({ error: true, code: "tool_error", message }),
79
+ },
80
+ ],
81
+ isError: true,
82
+ };
83
+ }
84
+ });
85
+ const transport = new StdioServerTransport();
86
+ await server.connect(transport);
87
+ // All logging to stderr — stdout is the MCP wire protocol
88
+ console.error("[bank-mcp] Server started");
89
+ }
90
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ import type { Balance } from "../types.js";
3
+ export declare const getBalanceSchema: z.ZodObject<{
4
+ connectionId: z.ZodOptional<z.ZodString>;
5
+ accountId: z.ZodOptional<z.ZodString>;
6
+ }, z.core.$strip>;
7
+ export declare function getBalance(args: z.infer<typeof getBalanceSchema>): Promise<Balance[]>;
8
+ //# sourceMappingURL=get-balance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-balance.d.ts","sourceRoot":"","sources":["../../src/tools/get-balance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAC;AAEH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,GACrC,OAAO,CAAC,OAAO,EAAE,CAAC,CAmCpB"}
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import { loadConfig, getConnection, getAllConnections } from "../config.js";
3
+ import { getProvider } from "../providers/registry.js";
4
+ import { cache, TTL } from "../utils/cache.js";
5
+ export const getBalanceSchema = z.object({
6
+ connectionId: z.string().optional(),
7
+ accountId: z.string().optional().describe("Account UID. If omitted, returns balances for all accounts."),
8
+ });
9
+ export async function getBalance(args) {
10
+ const config = loadConfig();
11
+ const connections = args.connectionId
12
+ ? [getConnection(config, args.connectionId)]
13
+ : getAllConnections(config);
14
+ const allBalances = [];
15
+ for (const conn of connections) {
16
+ const provider = getProvider(conn.provider);
17
+ let accountIds;
18
+ if (args.accountId) {
19
+ accountIds = [args.accountId];
20
+ }
21
+ else {
22
+ const accounts = await provider.listAccounts(conn.config);
23
+ accountIds = accounts.map((a) => a.uid);
24
+ }
25
+ for (const accId of accountIds) {
26
+ const cacheKey = `bal:${conn.id}:${accId}`;
27
+ const cached = cache.get(cacheKey);
28
+ if (cached) {
29
+ allBalances.push(...cached);
30
+ continue;
31
+ }
32
+ const balances = await provider.getBalance(conn.config, accId);
33
+ cache.set(cacheKey, balances, TTL.BALANCES);
34
+ allBalances.push(...balances);
35
+ }
36
+ }
37
+ return allBalances;
38
+ }
39
+ //# sourceMappingURL=get-balance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-balance.js","sourceRoot":"","sources":["../../src/tools/get-balance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAG/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;CACzG,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAsC;IAEtC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY;QACnC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAc,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE5C,IAAI,UAAoB,CAAC;QACzB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,UAAU,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1D,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAY,QAAQ,CAAC,CAAC;YAC9C,IAAI,MAAM,EAAE,CAAC;gBACX,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC5B,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC/D,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ import type { BankAccount } from "../types.js";
3
+ export declare const listAccountsSchema: z.ZodObject<{
4
+ connectionId: z.ZodOptional<z.ZodString>;
5
+ }, z.core.$strip>;
6
+ export declare function listAccounts(args: z.infer<typeof listAccountsSchema>): Promise<BankAccount[]>;
7
+ //# sourceMappingURL=list-accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-accounts.d.ts","sourceRoot":"","sources":["../../src/tools/list-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,eAAO,MAAM,kBAAkB;;iBAK7B,CAAC;AAEH,wBAAsB,YAAY,CAChC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GACvC,OAAO,CAAC,WAAW,EAAE,CAAC,CA2BxB"}
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { loadConfig, getConnection, getAllConnections } from "../config.js";
3
+ import { getProvider } from "../providers/registry.js";
4
+ import { cache, TTL } from "../utils/cache.js";
5
+ export const listAccountsSchema = z.object({
6
+ connectionId: z
7
+ .string()
8
+ .optional()
9
+ .describe("Connection ID to query. If omitted, queries all connections."),
10
+ });
11
+ export async function listAccounts(args) {
12
+ const config = loadConfig();
13
+ const connections = args.connectionId
14
+ ? [getConnection(config, args.connectionId)]
15
+ : getAllConnections(config);
16
+ const allAccounts = [];
17
+ for (const conn of connections) {
18
+ const cacheKey = `accounts:${conn.id}`;
19
+ const cached = cache.get(cacheKey);
20
+ if (cached) {
21
+ allAccounts.push(...cached);
22
+ continue;
23
+ }
24
+ const provider = getProvider(conn.provider);
25
+ const accounts = await provider.listAccounts(conn.config);
26
+ // Tag each account with its connection
27
+ const tagged = accounts.map((a) => ({ ...a, connectionId: conn.id }));
28
+ cache.set(cacheKey, tagged, TTL.ACCOUNTS);
29
+ allAccounts.push(...tagged);
30
+ }
31
+ return allAccounts;
32
+ }
33
+ //# sourceMappingURL=list-accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-accounts.js","sourceRoot":"","sources":["../../src/tools/list-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAG/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,8DAA8D,CAAC;CAC5E,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAwC;IAExC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY;QACnC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAkB,EAAE,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,YAAY,IAAI,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAgB,QAAQ,CAAC,CAAC;QAClD,IAAI,MAAM,EAAE,CAAC;YACX,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1D,uCAAuC;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACtE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ import type { Transaction } from "../types.js";
3
+ export declare const listTransactionsSchema: z.ZodObject<{
4
+ connectionId: z.ZodOptional<z.ZodString>;
5
+ accountId: z.ZodOptional<z.ZodString>;
6
+ dateFrom: z.ZodOptional<z.ZodString>;
7
+ dateTo: z.ZodOptional<z.ZodString>;
8
+ amountMin: z.ZodOptional<z.ZodNumber>;
9
+ amountMax: z.ZodOptional<z.ZodNumber>;
10
+ type: z.ZodOptional<z.ZodEnum<{
11
+ debit: "debit";
12
+ credit: "credit";
13
+ }>>;
14
+ limit: z.ZodOptional<z.ZodNumber>;
15
+ }, z.core.$strip>;
16
+ export declare function listTransactions(args: z.infer<typeof listTransactionsSchema>): Promise<Transaction[]>;
17
+ //# sourceMappingURL=list-transactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-transactions.d.ts","sourceRoot":"","sources":["../../src/tools/list-transactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,aAAa,CAAC;AAElE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;iBAiCjC,CAAC;AAEH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,GAC3C,OAAO,CAAC,WAAW,EAAE,CAAC,CAwDxB"}
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ import { loadConfig, getConnection, getAllConnections } from "../config.js";
3
+ import { getProvider } from "../providers/registry.js";
4
+ import { cache, TTL } from "../utils/cache.js";
5
+ export const listTransactionsSchema = z.object({
6
+ connectionId: z
7
+ .string()
8
+ .optional()
9
+ .describe("Connection ID. If omitted, queries all connections."),
10
+ accountId: z
11
+ .string()
12
+ .optional()
13
+ .describe("Account UID. If omitted, queries all accounts."),
14
+ dateFrom: z
15
+ .string()
16
+ .optional()
17
+ .describe('Start date (YYYY-MM-DD). Defaults to 90 days ago.'),
18
+ dateTo: z
19
+ .string()
20
+ .optional()
21
+ .describe('End date (YYYY-MM-DD). Defaults to today.'),
22
+ amountMin: z
23
+ .number()
24
+ .optional()
25
+ .describe("Minimum absolute amount."),
26
+ amountMax: z
27
+ .number()
28
+ .optional()
29
+ .describe("Maximum absolute amount."),
30
+ type: z
31
+ .enum(["debit", "credit"])
32
+ .optional()
33
+ .describe("Filter by transaction type."),
34
+ limit: z
35
+ .number()
36
+ .optional()
37
+ .describe("Maximum number of transactions to return."),
38
+ });
39
+ export async function listTransactions(args) {
40
+ const config = loadConfig();
41
+ const dateFrom = args.dateFrom || defaultDateFrom(config.defaults.transactionDays);
42
+ const dateTo = args.dateTo || today();
43
+ const filter = {
44
+ dateFrom,
45
+ dateTo,
46
+ amountMin: args.amountMin,
47
+ amountMax: args.amountMax,
48
+ type: args.type,
49
+ limit: args.limit,
50
+ };
51
+ // Resolve which connections and accounts to query
52
+ const connections = args.connectionId
53
+ ? [getConnection(config, args.connectionId)]
54
+ : getAllConnections(config);
55
+ const allTx = [];
56
+ for (const conn of connections) {
57
+ const provider = getProvider(conn.provider);
58
+ // Get account list (may come from cache)
59
+ let accountIds;
60
+ if (args.accountId) {
61
+ accountIds = [args.accountId];
62
+ }
63
+ else {
64
+ const accounts = await provider.listAccounts(conn.config);
65
+ accountIds = accounts.map((a) => a.uid);
66
+ }
67
+ for (const accId of accountIds) {
68
+ const cacheKey = `tx:${conn.id}:${accId}:${dateFrom}:${dateTo}`;
69
+ const cached = cache.get(cacheKey);
70
+ if (cached) {
71
+ allTx.push(...applyLocalFilters(cached, filter));
72
+ continue;
73
+ }
74
+ const transactions = await provider.listTransactions(conn.config, accId, { dateFrom, dateTo });
75
+ cache.set(cacheKey, transactions, TTL.TRANSACTIONS);
76
+ allTx.push(...applyLocalFilters(transactions, filter));
77
+ }
78
+ }
79
+ // Sort by date descending (most recent first)
80
+ allTx.sort((a, b) => b.date.localeCompare(a.date));
81
+ return args.limit ? allTx.slice(0, args.limit) : allTx;
82
+ }
83
+ function applyLocalFilters(txs, f) {
84
+ let result = txs;
85
+ if (f.amountMin !== undefined) {
86
+ result = result.filter((t) => Math.abs(t.amount) >= f.amountMin);
87
+ }
88
+ if (f.amountMax !== undefined) {
89
+ result = result.filter((t) => Math.abs(t.amount) <= f.amountMax);
90
+ }
91
+ if (f.type) {
92
+ result = result.filter((t) => t.type === f.type);
93
+ }
94
+ return result;
95
+ }
96
+ function defaultDateFrom(days) {
97
+ const d = new Date();
98
+ d.setDate(d.getDate() - days);
99
+ return d.toISOString().slice(0, 10);
100
+ }
101
+ function today() {
102
+ return new Date().toISOString().slice(0, 10);
103
+ }
104
+ //# sourceMappingURL=list-transactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-transactions.js","sourceRoot":"","sources":["../../src/tools/list-transactions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ export declare const searchTransactionsSchema: z.ZodObject<{
3
+ query: z.ZodString;
4
+ connectionId: z.ZodOptional<z.ZodString>;
5
+ dateFrom: z.ZodOptional<z.ZodString>;
6
+ dateTo: z.ZodOptional<z.ZodString>;
7
+ limit: z.ZodOptional<z.ZodNumber>;
8
+ }, z.core.$strip>;
9
+ export declare function searchTransactions(args: z.infer<typeof searchTransactionsSchema>): Promise<unknown>;
10
+ //# sourceMappingURL=search-transactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-transactions.d.ts","sourceRoot":"","sources":["../../src/tools/search-transactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,wBAAwB;;;;;;iBAQnC,CAAC;AAEH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,GAC7C,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { listTransactions } from "./list-transactions.js";
3
+ export const searchTransactionsSchema = z.object({
4
+ query: z
5
+ .string()
6
+ .describe("Search text — matched against description, merchant name, and reference."),
7
+ connectionId: z.string().optional(),
8
+ dateFrom: z.string().optional(),
9
+ dateTo: z.string().optional(),
10
+ limit: z.number().optional().describe("Max results. Default 50."),
11
+ });
12
+ export async function searchTransactions(args) {
13
+ // Fetch all transactions for the date range, then filter locally
14
+ const transactions = await listTransactions({
15
+ connectionId: args.connectionId,
16
+ dateFrom: args.dateFrom,
17
+ dateTo: args.dateTo,
18
+ });
19
+ const q = args.query.toLowerCase();
20
+ const limit = args.limit || 50;
21
+ const matches = transactions.filter((t) => {
22
+ const fields = [t.description, t.merchantName, t.reference].filter(Boolean);
23
+ return fields.some((f) => f.toLowerCase().includes(q));
24
+ });
25
+ return matches.slice(0, limit);
26
+ }
27
+ //# sourceMappingURL=search-transactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-transactions.js","sourceRoot":"","sources":["../../src/tools/search-transactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CAAC,0EAA0E,CAAC;IACvF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;CAClE,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAA8C;IAE9C,iEAAiE;IACjE,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC;QAC1C,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5E,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export declare const spendingSummarySchema: z.ZodObject<{
3
+ connectionId: z.ZodOptional<z.ZodString>;
4
+ dateFrom: z.ZodOptional<z.ZodString>;
5
+ dateTo: z.ZodOptional<z.ZodString>;
6
+ groupBy: z.ZodOptional<z.ZodEnum<{
7
+ merchant: "merchant";
8
+ category: "category";
9
+ }>>;
10
+ limit: z.ZodOptional<z.ZodNumber>;
11
+ }, z.core.$strip>;
12
+ interface SpendingGroup {
13
+ name: string;
14
+ totalSpent: number;
15
+ transactionCount: number;
16
+ currency: string;
17
+ }
18
+ export declare function spendingSummary(args: z.infer<typeof spendingSummarySchema>): Promise<{
19
+ groups: SpendingGroup[];
20
+ totalSpent: number;
21
+ currency: string;
22
+ period: string;
23
+ }>;
24
+ export {};
25
+ //# sourceMappingURL=spending-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spending-summary.d.ts","sourceRoot":"","sources":["../../src/tools/spending-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,qBAAqB;;;;;;;;;iBAYhC,CAAC;AAEH,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC1C,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAkD5F"}