@warmio/mcp 9.0.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export declare const WARM_CONTEXT_TOOL_NAMES: readonly ["get_financial_context", "get_transactions", "verify_key"];
2
- export declare const WARM_AUTOMATION_TOOL_NAMES: readonly ["search_operations", "describe_operation", "invoke_operation"];
3
- export declare const WARM_TOOL_NAMES: readonly ["get_financial_context", "get_transactions", "verify_key", "search_operations", "describe_operation", "invoke_operation"];
4
- export type WarmToolName = (typeof WARM_TOOL_NAMES)[number];
1
+ import { privateMcpToolDefinitions } from '@warmio/contracts/mcp';
2
+ export declare const WARM_CONTEXT_TOOL_NAMES: string[];
3
+ export declare const WARM_AUTOMATION_TOOL_NAMES: string[];
4
+ export declare const WARM_TOOL_NAMES: string[];
5
+ export type WarmToolName = (typeof privateMcpToolDefinitions)[number]['name'];
5
6
  export type { Account, AutomationInput, AutomationOperation, AutomationOperationDescription, Budget, DescribeOperationOutput, FinancialContext, FinancialContextMeta, GetTransactionsInput, GetTransactionsOutput, Goal, Health, Holding, InvokeOperationOutput, LatestTransactions, Liability, Position, Recurring, Snapshot, Status, Transaction, TransactionIndex, TransactionMonth, VerifyKeyOutput, WarmApiClient, WarmApiClientOptions, } from './warm-api-client.js';
6
7
  export type { PrivateMcpMode } from '@warmio/contracts/mcp';
7
8
  export type { WarmServerOptions } from './server.js';
package/dist/types.js CHANGED
@@ -1,11 +1,8 @@
1
- export const WARM_CONTEXT_TOOL_NAMES = [
2
- 'get_financial_context',
3
- 'get_transactions',
4
- 'verify_key',
5
- ];
6
- export const WARM_AUTOMATION_TOOL_NAMES = [
7
- 'search_operations',
8
- 'describe_operation',
9
- 'invoke_operation',
10
- ];
11
- export const WARM_TOOL_NAMES = [...WARM_CONTEXT_TOOL_NAMES, ...WARM_AUTOMATION_TOOL_NAMES];
1
+ import { privateMcpToolDefinitions } from '@warmio/contracts/mcp';
2
+ export const WARM_CONTEXT_TOOL_NAMES = privateMcpToolDefinitions
3
+ .filter((tool) => tool.mode === 'context')
4
+ .map((tool) => tool.name);
5
+ export const WARM_AUTOMATION_TOOL_NAMES = privateMcpToolDefinitions
6
+ .filter((tool) => tool.mode === 'automation')
7
+ .map((tool) => tool.name);
8
+ export const WARM_TOOL_NAMES = privateMcpToolDefinitions.map((tool) => tool.name);
@@ -1,11 +1,20 @@
1
1
  import { getWarmApiKeyPath, readConfigFile } from './config-paths.js';
2
+ import { API_ORIGIN, apiEndpointManifest, } from '@warmio/contracts/api';
2
3
  import { WARM_MCP_CREDENTIALS, WARM_MCP_INSTALLER_COMMANDS, } from '@warmio/contracts/mcp';
3
- const DEFAULT_API_URL = process.env.WARM_API_URL || 'https://app.warm.io';
4
+ const DEFAULT_API_URL = process.env.WARM_API_URL || API_ORIGIN;
4
5
  const DEFAULT_REQUEST_TIMEOUT_MS = (() => {
5
6
  const raw = Number(process.env.WARM_API_TIMEOUT_MS || 10_000);
6
7
  return Number.isFinite(raw) && raw > 0 ? raw : 10_000;
7
8
  })();
8
9
  const cachedApiKeys = new Map();
