@warmio/mcp 5.0.0 → 6.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/dist/schemas.js CHANGED
@@ -1,160 +1,223 @@
1
1
  import { z } from 'zod';
2
+ const monthSchema = z.string().regex(/^\d{4}-\d{2}$/, 'Expected YYYY-MM month.');
2
3
  const dateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Expected YYYY-MM-DD date.');
3
4
  const dateTimeSchema = z.string().datetime({ offset: true });
4
5
  export const emptyInputSchema = {};
5
- export const accountTypeSchema = z.enum([
6
- 'depository',
7
- 'credit',
8
- 'loan',
9
- 'investment',
10
- 'other',
11
- ]);
12
- export const getAccountsOutputSchema = {
13
- accounts: z.array(z
6
+ export const transactionIndexSchema = z
7
+ .object({
8
+ total: z.number().int().nonnegative(),
9
+ months: z.array(z
14
10
  .object({
15
- balance: z.number().finite(),
16
- institution: z.string().nullable(),
17
- mask: z.string().nullable(),
18
- name: z.string(),
19
- subtype: z.string().nullable(),
20
- type: accountTypeSchema,
11
+ month: monthSchema,
12
+ count: z.number().int().nonnegative(),
21
13
  })
22
14
  .strict()),
23
- };
15
+ })
16
+ .strict();
17
+ export const positionSchema = z
18
+ .object({
19
+ date: dateSchema.nullable(),
20
+ net_worth: z.number().finite().nullable(),
21
+ cash: z.number().finite().nullable(),
22
+ debt: z.number().finite().nullable(),
23
+ investments: z.number().finite().nullable(),
24
+ other_assets: z.number().finite().nullable(),
25
+ total_assets: z.number().finite().nullable(),
26
+ })
27
+ .strict();
28
+ export const accountSchema = z
29
+ .object({
30
+ id: z.string(),
31
+ name: z.string(),
32
+ type: z.enum(['depository', 'credit', 'loan', 'investment', 'brokerage', 'other']),
33
+ subtype: z.string().nullable(),
34
+ group: z.enum(['cash', 'debt', 'investments']).nullable(),
35
+ institution: z.string().nullable(),
36
+ mask: z.string().nullable(),
37
+ balance: z.number().finite().nullable(),
38
+ available: z.number().finite().nullable(),
39
+ currency: z.string().nullable(),
40
+ updated_at: dateTimeSchema.nullable(),
41
+ })
42
+ .strict();
43
+ export const statusSchema = z
44
+ .object({
45
+ position: positionSchema.nullable(),
46
+ accounts: z.array(accountSchema),
47
+ })
48
+ .strict();
49
+ export const recurringSchema = z
50
+ .object({
51
+ id: z.string(),
52
+ account_id: z.string().nullable(),
53
+ direction: z.enum(['inflow', 'outflow']).nullable(),
54
+ frequency: z
55
+ .enum(['WEEKLY', 'BIWEEKLY', 'MONTHLY', 'QUARTERLY', 'SEMI_ANNUALLY', 'ANNUALLY'])
56
+ .nullable(),
57
+ status: z.enum(['active', 'inactive', 'dismissed']).nullable(),
58
+ merchant: z.string().nullable(),
59
+ amount: z.number().finite().nullable(),
60
+ next_date: dateSchema.nullable(),
61
+ })
62
+ .strict();
63
+ export const budgetSchema = z
64
+ .object({
65
+ id: z.string(),
66
+ name: z.string(),
67
+ type: z.enum(['category', 'merchant']),
68
+ period: z.enum(['weekly', 'biweekly', 'monthly']),
69
+ status: z.enum(['under', 'warning', 'over']),
70
+ amount: z.number().finite(),
71
+ spent: z.number().finite(),
72
+ remaining: z.number().finite(),
73
+ used_percent: z.number().finite(),
74
+ })
75
+ .strict();
76
+ export const goalSchema = z
77
+ .object({
78
+ id: z.string(),
79
+ name: z.string(),
80
+ category: z.string(),
81
+ status: z.enum(['not_started', 'in_progress', 'on_track', 'behind', 'completed']),
82
+ target: z.number().finite(),
83
+ current: z.number().finite(),
84
+ progress_percent: z.number().finite(),
85
+ target_date: dateSchema.nullable(),
86
+ })
87
+ .strict();
88
+ export const snapshotSchema = z
89
+ .object({
90
+ date: dateSchema,
91
+ net_worth: z.number().finite().nullable(),
92
+ cash: z.number().finite().nullable(),
93
+ debt: z.number().finite().nullable(),
94
+ income: z.number().finite().nullable(),
95
+ expenses: z.number().finite().nullable(),
96
+ cash_flow: z.number().finite().nullable(),
97
+ savings_rate: z.number().finite().nullable(),
98
+ investments: z.number().finite().nullable(),
99
+ assets: z.number().finite().nullable(),
100
+ health_score: z.number().finite().nullable(),
101
+ })
102
+ .strict();
103
+ export const liabilitySchema = z
104
+ .object({
105
+ account_id: z.string().nullable(),
106
+ type: z.enum(['credit', 'student', 'mortgage', 'other']).nullable(),
107
+ balance: z.number().finite().nullable(),
108
+ minimum_payment: z.number().finite().nullable(),
109
+ due_date: dateSchema.nullable(),
110
+ interest_rate: z.number().finite().nullable(),
111
+ rate_type: z.enum(['fixed', 'variable']).nullable(),
112
+ overdue: z.boolean().nullable(),
113
+ })
114
+ .strict();
115
+ export const holdingSchema = z
116
+ .object({
117
+ account_id: z.string().nullable(),
118
+ symbol: z.string().nullable(),
119
+ name: z.string().nullable(),
120
+ type: z
121
+ .enum(['cash', 'derivative', 'equity', 'etf', 'fixed_income', 'mutual_fund', 'other'])
122
+ .nullable(),
123
+ quantity: z.number().finite().nullable(),
124
+ value: z.number().finite().nullable(),
125
+ cost_basis: z.number().finite().nullable(),
126
+ })
127
+ .strict();
128
+ export const healthSchema = z
129
+ .object({
130
+ score: z.number().finite(),
131
+ label: z.enum(['Needs Attention', 'Good', 'Strong']),
132
+ level: z.enum(['critical', 'poor', 'fair', 'good', 'strong']),
133
+ summary: z.string(),
134
+ data_completeness: z.number().finite(),
135
+ pillars: z
136
+ .object({
137
+ spend: z.number().finite().nullable(),
138
+ save: z.number().finite().nullable(),
139
+ borrow: z.number().finite().nullable(),
140
+ build: z.number().finite().nullable(),
141
+ })
142
+ .strict()
143
+ .nullable(),
144
+ })
145
+ .strict();
146
+ export const financialContextSchema = z
147
+ .object({
148
+ version: z.literal('v1'),
149
+ updated_at: dateTimeSchema,
150
+ currency: z.literal('USD'),
151
+ status: statusSchema,
152
+ transactions: transactionIndexSchema,
153
+ recurring: z.array(recurringSchema),
154
+ budgets: z.array(budgetSchema),
155
+ goals: z.array(goalSchema),
156
+ snapshots: z.array(snapshotSchema),
157
+ liabilities: z.array(liabilitySchema),
158
+ holdings: z.array(holdingSchema),
159
+ health: healthSchema.nullable(),
160
+ })
161
+ .strict();
162
+ export const transactionSchema = z
163
+ .object({
164
+ id: z.string(),
165
+ account_id: z.string().nullable(),
166
+ date: dateSchema.nullable(),
167
+ amount: z.number().finite(),
168
+ merchant: z.string().nullable(),
169
+ name: z.string().nullable(),
170
+ category: z.string().nullable(),
171
+ subcategory: z.string().nullable(),
172
+ pending: z.boolean().nullable(),
173
+ currency: z.string().nullable(),
174
+ })
175
+ .strict();
176
+ export const transactionMonthSchema = z
177
+ .object({
178
+ month: monthSchema,
179
+ start_date: dateSchema,
180
+ end_date: dateSchema,
181
+ count: z.number().int().nonnegative(),
182
+ items: z.array(transactionSchema),
183
+ })
184
+ .strict();
185
+ export const latestTransactionsSchema = z
186
+ .object({
187
+ since: dateSchema,
188
+ window_days: z.literal(10),
189
+ count: z.number().int().nonnegative(),
190
+ items: z.array(transactionSchema),
191
+ })
192
+ .strict();
24
193
  export const getTransactionsInputSchema = {
25
- cursor: z
26
- .string()
27
- .min(1)
194
+ month: monthSchema
28
195
  .optional()
29
- .describe('Opaque pagination cursor from a prior get_transactions response.'),
30
- last_knowledge: dateTimeSchema
196
+ .describe('Transaction month in YYYY-MM format. Mutually exclusive with latest. Months outside the covered range return an error.'),
197
+ latest: z
198
+ .boolean()
31
199
  .optional()
32
- .describe('Incremental sync checkpoint. Cannot be combined with cursor.'),
33
- limit: z
34
- .number()
35
- .int()
36
- .min(1)
37
- .max(1000)
38
- .default(500)
39
- .describe('Maximum transactions to return (default 500, max 1000).'),
40
- search: z
41
- .string()
42
- .min(1)
43
- .max(120)
44
- .optional()
45
- .describe('Optional merchant or description search query.'),
200
+ .describe('When true, return the fixed 10-day latest window. Mutually exclusive with month. A bare call with no arguments defaults to latest: true.'),
46
201
  };
47
- export const getTransactionsOutputSchema = {
48
- generated_at: dateTimeSchema.nullable(),
49
- next_knowledge: dateTimeSchema.nullable(),
50
- pagination: z
51
- .object({
52
- has_more: z.boolean(),
53
- limit: z.number().int().min(1).max(1000),
54
- next_cursor: z.string().nullable(),
55
- })
56
- .strict(),
57
- txns: z.array(z
58
- .object({
59
- amount: z.number().finite(),
60
- category: z.string().nullable(),
61
- date: dateSchema.nullable(),
62
- description: z.string().nullable(),
63
- detailed_category: z.string().nullable(),
64
- id: z.string().nullable(),
65
- merchant: z.string().nullable(),
66
- })
67
- .strict()),
68
- };
69
- export const getFinancialStateOutputSchema = {
70
- budgets: z.array(z
71
- .object({
72
- amount: z.number().finite(),
73
- name: z.string(),
74
- percent_used: z.number().finite(),
75
- period: z.string(),
76
- remaining: z.number().finite(),
77
- spent: z.number().finite(),
78
- status: z.string().nullable(),
79
- })
80
- .strict()),
81
- category_spending: z.array(z
82
- .object({
83
- amount: z.number().finite(),
84
- category: z.string(),
85
- })
86
- .strict()),
202
+ export const financialContextMetaSchema = z
203
+ .object({
204
+ version: z.literal('v1'),
205
+ user_id: z.string(),
206
+ context_id: z.string(),
87
207
  generated_at: dateTimeSchema,
88
- goals: z.array(z
208
+ updated_at: dateTimeSchema,
209
+ content_hash: z.string(),
210
+ byte_length: z.number().int().nonnegative(),
211
+ counts: z
89
212
  .object({
90
- category: z.string().nullable(),
91
- current: z.number().finite(),
92
- monthly_contribution_needed: z.number().finite().nullable(),
93
- name: z.string(),
94
- progress_percent: z.number().finite(),
95
- status: z.string().nullable(),
96
- target: z.number().finite(),
97
- target_date: dateSchema.nullable(),
98
- })
99
- .strict()),
100
- health: z
101
- .object({
102
- data_completeness: z.number().finite().nullable(),
103
- label: z.string().nullable(),
104
- message: z.string().nullable(),
105
- pillars: z
106
- .object({
107
- borrow: z.number().finite().nullable(),
108
- build: z.number().finite().nullable(),
109
- save: z.number().finite().nullable(),
110
- spend: z.number().finite().nullable(),
111
- })
112
- .strict()
113
- .nullable(),
114
- score: z.number().finite().nullable(),
213
+ accounts: z.number().int().nonnegative(),
214
+ transaction_months: z.number().int().nonnegative(),
215
+ transactions: z.number().int().nonnegative(),
216
+ snapshots: z.number().int().nonnegative(),
115
217
  })
116
218
  .strict(),
117
- holdings: z.array(z
118
- .object({
119
- account_id: z.string(),
120
- cost_basis: z.number().finite().nullable(),
121
- quantity: z.number().finite(),
122
- security_name: z.string().nullable(),
123
- symbol: z.string().nullable(),
124
- type: z.string().nullable(),
125
- value: z.number().finite().nullable(),
126
- })
127
- .strict()),
128
- liabilities: z.array(z
129
- .object({
130
- account_id: z.string(),
131
- apr_percentage: z.number().finite().nullable(),
132
- balance: z.number().finite().nullable(),
133
- is_overdue: z.boolean().nullable(),
134
- minimum_payment: z.number().finite().nullable(),
135
- next_payment_due_date: dateSchema.nullable(),
136
- type: z.string(),
137
- })
138
- .strict()),
139
- recurring: z.array(z
140
- .object({
141
- active: z.boolean(),
142
- amount: z.number().finite(),
143
- frequency: z.string(),
144
- merchant: z.string(),
145
- next_date: dateSchema.nullable(),
146
- type: z.string().nullable(),
147
- })
148
- .strict()),
149
- snapshots: z.array(z
150
- .object({
151
- date: dateSchema,
152
- net_worth: z.number().finite(),
153
- total_assets: z.number().finite(),
154
- total_liabilities: z.number().finite(),
155
- })
156
- .strict()),
157
- };
219
+ })
220
+ .strict();
158
221
  export const verifyKeyOutputSchema = {
159
222
  status: z.string(),
160
223
  valid: z.boolean(),
package/dist/server.js CHANGED
@@ -32,38 +32,38 @@ function createStructuredToolResult(structuredContent) {
32
32
  structuredContent,
33
33
  };
34
34
  }
35
+ function parseGetTransactionsArgs(args) {
36
+ const hasMonth = typeof args.month === 'string';
37
+ const hasLatestKey = Object.prototype.hasOwnProperty.call(args, 'latest');
38
+ const hasLatest = args.latest === true;
39
+ if (hasMonth && hasLatestKey) {
40
+ throw new Error('`month` and `latest` are mutually exclusive.');
41
+ }
42
+ if (hasMonth) {
43
+ return { month: args.month };
44
+ }
45
+ if (hasLatest || Object.keys(args).length === 0) {
46
+ return { latest: true };
47
+ }
48
+ throw new Error('Call get_transactions with `month` in YYYY-MM format, `latest: true`, or no arguments.');
49
+ }
35
50
  export function registerWarmTools(server, options = {}) {
36
51
  const client = createWarmApiClient(options);
37
52
  const tools = [
38
53
  {
39
- description: 'Read-only list of connected financial accounts with balances, subtypes, institutions, and masks when available.',
40
- handler: async () => await client.getAccounts(),
54
+ description: 'Read-only compact FinancialContext JSON. Includes status.position, status.accounts, transaction index total/months, recurring, budgets, goals, snapshots, liabilities, holdings, and health. Transaction items are not inline; use get_transactions for items.',
55
+ handler: async () => await client.getFinancialContext(),
41
56
  inputShape: emptyInputSchema,
42
- name: 'get_accounts',
57
+ name: 'get_financial_context',
43
58
  },
44
59
  {
45
- description: 'Read-only transaction export with strict opaque cursor pagination and optional last_knowledge incremental sync.',
60
+ description: 'Read-only transactions from the FinancialContext artifact. Pass exactly one selector: `month` in YYYY-MM format for a month page, or `latest: true` for the fixed latest window. A bare call with no arguments defaults to `latest: true`. The latest window is fixed at 10 days and is not caller-configurable. `month` and `latest` are mutually exclusive. Months outside the covered range return an error.',
46
61
  handler: async (args) => {
47
- const transactionArgs = {
48
- cursor: typeof args.cursor === 'string' ? args.cursor : undefined,
49
- last_knowledge: typeof args.last_knowledge === 'string' ? args.last_knowledge : undefined,
50
- limit: typeof args.limit === 'number' ? args.limit : 500,
51
- search: typeof args.search === 'string' ? args.search : undefined,
52
- };
53
- if (transactionArgs.cursor && transactionArgs.last_knowledge) {
54
- throw new Error('`cursor` cannot be combined with `last_knowledge`.');
55
- }
56
- return await client.getTransactions(transactionArgs);
62
+ return await client.getTransactions(parseGetTransactionsArgs(args));
57
63
  },
58
64
  inputShape: getTransactionsInputSchema,
59
65
  name: 'get_transactions',
60
66
  },
61
- {
62
- description: 'Read-only broad financial state bundle with snapshots, recurring payments, budgets, goals, financial health, liabilities, holdings, and category spending.',
63
- handler: async () => await client.getFinancialState(),
64
- inputShape: emptyInputSchema,
65
- name: 'get_financial_state',
66
- },
67
67
  {
68
68
  description: 'Read-only API key validation for the configured Warm account.',
69
69
  handler: async () => await client.verifyKey(),
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const WARM_TOOL_NAMES: readonly ["get_accounts", "get_transactions", "get_financial_state", "verify_key"];
1
+ export declare const WARM_TOOL_NAMES: readonly ["get_financial_context", "get_transactions", "verify_key"];
2
2
  export type WarmToolName = (typeof WARM_TOOL_NAMES)[number];
3
- export type { GetAccountsOutput, GetTransactionsInput, GetTransactionsOutput, VerifyKeyOutput, WarmApiAccount, WarmApiBudget, WarmApiClient, WarmApiClientOptions, WarmApiGoal, WarmApiHolding, WarmApiLiability, WarmApiTransaction, WarmFinancialState, } from './warm-api-client.js';
3
+ export type { Account, Budget, FinancialContext, FinancialContextMeta, GetTransactionsInput, GetTransactionsOutput, Goal, Health, Holding, LatestTransactions, Liability, Position, Recurring, Snapshot, Status, Transaction, TransactionIndex, TransactionMonth, VerifyKeyOutput, WarmApiClient, WarmApiClientOptions, } from './warm-api-client.js';
4
4
  export type { WarmServerOptions } from './server.js';
package/dist/types.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export const WARM_TOOL_NAMES = [
2
- 'get_accounts',
2
+ 'get_financial_context',
3
3
  'get_transactions',
4
- 'get_financial_state',
5
4
  'verify_key',
6
5
  ];