@warmio/mcp 10.0.0 → 11.0.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 +8 -318
- package/dist/config-paths.d.ts +2 -2
- package/dist/config-paths.d.ts.map +1 -0
- package/dist/config-paths.js +12 -16
- package/dist/config-paths.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -206
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +17 -3
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +262 -492
- package/dist/install.js.map +1 -0
- package/dist/load-env.d.ts +1 -0
- package/dist/load-env.d.ts.map +1 -0
- package/dist/load-env.js +6 -23
- package/dist/load-env.js.map +1 -0
- package/dist/server.d.ts +10 -8
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +76 -105
- package/dist/server.js.map +1 -0
- package/dist/warm-api-client.d.ts +17 -30
- package/dist/warm-api-client.d.ts.map +1 -0
- package/dist/warm-api-client.js +118 -180
- package/dist/warm-api-client.js.map +1 -0
- package/package.json +9 -16
- package/dist/http.d.ts +0 -14
- package/dist/http.js +0 -154
- package/dist/schemas.d.ts +0 -2
- package/dist/schemas.js +0 -2
- package/dist/stdio.d.ts +0 -29
- package/dist/stdio.js +0 -200
- package/dist/types.d.ts +0 -8
- package/dist/types.js +0 -8
- package/dist/warm-server.d.ts +0 -2
- package/dist/warm-server.js +0 -2
package/README.md
CHANGED
|
@@ -1,325 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @warmio/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@warmio/mcp` is Warm's local stdio MCP server. Run the interactive installer to validate and store one full-access `WARM_API_KEY`, then configure detected supported clients:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx -y @warmio/mcp@latest
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
The installer detects supported MCP clients, prompts for a mode-specific Warm API key, validates
|
|
12
|
-
its audience, and writes the local `stdio` MCP config automatically. Context and automation keys
|
|
13
|
-
are stored separately and are never shared between modes.
|
|
14
|
-
|
|
15
|
-
## Requirements
|
|
16
|
-
|
|
17
|
-
- Any paid Warm plan (Plus or Pro)
|
|
18
|
-
- A context key or an automation key from [Settings -> API Keys](https://warm.io/settings)
|
|
19
|
-
- Node.js 18+
|
|
20
|
-
|
|
21
|
-
## Manual MCP Config
|
|
22
|
-
|
|
23
|
-
Context is the default read-only mode. Install it with its own key:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npx -y @warmio/mcp@latest install --mode context
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Use this when a client asks you to paste a context MCP JSON config:
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"mcpServers": {
|
|
34
|
-
"warm": {
|
|
35
|
-
"command": "npx",
|
|
36
|
-
"args": ["-y", "@warmio/mcp@latest", "mcp", "--mode", "context"]
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
5
|
+
```sh
|
|
6
|
+
npx -y @warmio/mcp@latest install
|
|
40
7
|
```
|
|
41
8
|
|
|
42
|
-
|
|
9
|
+
Each client starts the server with:
|
|
43
10
|
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
"mcpServers": {
|
|
47
|
-
"warm": {
|
|
48
|
-
"command": "cmd",
|
|
49
|
-
"args": ["/c", "npx", "-y", "@warmio/mcp@latest", "mcp", "--mode", "context"]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
11
|
+
```sh
|
|
12
|
+
npx -y @warmio/mcp@latest mcp
|
|
53
13
|
```
|
|
54
14
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- `WARM_CONTEXT_API_KEY`
|
|
58
|
-
- `WARM_CONTEXT_API_KEY_FILE`
|
|
59
|
-
|
|
60
|
-
Automation is intentionally opt-in and must use a distinct automation key:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
npx -y @warmio/mcp@latest install --mode automation
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
{
|
|
68
|
-
"mcpServers": {
|
|
69
|
-
"warm-automation": {
|
|
70
|
-
"command": "npx",
|
|
71
|
-
"args": ["-y", "@warmio/mcp@latest", "mcp", "--mode", "automation"]
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Automation credential overrides are `WARM_AUTOMATION_API_KEY` and
|
|
78
|
-
`WARM_AUTOMATION_API_KEY_FILE`. The default key files are `${WARM_CONFIG_DIR}/context_api_key`
|
|
79
|
-
and `${WARM_CONFIG_DIR}/automation_api_key`; `WARM_API_KEY` and `WARM_API_KEY_FILE` are not read.
|
|
80
|
-
The API verifies the key audience before every MCP tool call, so a context key cannot operate the
|
|
81
|
-
automation server and an automation key cannot operate the context server.
|
|
82
|
-
|
|
83
|
-
Installer validation fails closed for API responses `401` and `403`. A `429` rate limit or a
|
|
84
|
-
temporary network failure remains a soft validation failure so setup can finish; the MCP server
|
|
85
|
-
will still validate the key audience before serving tools.
|
|
86
|
-
|
|
87
|
-
Both modes send API requests to `https://app.warm.io` by default. Set `WARM_API_URL` only when an
|
|
88
|
-
explicit API base URL override is required.
|
|
89
|
-
|
|
90
|
-
## Universal Copy/Paste Setup Prompt
|
|
91
|
-
|
|
92
|
-
```text
|
|
93
|
-
I want to connect Warm to this AI app using MCP.
|
|
94
|
-
|
|
95
|
-
Use this MCP server config:
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
"mcpServers": {
|
|
99
|
-
"warm": {
|
|
100
|
-
"command": "npx",
|
|
101
|
-
"args": ["-y", "@warmio/mcp@latest", "mcp", "--mode", "context"]
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
If this app supports MCP configuration, add a server named "warm" with that command.
|
|
107
|
-
|
|
108
|
-
Do not ask me to paste my Warm API key into this chat. Help me store it locally using Warm's setup
|
|
109
|
-
flow, then test the connection by calling Warm's verify_key tool.
|
|
110
|
-
|
|
111
|
-
After setup, I should be able to ask:
|
|
112
|
-
- What is my net worth?
|
|
113
|
-
- Summarize my recent transactions.
|
|
114
|
-
- What changed recently?
|
|
115
|
-
- What recurring charges do I have?
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## CLI
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
npx -y @warmio/mcp@latest context get
|
|
122
|
-
npx -y @warmio/mcp@latest context meta
|
|
123
|
-
npx -y @warmio/mcp@latest transactions get --month 2026-07
|
|
124
|
-
npx -y @warmio/mcp@latest transactions get --latest
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
All CLI read commands print JSON.
|
|
128
|
-
|
|
129
|
-
## Optional Streamable HTTP
|
|
130
|
-
|
|
131
|
-
If your MCP client supports Streamable HTTP, you can run:
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
npx -y @warmio/mcp@latest http --mode context --host 127.0.0.1 --port 3000 --path /mcp
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Relevant optional environment variables:
|
|
138
|
-
|
|
139
|
-
- `WARM_MCP_HTTP_HOST`
|
|
140
|
-
- `WARM_MCP_HTTP_PORT`
|
|
141
|
-
- `WARM_MCP_HTTP_PATH`
|
|
142
|
-
- `WARM_MCP_ALLOWED_HOSTS`
|
|
143
|
-
- `WARM_MCP_AUTH_TOKEN`
|
|
144
|
-
|
|
145
|
-
`WARM_MCP_AUTH_TOKEN` is a separate bearer token for the MCP HTTP transport, never a Warm API
|
|
146
|
-
key. Automation HTTP always requires it, including on loopback. Context HTTP requires it whenever
|
|
147
|
-
the server binds anything other than the exact SDK-protected loopback hosts `127.0.0.1`,
|
|
148
|
-
`localhost`, or `::1`. Send it on every request as
|
|
149
|
-
`Authorization: Bearer <WARM_MCP_AUTH_TOKEN>`.
|
|
150
|
-
|
|
151
|
-
## MCP Tools
|
|
152
|
-
|
|
153
|
-
Context mode remains exactly three read-only tools:
|
|
154
|
-
|
|
155
|
-
| Tool | Description |
|
|
156
|
-
| ----------------------- | ------------------------------------------------ |
|
|
157
|
-
| `get_financial_context` | Return compact `FinancialContext` JSON |
|
|
158
|
-
| `get_transactions` | Return one month page or the fixed latest window |
|
|
159
|
-
| `verify_key` | Validate the configured API key |
|
|
160
|
-
|
|
161
|
-
Automation mode is also exactly three tools:
|
|
162
|
-
|
|
163
|
-
| Tool | Description |
|
|
164
|
-
| -------------------- | ------------------------------------------------------------------ |
|
|
165
|
-
| `search_operations` | Find supported operations without loading the full catalog |
|
|
166
|
-
| `describe_operation` | Read an operation schema and request approval for a write input |
|
|
167
|
-
| `invoke_operation` | Invoke the operation; every write requires an `approval_id` |
|
|
168
|
-
|
|
169
|
-
## Parameter Contract
|
|
170
|
-
|
|
171
|
-
- Every tool takes a JSON object input and returns a JSON object output.
|
|
172
|
-
- `get_financial_context` takes `{}` and returns compact context JSON without transaction items.
|
|
173
|
-
- `get_transactions` takes one required `period` string: `{ "period": "latest" }` or `{ "period": "YYYY-MM" }`.
|
|
174
|
-
- `period: "latest"` returns a fixed 10-day window anchored to the current artifact; the caller cannot configure the window.
|
|
175
|
-
- A month period must use `YYYY-MM` format, for example `2026-07`.
|
|
176
|
-
- A malformed month returns an error.
|
|
177
|
-
- A well-formed month outside the covered range returns an error.
|
|
178
|
-
- A well-formed month inside the covered range with no transactions returns `count: 0` and `items: []`.
|
|
179
|
-
- Transaction amounts follow the Plaid sign convention: positive = expense/debit, negative = income/credit.
|
|
180
|
-
- `describe_operation` returns `approval: { id, status, approval_url, expires_at }` for every write operation.
|
|
181
|
-
- `invoke_operation` accepts that approval as `approval_id`; confirmation tokens are not supported.
|
|
182
|
-
- Tool and Warm API failures return structured MCP results with `isError: true`; malformed MCP input remains a protocol error.
|
|
183
|
-
|
|
184
|
-
## Shapes
|
|
185
|
-
|
|
186
|
-
### `get_financial_context`
|
|
187
|
-
|
|
188
|
-
Input:
|
|
189
|
-
|
|
190
|
-
```json
|
|
191
|
-
{}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
Returns compact `FinancialContext`:
|
|
195
|
-
|
|
196
|
-
```json
|
|
197
|
-
{
|
|
198
|
-
"version": "v1",
|
|
199
|
-
"updated_at": "2026-07-06T11:58:41.000Z",
|
|
200
|
-
"currency": "USD",
|
|
201
|
-
"status": {
|
|
202
|
-
"position": {
|
|
203
|
-
"date": "2026-07-06",
|
|
204
|
-
"net_worth": 84500,
|
|
205
|
-
"cash": 18200,
|
|
206
|
-
"debt": 6400,
|
|
207
|
-
"investments": 72700,
|
|
208
|
-
"other_assets": 0,
|
|
209
|
-
"total_assets": 90900
|
|
210
|
-
},
|
|
211
|
-
"accounts": []
|
|
212
|
-
},
|
|
213
|
-
"transactions": {
|
|
214
|
-
"total": 2,
|
|
215
|
-
"months": [{ "month": "2026-07", "count": 2 }]
|
|
216
|
-
},
|
|
217
|
-
"recurring": [],
|
|
218
|
-
"budgets": [],
|
|
219
|
-
"goals": [],
|
|
220
|
-
"snapshots": [],
|
|
221
|
-
"liabilities": [],
|
|
222
|
-
"holdings": [],
|
|
223
|
-
"health": null
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### `get_transactions`
|
|
228
|
-
|
|
229
|
-
Month input:
|
|
230
|
-
|
|
231
|
-
```json
|
|
232
|
-
{ "period": "2026-07" }
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Month response:
|
|
236
|
-
|
|
237
|
-
```json
|
|
238
|
-
{
|
|
239
|
-
"month": "2026-07",
|
|
240
|
-
"start_date": "2026-07-01",
|
|
241
|
-
"end_date": "2026-07-31",
|
|
242
|
-
"count": 1,
|
|
243
|
-
"items": [
|
|
244
|
-
{
|
|
245
|
-
"id": "txn_1",
|
|
246
|
-
"account_id": "acct_1",
|
|
247
|
-
"date": "2026-07-05",
|
|
248
|
-
"amount": 42.18,
|
|
249
|
-
"merchant": "Whole Foods",
|
|
250
|
-
"name": "WHOLE FOODS",
|
|
251
|
-
"category": "FOOD_AND_DRINK",
|
|
252
|
-
"subcategory": "FOOD_AND_DRINK_GROCERIES",
|
|
253
|
-
"pending": false,
|
|
254
|
-
"currency": "USD"
|
|
255
|
-
}
|
|
256
|
-
]
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Latest input:
|
|
261
|
-
|
|
262
|
-
```json
|
|
263
|
-
{ "period": "latest" }
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
Latest response:
|
|
267
|
-
|
|
268
|
-
```json
|
|
269
|
-
{
|
|
270
|
-
"since": "2026-06-26",
|
|
271
|
-
"window_days": 10,
|
|
272
|
-
"count": 1,
|
|
273
|
-
"items": [
|
|
274
|
-
{
|
|
275
|
-
"id": "txn_1",
|
|
276
|
-
"account_id": "acct_1",
|
|
277
|
-
"date": "2026-07-05",
|
|
278
|
-
"amount": 42.18,
|
|
279
|
-
"merchant": "Whole Foods",
|
|
280
|
-
"name": "WHOLE FOODS",
|
|
281
|
-
"category": "FOOD_AND_DRINK",
|
|
282
|
-
"subcategory": "FOOD_AND_DRINK_GROCERIES",
|
|
283
|
-
"pending": false,
|
|
284
|
-
"currency": "USD"
|
|
285
|
-
}
|
|
286
|
-
]
|
|
287
|
-
}
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### `verify_key`
|
|
291
|
-
|
|
292
|
-
Input:
|
|
293
|
-
|
|
294
|
-
```json
|
|
295
|
-
{}
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
Returns:
|
|
299
|
-
|
|
300
|
-
```json
|
|
301
|
-
{
|
|
302
|
-
"valid": true,
|
|
303
|
-
"status": "ok"
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
## Security
|
|
308
|
-
|
|
309
|
-
- Context mode is read-only and uses a context-only key.
|
|
310
|
-
- Automation mode uses a separate automation-only key and a curated server-side operation allowlist.
|
|
311
|
-
- Streamable HTTP is bearer-protected with an independent `WARM_MCP_AUTH_TOKEN` where required.
|
|
312
|
-
- Write operations return an approval `{ id, status, approval_url, expires_at }`; invoke the exact input with its `approval_id`.
|
|
313
|
-
- Revocable: delete the key in Settings to revoke access immediately
|
|
314
|
-
|
|
315
|
-
## Development
|
|
316
|
-
|
|
317
|
-
```bash
|
|
318
|
-
npm install
|
|
319
|
-
npm run build
|
|
320
|
-
npm test
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
## License
|
|
324
|
-
|
|
325
|
-
MIT
|
|
15
|
+
The server exposes financial-context read tools plus the automation operation catalog.
|
package/dist/config-paths.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PrivateMcpMode } from '@warmio/contracts/mcp';
|
|
2
1
|
export declare function getWarmConfigDir(): string;
|
|
3
|
-
export declare function getWarmApiKeyPath(
|
|
2
|
+
export declare function getWarmApiKeyPath(): string;
|
|
4
3
|
export declare function readConfigFile(configPath: string): string | null;
|
|
4
|
+
//# sourceMappingURL=config-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-paths.d.ts","sourceRoot":"","sources":["../src/config-paths.ts"],"names":[],"mappings":"AAKA,wBAAgB,gBAAgB,IAAI,MAAM,CAUzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAI1C;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMhE"}
|
package/dist/config-paths.js
CHANGED
|
@@ -3,33 +3,29 @@ import * as os from 'node:os';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { WARM_MCP_CREDENTIALS } from '@warmio/contracts/mcp';
|
|
5
5
|
export function getWarmConfigDir() {
|
|
6
|
-
if (process.env.WARM_CONFIG_DIR?.trim())
|
|
6
|
+
if (process.env.WARM_CONFIG_DIR?.trim())
|
|
7
7
|
return process.env.WARM_CONFIG_DIR.trim();
|
|
8
|
-
}
|
|
9
8
|
if (process.platform === 'win32') {
|
|
10
9
|
return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Warm');
|
|
11
10
|
}
|
|
12
|
-
if (process.env.XDG_CONFIG_HOME?.trim())
|
|
11
|
+
if (process.env.XDG_CONFIG_HOME?.trim())
|
|
13
12
|
return path.join(process.env.XDG_CONFIG_HOME.trim(), 'warm');
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
return path.join(os.homedir(), '.config', 'warm');
|
|
13
|
+
return process.platform === 'darwin'
|
|
14
|
+
? path.join(os.homedir(), 'Library', 'Application Support', 'Warm')
|
|
15
|
+
: path.join(os.homedir(), '.config', 'warm');
|
|
19
16
|
}
|
|
20
|
-
export function getWarmApiKeyPath(
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
return path.join(getWarmConfigDir(), credential.defaultFileName);
|
|
17
|
+
export function getWarmApiKeyPath() {
|
|
18
|
+
const override = process.env[WARM_MCP_CREDENTIALS.apiKeyFileEnv]?.trim();
|
|
19
|
+
if (override)
|
|
20
|
+
return override;
|
|
21
|
+
return path.join(getWarmConfigDir(), WARM_MCP_CREDENTIALS.defaultFileName);
|
|
27
22
|
}
|
|
28
23
|
export function readConfigFile(configPath) {
|
|
29
24
|
try {
|
|
30
|
-
return fs.readFileSync(configPath, '
|
|
25
|
+
return fs.readFileSync(configPath, 'utf8').trim() || null;
|
|
31
26
|
}
|
|
32
27
|
catch {
|
|
33
28
|
return null;
|
|
34
29
|
}
|
|
35
30
|
}
|
|
31
|
+
//# sourceMappingURL=config-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-paths.js","sourceRoot":"","sources":["../src/config-paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,UAAU,gBAAgB;IAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACnF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAClC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,CAAC;QACnE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC;IACzE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
export
|
|
2
|
+
export { install } from './install.js';
|
|
3
|
+
export * from './server.js';
|
|
4
|
+
export * from './warm-api-client.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAkCA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,214 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { WARM_MCP_INSTALLER_COMMAND, WARM_MCP_SERVER_COMMAND } from '@warmio/contracts/mcp';
|
|
2
4
|
import { install } from './install.js';
|
|
3
|
-
import { startHttpServer } from './http.js';
|
|
4
5
|
import { loadDotEnv } from './load-env.js';
|
|
5
6
|
import { createWarmServer } from './server.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function isInteractiveSession() {
|
|
9
|
-
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
7
|
+
function usage() {
|
|
8
|
+
console.log(`Usage: ${WARM_MCP_INSTALLER_COMMAND} [--force] | ${WARM_MCP_SERVER_COMMAND}`);
|
|
10
9
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
console.log(' Run the interactive installer');
|
|
18
|
-
console.log('');
|
|
19
|
-
console.log(' warmio install --mode context|automation [--force] [--no-validate]');
|
|
20
|
-
console.log(' warmio mcp [--mode context|automation]');
|
|
21
|
-
console.log(' warmio http [--mode context|automation] [--host 127.0.0.1] [--port 3000] [--path /mcp]');
|
|
22
|
-
console.log(' warmio context get');
|
|
23
|
-
console.log(' warmio context meta');
|
|
24
|
-
console.log(' warmio transactions get --month YYYY-MM');
|
|
25
|
-
console.log(' warmio transactions get --latest');
|
|
26
|
-
console.log('');
|
|
27
|
-
console.log(' Transactions require exactly one selector: --month YYYY-MM or --latest.');
|
|
28
|
-
console.log(' Month and latest are mutually exclusive. Latest is a fixed 10-day window.');
|
|
29
|
-
console.log('');
|
|
30
|
-
}
|
|
31
|
-
function parseCliArgs(args) {
|
|
32
|
-
const options = {
|
|
33
|
-
command: isInteractiveSession() ? 'install' : 'mcp',
|
|
34
|
-
force: false,
|
|
35
|
-
mode: 'context',
|
|
36
|
-
validateApiKey: true,
|
|
37
|
-
};
|
|
38
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
39
|
-
const arg = args[index];
|
|
40
|
-
if (arg === 'help' || arg === '--help' || arg === '-h') {
|
|
41
|
-
options.command = 'help';
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (arg === 'install' || arg === '--install') {
|
|
45
|
-
options.command = 'install';
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
if (arg === 'mcp') {
|
|
49
|
-
options.command = 'mcp';
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (arg === 'http') {
|
|
53
|
-
options.command = 'http';
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (arg === 'context') {
|
|
57
|
-
const subcommand = args[index + 1];
|
|
58
|
-
if (subcommand === 'get') {
|
|
59
|
-
options.command = 'context-get';
|
|
60
|
-
index += 1;
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (subcommand === 'meta') {
|
|
64
|
-
options.command = 'context-meta';
|
|
65
|
-
index += 1;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
throw new Error('Usage: warmio context get | warmio context meta');
|
|
69
|
-
}
|
|
70
|
-
if (arg === 'transactions') {
|
|
71
|
-
const subcommand = args[index + 1];
|
|
72
|
-
if (subcommand !== 'get') {
|
|
73
|
-
throw new Error('Usage: warmio transactions get --month YYYY-MM | --latest');
|
|
74
|
-
}
|
|
75
|
-
options.command = 'transactions-get';
|
|
76
|
-
index += 1;
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
if (arg === '--format') {
|
|
80
|
-
const format = args[index + 1];
|
|
81
|
-
if (format !== 'json') {
|
|
82
|
-
throw new Error('Only --format json is supported.');
|
|
83
|
-
}
|
|
84
|
-
index += 1;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (arg === '--month') {
|
|
88
|
-
const month = args[index + 1];
|
|
89
|
-
if (!month) {
|
|
90
|
-
throw new Error('Missing value for --month');
|
|
91
|
-
}
|
|
92
|
-
if (!/^\d{4}-\d{2}$/.test(month)) {
|
|
93
|
-
throw new Error(`Invalid value for --month: ${month}. Expected YYYY-MM.`);
|
|
94
|
-
}
|
|
95
|
-
options.month = month;
|
|
96
|
-
index += 1;
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
if (arg === '--latest') {
|
|
100
|
-
options.latest = true;
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
if (arg === '--mode') {
|
|
104
|
-
const mode = args[index + 1];
|
|
105
|
-
if (mode !== 'context' && mode !== 'automation') {
|
|
106
|
-
throw new Error('Expected --mode context or --mode automation.');
|
|
107
|
-
}
|
|
108
|
-
options.mode = mode;
|
|
109
|
-
index += 1;
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
if (arg === '--host') {
|
|
113
|
-
options.httpHost = args[index + 1];
|
|
114
|
-
index += 1;
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
if (arg === '--path') {
|
|
118
|
-
options.httpPath = args[index + 1];
|
|
119
|
-
index += 1;
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
if (arg === '--port') {
|
|
123
|
-
const nextArg = args[index + 1];
|
|
124
|
-
if (!nextArg) {
|
|
125
|
-
throw new Error('Missing value for --port');
|
|
126
|
-
}
|
|
127
|
-
const port = Number.parseInt(nextArg, 10);
|
|
128
|
-
if (!Number.isInteger(port) || port <= 0) {
|
|
129
|
-
throw new Error(`Invalid value for --port: ${nextArg}`);
|
|
130
|
-
}
|
|
131
|
-
options.httpPort = port;
|
|
132
|
-
index += 1;
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
if (arg === '--force') {
|
|
136
|
-
options.force = true;
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
if (arg === '--no-validate') {
|
|
140
|
-
options.validateApiKey = false;
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
throw new Error(`Unknown argument: ${arg}`);
|
|
144
|
-
}
|
|
145
|
-
return options;
|
|
146
|
-
}
|
|
147
|
-
function validateCliOptions(options) {
|
|
148
|
-
if (options.command !== 'transactions-get') {
|
|
149
|
-
if (options.month || options.latest) {
|
|
150
|
-
throw new Error('--month and --latest are only valid with `warmio transactions get`.');
|
|
151
|
-
}
|
|
10
|
+
async function main(args) {
|
|
11
|
+
loadDotEnv();
|
|
12
|
+
const command = args[0] || (process.stdin.isTTY && process.stdout.isTTY ? 'install' : 'mcp');
|
|
13
|
+
if (command === 'mcp') {
|
|
14
|
+
const server = createWarmServer();
|
|
15
|
+
await server.connect(new StdioServerTransport());
|
|
152
16
|
return;
|
|
153
17
|
}
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
function printJson(value) {
|
|
162
|
-
console.log(JSON.stringify(value, null, 2));
|
|
163
|
-
}
|
|
164
|
-
export async function startStdioServer(mode = 'context') {
|
|
165
|
-
const server = createWarmServer({ mode });
|
|
166
|
-
const transport = new AdaptiveStdioTransport();
|
|
167
|
-
await server.connect(transport);
|
|
168
|
-
return server;
|
|
169
|
-
}
|
|
170
|
-
async function main() {
|
|
171
|
-
loadDotEnv();
|
|
172
|
-
const options = parseCliArgs(process.argv.slice(2));
|
|
173
|
-
validateCliOptions(options);
|
|
174
|
-
switch (options.command) {
|
|
175
|
-
case 'context-get':
|
|
176
|
-
printJson(await createWarmApiClient().getFinancialContext());
|
|
177
|
-
return;
|
|
178
|
-
case 'context-meta':
|
|
179
|
-
printJson(await createWarmApiClient().getFinancialContextMeta());
|
|
180
|
-
return;
|
|
181
|
-
case 'transactions-get':
|
|
182
|
-
printJson(await createWarmApiClient().getTransactions(options.month ? { month: options.month } : { latest: true }));
|
|
183
|
-
return;
|
|
184
|
-
case 'help':
|
|
185
|
-
printUsage();
|
|
186
|
-
return;
|
|
187
|
-
case 'mcp':
|
|
188
|
-
await startStdioServer(options.mode);
|
|
189
|
-
return;
|
|
190
|
-
case 'http':
|
|
191
|
-
await startHttpServer({
|
|
192
|
-
host: options.httpHost,
|
|
193
|
-
path: options.httpPath,
|
|
194
|
-
port: options.httpPort,
|
|
195
|
-
mode: options.mode,
|
|
196
|
-
});
|
|
197
|
-
return;
|
|
198
|
-
case 'install':
|
|
199
|
-
await install({
|
|
200
|
-
force: options.force,
|
|
201
|
-
mode: options.mode,
|
|
202
|
-
validateApiKey: options.validateApiKey,
|
|
203
|
-
});
|
|
204
|
-
return;
|
|
18
|
+
if (command === 'install') {
|
|
19
|
+
const invalidArgument = args.slice(1).find((argument) => argument !== '--force');
|
|
20
|
+
if (invalidArgument)
|
|
21
|
+
throw new Error(`Unknown argument: ${invalidArgument}`);
|
|
22
|
+
await install({ force: args.includes('--force') });
|
|
23
|
+
return;
|
|
205
24
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
25
|
+
usage();
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
}
|
|
28
|
+
void main(process.argv.slice(2)).catch((error) => {
|
|
29
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
});
|
|
32
|
+
export { install } from './install.js';
|
|
33
|
+
export * from './server.js';
|
|
34
|
+
export * from './warm-api-client.js';
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,SAAS,KAAK;IACZ,OAAO,CAAC,GAAG,CAAC,UAAU,0BAA0B,gBAAgB,uBAAuB,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,UAAU,EAAE,CAAC;IACb,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7F,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QACjF,IAAI,eAAe;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,eAAe,EAAE,CAAC,CAAC;QAC7E,MAAM,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC/C,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
|
package/dist/install.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
import { type PrivateMcpMode } from '@warmio/contracts/mcp';
|
|
2
1
|
export interface InstallOptions {
|
|
2
|
+
/** Replace an existing Warm server configuration without an additional confirmation. */
|
|
3
3
|
force?: boolean;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/** Test seam for the API request. It is not used by the CLI. */
|
|
5
|
+
fetchImplementation?: typeof fetch;
|
|
6
|
+
/** Test seam for local client discovery. It is not used by the CLI. */
|
|
7
|
+
homeDir?: string;
|
|
8
|
+
/** Test seam for the API endpoint. It is not used by the CLI. */
|
|
9
|
+
apiUrl?: string;
|
|
10
|
+
/** Test seam for installer interaction. It is not used by the CLI. */
|
|
11
|
+
prompt?: (question: string) => Promise<string>;
|
|
12
|
+
/** Test seam for installer interaction. It is not used by the CLI. */
|
|
13
|
+
confirm?: (question: string) => Promise<boolean>;
|
|
14
|
+
/** Test seam for project client discovery. It is not used by the CLI. */
|
|
15
|
+
workingDirectory?: string;
|
|
16
|
+
/** Test seam for atomic file replacement failures. It is not used by the CLI. */
|
|
17
|
+
atomicReplaceFile?: (target: string, content: string, mode: number) => void;
|
|
6
18
|
}
|
|
19
|
+
/** Configure detected supported MCP clients for the local stdio server. */
|
|
7
20
|
export declare function install(options?: InstallOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=install.d.ts.map
|