10
+ const endpointByOperationId = Object.fromEntries(apiEndpointManifest.map((endpoint) => [endpoint.operation_id, endpoint]));
11
+ function getEndpointPath(operationId, audience) {
12
+ const endpoint = endpointByOperationId[operationId];
13
+ if (endpoint.audience !== audience) {
14
+ throw new Error(`API operation ${operationId} is not available to ${audience}.`);
15
+ }
16
+ return endpoint.path;
17
+ }
9
18
  function getRequestSignal(timeoutMs) {
10
19
  if (typeof AbortSignal.timeout === 'function') {
11
20
  return AbortSignal.timeout(timeoutMs);
@@ -120,23 +129,29 @@ async function requestSuccessfulJson(request, options) {
120
129
  return response.body;
121
130
  }
122
131
  export function createWarmApiClient(options = {}) {
123
- const getFinancialContext = async () => await requestSuccessfulJson({ endpoint: '/api/financial-context' }, options);
124
- const getFinancialContextMeta = async () => await requestSuccessfulJson({ endpoint: '/api/financial-context/meta' }, options);
132
+ const getFinancialContext = async () => await requestSuccessfulJson({ endpoint: getEndpointPath('getFinancialContext', 'context') }, options);
133
+ const getFinancialContextMeta = async () => await requestSuccessfulJson({ endpoint: getEndpointPath('getFinancialContextMeta', 'context') }, options);
125
134
  const getTransactions = async (input) => {
126
135
  const rawInput = input;
127
136
  if (typeof rawInput.month === 'string' && rawInput.latest !== undefined) {
128
137
  throw new Error('`month` and `latest` are mutually exclusive.');
129
138
  }
130
139
  if (typeof rawInput.month === 'string') {
131
- return await requestSuccessfulJson({ endpoint: '/api/financial-context/transactions', query: { month: rawInput.month } }, options);
140
+ return await requestSuccessfulJson({
141
+ endpoint: getEndpointPath('getFinancialContextTransactions', 'context'),
142
+ query: { month: rawInput.month },
143
+ }, options);
132
144
  }
133
145
  if (rawInput.latest === true) {
134
- return await requestSuccessfulJson({ endpoint: '/api/financial-context/transactions', query: { latest: '1' } }, options);
146
+ return await requestSuccessfulJson({
147
+ endpoint: getEndpointPath('getFinancialContextTransactions', 'context'),
148
+ query: { latest: '1' },
149
+ }, options);
135
150
  }
136
151
  throw new Error('Call getTransactions with `month` in YYYY-MM format or `latest: true`.');
137
152
  };
138
153
  const verifyKey = async () => {
139
- const response = await requestSuccessfulJson({ endpoint: '/api/verify' }, options);
154
+ const response = await requestSuccessfulJson({ endpoint: getEndpointPath('verifyApiAccess', 'context') }, options);
140
155
  return {
141
156
  audience: response.audience,
142
157
  status: response.status || (response.valid ? 'ok' : 'invalid'),
@@ -146,7 +161,8 @@ export function createWarmApiClient(options = {}) {
146
161
  const validateAudience = async () => {
147
162
  const result = await verifyKey();
148
163
  const expectedAudience = createWarmApiClientConfig(options).audience;
149
- if (!result.valid || result.audience !== expectedAudience) {
164
+ const hasCompatibleAudience = result.audience === expectedAudience || result.audience === 'oauth';
165
+ if (!result.valid || !hasCompatibleAudience) {
150
166
  const article = expectedAudience === 'automation' ? 'an' : 'a';
151
167
  throw new Error(`This MCP mode requires ${article} ${expectedAudience} API key. Run "${WARM_MCP_INSTALLER_COMMANDS[expectedAudience]}" to configure a separate key.`);
152
168
  }
@@ -154,12 +170,12 @@ export function createWarmApiClient(options = {}) {
154
170
  };
155
171
  const searchOperations = async (query) => await requestSuccessfulJson({
156
172
  body: query ? { query } : {},
157
- endpoint: '/api/automation/operations/search',
173
+ endpoint: getEndpointPath('searchOperations', 'automation'),
158
174
  method: 'POST',
159
175
  }, options);
160
176
  const describeOperation = async (operationId, input) => await requestSuccessfulJson({
161
177
  body: { operation_id: operationId, ...(input ? { input } : {}) },
162
- endpoint: '/api/automation/operations/describe',
178
+ endpoint: getEndpointPath('describeOperation', 'automation'),
163
179
  method: 'POST',
164
180
  }, options);
165
181
  const invokeOperation = async (operationId, input, approvalId) => await requestSuccessfulJson({
@@ -168,7 +184,7 @@ export function createWarmApiClient(options = {}) {
168
184
  input: input ?? {},
169
185
  ...(approvalId ? { approval_id: approvalId } : {}),
170
186
  },
171
- endpoint: '/api/automation/operations/invoke',
187
+ endpoint: getEndpointPath('invokeOperation', 'automation'),
172
188
  method: 'POST',
173
189
  }, options);
174
190
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmio/mcp",
3
- "version": "9.0.0",
3
+ "version": "9.1.1",
4
4
  "mcpName": "io.github.jasonstockman/warmio",
5
5
  "description": "Warm CLI and compact context or automation MCP server",
6
6
  "type": "module",
@@ -60,7 +60,7 @@
60
60
  "url": "git+https://github.com/jasonstockman/warm-mcp.git"
61
61
  },
62
62
  "dependencies": {
63
- "@warmio/contracts": "1.1.0",
63
+ "@warmio/contracts": "1.2.0",
64
64
  "@modelcontextprotocol/sdk": "^1.27.1",
65
65
  "dotenv": "^17.2.3",
66
66
  "zod": "^3.25.76"