@warmio/mcp 5.0.0 → 5.0.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/README.md +10 -7
- package/dist/install.js +2 -2
- package/dist/warm-api-client.js +7 -9
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@ Warmio is the one-command CLI and read-only MCP server for Warm financial data.
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx @warmio/mcp
|
|
8
|
+
npx -y @warmio/mcp@latest
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The installer detects supported MCP clients, prompts for your Warm API key, validates it, and
|
|
11
|
+
The installer detects supported MCP clients, prompts for your Warm API key, validates it, and
|
|
12
|
+
writes the local `stdio` MCP config automatically. The key is stored once in your local Warm
|
|
13
|
+
profile instead of being duplicated into every MCP client config.
|
|
12
14
|
|
|
13
15
|
## Requirements
|
|
14
16
|
|
|
@@ -25,7 +27,7 @@ Use this when a client asks you to paste an MCP JSON config:
|
|
|
25
27
|
"mcpServers": {
|
|
26
28
|
"warm": {
|
|
27
29
|
"command": "npx",
|
|
28
|
-
"args": ["-y", "@warmio/mcp", "mcp"]
|
|
30
|
+
"args": ["-y", "@warmio/mcp@latest", "mcp"]
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -38,7 +40,7 @@ On Windows, prefer:
|
|
|
38
40
|
"mcpServers": {
|
|
39
41
|
"warm": {
|
|
40
42
|
"command": "cmd",
|
|
41
|
-
"args": ["/c", "npx", "-y", "@warmio/mcp", "mcp"]
|
|
43
|
+
"args": ["/c", "npx", "-y", "@warmio/mcp@latest", "mcp"]
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
}
|
|
@@ -60,14 +62,15 @@ Use this MCP server config:
|
|
|
60
62
|
"mcpServers": {
|
|
61
63
|
"warm": {
|
|
62
64
|
"command": "npx",
|
|
63
|
-
"args": ["-y", "@warmio/mcp", "mcp"]
|
|
65
|
+
"args": ["-y", "@warmio/mcp@latest", "mcp"]
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
If this app supports MCP configuration, add a server named "warm" with that command.
|
|
69
71
|
|
|
70
|
-
Do not ask me to paste my Warm API key into this chat. Help me store it locally using Warm's setup
|
|
72
|
+
Do not ask me to paste my Warm API key into this chat. Help me store it locally using Warm's setup
|
|
73
|
+
flow, then test the connection by calling Warm's verify_key tool.
|
|
71
74
|
|
|
72
75
|
After setup, I should be able to ask:
|
|
73
76
|
- What’s my net worth?
|
|
@@ -81,7 +84,7 @@ After setup, I should be able to ask:
|
|
|
81
84
|
If your MCP client supports Streamable HTTP, you can run:
|
|
82
85
|
|
|
83
86
|
```bash
|
|
84
|
-
npx -y @warmio/mcp http --host 127.0.0.1 --port 3000 --path /mcp
|
|
87
|
+
npx -y @warmio/mcp@latest http --host 127.0.0.1 --port 3000 --path /mcp
|
|
85
88
|
```
|
|
86
89
|
|
|
87
90
|
Relevant optional environment variables:
|
package/dist/install.js
CHANGED
|
@@ -46,7 +46,7 @@ const GLOBAL_CLIENTS = [
|
|
|
46
46
|
{ name: 'Gemini CLI', configPath: join(HOME, '.gemini', 'settings.json'), format: 'json' },
|
|
47
47
|
];
|
|
48
48
|
const PROJECT_CONFIGS = ['.mcp.json', '.cursor/mcp.json', '.vscode/mcp.json'];
|
|
49
|
-
const MCP_PACKAGE_SPEC = '@warmio/mcp';
|
|
49
|
+
const MCP_PACKAGE_SPEC = '@warmio/mcp@latest';
|
|
50
50
|
const MCP_CONFIG = platform() === 'win32'
|
|
51
51
|
? { command: 'cmd', args: ['/c', 'npx', '-y', MCP_PACKAGE_SPEC, 'mcp'] }
|
|
52
52
|
: { command: 'npx', args: ['-y', MCP_PACKAGE_SPEC, 'mcp'] };
|
|
@@ -81,7 +81,7 @@ function getStringArray(value) {
|
|
|
81
81
|
return value.filter((entry) => typeof entry === 'string');
|
|
82
82
|
}
|
|
83
83
|
function isWarmPackageSpecifier(value) {
|
|
84
|
-
return /^@warmio\/
|
|
84
|
+
return /^@warmio\/mcp(?:@.+)?$/.test(value);
|
|
85
85
|
}
|
|
86
86
|
function isSupportedWarmInvocation(command, args) {
|
|
87
87
|
if (command !== 'npx' && command !== 'cmd') {
|
package/dist/warm-api-client.js
CHANGED
|
@@ -4,7 +4,6 @@ const DEFAULT_REQUEST_TIMEOUT_MS = (() => {
|
|
|
4
4
|
const raw = Number(process.env.WARM_API_TIMEOUT_MS || 10_000);
|
|
5
5
|
return Number.isFinite(raw) && raw > 0 ? raw : 10_000;
|
|
6
6
|
})();
|
|
7
|
-
const DEFAULT_SPENDING_MONTHS = 6;
|
|
8
7
|
let cachedApiKey;
|
|
9
8
|
function roundMoney(value) {
|
|
10
9
|
return Math.round(value * 100) / 100;
|
|
@@ -56,6 +55,8 @@ function normalizeAccounts(accounts) {
|
|
|
56
55
|
};
|
|
57
56
|
}
|
|
58
57
|
function normalizeFinancialState(input) {
|
|
58
|
+
const latestSnapshot = input.snapshots?.[0];
|
|
59
|
+
const categorySpending = latestSnapshot?.spending_by_category ?? [];
|
|
59
60
|
return {
|
|
60
61
|
budgets: (input.budgets || []).map((budget) => ({
|
|
61
62
|
amount: budget.amount ?? 0,
|
|
@@ -66,8 +67,8 @@ function normalizeFinancialState(input) {
|
|
|
66
67
|
spent: budget.spent ?? 0,
|
|
67
68
|
status: budget.status ?? null,
|
|
68
69
|
})),
|
|
69
|
-
category_spending:
|
|
70
|
-
amount: roundMoney(item?.total ?? 0),
|
|
70
|
+
category_spending: categorySpending.map((item) => ({
|
|
71
|
+
amount: roundMoney(item?.amount ?? item?.total ?? 0),
|
|
71
72
|
category: item?.category || 'Uncategorized',
|
|
72
73
|
})),
|
|
73
74
|
generated_at: input.generatedAt,
|
|
@@ -193,7 +194,7 @@ export async function apiRequest(endpoint, params = {}, options = {}) {
|
|
|
193
194
|
if (!response.ok) {
|
|
194
195
|
const errorMessages = {
|
|
195
196
|
401: 'Invalid or expired API key. Regenerate at https://warm.io/settings',
|
|
196
|
-
403: '
|
|
197
|
+
403: 'API access is available on paid plans only. Upgrade at https://warm.io/settings',
|
|
197
198
|
429: 'Rate limit exceeded. Try again in a few minutes.',
|
|
198
199
|
};
|
|
199
200
|
if (errorMessages[response.status]) {
|
|
@@ -219,7 +220,7 @@ export function createWarmApiClient(options = {}) {
|
|
|
219
220
|
return normalizeAccounts(response.accounts || []);
|
|
220
221
|
};
|
|
221
222
|
const getFinancialState = async () => {
|
|
222
|
-
const [snapshotsResponse, recurringResponse, budgetsResponse, goalsResponse, healthResponse, liabilitiesResponse, holdingsResponse,
|
|
223
|
+
const [snapshotsResponse, recurringResponse, budgetsResponse, goalsResponse, healthResponse, liabilitiesResponse, holdingsResponse,] = await Promise.all([
|
|
223
224
|
apiRequest('/api/export', { dataset: 'snapshots' }, options),
|
|
224
225
|
apiRequest('/api/export', { dataset: 'recurring' }, options),
|
|
225
226
|
apiRequest('/api/export', { dataset: 'budgets' }, options),
|
|
@@ -227,10 +228,8 @@ export function createWarmApiClient(options = {}) {
|
|
|
227
228
|
apiRequest('/api/export', { dataset: 'health' }, options),
|
|
228
229
|
apiRequest('/api/export', { dataset: 'liabilities' }, options),
|
|
229
230
|
apiRequest('/api/export', { dataset: 'holdings' }, options),
|
|
230
|
-
apiRequest('/api/spending', { months: String(DEFAULT_SPENDING_MONTHS) }, options),
|
|
231
231
|
]);
|
|
232
|
-
const generatedAt =
|
|
233
|
-
holdingsResponse.generated_at ||
|
|
232
|
+
const generatedAt = holdingsResponse.generated_at ||
|
|
234
233
|
liabilitiesResponse.generated_at ||
|
|
235
234
|
healthResponse.generated_at ||
|
|
236
235
|
goalsResponse.generated_at ||
|
|
@@ -240,7 +239,6 @@ export function createWarmApiClient(options = {}) {
|
|
|
240
239
|
new Date().toISOString();
|
|
241
240
|
return normalizeFinancialState({
|
|
242
241
|
budgets: budgetsResponse.budgets,
|
|
243
|
-
categorySpending: spendingResponse.spending,
|
|
244
242
|
generatedAt,
|
|
245
243
|
goals: goalsResponse.goals,
|
|
246
244
|
health: healthResponse,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warmio/mcp",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "Warm CLI and MCP server for personal financial data",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc",
|
|
37
|
+
"test": "npm run build && node --test test/*.mjs",
|
|
37
38
|
"start": "node dist/index.js mcp",
|
|
38
39
|
"start:http": "node dist/index.js http",
|
|
39
40
|
"start:install": "node dist/index.js install",
|