@warmio/mcp 4.1.0 → 4.2.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/README.md CHANGED
@@ -16,7 +16,8 @@ npx @warmio/mcp
16
16
  ```
17
17
 
18
18
  The installer detects supported MCP clients, prompts for your Warm API key, and writes the local
19
- `stdio` server config automatically.
19
+ `stdio` server config automatically. The key is stored once in your local Warm profile instead of
20
+ being duplicated into every MCP client config.
20
21
 
21
22
  ## Requirements
22
23
 
@@ -26,28 +27,31 @@ The installer detects supported MCP clients, prompts for your Warm API key, and
26
27
 
27
28
  ## Manual `stdio` Config
28
29
 
29
- Use this shape when configuring a local MCP client manually:
30
+ The installer stores your API key in the Warm config directory and generated MCP client configs can
31
+ stay secret-free:
30
32
 
31
33
  ```json
32
34
  {
33
35
  "mcpServers": {
34
36
  "warm": {
35
37
  "command": "npx",
36
- "args": ["-y", "@warmio/mcp", "--server"],
37
- "env": {
38
- "WARM_API_KEY": "your_warm_api_key"
39
- }
38
+ "args": ["-y", "@warmio/mcp", "--server"]
40
39
  }
41
40
  }
42
41
  }
43
42
  ```
44
43
 
44
+ Optional auth overrides:
45
+
46
+ - `WARM_API_KEY`
47
+ - `WARM_API_KEY_FILE`
48
+
45
49
  ## Self-hosted Streamable HTTP
46
50
 
47
51
  Run the HTTP server locally or behind your own reverse proxy:
48
52
 
49
53
  ```bash
50
- npx @warmio/mcp http --host 0.0.0.0 --port 3000 --path /mcp
54
+ npx @warmio/mcp http --host 127.0.0.1 --port 3000 --path /mcp
51
55
  ```
52
56
 
53
57
  Environment overrides:
@@ -56,6 +60,7 @@ Environment overrides:
56
60
  - `WARM_MCP_HTTP_PORT`
57
61
  - `WARM_MCP_HTTP_PATH`
58
62
  - `WARM_MCP_ALLOWED_HOSTS`
63
+ - `WARM_API_KEY_FILE`
59
64
 
60
65
  On Windows, prefer:
61
66
 
@@ -64,10 +69,7 @@ On Windows, prefer:
64
69
  "mcpServers": {
65
70
  "warm": {
66
71
  "command": "cmd",
67
- "args": ["/c", "npx", "-y", "@warmio/mcp", "--server"],
68
- "env": {
69
- "WARM_API_KEY": "your_warm_api_key"
70
- }
72
+ "args": ["/c", "npx", "-y", "@warmio/mcp", "--server"]
71
73
  }
72
74
  }
73
75
  }
@@ -77,12 +79,12 @@ On Windows, prefer:
77
79
 
78
80
  Warm's published/documented MCP surface is the following four-tool core:
79
81
 
80
- | Tool | Description |
81
- |------|-------------|
82
- | `get_accounts` | List connected accounts with current balances |
83
- | `get_transactions` | Page through transactions with an opaque cursor |
82
+ | Tool | Description |
83
+ | --------------------- | ----------------------------------------------- |
84
+ | `get_accounts` | List connected accounts with current balances |
85
+ | `get_transactions` | Page through transactions with an opaque cursor |
84
86
  | `get_financial_state` | Return the current typed financial state bundle |
85
- | `verify_key` | Validate the configured API key |
87
+ | `verify_key` | Validate the configured API key |
86
88
 
87
89
  ## Strict Contract
88
90
 
@@ -127,7 +129,8 @@ Input:
127
129
  {
128
130
  "limit": 100,
129
131
  "cursor": "opaque-cursor-from-a-prior-page",
130
- "last_knowledge": "2026-03-11T00:00:00.000Z"
132
+ "last_knowledge": "2026-03-11T00:00:00.000Z",
133
+ "search": "coffee"
131
134
  }
132
135
  ```
133
136
 
@@ -159,7 +162,7 @@ Returns:
159
162
  Cursor model:
160
163
 
161
164
  1. Omit `cursor` on the first call.
