@openfinance-sh/mcp 0.1.0 → 0.1.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.
package/build/index.js CHANGED
@@ -51,8 +51,22 @@ var OpenFinanceClient = class {
51
51
  if (filter?.cursor) params.cursor = filter.cursor;
52
52
  if (filter?.pending !== void 0) params.pending = String(filter.pending);
53
53
  if (filter?.status?.length) params.status = filter.status.join(",");
54
+ if (filter?.fields?.length) params.fields = filter.fields.join(",");
55
+ if (filter?.amountFilters?.length)
56
+ params.amountFilters = JSON.stringify(filter.amountFilters);
54
57
  return this.request("/api/transactions", params);
55
58
  }
59
+ async queryTransactions(sql) {
60
+ const res = await fetch(`${this.baseUrl}/api/transactions/query`, {
61
+ method: "POST",
62
+ headers: {
63
+ Authorization: `Bearer ${this.apiKey}`,
64
+ "Content-Type": "application/json"
65
+ },
66
+ body: JSON.stringify({ sql })
67
+ });
68
+ return res.json();
69
+ }
56
70
  };
57
71
 
58
72
  // src/tools/accounts.ts
@@ -80,7 +94,7 @@ import { z } from "zod";
80
94
  function registerTransactionTools(server, client) {
81
95
  server.tool(
82
96
  "get_transactions",
83
- "Search and filter financial transactions. Returns transactions sorted by date (newest first) by default.",
97
+ "Search and filter financial transactions. Returns transactions sorted by date (newest first) by default. Use the `fields` parameter to reduce payload size by requesting only the fields you need. For spending analysis, aggregations, or category breakdowns, use the `query_transactions` tool instead \u2014 it lets you write SQL for efficient server-side computation.",
84
98
  {
85
99
  startDate: z.string().describe("Start date filter (YYYY-MM-DD)").optional(),
86
100
  endDate: z.string().describe("End date filter (YYYY-MM-DD)").optional(),
@@ -90,7 +104,18 @@ function registerTransactionTools(server, client) {
90
104
  limit: z.number().int().positive().max(500).describe("Max results (default 100, max 500)").optional(),
91
105
  cursor: z.string().describe("Cursor for pagination").optional(),
92
106
  pending: z.boolean().describe("Filter pending transactions").optional(),
93
- status: z.array(z.enum(["active", "hidden", "deleted"])).describe("Filter by status").optional()
107
+ status: z.array(z.enum(["active", "hidden", "deleted"])).describe("Filter by status").optional(),
108
+ fields: z.array(z.string()).describe(
109
+ "Return only these fields per transaction (e.g. ['name', 'amount', 'date', 'merchantName']). Omit to return all fields."
110
+ ).optional(),
111
+ amountFilters: z.array(
112
+ z.object({
113
+ operator: z.enum([">", "<", ">=", "<=", "="]),
114
+ amount: z.number()
115
+ })
116
+ ).describe(
117
+ "Filter by amount using comparison operators (e.g. [{ operator: '>', amount: 100 }])"
118
+ ).optional()
94
119
  },
95
120
  async (params) => {
96
121
  const result = await client.getTransactions({
@@ -102,7 +127,9 @@ function registerTransactionTools(server, client) {
102
127
  limit: params.limit,
103
128
  cursor: params.cursor,
104
129
  pending: params.pending,
105
- status: params.status
130
+ status: params.status,
131
+ fields: params.fields,
132
+ amountFilters: params.amountFilters
106
133
  });
107
134
  return {
108
135
  content: [
@@ -114,6 +141,46 @@ function registerTransactionTools(server, client) {
114
141
  };
115
142
  }
116
143
  );
144
+ server.tool(
145
+ "query_transactions",
146
+ `Run a SQL query against the user's transactions. Write a SELECT query referencing the \`txns\` CTE which has columns: id, name, amount (numeric), date, authorized_date, merchant_name, pending, iso_currency_code, account_id, status, created_at, updated_at. The query runs in a read-only transaction with a 5s timeout. Errors are returned so you can self-correct SQL syntax.
147
+
148
+ Example queries:
149
+ - SELECT SUM(amount), COUNT(*) FROM txns WHERE merchant_name ILIKE '%starbucks%'
150
+ - SELECT TO_CHAR(date, 'YYYY-MM') as month, SUM(amount), COUNT(*) FROM txns GROUP BY 1 ORDER BY 1
151
+ - SELECT COALESCE(merchant_name, name) as merchant, SUM(amount) as total FROM txns GROUP BY 1 ORDER BY total DESC LIMIT 10`,
152
+ {
153
+ sql: z.string().describe(
154
+ "SQL SELECT query referencing the `txns` CTE. Do not include CTE definition or transaction control statements."
155
+ )
156
+ },
157
+ async (params) => {
158
+ const result = await client.queryTransactions(params.sql);
159
+ if ("error" in result) {
160
+ return {
161
+ content: [
162
+ {
163
+ type: "text",
164
+ text: `SQL error: ${result.error}`
165
+ }
166
+ ],
167
+ isError: true
168
+ };
169
+ }
170
+ return {
171
+ content: [
172
+ {
173
+ type: "text",
174
+ text: JSON.stringify(
175
+ { rows: result.rows, rowCount: result.rowCount },
176
+ null,
177
+ 2
178
+ )
179
+ }
180
+ ]
181
+ };
182
+ }
183
+ );
117
184
  }
118
185
 
119
186
  // src/index.ts
package/openfinance.mcpb CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfinance-sh/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "openfinance-mcp": "./build/index.js"
@@ -9,7 +9,8 @@
9
9
  "dev": "tsx src/index.ts",
10
10
  "build": "tsup src/index.ts --format esm --dts --clean --outDir build",
11
11
  "start": "node build/index.js",
12
- "bundle": "pnpm build && mcpb pack . openfinance.mcpb"
12
+ "bundle": "pnpm build && mcpb pack . openfinance.mcpb",
13
+ "prepack": "pnpm run bundle"
13
14
  },
14
15
  "dependencies": {
15
16
  "@modelcontextprotocol/sdk": "^1.12.1",