@wavespeed/mcp 1.0.9 → 1.0.11
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 +24 -0
- package/dist/lib/api.js +18 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -43,6 +43,30 @@ Some generations take minutes to hours. `run_model` waits up to `wait_seconds` (
|
|
|
43
43
|
|
|
44
44
|
## Setup
|
|
45
45
|
|
|
46
|
+
### Remote (nothing to install)
|
|
47
|
+
|
|
48
|
+
The same server is hosted at:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
https://api.wavespeed.ai/mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- **Claude on the web / ChatGPT:** add a custom connector with that address and approve the connection on the WaveSpeed page that opens. Approving creates a dedicated API key (named `MCP · <app>`) that you can delete on the [API Keys](https://wavespeed.ai/accesskey) page to disconnect.
|
|
55
|
+
- **Claude Code:** `claude mcp add --transport http wavespeed https://api.wavespeed.ai/mcp`
|
|
56
|
+
- **Cursor:**
|
|
57
|
+
<a href="https://cursor.com/install-mcp?name=wavespeed&config=eyJ1cmwiOiJodHRwczovL2FwaS53YXZlc3BlZWQuYWkvbWNwIn0%3D">
|
|
58
|
+
<picture>
|
|
59
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/deeplink/mcp-install-light.svg">
|
|
60
|
+
<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Add the hosted wavespeed MCP server to Cursor" height="32"/>
|
|
61
|
+
</picture>
|
|
62
|
+
</a>
|
|
63
|
+
- **VS Code:** `code --add-mcp '{"name":"wavespeed","type":"http","url":"https://api.wavespeed.ai/mcp"}'`
|
|
64
|
+
- **Any other client that sends request headers:** point it at the URL with `Authorization: Bearer <your API key>`.
|
|
65
|
+
|
|
66
|
+
The hosted server has the same tools except for files: it cannot read files on your computer, so pass public URLs, or use `create_upload` from a tool that can send HTTP requests (it returns a temporary upload address and the `download_url` to use as an input). Full guide: [wavespeed.ai/docs/mcp](https://wavespeed.ai/docs/mcp).
|
|
67
|
+
|
|
68
|
+
### Local (npx)
|
|
69
|
+
|
|
46
70
|
Auth resolves from `WAVESPEED_API_KEY`, or from the CLI's stored login (`wavespeed login`) — one login covers both tools. Keys: [wavespeed.ai/accesskey](https://wavespeed.ai/accesskey).
|
|
47
71
|
|
|
48
72
|
**Claude Code**
|
package/dist/lib/api.js
CHANGED
|
@@ -77,9 +77,12 @@ function authHeaders() {
|
|
|
77
77
|
}
|
|
78
78
|
return { Authorization: `Bearer ${apiKey}`, ...clientAttributionHeaders() };
|
|
79
79
|
}
|
|
80
|
-
// A hung socket would otherwise stall
|
|
81
|
-
//
|
|
82
|
-
|
|
80
|
+
// Per-request timeouts (no overall cap). A hung socket would otherwise stall
|
|
81
|
+
// the tool call. Read-only GETs are far below 30s in practice (result p99.9
|
|
82
|
+
// < 1s); the async submit gets more headroom because a timeout there is an
|
|
83
|
+
// ambiguous outcome, not a clean failure.
|
|
84
|
+
export const GET_TIMEOUT_MS = 30_000;
|
|
85
|
+
export const SUBMIT_TIMEOUT_MS = 60_000;
|
|
83
86
|
async function apiGetOnce(apiPath) {
|
|
84
87
|
const res = await fetch(`${getBaseUrl()}${apiPath}`, {
|
|
85
88
|
headers: authHeaders(),
|
|
@@ -119,11 +122,12 @@ async function apiGet(apiPath, opts = {}) {
|
|
|
119
122
|
}
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
|
-
async function apiPost(apiPath, body) {
|
|
125
|
+
async function apiPost(apiPath, body, opts = {}) {
|
|
123
126
|
const res = await fetch(`${getBaseUrl()}${apiPath}`, {
|
|
124
127
|
method: 'POST',
|
|
125
128
|
headers: { ...authHeaders(), 'Content-Type': 'application/json' },
|
|
126
129
|
body: JSON.stringify(body),
|
|
130
|
+
signal: opts.timeoutMs ? AbortSignal.timeout(opts.timeoutMs) : undefined,
|
|
127
131
|
});
|
|
128
132
|
if (!res.ok)
|
|
129
133
|
throw await httpError(res, 'POST', apiPath);
|
|
@@ -168,7 +172,16 @@ export async function fetchPricing(modelId, inputs) {
|
|
|
168
172
|
* mid-generation must never orphan a paid task.
|
|
169
173
|
*/
|
|
170
174
|
export async function submitPrediction(model, input) {
|
|
171
|
-
|
|
175
|
+
try {
|
|
176
|
+
return await apiPost(`/api/v3/${model}`, { ...input }, { timeoutMs: SUBMIT_TIMEOUT_MS });
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
// Never retried: the server may already have created (and billed) the task.
|
|
180
|
+
if (err?.name === 'TimeoutError') {
|
|
181
|
+
throw new Error(`Submission outcome unknown: no response within ${SUBMIT_TIMEOUT_MS / 1000}s. The task may have been created and billed — do not resubmit blindly; if you have a prediction id, check it with get_prediction.`);
|
|
182
|
+
}
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
172
185
|
}
|
|
173
186
|
// The message always carries the task id and says the task was not declared
|
|
174
187
|
// failed — a status read that dies after submit must not look like a lost
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wavespeed/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
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": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
42
|
-
"wavespeed": "^0.3.
|
|
42
|
+
"wavespeed": "^0.3.4",
|
|
43
43
|
"zod": "^3.24.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|