@warmio/mcp 9.1.1 → 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 CHANGED
@@ -1,327 +1,15 @@
1
- # Warmio
1
+ # @warmio/mcp
2
2
 
3
- Warmio is the one-command CLI with separate compact MCP modes for financial context and supported automations.
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
- ## Install
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
- On Windows, prefer:
9
+ Each client starts the server with:
43
10
 
44
- ```json
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
- Context credential overrides:
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 either `{ "month": "YYYY-MM" }`, `{ "latest": true }`, or `{}`.
174
- - A bare `get_transactions` call with no arguments defaults to `{ "latest": true }`.
175
- - `month` must use `YYYY-MM` format, for example `2026-07`.
176
- - `latest` is a fixed 10-day window anchored to the current artifact; the caller cannot configure the window.
177
- - `month` and `latest` are mutually exclusive.
178
- - A malformed month returns an error.
179
- - A well-formed month outside the covered range returns an error.
180
- - A well-formed month inside the covered range with no transactions returns `count: 0` and `items: []`.
181
- - Transaction amounts follow the Plaid sign convention: positive = expense/debit, negative = income/credit.
182
- - `describe_operation` returns `approval: { id, status, approval_url, expires_at }` for every write operation.
183
- - `invoke_operation` accepts that approval as `approval_id`; confirmation tokens are not supported.
184
- - Tool and Warm API failures return structured MCP results with `isError: true`; malformed MCP input remains a protocol error.
185
-
186
- ## Shapes
187
-
188
- ### `get_financial_context`
189
-
190
- Input:
191
-
192
- ```json
193
- {}
194
- ```
195
-
196
- Returns compact `FinancialContext`:
197
-
198
- ```json
199
- {
200
- "version": "v1",
201
- "updated_at": "2026-07-06T11:58:41.000Z",
202
- "currency": "USD",
203
- "status": {
204
- "position": {
205
- "date": "2026-07-06",
206
- "net_worth": 84500,
207
- "cash": 18200,
208
- "debt": 6400,
209
- "investments": 72700,
210
- "other_assets": 0,
211
- "total_assets": 90900
212
- },
213
- "accounts": []
214
- },
215
- "transactions": {
216
- "total": 2,
217
- "months": [{ "month": "2026-07", "count": 2 }]
218
- },
219
- "recurring": [],
220
- "budgets": [],
221
- "goals": [],
222
- "snapshots": [],
223
- "liabilities": [],
224
- "holdings": [],
225
- "health": null
226
- }
227
- ```
228
-
229
- ### `get_transactions`
230
-
231
- Month input:
232
-
233
- ```json
234
- { "month": "2026-07" }
235
- ```
236
-
237
- Month response:
238
-
239
- ```json
240
- {
241
- "month": "2026-07",
242
- "start_date": "2026-07-01",
243
- "end_date": "2026-07-31",
244
- "count": 1,
245
- "items": [
246
- {
247
- "id": "txn_1",
248
- "account_id": "acct_1",
249
- "date": "2026-07-05",
250
- "amount": 42.18,
251
- "merchant": "Whole Foods",
252
- "name": "WHOLE FOODS",
253
- "category": "FOOD_AND_DRINK",
254
- "subcategory": "FOOD_AND_DRINK_GROCERIES",
255
- "pending": false,
256
- "currency": "USD"
257
- }
258
- ]
259
- }
260
- ```
261
-
262
- Latest input:
263
-
264
- ```json
265
- { "latest": true }
266
- ```
267
-
268
- Latest response:
269
-
270
- ```json
271
- {
272
- "since": "2026-06-26",
273
- "window_days": 10,
274
- "count": 1,
275
- "items": [
276
- {
277
- "id": "txn_1",
278
- "account_id": "acct_1",
279
- "date": "2026-07-05",
280
- "amount": 42.18,
281
- "merchant": "Whole Foods",
282
- "name": "WHOLE FOODS",
283
- "category": "FOOD_AND_DRINK",
284
- "subcategory": "FOOD_AND_DRINK_GROCERIES",
285
- "pending": false,
286
- "currency": "USD"
287
- }
288
- ]
289
- }
290
- ```
291
-
292
- ### `verify_key`
293
-
294
- Input:
295
-
296
- ```json
297
- {}
298
- ```
299
-
300
- Returns:
301
-
302
- ```json
303
- {
304
- "valid": true,
305
- "status": "ok"
306
- }
307
- ```
308
-
309
- ## Security
310
-
311
- - Context mode is read-only and uses a context-only key.
312
- - Automation mode uses a separate automation-only key and a curated server-side operation allowlist.
313
- - Streamable HTTP is bearer-protected with an independent `WARM_MCP_AUTH_TOKEN` where required.
314
- - Write operations return an approval `{ id, status, approval_url, expires_at }`; invoke the exact input with its `approval_id`.
315
- - Revocable: delete the key in Settings to revoke access immediately
316
-
317
- ## Development
318
-
319
- ```bash
320
- npm install
321
- npm run build
322
- npm test
323
- ```
324
-
325
- ## License
326
-
327
- MIT
15
+ The server exposes financial-context read tools plus the automation operation catalog.
@@ -1,4 +1,4 @@
1
- import { type PrivateMcpMode } from '@warmio/contracts/mcp';
2
1
  export declare function getWarmConfigDir(): string;
3
- export declare function getWarmApiKeyPath(audience?: PrivateMcpMode): string;
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"}
@@ -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
- if (process.platform === 'darwin') {
16
- return path.join(os.homedir(), 'Library', 'Application Support', 'Warm');
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(audience = 'context') {
21
- const credential = WARM_MCP_CREDENTIALS[audience];
22
- const configuredPath = process.env[credential.apiKeyFileEnv]?.trim();
23
- if (configuredPath) {
24
- return configuredPath;
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, 'utf-8').trim() || null;
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
- import { type WarmServerMode } from './server.js';
3
- export declare function startStdioServer(mode?: WarmServerMode): Promise<import("@modelcontextprotocol/sdk/server/mcp").McpServer>;
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
- import { AdaptiveStdioTransport } from './stdio.js';
7
- import { createWarmApiClient } from './warm-api-client.js';
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 printUsage() {
12
- console.log('');
13
- console.log(' Warmio');
14
- console.log(' ------');
15
- console.log('');
16
- console.log(' warmio');
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 (options.month && options.latest) {
155
- throw new Error('--month and --latest are mutually exclusive.');
156
- }
157
- if (!options.month && !options.latest) {
158
- throw new Error('Usage: warmio transactions get --month YYYY-MM | --latest');
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
- try {
208
- await main();
209
- }
210
- catch (error) {
211
- const message = error instanceof Error ? error.stack || error.message : String(error);
212
- console.error(message);
213
- process.exit(1);
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
- mode?: PrivateMcpMode;
5
- validateApiKey?: boolean;
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