@wavespeed/mcp 1.0.12 → 1.0.13

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
@@ -36,6 +36,9 @@ Built on the same design as the open-source [`@wavespeed/cli`](https://github.co
36
36
  | `run_model` | Submit + wait; rejects input keys the model doesn't accept; `@path` inputs upload automatically; returns output URLs |
37
37
  | `get_price` | Cost estimate with `unpriced_inputs` / `at_base_price` disclosure |
38
38
  | `get_balance` | Account credit balance |
39
+ | `list_predictions` | Run history (default last 24h); filter by model, status, time range |
40
+ | `list_billings` | Itemized charges and refunds (needs a Billing-access key) |
41
+ | `get_usage` | Spend, request counts and per-model breakdown (default last 7 days; needs a Billing-access key) |
39
42
  | `upload_file` | Local file → hosted URL (24h content-hash dedupe) |
40
43
  | `get_prediction` | Status/outputs of any run by id; optional `wait_seconds` to wait for it |
41
44
 
package/dist/lib/api.js CHANGED
@@ -162,6 +162,44 @@ export async function fetchModels(opts = {}) {
162
162
  export async function fetchBalance() {
163
163
  return apiGet('/api/v3/balance');
164
164
  }
165
+ export const PREDICTION_STATUSES = ['created', 'processing', 'completed', 'failed', 'cancelled', 'timeout', 'deleted'];
166
+ // Same contract as wavespeed-cli `history`: the endpoint needs a time window,
167
+ // so default to the last 24 hours.
168
+ export async function fetchHistory(query = {}) {
169
+ const now = new Date();
170
+ const body = {
171
+ page: query.page ?? 1,
172
+ page_size: query.pageSize ?? 20,
173
+ created_after: query.createdAfter ?? new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString(),
174
+ created_before: query.createdBefore ?? now.toISOString(),
175
+ };
176
+ if (query.model)
177
+ body.model = query.model;
178
+ if (query.status)
179
+ body.status = query.status;
180
+ return apiPost('/api/v3/predictions', body, { timeoutMs: GET_TIMEOUT_MS });
181
+ }
182
+ // Needs a key with Billing access; otherwise the platform's own error is surfaced.
183
+ export async function fetchBillings(query = {}) {
184
+ const body = { page: query.page ?? 1, page_size: query.pageSize ?? 20 };
185
+ if (query.type)
186
+ body.billing_type = query.type;
187
+ if (query.startTime)
188
+ body.start_time = query.startTime;
189
+ if (query.endTime)
190
+ body.end_time = query.endTime;
191
+ if (query.model)
192
+ body.model_uuid = query.model;
193
+ if (query.accessKey)
194
+ body.access_key_uuid = query.accessKey;
195
+ return apiPost('/api/v3/billings/search', body, { timeoutMs: GET_TIMEOUT_MS });
196
+ }
197
+ export async function fetchUsageStats(startTime, endTime, model) {
198
+ const body = { start_time: startTime, end_time: endTime };
199
+ if (model)
200
+ body.model_uuid = model;
201
+ return apiPost('/api/v3/user/usage_stats', body, { timeoutMs: GET_TIMEOUT_MS });
202
+ }
165
203
  export async function fetchPricing(modelId, inputs) {
166
204
  // /model/price is the documented pricing endpoint.
167
205
  return apiPost('/api/v3/model/price', { model_id: modelId, inputs });
package/dist/server.js CHANGED
@@ -15,7 +15,7 @@ import { createRequire } from 'node:module';
15
15
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
16
16
  import { z } from 'zod';
17
17
  import { Client } from 'wavespeed';
18
- import { fetchModels, fetchBalance, fetchPricing, submitPrediction, waitForPrediction, MCP_CLIENT_NAME, TERMINAL_FAILURES, } from './lib/api.js';
18
+ import { fetchModels, fetchBalance, fetchHistory, fetchBillings, fetchUsageStats, PREDICTION_STATUSES, fetchPricing, submitPrediction, waitForPrediction, MCP_CLIENT_NAME, TERMINAL_FAILURES, } from './lib/api.js';
19
19
  import { getApiKey, getBaseUrl } from './lib/config.js';
20
20
  import { resolveLocalFiles } from './lib/local-files.js';
21
21
  import { uploadWithCache } from './lib/upload-cache.js';
@@ -23,6 +23,14 @@ import { missingPriceVars, isFloorQuote } from './lib/pricing-vars.js';
23
23
  import { findUnknownInputs } from './lib/validate-inputs.js';
24
24
  const require = createRequire(import.meta.url);
25
25
  const { version: PKG_VERSION } = require('../package.json');
26
+ function toIso(value, name) {
27
+ if (!value)
28
+ return undefined;
29
+ const t = Date.parse(value);
30
+ if (Number.isNaN(t))
31
+ throw new Error(`Invalid ${name} "${value}": use ISO 8601 or YYYY-MM-DD.`);
32
+ return new Date(t).toISOString();
33
+ }
26
34
  const PRICE_DISCLAIMER = 'Estimate only, for reference — the amount actually charged for a run is authoritative.';
27
35
  function requestSchema(m) {
28
36
  return m.api_schema?.api_schemas?.[0]?.request_schema;
@@ -235,6 +243,51 @@ export function createServer() {
235
243
  server.tool('get_balance', 'Show the WaveSpeed account credit balance.', {}, { readOnlyHint: true, openWorldHint: true }, async () => {
236
244
  return ok(await fetchBalance());
237
245
  });
246
+ server.tool('list_predictions', 'List past predictions (run history), newest window first. Defaults to the last 24 hours; pass since/until (ISO or YYYY-MM-DD) for other ranges. Use get_prediction with an id for one task in full.', {
247
+ page: z.number().int().min(1).default(1),
248
+ limit: z.number().int().min(1).max(100).default(20).describe('Page size'),
249
+ model: z.string().optional().describe('Filter by model ID'),
250
+ status: z.enum(PREDICTION_STATUSES).optional(),
251
+ since: z.string().optional().describe('Created after this time (ISO or YYYY-MM-DD)'),
252
+ until: z.string().optional().describe('Created before this time (ISO or YYYY-MM-DD)'),
253
+ }, { readOnlyHint: true, openWorldHint: true }, async ({ page, limit, model, status, since, until }) => {
254
+ return ok(await fetchHistory({
255
+ page,
256
+ pageSize: limit,
257
+ model,
258
+ status,
259
+ createdAfter: toIso(since, 'since'),
260
+ createdBefore: toIso(until, 'until'),
261
+ }));
262
+ });
263
+ server.tool('list_billings', 'List itemized charges and refunds (billing records). Requires an API key with Billing access.', {
264
+ page: z.number().int().min(1).default(1),
265
+ limit: z.number().int().min(1).max(100).default(20).describe('Page size'),
266
+ type: z.enum(['deduct', 'refund']).optional(),
267
+ model: z.string().optional().describe('Filter by model uuid'),
268
+ key: z.string().optional().describe('Filter by the API key uuid that generated the charge'),
269
+ since: z.string().optional().describe('Records after this time (ISO or YYYY-MM-DD)'),
270
+ until: z.string().optional().describe('Records before this time (ISO or YYYY-MM-DD)'),
271
+ }, { readOnlyHint: true, openWorldHint: true }, async ({ page, limit, type, model, key, since, until }) => {
272
+ return ok(await fetchBillings({
273
+ page,
274
+ pageSize: limit,
275
+ type,
276
+ model,
277
+ accessKey: key,
278
+ startTime: toIso(since, 'since'),
279
+ endTime: toIso(until, 'until'),
280
+ }));
281
+ });
282
+ server.tool('get_usage', 'Usage statistics: spend, request counts, daily series and per-model breakdown. Defaults to the last 7 days. Requires an API key with Billing access.', {
283
+ since: z.string().optional().describe('Start (ISO or YYYY-MM-DD); default 7 days ago'),
284
+ until: z.string().optional().describe('End (ISO or YYYY-MM-DD); default now'),
285
+ model: z.string().optional().describe('Filter by model uuid'),
286
+ }, { readOnlyHint: true, openWorldHint: true }, async ({ since, until, model }) => {
287
+ const end = toIso(until, 'until') ?? new Date().toISOString();
288
+ const start = toIso(since, 'since') ?? new Date(Date.parse(end) - 7 * 24 * 60 * 60 * 1000).toISOString();
289
+ return ok(await fetchUsageStats(start, end, model));
290
+ });
238
291
  server.tool('upload_file', 'Upload a local file to WaveSpeed and get its hosted URL (identical bytes reuse the same upload for 24h). Usually unnecessary — run_model handles "@./path" inputs itself.', { path: z.string().describe('Local file path') }, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }, async ({ path: filePath }) => {
239
292
  return ok(await uploadFile(filePath));
240
293
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wavespeed/mcp",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "WaveSpeed MCP server — run any model on the live WaveSpeed catalog (image, video, audio, 3D) with schema introspection, local-file upload, and price quotes.",
5
5
  "type": "module",
6
6
  "bin": {