@codespar/mcp-open-finance 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.
package/dist/index.js ADDED
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Server for Open Finance Brasil — open banking standard.
4
+ *
5
+ * Tools:
6
+ * - list_accounts: List customer accounts
7
+ * - get_account_balance: Get account balance
8
+ * - list_transactions: List account transactions
9
+ * - get_consent: Get consent details
10
+ * - create_consent: Create a new consent request
11
+ * - list_credit_cards: List credit card accounts
12
+ * - get_credit_card_transactions: Get credit card transactions
13
+ * - list_investments: List investment products
14
+ *
15
+ * Environment:
16
+ * OPEN_FINANCE_BASE_URL — Institution API base URL
17
+ * OPEN_FINANCE_CLIENT_ID — OAuth2 client ID
18
+ * OPEN_FINANCE_CLIENT_SECRET — OAuth2 client secret
19
+ */
20
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
23
+ const BASE_URL = process.env.OPEN_FINANCE_BASE_URL || "";
24
+ const CLIENT_ID = process.env.OPEN_FINANCE_CLIENT_ID || "";
25
+ const CLIENT_SECRET = process.env.OPEN_FINANCE_CLIENT_SECRET || "";
26
+ let accessToken = "";
27
+ let tokenExpiry = 0;
28
+ async function getAccessToken() {
29
+ if (accessToken && Date.now() < tokenExpiry)
30
+ return accessToken;
31
+ const res = await fetch(`${BASE_URL}/auth/token`, {
32
+ method: "POST",
33
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
34
+ body: new URLSearchParams({
35
+ grant_type: "client_credentials",
36
+ client_id: CLIENT_ID,
37
+ client_secret: CLIENT_SECRET,
38
+ scope: "openid accounts credit-cards-accounts resources consents investments",
39
+ }),
40
+ });
41
+ if (!res.ok) {
42
+ const err = await res.text();
43
+ throw new Error(`Open Finance OAuth ${res.status}: ${err}`);
44
+ }
45
+ const data = await res.json();
46
+ accessToken = data.access_token;
47
+ tokenExpiry = Date.now() + (data.expires_in - 60) * 1000;
48
+ return accessToken;
49
+ }
50
+ async function openFinanceRequest(method, path, body) {
51
+ const token = await getAccessToken();
52
+ const res = await fetch(`${BASE_URL}${path}`, {
53
+ method,
54
+ headers: {
55
+ "Content-Type": "application/json",
56
+ "Authorization": `Bearer ${token}`,
57
+ },
58
+ body: body ? JSON.stringify(body) : undefined,
59
+ });
60
+ if (!res.ok) {
61
+ const err = await res.text();
62
+ throw new Error(`Open Finance API ${res.status}: ${err}`);
63
+ }
64
+ return res.json();
65
+ }
66
+ const server = new Server({ name: "mcp-open-finance", version: "0.1.0" }, { capabilities: { tools: {} } });
67
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
68
+ tools: [
69
+ {
70
+ name: "list_accounts",
71
+ description: "List customer bank accounts via Open Finance",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ consentId: { type: "string", description: "Consent ID (required for data access)" },
76
+ page: { type: "number", description: "Page number" },
77
+ pageSize: { type: "number", description: "Items per page" },
78
+ },
79
+ required: ["consentId"],
80
+ },
81
+ },
82
+ {
83
+ name: "get_account_balance",
84
+ description: "Get account balance via Open Finance",
85
+ inputSchema: {
86
+ type: "object",
87
+ properties: {
88
+ consentId: { type: "string", description: "Consent ID" },
89
+ accountId: { type: "string", description: "Account ID" },
90
+ },
91
+ required: ["consentId", "accountId"],
92
+ },
93
+ },
94
+ {
95
+ name: "list_transactions",
96
+ description: "List account transactions via Open Finance",
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {
100
+ consentId: { type: "string", description: "Consent ID" },
101
+ accountId: { type: "string", description: "Account ID" },
102
+ fromDate: { type: "string", description: "Start date (YYYY-MM-DD)" },
103
+ toDate: { type: "string", description: "End date (YYYY-MM-DD)" },
104
+ page: { type: "number", description: "Page number" },
105
+ pageSize: { type: "number", description: "Items per page" },
106
+ },
107
+ required: ["consentId", "accountId"],
108
+ },
109
+ },
110
+ {
111
+ name: "get_consent",
112
+ description: "Get consent details by ID",
113
+ inputSchema: {
114
+ type: "object",
115
+ properties: {
116
+ consentId: { type: "string", description: "Consent ID" },
117
+ },
118
+ required: ["consentId"],
119
+ },
120
+ },
121
+ {
122
+ name: "create_consent",
123
+ description: "Create a new consent request for data access",
124
+ inputSchema: {
125
+ type: "object",
126
+ properties: {
127
+ permissions: {
128
+ type: "array",
129
+ description: "Requested permissions (e.g., ACCOUNTS_READ, ACCOUNTS_BALANCES_READ, ACCOUNTS_TRANSACTIONS_READ)",
130
+ items: { type: "string" },
131
+ },
132
+ expirationDateTime: { type: "string", description: "Consent expiration (ISO 8601)" },
133
+ transactionFromDateTime: { type: "string", description: "Transaction data start (ISO 8601)" },
134
+ transactionToDateTime: { type: "string", description: "Transaction data end (ISO 8601)" },
135
+ },
136
+ required: ["permissions", "expirationDateTime"],
137
+ },
138
+ },
139
+ {
140
+ name: "list_credit_cards",
141
+ description: "List credit card accounts via Open Finance",
142
+ inputSchema: {
143
+ type: "object",
144
+ properties: {
145
+ consentId: { type: "string", description: "Consent ID" },
146
+ page: { type: "number", description: "Page number" },
147
+ pageSize: { type: "number", description: "Items per page" },
148
+ },
149
+ required: ["consentId"],
150
+ },
151
+ },
152
+ {
153
+ name: "get_credit_card_transactions",
154
+ description: "Get credit card transactions via Open Finance",
155
+ inputSchema: {
156
+ type: "object",
157
+ properties: {
158
+ consentId: { type: "string", description: "Consent ID" },
159
+ creditCardAccountId: { type: "string", description: "Credit card account ID" },
160
+ fromDate: { type: "string", description: "Start date (YYYY-MM-DD)" },
161
+ toDate: { type: "string", description: "End date (YYYY-MM-DD)" },
162
+ page: { type: "number", description: "Page number" },
163
+ pageSize: { type: "number", description: "Items per page" },
164
+ },
165
+ required: ["consentId", "creditCardAccountId"],
166
+ },
167
+ },
168
+ {
169
+ name: "list_investments",
170
+ description: "List investment products via Open Finance",
171
+ inputSchema: {
172
+ type: "object",
173
+ properties: {
174
+ consentId: { type: "string", description: "Consent ID" },
175
+ investmentType: { type: "string", enum: ["BANK_FIXED_INCOMES", "CREDIT_FIXED_INCOMES", "VARIABLE_INCOMES", "TREASURE_TITLES", "FUNDS"], description: "Investment type filter" },
176
+ page: { type: "number", description: "Page number" },
177
+ pageSize: { type: "number", description: "Items per page" },
178
+ },
179
+ required: ["consentId"],
180
+ },
181
+ },
182
+ ],
183
+ }));
184
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
185
+ const { name, arguments: args } = request.params;
186
+ try {
187
+ switch (name) {
188
+ case "list_accounts": {
189
+ const params = new URLSearchParams();
190
+ if (args?.page)
191
+ params.set("page", String(args.page));
192
+ if (args?.pageSize)
193
+ params.set("page-size", String(args.pageSize));
194
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts?${params}`), null, 2) }] };
195
+ }
196
+ case "get_account_balance":
197
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts/${args?.accountId}/balances`), null, 2) }] };
198
+ case "list_transactions": {
199
+ const params = new URLSearchParams();
200
+ if (args?.fromDate)
201
+ params.set("fromBookingDate", String(args.fromDate));
202
+ if (args?.toDate)
203
+ params.set("toBookingDate", String(args.toDate));
204
+ if (args?.page)
205
+ params.set("page", String(args.page));
206
+ if (args?.pageSize)
207
+ params.set("page-size", String(args.pageSize));
208
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts/${args?.accountId}/transactions?${params}`), null, 2) }] };
209
+ }
210
+ case "get_consent":
211
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/consents/v2/consents/${args?.consentId}`), null, 2) }] };
212
+ case "create_consent": {
213
+ const payload = {
214
+ data: {
215
+ permissions: args?.permissions,
216
+ expirationDateTime: args?.expirationDateTime,
217
+ transactionFromDateTime: args?.transactionFromDateTime,
218
+ transactionToDateTime: args?.transactionToDateTime,
219
+ },
220
+ };
221
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("POST", "/open-banking/consents/v2/consents", payload), null, 2) }] };
222
+ }
223
+ case "list_credit_cards": {
224
+ const params = new URLSearchParams();
225
+ if (args?.page)
226
+ params.set("page", String(args.page));
227
+ if (args?.pageSize)
228
+ params.set("page-size", String(args.pageSize));
229
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/credit-cards-accounts/v2/accounts?${params}`), null, 2) }] };
230
+ }
231
+ case "get_credit_card_transactions": {
232
+ const params = new URLSearchParams();
233
+ if (args?.fromDate)
234
+ params.set("fromTransactionDate", String(args.fromDate));
235
+ if (args?.toDate)
236
+ params.set("toTransactionDate", String(args.toDate));
237
+ if (args?.page)
238
+ params.set("page", String(args.page));
239
+ if (args?.pageSize)
240
+ params.set("page-size", String(args.pageSize));
241
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/credit-cards-accounts/v2/accounts/${args?.creditCardAccountId}/transactions?${params}`), null, 2) }] };
242
+ }
243
+ case "list_investments": {
244
+ const investmentType = args?.investmentType || "BANK_FIXED_INCOMES";
245
+ const params = new URLSearchParams();
246
+ if (args?.page)
247
+ params.set("page", String(args.page));
248
+ if (args?.pageSize)
249
+ params.set("page-size", String(args.pageSize));
250
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/investments/v1/${investmentType.toLowerCase().replace(/_/g, "-")}?${params}`), null, 2) }] };
251
+ }
252
+ default:
253
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
254
+ }
255
+ }
256
+ catch (err) {
257
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
258
+ }
259
+ });
260
+ async function main() {
261
+ if (!BASE_URL || !CLIENT_ID || !CLIENT_SECRET) {
262
+ console.error("OPEN_FINANCE_BASE_URL, OPEN_FINANCE_CLIENT_ID, and OPEN_FINANCE_CLIENT_SECRET environment variables are required");
263
+ process.exit(1);
264
+ }
265
+ const transport = new StdioServerTransport();
266
+ await server.connect(transport);
267
+ }
268
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@codespar/mcp-open-finance",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Open Finance Brasil — accounts, transactions, consents, investments",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "mcp-open-finance": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^25.5.0",
19
+ "typescript": "^5.8.0"
20
+ },
21
+ "license": "MIT",
22
+ "keywords": [
23
+ "mcp",
24
+ "open-finance",
25
+ "banking",
26
+ "pix",
27
+ "accounts",
28
+ "brazil"
29
+ ]
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP Server for Open Finance Brasil — open banking standard.
5
+ *
6
+ * Tools:
7
+ * - list_accounts: List customer accounts
8
+ * - get_account_balance: Get account balance
9
+ * - list_transactions: List account transactions
10
+ * - get_consent: Get consent details
11
+ * - create_consent: Create a new consent request
12
+ * - list_credit_cards: List credit card accounts
13
+ * - get_credit_card_transactions: Get credit card transactions
14
+ * - list_investments: List investment products
15
+ *
16
+ * Environment:
17
+ * OPEN_FINANCE_BASE_URL — Institution API base URL
18
+ * OPEN_FINANCE_CLIENT_ID — OAuth2 client ID
19
+ * OPEN_FINANCE_CLIENT_SECRET — OAuth2 client secret
20
+ */
21
+
22
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
23
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
+ import {
25
+ CallToolRequestSchema,
26
+ ListToolsRequestSchema,
27
+ } from "@modelcontextprotocol/sdk/types.js";
28
+
29
+ const BASE_URL = process.env.OPEN_FINANCE_BASE_URL || "";
30
+ const CLIENT_ID = process.env.OPEN_FINANCE_CLIENT_ID || "";
31
+ const CLIENT_SECRET = process.env.OPEN_FINANCE_CLIENT_SECRET || "";
32
+
33
+ let accessToken = "";
34
+ let tokenExpiry = 0;
35
+
36
+ async function getAccessToken(): Promise<string> {
37
+ if (accessToken && Date.now() < tokenExpiry) return accessToken;
38
+
39
+ const res = await fetch(`${BASE_URL}/auth/token`, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
42
+ body: new URLSearchParams({
43
+ grant_type: "client_credentials",
44
+ client_id: CLIENT_ID,
45
+ client_secret: CLIENT_SECRET,
46
+ scope: "openid accounts credit-cards-accounts resources consents investments",
47
+ }),
48
+ });
49
+ if (!res.ok) {
50
+ const err = await res.text();
51
+ throw new Error(`Open Finance OAuth ${res.status}: ${err}`);
52
+ }
53
+ const data = await res.json() as { access_token: string; expires_in: number };
54
+ accessToken = data.access_token;
55
+ tokenExpiry = Date.now() + (data.expires_in - 60) * 1000;
56
+ return accessToken;
57
+ }
58
+
59
+ async function openFinanceRequest(method: string, path: string, body?: unknown): Promise<unknown> {
60
+ const token = await getAccessToken();
61
+ const res = await fetch(`${BASE_URL}${path}`, {
62
+ method,
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ "Authorization": `Bearer ${token}`,
66
+ },
67
+ body: body ? JSON.stringify(body) : undefined,
68
+ });
69
+ if (!res.ok) {
70
+ const err = await res.text();
71
+ throw new Error(`Open Finance API ${res.status}: ${err}`);
72
+ }
73
+ return res.json();
74
+ }
75
+
76
+ const server = new Server(
77
+ { name: "mcp-open-finance", version: "0.1.0" },
78
+ { capabilities: { tools: {} } }
79
+ );
80
+
81
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
82
+ tools: [
83
+ {
84
+ name: "list_accounts",
85
+ description: "List customer bank accounts via Open Finance",
86
+ inputSchema: {
87
+ type: "object",
88
+ properties: {
89
+ consentId: { type: "string", description: "Consent ID (required for data access)" },
90
+ page: { type: "number", description: "Page number" },
91
+ pageSize: { type: "number", description: "Items per page" },
92
+ },
93
+ required: ["consentId"],
94
+ },
95
+ },
96
+ {
97
+ name: "get_account_balance",
98
+ description: "Get account balance via Open Finance",
99
+ inputSchema: {
100
+ type: "object",
101
+ properties: {
102
+ consentId: { type: "string", description: "Consent ID" },
103
+ accountId: { type: "string", description: "Account ID" },
104
+ },
105
+ required: ["consentId", "accountId"],
106
+ },
107
+ },
108
+ {
109
+ name: "list_transactions",
110
+ description: "List account transactions via Open Finance",
111
+ inputSchema: {
112
+ type: "object",
113
+ properties: {
114
+ consentId: { type: "string", description: "Consent ID" },
115
+ accountId: { type: "string", description: "Account ID" },
116
+ fromDate: { type: "string", description: "Start date (YYYY-MM-DD)" },
117
+ toDate: { type: "string", description: "End date (YYYY-MM-DD)" },
118
+ page: { type: "number", description: "Page number" },
119
+ pageSize: { type: "number", description: "Items per page" },
120
+ },
121
+ required: ["consentId", "accountId"],
122
+ },
123
+ },
124
+ {
125
+ name: "get_consent",
126
+ description: "Get consent details by ID",
127
+ inputSchema: {
128
+ type: "object",
129
+ properties: {
130
+ consentId: { type: "string", description: "Consent ID" },
131
+ },
132
+ required: ["consentId"],
133
+ },
134
+ },
135
+ {
136
+ name: "create_consent",
137
+ description: "Create a new consent request for data access",
138
+ inputSchema: {
139
+ type: "object",
140
+ properties: {
141
+ permissions: {
142
+ type: "array",
143
+ description: "Requested permissions (e.g., ACCOUNTS_READ, ACCOUNTS_BALANCES_READ, ACCOUNTS_TRANSACTIONS_READ)",
144
+ items: { type: "string" },
145
+ },
146
+ expirationDateTime: { type: "string", description: "Consent expiration (ISO 8601)" },
147
+ transactionFromDateTime: { type: "string", description: "Transaction data start (ISO 8601)" },
148
+ transactionToDateTime: { type: "string", description: "Transaction data end (ISO 8601)" },
149
+ },
150
+ required: ["permissions", "expirationDateTime"],
151
+ },
152
+ },
153
+ {
154
+ name: "list_credit_cards",
155
+ description: "List credit card accounts via Open Finance",
156
+ inputSchema: {
157
+ type: "object",
158
+ properties: {
159
+ consentId: { type: "string", description: "Consent ID" },
160
+ page: { type: "number", description: "Page number" },
161
+ pageSize: { type: "number", description: "Items per page" },
162
+ },
163
+ required: ["consentId"],
164
+ },
165
+ },
166
+ {
167
+ name: "get_credit_card_transactions",
168
+ description: "Get credit card transactions via Open Finance",
169
+ inputSchema: {
170
+ type: "object",
171
+ properties: {
172
+ consentId: { type: "string", description: "Consent ID" },
173
+ creditCardAccountId: { type: "string", description: "Credit card account ID" },
174
+ fromDate: { type: "string", description: "Start date (YYYY-MM-DD)" },
175
+ toDate: { type: "string", description: "End date (YYYY-MM-DD)" },
176
+ page: { type: "number", description: "Page number" },
177
+ pageSize: { type: "number", description: "Items per page" },
178
+ },
179
+ required: ["consentId", "creditCardAccountId"],
180
+ },
181
+ },
182
+ {
183
+ name: "list_investments",
184
+ description: "List investment products via Open Finance",
185
+ inputSchema: {
186
+ type: "object",
187
+ properties: {
188
+ consentId: { type: "string", description: "Consent ID" },
189
+ investmentType: { type: "string", enum: ["BANK_FIXED_INCOMES", "CREDIT_FIXED_INCOMES", "VARIABLE_INCOMES", "TREASURE_TITLES", "FUNDS"], description: "Investment type filter" },
190
+ page: { type: "number", description: "Page number" },
191
+ pageSize: { type: "number", description: "Items per page" },
192
+ },
193
+ required: ["consentId"],
194
+ },
195
+ },
196
+ ],
197
+ }));
198
+
199
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
200
+ const { name, arguments: args } = request.params;
201
+
202
+ try {
203
+ switch (name) {
204
+ case "list_accounts": {
205
+ const params = new URLSearchParams();
206
+ if (args?.page) params.set("page", String(args.page));
207
+ if (args?.pageSize) params.set("page-size", String(args.pageSize));
208
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts?${params}`), null, 2) }] };
209
+ }
210
+ case "get_account_balance":
211
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts/${args?.accountId}/balances`), null, 2) }] };
212
+ case "list_transactions": {
213
+ const params = new URLSearchParams();
214
+ if (args?.fromDate) params.set("fromBookingDate", String(args.fromDate));
215
+ if (args?.toDate) params.set("toBookingDate", String(args.toDate));
216
+ if (args?.page) params.set("page", String(args.page));
217
+ if (args?.pageSize) params.set("page-size", String(args.pageSize));
218
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/accounts/v2/accounts/${args?.accountId}/transactions?${params}`), null, 2) }] };
219
+ }
220
+ case "get_consent":
221
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/consents/v2/consents/${args?.consentId}`), null, 2) }] };
222
+ case "create_consent": {
223
+ const payload = {
224
+ data: {
225
+ permissions: args?.permissions,
226
+ expirationDateTime: args?.expirationDateTime,
227
+ transactionFromDateTime: args?.transactionFromDateTime,
228
+ transactionToDateTime: args?.transactionToDateTime,
229
+ },
230
+ };
231
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("POST", "/open-banking/consents/v2/consents", payload), null, 2) }] };
232
+ }
233
+ case "list_credit_cards": {
234
+ const params = new URLSearchParams();
235
+ if (args?.page) params.set("page", String(args.page));
236
+ if (args?.pageSize) params.set("page-size", String(args.pageSize));
237
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/credit-cards-accounts/v2/accounts?${params}`), null, 2) }] };
238
+ }
239
+ case "get_credit_card_transactions": {
240
+ const params = new URLSearchParams();
241
+ if (args?.fromDate) params.set("fromTransactionDate", String(args.fromDate));
242
+ if (args?.toDate) params.set("toTransactionDate", String(args.toDate));
243
+ if (args?.page) params.set("page", String(args.page));
244
+ if (args?.pageSize) params.set("page-size", String(args.pageSize));
245
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/credit-cards-accounts/v2/accounts/${args?.creditCardAccountId}/transactions?${params}`), null, 2) }] };
246
+ }
247
+ case "list_investments": {
248
+ const investmentType = args?.investmentType || "BANK_FIXED_INCOMES";
249
+ const params = new URLSearchParams();
250
+ if (args?.page) params.set("page", String(args.page));
251
+ if (args?.pageSize) params.set("page-size", String(args.pageSize));
252
+ return { content: [{ type: "text", text: JSON.stringify(await openFinanceRequest("GET", `/open-banking/investments/v1/${investmentType.toLowerCase().replace(/_/g, "-")}?${params}`), null, 2) }] };
253
+ }
254
+ default:
255
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
256
+ }
257
+ } catch (err) {
258
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
259
+ }
260
+ });
261
+
262
+ async function main() {
263
+ if (!BASE_URL || !CLIENT_ID || !CLIENT_SECRET) {
264
+ console.error("OPEN_FINANCE_BASE_URL, OPEN_FINANCE_CLIENT_ID, and OPEN_FINANCE_CLIENT_SECRET environment variables are required");
265
+ process.exit(1);
266
+ }
267
+ const transport = new StdioServerTransport();
268
+ await server.connect(transport);
269
+ }
270
+
271
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "declaration": true
11
+ },
12
+ "include": ["src"]
13
+ }