162
- 2. Keep `limit` fixed while following a cursor chain.
165
+ 2. Keep `limit` and any filters such as `search` fixed while following a cursor chain.
163
166
  3. If `pagination.next_cursor` is non-null, pass it unchanged to fetch the next page.
164
167
  4. Stop when `next_cursor` is `null`.
165
168
  5. Do not combine `cursor` with `last_knowledge`.
@@ -229,7 +232,35 @@ Returns:
229
232
  "build": 20
230
233
  },
231
234
  "message": null
232
- }
235
+ },
236
+ "liabilities": [
237
+ {
238
+ "account_id": "acc_loan_1",
239
+ "type": "student",
240
+ "balance": 12450.22,
241
+ "apr_percentage": 5.2,
242
+ "minimum_payment": 145,
243
+ "next_payment_due_date": "2026-03-22",
244
+ "is_overdue": false
245
+ }
246
+ ],
247
+ "holdings": [
248
+ {
249
+ "account_id": "acc_inv_1",
250
+ "security_name": "Vanguard Total Stock Market ETF",
251
+ "symbol": "VTI",
252
+ "type": "etf",
253
+ "quantity": 12.5,
254
+ "value": 3541.25,
255
+ "cost_basis": 3010
256
+ }
257
+ ],
258
+ "category_spending": [
259
+ {
260
+ "category": "FOOD_AND_DRINK",
261
+ "amount": 182.55
262
+ }
263
+ ]
233
264
  }
