@warmio/mcp 3.0.1 → 4.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/README.md +237 -35
- package/dist/http.d.ts +9 -0
- package/dist/http.js +117 -0
- package/dist/index.js +140 -7
- package/dist/install.d.ts +5 -1
- package/dist/install.js +95 -35
- package/dist/schemas.d.ts +225 -0
- package/dist/schemas.js +186 -0
- package/dist/server.d.ts +5 -7
- package/dist/server.js +9 -299
- package/dist/types.d.ts +157 -0
- package/dist/types.js +6 -0
- package/dist/warm-server.d.ts +14 -0
- package/dist/warm-server.js +358 -0
- package/package.json +25 -2
package/dist/server.js
CHANGED
|
@@ -1,304 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Warm MCP
|
|
2
|
+
* Warm MCP stdio entrypoint and compatibility exports.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Reads API key from WARM_API_KEY env var or ~/.config/warm/api_key.
|
|
6
|
-
*
|
|
7
|
-
* Four read-only tools: get_accounts, get_transactions, get_snapshots, verify_key.
|
|
8
|
-
* The AI client handles all analysis — no sandbox needed.
|
|
4
|
+
* The typed MCP contract and Warm API helpers live in `warm-server.ts`.
|
|
9
5
|
*/
|
|
10
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
6
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const TRANSACTION_PAGE_SIZE = 200;
|
|
20
|
-
const REQUEST_TIMEOUT_MS = (() => {
|
|
21
|
-
const raw = Number(process.env.WARM_API_TIMEOUT_MS || 10_000);
|
|
22
|
-
return Number.isFinite(raw) && raw > 0 ? raw : 10_000;
|
|
23
|
-
})();
|
|
24
|
-
let cachedApiKey;
|
|
25
|
-
function compactTransaction(t) {
|
|
26
|
-
return {
|
|
27
|
-
d: t.date || '',
|
|
28
|
-
a: t.amount ? Math.round(t.amount * 100) / 100 : 0,
|
|
29
|
-
m: t.merchant_name || t.name || 'Unknown',
|
|
30
|
-
c: t.primary_category ?? null,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function inDateRange(t, since, until) {
|
|
34
|
-
if (!t.date)
|
|
35
|
-
return false;
|
|
36
|
-
if (since && t.date < since)
|
|
37
|
-
return false;
|
|
38
|
-
if (until && t.date > until)
|
|
39
|
-
return false;
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
function calculateSummary(transactions) {
|
|
43
|
-
if (transactions.length === 0) {
|
|
44
|
-
return { total: 0, count: 0, avg: 0 };
|
|
45
|
-
}
|
|
46
|
-
const total = transactions.reduce((sum, t) => sum + t.a, 0);
|
|
47
|
-
return {
|
|
48
|
-
total: Math.round(total * 100) / 100,
|
|
49
|
-
count: transactions.length,
|
|
50
|
-
avg: Math.round((total / transactions.length) * 100) / 100,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function getApiKey() {
|
|
54
|
-
if (cachedApiKey !== undefined) {
|
|
55
|
-
return cachedApiKey;
|
|
56
|
-
}
|
|
57
|
-
if (process.env.WARM_API_KEY) {
|
|
58
|
-
cachedApiKey = process.env.WARM_API_KEY;
|
|
59
|
-
return cachedApiKey;
|
|
60
|
-
}
|
|
61
|
-
const configPath = path.join(os.homedir(), '.config', 'warm', 'api_key');
|
|
62
|
-
try {
|
|
63
|
-
cachedApiKey = fs.readFileSync(configPath, 'utf-8').trim();
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
cachedApiKey = null;
|
|
67
|
-
}
|
|
68
|
-
return cachedApiKey;
|
|
69
|
-
}
|
|
70
|
-
function getRequestSignal(timeoutMs) {
|
|
71
|
-
if (typeof AbortSignal.timeout === 'function') {
|
|
72
|
-
return AbortSignal.timeout(timeoutMs);
|
|
73
|
-
}
|
|
74
|
-
const controller = new AbortController();
|
|
75
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
76
|
-
timer.unref?.();
|
|
77
|
-
return controller.signal;
|
|
78
|
-
}
|
|
79
|
-
async function apiRequest(endpoint, params = {}) {
|
|
80
|
-
const apiKey = getApiKey();
|
|
81
|
-
if (!apiKey) {
|
|
82
|
-
throw new Error('WARM_API_KEY not set. Run "npx @warmio/mcp" to configure.');
|
|
83
|
-
}
|
|
84
|
-
const url = new URL(endpoint, API_URL);
|
|
85
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
86
|
-
if (value)
|
|
87
|
-
url.searchParams.append(key, value);
|
|
88
|
-
});
|
|
89
|
-
let response;
|
|
90
|
-
try {
|
|
91
|
-
response = await fetch(url.toString(), {
|
|
92
|
-
headers: {
|
|
93
|
-
Authorization: `Bearer ${apiKey}`,
|
|
94
|
-
Accept: 'application/json',
|
|
95
|
-
},
|
|
96
|
-
signal: getRequestSignal(REQUEST_TIMEOUT_MS),
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
if (error instanceof Error && error.name === 'TimeoutError') {
|
|
101
|
-
throw new Error(`Warm API timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
102
|
-
}
|
|
103
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
104
|
-
throw new Error(`Warm API request aborted after ${REQUEST_TIMEOUT_MS}ms`);
|
|
105
|
-
}
|
|
106
|
-
throw error;
|
|
107
|
-
}
|
|
108
|
-
if (!response.ok) {
|
|
109
|
-
const errorMessages = {
|
|
110
|
-
401: 'Invalid or expired API key. Regenerate at https://warm.io/settings',
|
|
111
|
-
403: 'Pro subscription required. Upgrade at https://warm.io/settings',
|
|
112
|
-
429: 'Rate limit exceeded. Try again in a few minutes.',
|
|
113
|
-
};
|
|
114
|
-
if (errorMessages[response.status]) {
|
|
115
|
-
throw new Error(errorMessages[response.status]);
|
|
116
|
-
}
|
|
117
|
-
let detail = `HTTP ${response.status}`;
|
|
118
|
-
try {
|
|
119
|
-
const body = (await response.json());
|
|
120
|
-
if (body?.error)
|
|
121
|
-
detail = body.error;
|
|
122
|
-
}
|
|
123
|
-
catch { /* ignore parse failures */ }
|
|
124
|
-
throw new Error(detail);
|
|
125
|
-
}
|
|
126
|
-
return response.json();
|
|
127
|
-
}
|
|
128
|
-
// ============================================
|
|
129
|
-
// TOOL HANDLERS
|
|
130
|
-
// ============================================
|
|
131
|
-
async function handleGetAccounts() {
|
|
132
|
-
const response = (await apiRequest('/api/accounts'));
|
|
133
|
-
return {
|
|
134
|
-
accounts: response.accounts || [],
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
async function handleGetTransactions(args) {
|
|
138
|
-
const since = args?.since ? String(args.since) : undefined;
|
|
139
|
-
const until = args?.until ? String(args.until) : undefined;
|
|
140
|
-
const limit = Math.min(Math.max(args?.limit ? Number(args.limit) : 200, 1), 500);
|
|
141
|
-
const offset = Math.max(args?.offset ? Number(args.offset) : 0, 0);
|
|
142
|
-
let transactions = [];
|
|
143
|
-
let cursor;
|
|
144
|
-
let pagesFetched = 0;
|
|
145
|
-
let scanned = 0;
|
|
146
|
-
do {
|
|
147
|
-
const params = {
|
|
148
|
-
limit: String(TRANSACTION_PAGE_SIZE),
|
|
149
|
-
};
|
|
150
|
-
if (since && !cursor)
|
|
151
|
-
params.last_knowledge = since;
|
|
152
|
-
if (cursor)
|
|
153
|
-
params.cursor = cursor;
|
|
154
|
-
const response = (await apiRequest('/api/transactions', params));
|
|
155
|
-
const batch = (response.transactions || []);
|
|
156
|
-
transactions.push(...batch);
|
|
157
|
-
scanned += batch.length;
|
|
158
|
-
pagesFetched += 1;
|
|
159
|
-
cursor = response.pagination?.next_cursor ?? undefined;
|
|
160
|
-
} while (cursor && pagesFetched < MAX_TRANSACTION_PAGES && scanned < MAX_TRANSACTION_SCAN);
|
|
161
|
-
if (until) {
|
|
162
|
-
transactions = transactions.filter((t) => inDateRange(t, since, until));
|
|
163
|
-
}
|
|
164
|
-
const compactTxns = transactions.map(compactTransaction);
|
|
165
|
-
const summary = calculateSummary(compactTxns);
|
|
166
|
-
const total = compactTxns.length;
|
|
167
|
-
const page = compactTxns.slice(offset, offset + limit);
|
|
168
|
-
return {
|
|
169
|
-
summary,
|
|
170
|
-
txns: page,
|
|
171
|
-
total,
|
|
172
|
-
has_more: offset + limit < total,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
async function handleGetSnapshots(args) {
|
|
176
|
-
const response = (await apiRequest('/api/snapshots'));
|
|
177
|
-
const snapshots = response.snapshots || [];
|
|
178
|
-
const limit = args?.limit ? Number(args.limit) : 30;
|
|
179
|
-
const since = args?.since;
|
|
180
|
-
const normalized = snapshots.map((s) => ({
|
|
181
|
-
date: s.snapshot_date || s.d || '',
|
|
182
|
-
net_worth: s.net_worth ?? s.nw ?? 0,
|
|
183
|
-
total_assets: s.total_assets ?? s.a ?? 0,
|
|
184
|
-
total_liabilities: s.total_liabilities ?? s.l ?? 0,
|
|
185
|
-
}));
|
|
186
|
-
let filtered = normalized;
|
|
187
|
-
if (since) {
|
|
188
|
-
filtered = filtered.filter((s) => s.date >= since);
|
|
189
|
-
}
|
|
190
|
-
filtered.sort((a, b) => b.date.localeCompare(a.date));
|
|
191
|
-
if (limit > 0) {
|
|
192
|
-
filtered = filtered.slice(0, limit);
|
|
193
|
-
}
|
|
194
|
-
const result = filtered.map((s) => ({
|
|
195
|
-
d: s.date,
|
|
196
|
-
nw: Math.round(s.net_worth * 100) / 100,
|
|
197
|
-
a: Math.round(s.total_assets * 100) / 100,
|
|
198
|
-
l: Math.round(s.total_liabilities * 100) / 100,
|
|
199
|
-
}));
|
|
200
|
-
return { snapshots: result };
|
|
201
|
-
}
|
|
202
|
-
async function handleVerifyKey() {
|
|
203
|
-
const response = (await apiRequest('/api/verify'));
|
|
204
|
-
return {
|
|
205
|
-
valid: response.valid === true,
|
|
206
|
-
status: response.status || (response.valid ? 'ok' : 'invalid'),
|
|
207
|
-
};
|
|
7
|
+
import { API_URL, WARM_SERVER_INFO, apiRequest, createWarmApiClient, createWarmServer, getConfiguredApiKey, verifyWarmApiKey, } from './warm-server.js';
|
|
8
|
+
export { API_URL, WARM_SERVER_INFO, apiRequest, createWarmApiClient, createWarmServer, getConfiguredApiKey, verifyWarmApiKey, };
|
|
9
|
+
export async function startStdioServer() {
|
|
10
|
+
const server = createWarmServer();
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
return server;
|
|
208
14
|
}
|
|
209
|
-
const toolHandlers = {
|
|
210
|
-
get_accounts: handleGetAccounts,
|
|
211
|
-
get_transactions: handleGetTransactions,
|
|
212
|
-
get_snapshots: handleGetSnapshots,
|
|
213
|
-
verify_key: handleVerifyKey,
|
|
214
|
-
};
|
|
215
|
-
// ============================================
|
|
216
|
-
// SERVER SETUP
|
|
217
|
-
// ============================================
|
|
218
|
-
const server = new Server({ name: 'warm', version: '3.0.0' }, { capabilities: { tools: {} } });
|
|
219
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
220
|
-
tools: [
|
|
221
|
-
{
|
|
222
|
-
name: 'get_accounts',
|
|
223
|
-
description: 'Get all connected bank accounts with current balances.\n\nReturns: { accounts: Array<{ name: string; type: string; balance: number; institution: string }> }\n\nAccount types: depository (checking/savings), credit, loan, investment, other.',
|
|
224
|
-
inputSchema: {
|
|
225
|
-
type: 'object',
|
|
226
|
-
properties: {},
|
|
227
|
-
},
|
|
228
|
-
annotations: { readOnlyHint: true },
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: 'get_transactions',
|
|
232
|
-
description: 'Get transactions with date filtering and pagination. Returns a summary of the FULL date range plus a paginated slice of individual transactions.\n\nAmounts: positive = expense/debit, negative = income/credit (Plaid convention).\nCategories in field `c`: INCOME, TRANSFER_IN = income. FOOD_AND_DRINK, TRANSPORTATION, ENTERTAINMENT, GENERAL_MERCHANDISE, RENT_AND_UTILITIES, LOAN_PAYMENTS, etc. = expenses.\n\nReturns: { summary: { total: number; count: number; avg: number }; txns: Array<{ d: string; a: number; m: string; c: string | null }>; total: number; has_more: boolean }\n\nCall multiple times with increasing offset to paginate. The summary is always computed over ALL matching transactions regardless of limit/offset.',
|
|
233
|
-
inputSchema: {
|
|
234
|
-
type: 'object',
|
|
235
|
-
properties: {
|
|
236
|
-
since: {
|
|
237
|
-
type: 'string',
|
|
238
|
-
description: 'Start date inclusive (YYYY-MM-DD). Omit to get all available transactions.',
|
|
239
|
-
},
|
|
240
|
-
until: {
|
|
241
|
-
type: 'string',
|
|
242
|
-
description: 'End date inclusive (YYYY-MM-DD). Omit for no end date filter.',
|
|
243
|
-
},
|
|
244
|
-
limit: {
|
|
245
|
-
type: 'number',
|
|
246
|
-
description: 'Max transactions per page (default 200, max 500).',
|
|
247
|
-
},
|
|
248
|
-
offset: {
|
|
249
|
-
type: 'number',
|
|
250
|
-
description: 'Skip N transactions for pagination (default 0).',
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
annotations: { readOnlyHint: true },
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
name: 'get_snapshots',
|
|
258
|
-
description: 'Get daily net worth snapshots over time.\n\nReturns: { snapshots: Array<{ d: string; nw: number; a: number; l: number }> }\n\nFields: d = date, nw = net worth, a = total assets, l = total liabilities. Sorted newest first.',
|
|
259
|
-
inputSchema: {
|
|
260
|
-
type: 'object',
|
|
261
|
-
properties: {
|
|
262
|
-
limit: {
|
|
263
|
-
type: 'number',
|
|
264
|
-
description: 'Max snapshots to return (default 30).',
|
|
265
|
-
},
|
|
266
|
-
since: {
|
|
267
|
-
type: 'string',
|
|
268
|
-
description: 'Start date inclusive (YYYY-MM-DD).',
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
annotations: { readOnlyHint: true },
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
name: 'verify_key',
|
|
276
|
-
description: 'Check if the API key is valid.\n\nReturns: { valid: boolean; status: string }',
|
|
277
|
-
inputSchema: {
|
|
278
|
-
type: 'object',
|
|
279
|
-
properties: {},
|
|
280
|
-
},
|
|
281
|
-
annotations: { readOnlyHint: true },
|
|
282
|
-
},
|
|
283
|
-
],
|
|
284
|
-
}));
|
|
285
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
286
|
-
const { name, arguments: args } = request.params;
|
|
287
|
-
try {
|
|
288
|
-
const handler = toolHandlers[name];
|
|
289
|
-
if (!handler) {
|
|
290
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
291
|
-
}
|
|
292
|
-
const data = await handler(args);
|
|
293
|
-
return { content: [{ type: 'text', text: JSON.stringify(data) }] };
|
|
294
|
-
}
|
|
295
|
-
catch (error) {
|
|
296
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
297
|
-
return {
|
|
298
|
-
content: [{ type: 'text', text: JSON.stringify({ error: message }) }],
|
|
299
|
-
isError: true,
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
const transport = new StdioServerTransport();
|
|
304
|
-
await server.connect(transport);
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { GetAccountsOutput, GetFinancialStateOutput, GetTransactionsInput, GetTransactionsOutput, VerifyKeyOutput } from './schemas.js';
|
|
4
|
+
export declare const WARM_TOOL_NAMES: readonly ["get_accounts", "get_transactions", "get_financial_state", "verify_key"];
|
|
5
|
+
export type WarmToolName = (typeof WARM_TOOL_NAMES)[number];
|
|
6
|
+
export interface WarmApiClientOptions {
|
|
7
|
+
apiUrl?: string;
|
|
8
|
+
requestTimeoutMs?: number;
|
|
9
|
+
fetchImplementation?: typeof fetch;
|
|
10
|
+
apiKeyResolver?: () => string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface WarmServerOptions extends WarmApiClientOptions {
|
|
13
|
+
serverInfo?: Implementation;
|
|
14
|
+
}
|
|
15
|
+
export type WarmToolRegistrationTarget = McpServer;
|
|
16
|
+
export type RegisteredWarmTools = Record<WarmToolName, RegisteredTool>;
|
|
17
|
+
export interface WarmApiClient {
|
|
18
|
+
getAccounts(): Promise<GetAccountsOutput>;
|
|
19
|
+
getTransactions(input: GetTransactionsInput): Promise<GetTransactionsOutput>;
|
|
20
|
+
getFinancialState(): Promise<GetFinancialStateOutput>;
|
|
21
|
+
verifyKey(): Promise<VerifyKeyOutput>;
|
|
22
|
+
}
|
|
23
|
+
export interface WarmApiAccount {
|
|
24
|
+
name?: string | null;
|
|
25
|
+
type?: string | null;
|
|
26
|
+
subtype?: string | null;
|
|
27
|
+
current_balance?: number | null;
|
|
28
|
+
institution_name?: string | null;
|
|
29
|
+
mask?: string | null;
|
|
30
|
+
}
|
|
31
|
+
export interface WarmApiAccountsResponse {
|
|
32
|
+
accounts?: WarmApiAccount[];
|
|
33
|
+
generated_at?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface WarmApiTransaction {
|
|
36
|
+
id?: string | null;
|
|
37
|
+
date?: string | null;
|
|
38
|
+
amount?: number | null;
|
|
39
|
+
merchant_name?: string | null;
|
|
40
|
+
name?: string | null;
|
|
41
|
+
primary_category?: string | null;
|
|
42
|
+
detailed_category?: string | null;
|
|
43
|
+
}
|
|
44
|
+
export interface WarmApiTransactionsResponse {
|
|
45
|
+
generated_at?: string;
|
|
46
|
+
next_knowledge?: string;
|
|
47
|
+
transactions?: WarmApiTransaction[];
|
|
48
|
+
pagination?: {
|
|
49
|
+
limit?: number | null;
|
|
50
|
+
next_cursor?: string | null;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export interface WarmApiSnapshot {
|
|
54
|
+
snapshot_date?: string | null;
|
|
55
|
+
period_end?: string | null;
|
|
56
|
+
net_worth?: number | null;
|
|
57
|
+
total_assets?: number | null;
|
|
58
|
+
total_liabilities?: number | null;
|
|
59
|
+
total_cash?: number | null;
|
|
60
|
+
investment_value?: number | null;
|
|
61
|
+
asset_value?: number | null;
|
|
62
|
+
total_debt?: number | null;
|
|
63
|
+
liability_value?: number | null;
|
|
64
|
+
}
|
|
65
|
+
export interface WarmApiSnapshotsResponse {
|
|
66
|
+
snapshots?: WarmApiSnapshot[];
|
|
67
|
+
generated_at?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface WarmApiRecurring {
|
|
70
|
+
average_amount?: number | null;
|
|
71
|
+
description?: string | null;
|
|
72
|
+
frequency?: string | null;
|
|
73
|
+
is_active?: boolean | null;
|
|
74
|
+
last_amount?: number | null;
|
|
75
|
+
merchant_name?: string | null;
|
|
76
|
+
next_date?: string | null;
|
|
77
|
+
stream_type?: string | null;
|
|
78
|
+
}
|
|
79
|
+
export interface WarmApiRecurringResponse {
|
|
80
|
+
recurring_transactions?: WarmApiRecurring[];
|
|
81
|
+
generated_at?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface WarmApiBudget {
|
|
84
|
+
amount?: number | null;
|
|
85
|
+
name?: string | null;
|
|
86
|
+
period?: string | null;
|
|
87
|
+
percent_used?: number | null;
|
|
88
|
+
remaining?: number | null;
|
|
89
|
+
spent?: number | null;
|
|
90
|
+
status?: string | null;
|
|
91
|
+
}
|
|
92
|
+
export interface WarmApiBudgetsResponse {
|
|
93
|
+
budgets?: WarmApiBudget[];
|
|
94
|
+
generated_at?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface WarmApiGoal {
|
|
97
|
+
category?: string | null;
|
|
98
|
+
current?: number | null;
|
|
99
|
+
monthly_contribution_needed?: number | null;
|
|
100
|
+
name?: string | null;
|
|
101
|
+
progress_percent?: number | null;
|
|
102
|
+
status?: string | null;
|
|
103
|
+
target?: number | null;
|
|
104
|
+
target_date?: string | null;
|
|
105
|
+
}
|
|
106
|
+
export interface WarmApiGoalsResponse {
|
|
107
|
+
goals?: WarmApiGoal[];
|
|
108
|
+
generated_at?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface WarmApiHealthResponse {
|
|
111
|
+
score?: number | null;
|
|
112
|
+
label?: string | null;
|
|
113
|
+
pillars?: {
|
|
114
|
+
spend?: number | null;
|
|
115
|
+
save?: number | null;
|
|
116
|
+
borrow?: number | null;
|
|
117
|
+
build?: number | null;
|
|
118
|
+
} | null;
|
|
119
|
+
data_completeness?: number | null;
|
|
120
|
+
message?: string | null;
|
|
121
|
+
generated_at?: string;
|
|
122
|
+
}
|
|
123
|
+
export interface WarmApiLiability {
|
|
124
|
+
account_id?: string | null;
|
|
125
|
+
type?: string | null;
|
|
126
|
+
balance?: number | null;
|
|
127
|
+
apr_percentage?: number | null;
|
|
128
|
+
interest_rate_percentage?: number | null;
|
|
129
|
+
interest_rate_type?: string | null;
|
|
130
|
+
minimum_payment?: number | null;
|
|
131
|
+
next_payment_due_date?: string | null;
|
|
132
|
+
expected_payoff_date?: string | null;
|
|
133
|
+
origination_principal_amount?: number | null;
|
|
134
|
+
is_overdue?: boolean | null;
|
|
135
|
+
}
|
|
136
|
+
export interface WarmApiLiabilitiesResponse {
|
|
137
|
+
liabilities?: WarmApiLiability[];
|
|
138
|
+
generated_at?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface WarmApiHolding {
|
|
141
|
+
account_id?: string | null;
|
|
142
|
+
security_name?: string | null;
|
|
143
|
+
symbol?: string | null;
|
|
144
|
+
type?: string | null;
|
|
145
|
+
quantity?: number | null;
|
|
146
|
+
value?: number | null;
|
|
147
|
+
cost_basis?: number | null;
|
|
148
|
+
}
|
|
149
|
+
export interface WarmApiHoldingsResponse {
|
|
150
|
+
holdings?: WarmApiHolding[];
|
|
151
|
+
generated_at?: string;
|
|
152
|
+
}
|
|
153
|
+
export interface WarmApiVerifyResponse {
|
|
154
|
+
valid?: boolean;
|
|
155
|
+
status?: string;
|
|
156
|
+
error?: string;
|
|
157
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type VerifyKeyOutput } from './schemas.js';
|
|
3
|
+
import type { RegisteredWarmTools, WarmApiClient, WarmApiClientOptions, WarmServerOptions, WarmToolRegistrationTarget } from './types.js';
|
|
4
|
+
export declare const WARM_SERVER_INFO: {
|
|
5
|
+
readonly name: "warm";
|
|
6
|
+
readonly version: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const API_URL: string;
|
|
9
|
+
export declare function getConfiguredApiKey(): string | null;
|
|
10
|
+
export declare function apiRequest<TResponse>(endpoint: string, params?: Record<string, string | undefined>, options?: WarmApiClientOptions): Promise<TResponse>;
|
|
11
|
+
export declare function createWarmApiClient(options?: WarmApiClientOptions): WarmApiClient;
|
|
12
|
+
export declare function registerWarmTools(server: WarmToolRegistrationTarget, options?: WarmApiClientOptions): RegisteredWarmTools;
|
|
13
|
+
export declare function createWarmServer(options?: WarmServerOptions): McpServer;
|
|
14
|
+
export declare function verifyWarmApiKey(apiKey: string): Promise<VerifyKeyOutput>;
|