234
265
  ```
235
266
 
@@ -0,0 +1,2 @@
1
+ export declare function getWarmConfigDir(): string;
2
+ export declare function getWarmApiKeyPath(): string;
@@ -0,0 +1,23 @@
1
+ import * as os from 'node:os';
2
+ import * as path from 'node:path';
3
+ export function getWarmConfigDir() {
4
+ if (process.env.WARM_CONFIG_DIR?.trim()) {
5
+ return process.env.WARM_CONFIG_DIR.trim();
6
+ }
7
+ if (process.platform === 'win32') {
8
+ return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Warm');
9
+ }
10
+ if (process.env.XDG_CONFIG_HOME?.trim()) {
11
+ return path.join(process.env.XDG_CONFIG_HOME.trim(), 'warm');
12
+ }
13
+ if (process.platform === 'darwin') {
14
+ return path.join(os.homedir(), 'Library', 'Application Support', 'Warm');
15
+ }
16
+ return path.join(os.homedir(), '.config', 'warm');
17
+ }
18
+ export function getWarmApiKeyPath() {
19
+ if (process.env.WARM_API_KEY_FILE?.trim()) {
20
+ return process.env.WARM_API_KEY_FILE.trim();
21
+ }
22
+ return path.join(getWarmConfigDir(), 'api_key');
23
+ }
package/dist/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js';
2
2
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
3
  import { createWarmServer } from './server.js';
4
- const DEFAULT_HTTP_HOST = '0.0.0.0';
4
+ const DEFAULT_HTTP_HOST = '127.0.0.1';
5
5
  const DEFAULT_HTTP_PORT = 3000;
6
6
  const DEFAULT_HTTP_PATH = '/mcp';
7
7
  function parsePort(value, fallback) {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ function printUsage() {
9
9
  console.log('');
10
10
  console.log(' warm-mcp [install] [--force] [--no-validate]');
11
11
  console.log(' warm-mcp stdio');
12
- console.log(' warm-mcp http [--host 0.0.0.0] [--port 3000] [--path /mcp]');
12
+ console.log(' warm-mcp http [--host 127.0.0.1] [--port 3000] [--path /mcp]');
13
13
  console.log(' [--allowed-hosts host1,host2]');
14
14
  console.log('');
15
15
  console.log(' Aliases:');
package/dist/install.js CHANGED
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
3
  import { dirname, join, resolve } from 'path';
4
4
  import { homedir, platform } from 'os';
5
5
  import { verifyWarmApiKey } from './server.js';
6
+ import { getWarmApiKeyPath } from './config-paths.js';
6
7
  const HOME = homedir();
7
8
  const CWD = process.cwd();
8
9
  function isRecord(value) {
@@ -31,7 +32,11 @@ const GLOBAL_CLIENTS = [
31
32
  configPath: join(HOME, '.codeium', 'windsurf', 'mcp_config.json'),
32
33
  format: 'json',
33
34
  },
34
- { name: 'OpenCode', configPath: join(HOME, '.config', 'opencode', 'opencode.json'), format: 'json' },
35
+ {
36
+ name: 'OpenCode',
37
+ configPath: join(HOME, '.config', 'opencode', 'opencode.json'),
38
+ format: 'json',
39
+ },
35
40
  { name: 'Codex CLI', configPath: join(HOME, '.codex', 'config.toml'), format: 'toml' },
36
41
  {
37
42
  name: 'Antigravity',
@@ -44,6 +49,7 @@ const PROJECT_CONFIGS = ['.mcp.json', '.cursor/mcp.json', '.vscode/mcp.json'];
44
49
  const MCP_CONFIG = platform() === 'win32'
45
50
  ? { command: 'cmd', args: ['/c', 'npx', '-y', '@warmio/mcp', '--server'] }
46
51
  : { command: 'npx', args: ['-y', '@warmio/mcp', '--server'] };
52
+ const WARM_API_KEY_PATH = getWarmApiKeyPath();
47
53
  function detectProjectClients() {
48
54
  const found = [];
49
55
  for (const name of PROJECT_CONFIGS) {
@@ -80,7 +86,7 @@ function isConfigured(client) {
80
86
  return false;
81
87
  }
82
88
  }
83
- function configureJson(client, apiKey) {
89
+ function configureJson(client) {
84
90
  let config = {};
85
91
  if (existsSync(client.configPath)) {
86
92
  try {
@@ -96,23 +102,25 @@ function configureJson(client, apiKey) {
96
102
  const servers = config.mcpServers;
97
103
  const existing = isRecord(servers.warm) ? servers.warm : undefined;
98
104
  const existingEnv = isRecord(existing?.env) ? existing.env : {};
105
+ const nextEnv = { ...existingEnv };
106
+ delete nextEnv.WARM_API_KEY;
99
107
  if (client.isProjectLevel && existing?.command) {
100
108
  servers.warm = {
101
109
  ...existing,
102
- env: { ...existingEnv, WARM_API_KEY: apiKey },
110
+ ...(Object.keys(nextEnv).length > 0 ? { env: nextEnv } : {}),
103
111
  };
104
112
  }
105
113
  else {
106
114
  servers.warm = {
107
115
  ...existing,
108
116
  ...MCP_CONFIG,
109
- env: { ...existingEnv, WARM_API_KEY: apiKey },
117
+ ...(Object.keys(nextEnv).length > 0 ? { env: nextEnv } : {}),
110
118
  };
111
119
  }
112
120
  mkdirSync(dirname(client.configPath), { recursive: true });
113
121
  writeFileSync(client.configPath, JSON.stringify(config, null, 2) + '\n');
114
122
  }
115
- function configureToml(client, apiKey) {
123
+ function configureToml(client) {
116
124
  let content = '';
117
125
  if (existsSync(client.configPath)) {
118
126
  content = readFileSync(client.configPath, 'utf-8');
@@ -124,7 +132,7 @@ function configureToml(client, apiKey) {
124
132
  const tomlArgs = platform() === 'win32'
125
133
  ? '["/c", "npx", "-y", "@warmio/mcp", "--server"]'
126
134
  : '["-y", "@warmio/mcp", "--server"]';
127
- const warmBlock = `[mcp_servers.warm]\ncommand = "${tomlCommand}"\nargs = ${tomlArgs}\n\n[mcp_servers.warm.env]\nWARM_API_KEY = "${apiKey}"\n`;
135
+ const warmBlock = `[mcp_servers.warm]\ncommand = "${tomlCommand}"\nargs = ${tomlArgs}\n`;
128
136
  const warmBlockPattern = /\n?\[mcp_servers\.warm\][\s\S]*?(?=\n\[[^\n]+\]|\s*$)/g;
129
137
  let nextContent = content.replace(warmBlockPattern, '').trimEnd();
130
138
  if (nextContent.length > 0) {
@@ -134,12 +142,12 @@ function configureToml(client, apiKey) {
134
142
  mkdirSync(dirname(client.configPath), { recursive: true });
135
143
  writeFileSync(client.configPath, nextContent.endsWith('\n') ? nextContent : `${nextContent}\n`);
136
144
  }
137
- function configure(client, apiKey) {
145
+ function configure(client) {
138
146
  if (client.format === 'json') {
139
- configureJson(client, apiKey);
147
+ configureJson(client);
140
148
  return;
141
149
  }
142
- configureToml(client, apiKey);
150
+ configureToml(client);
143
151
  }
144
152
  function shortPath(filePath) {
145
153
  return filePath.replace(HOME, '~').replace(CWD, '.');
@@ -185,6 +193,10 @@ async function validateApiKey(apiKey) {
185
193
  return true;
186
194
  }
187
195
  }
196
+ function storeApiKey(apiKey) {
197
+ mkdirSync(dirname(WARM_API_KEY_PATH), { recursive: true });
198
+ writeFileSync(WARM_API_KEY_PATH, `${apiKey}\n`, { mode: 0o600 });
199
+ }
188
200
  export async function install(options = {}) {
189
201
  const force = options.force ?? false;
190
202
  const shouldValidateApiKey = options.validateApiKey ?? true;
@@ -222,11 +234,12 @@ export async function install(options = {}) {
222
234
  return;
223
235
  }
224
236
  }
237
+ storeApiKey(apiKey);
225
238
  console.log(' Configuring...');
226
239
  console.log('');
227
240
  needsSetup.forEach((client) => {
228
241
  try {
229
- configure(client, apiKey);
242
+ configure(client);
230
243
  console.log(` ${client.name.padEnd(22)} done`);
231
244
  }
232
245
  catch (error) {
@@ -235,6 +248,7 @@ export async function install(options = {}) {
235
248
  }
236
249
  });
237
250
  console.log('');
251
+ console.log(` Stored API key at ${shortPath(WARM_API_KEY_PATH)}`);
238
252
  console.log(' All set! Restart your MCP clients and try:');
239
253
  console.log(' "What\'s my net worth?"');
240
254
  console.log('');
package/dist/schemas.d.ts CHANGED
@@ -41,6 +41,7 @@ export declare const getTransactionsInputSchema: z.ZodObject<{
41
41
  limit: z.ZodDefault<z.ZodInt>;
42
42
  cursor: z.ZodOptional<z.ZodString>;
43
43
  last_knowledge: z.ZodOptional<z.ZodString>;
44
+ search: z.ZodOptional<z.ZodString>;
44
45
  }, z.core.$strict>;
45
46
  export declare const transactionSchema: z.ZodObject<{
46
47
  id: z.ZodNullable<z.ZodString>;
package/dist/schemas.js CHANGED
@@ -1,16 +1,8 @@
1
1
  import * as z from 'zod/v4';
2
- const dateSchema = z
3
- .string()
4
- .regex(/^\d{4}-\d{2}-\d{2}$/, 'Expected date in YYYY-MM-DD format.');
2
+ const dateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Expected date in YYYY-MM-DD format.');
5
3
  const dateTimeSchema = z.string().datetime({ offset: true });
6
4
  export const emptyInputSchema = z.object({}).strict().default({});
7
- export const accountTypeSchema = z.enum([
8
- 'depository',
9
- 'credit',
10
- 'loan',
11
- 'investment',
12
- 'other',
13
- ]);
5
+ export const accountTypeSchema = z.enum(['depository', 'credit', 'loan', 'investment', 'other']);
14
6
  export const accountSchema = z
15
7
  .object({
16
8
  name: z.string(),
@@ -42,6 +34,12 @@ const getTransactionsInputObjectSchema = z
42
34
  last_knowledge: dateTimeSchema
43
35
  .optional()
44
36
  .describe('Incremental sync checkpoint from a prior get_transactions response. Cannot be combined with cursor.'),
37
+ search: z
38
+ .string()
39
+ .min(1)
40
+ .max(120)
41
+ .optional()
42
+ .describe('Optional merchant or description search string. Keep it unchanged while following a cursor chain.'),
45
43
  })
46
44
  .strict()
47
45
  .superRefine((value, ctx) => {
@@ -1,8 +1,7 @@
1
1
  import * as fs from 'node:fs';
2
- import * as os from 'node:os';
3
- import * as path from 'node:path';
4
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
3
  import { emptyInputSchema, getAccountsOutputSchema, getFinancialStateOutputSchema, getTransactionsInputSchema, getTransactionsOutputSchema, verifyKeyOutputSchema, } from './schemas.js';
4
+ import { getWarmApiKeyPath } from './config-paths.js';
6
5
  const DEFAULT_API_URL = process.env.WARM_API_URL || 'https://warm.io';
7
6
  const DEFAULT_REQUEST_TIMEOUT_MS = (() => {
8
7
  const raw = Number(process.env.WARM_API_TIMEOUT_MS || 10_000);
@@ -63,70 +62,6 @@ function normalizeAccount(account) {
63
62
  mask: account.mask ?? null,
64
63
  };
65
64
  }
66
- function normalizeSnapshot(snapshot) {
67
- const date = snapshot.snapshot_date || snapshot.period_end || null;
68
- if (!date) {
69
- return null;
70
- }
71
- const totalAssets = snapshot.total_assets ??
72
- (snapshot.total_cash ?? 0) + (snapshot.investment_value ?? 0) + (snapshot.asset_value ?? 0);
73
- const totalLiabilities = snapshot.total_liabilities ?? snapshot.total_debt ?? snapshot.liability_value ?? 0;
74
- return {
75
- date,
76
- net_worth: roundMoney(snapshot.net_worth ?? totalAssets - totalLiabilities),
77
- total_assets: roundMoney(totalAssets),
78
- total_liabilities: roundMoney(totalLiabilities),
79
- };
80
- }
81
- function normalizeRecurring(stream) {
82
- return {
83
- merchant: stream.merchant_name || stream.description || 'Unknown',
84
- amount: roundMoney(Math.abs(stream.average_amount ?? stream.last_amount ?? 0)),
85
- frequency: stream.frequency || 'UNKNOWN',
86
- next_date: stream.next_date ?? null,
87
- type: stream.stream_type ?? null,
88
- active: stream.is_active !== false,
89
- };
90
- }
91
- function normalizeGoal(goal) {
92
- return {
93
- name: goal.name || 'Unnamed Goal',
94
- target: roundMoney(goal.target ?? 0),
95
- current: roundMoney(goal.current ?? 0),
96
- progress_percent: roundMoney(goal.progress_percent ?? 0),
97
- target_date: goal.target_date ?? null,
98
- status: goal.status ?? null,
99
- category: goal.category ?? null,
100
- monthly_contribution_needed: goal.monthly_contribution_needed == null
101
- ? null
102
- : roundMoney(goal.monthly_contribution_needed),
103
- };
104
- }
105
- function normalizeLiability(liability) {
106
- return {
107
- account_id: liability.account_id || '',
108
- type: liability.type || 'unknown',
109
- balance: liability.balance == null ? null : roundMoney(liability.balance),
110
- apr_percentage: liability.apr_percentage ?? liability.interest_rate_percentage ?? null,
111
- minimum_payment: liability.minimum_payment == null ? null : roundMoney(liability.minimum_payment),
112
- next_payment_due_date: liability.next_payment_due_date ?? null,
113
- is_overdue: liability.is_overdue ?? null,
114
- };
115
- }
116
- function normalizeHolding(holding) {
117
- return {
118
- account_id: holding.account_id || '',
119
- security_name: holding.security_name ?? null,
120
- symbol: holding.symbol ?? null,
121
- type: holding.type ?? null,
122
- quantity: holding.quantity ?? 0,
123
- value: holding.value == null ? null : roundMoney(holding.value),
124
- cost_basis: holding.cost_basis == null ? null : roundMoney(holding.cost_basis),
125
- };
126
- }
127
- function asGeneratedAt(...values) {
128
- return values.find((value) => Boolean(value)) || new Date().toISOString();
129
- }
130
65
  function createWarmApiClientConfig(options) {
131
66
  return {
132
67
  apiUrl: options.apiUrl || DEFAULT_API_URL,
@@ -143,7 +78,7 @@ export function getConfiguredApiKey() {
143
78
  cachedApiKey = process.env.WARM_API_KEY.trim();
144
79
  return cachedApiKey;
145
80
  }
146
- const configPath = path.join(os.homedir(), '.config', 'warm', 'api_key');
81
+ const configPath = getWarmApiKeyPath();
147
82
  try {
148
83
  cachedApiKey = fs.readFileSync(configPath, 'utf-8').trim() || null;
149
84
  }
@@ -229,6 +164,7 @@ export function createWarmApiClient(options = {}) {
229
164
  limit: String(input.limit),
230
165
  cursor: input.cursor,
231
166
  last_knowledge: input.last_knowledge,
167
+ search: input.search,
232
168
  }, options);
233
169
  const nextCursor = response.pagination?.next_cursor ?? null;
234
170
  return {
@@ -251,56 +187,7 @@ export function createWarmApiClient(options = {}) {
251
187
  };
252
188
  }
253
189
  async function getFinancialState() {
254
- const [snapshotsResponse, recurringResponse, budgetsResponse, goalsResponse, healthResponse, liabilitiesResponse, holdingsResponse,] = await Promise.all([
255
- apiRequest('/api/export', { dataset: 'snapshots' }, options),
256
- apiRequest('/api/export', { dataset: 'recurring' }, options),
257
- apiRequest('/api/export', { dataset: 'budgets' }, options),
258
- apiRequest('/api/export', { dataset: 'goals' }, options),
259
- apiRequest('/api/export', { dataset: 'health' }, options),
260
- apiRequest('/api/export', { dataset: 'liabilities' }, options),
261
- apiRequest('/api/export', { dataset: 'holdings' }, options),
262
- ]);
263
- // Extract category spending from the most recent snapshot's spending_by_category
264
- const snapshots = snapshotsResponse.snapshots || [];
265
- const latestWithCategories = snapshots.find((s) => Array.isArray(s.spending_by_category));
266
- const categorySpending = (latestWithCategories?.spending_by_category || []).map((c) => ({
267
- category: c.category || 'Unknown',
268
- amount: roundMoney(Math.abs(c.amount ?? 0)),
269
- }));
270
- return {
271
- generated_at: asGeneratedAt(snapshotsResponse.generated_at, recurringResponse.generated_at, budgetsResponse.generated_at, goalsResponse.generated_at, healthResponse.generated_at),
272
- snapshots: snapshots
273
- .map(normalizeSnapshot)
274
- .filter((snapshot) => snapshot !== null),
275
- recurring: (recurringResponse.recurring_transactions || []).map(normalizeRecurring),
276
- budgets: (budgetsResponse.budgets || []).map((budget) => ({
277
- name: budget.name || 'Unnamed Budget',
278
- amount: roundMoney(budget.amount ?? 0),
279
- spent: roundMoney(budget.spent ?? 0),
280
- remaining: roundMoney(budget.remaining ?? 0),
281
- percent_used: roundMoney(budget.percent_used ?? 0),
282
- period: budget.period || 'monthly',
283
- status: budget.status ?? null,
284
- })),
285
- goals: (goalsResponse.goals || []).map(normalizeGoal),
286
- health: {
287
- score: healthResponse.score ?? null,
288
- label: healthResponse.label ?? null,
289
- data_completeness: healthResponse.data_completeness ?? null,
290
- pillars: healthResponse.pillars
291
- ? {
292
- spend: healthResponse.pillars.spend ?? null,
293
- save: healthResponse.pillars.save ?? null,
294
- borrow: healthResponse.pillars.borrow ?? null,
295
- build: healthResponse.pillars.build ?? null,
296
- }
297
- : null,
298
- message: healthResponse.message ?? null,
299
- },
300
- liabilities: (liabilitiesResponse.liabilities || []).map(normalizeLiability),
301
- holdings: (holdingsResponse.holdings || []).map(normalizeHolding),
302
- category_spending: categorySpending,
303
- };
190
+ return apiRequest('/api/financial-state', {}, options);
304
191
  }
305
192
  async function verifyKey() {
306
193
  const response = await apiRequest('/api/verify', {}, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmio/mcp",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "MCP server for Warm Financial API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",