@blockrun/mcp 0.21.3 → 0.21.5
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/index.js +52 -69
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -209,6 +209,18 @@ async function getChainBalance(chain, address) {
|
|
|
209
209
|
return chain === "solana" ? getSolanaUsdcBalance() : getBaseUsdcBalance(address);
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// src/utils/model-cache.ts
|
|
213
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
214
|
+
async function loadModels(llm, cache) {
|
|
215
|
+
if (!cache.models) {
|
|
216
|
+
cache.models = llm.listAllModels ? await llm.listAllModels() : await llm.listModels();
|
|
217
|
+
setTimeout(() => {
|
|
218
|
+
cache.models = null;
|
|
219
|
+
}, CACHE_TTL_MS).unref();
|
|
220
|
+
}
|
|
221
|
+
return cache.models;
|
|
222
|
+
}
|
|
223
|
+
|
|
212
224
|
// src/tools/wallet.ts
|
|
213
225
|
import { z } from "zod";
|
|
214
226
|
|
|
@@ -1043,14 +1055,7 @@ function registerModelsTool(server, modelCache) {
|
|
|
1043
1055
|
}
|
|
1044
1056
|
},
|
|
1045
1057
|
async ({ category, provider }) => {
|
|
1046
|
-
|
|
1047
|
-
if (!modelCache.models) {
|
|
1048
|
-
modelCache.models = "listAllModels" in llm ? await llm.listAllModels() : await llm.listModels();
|
|
1049
|
-
setTimeout(() => {
|
|
1050
|
-
modelCache.models = null;
|
|
1051
|
-
}, 5 * 60 * 1e3);
|
|
1052
|
-
}
|
|
1053
|
-
let models = modelCache.models;
|
|
1058
|
+
let models = await loadModels(getClient(), modelCache);
|
|
1054
1059
|
if (provider) {
|
|
1055
1060
|
const p = provider.toLowerCase();
|
|
1056
1061
|
models = models.filter((m) => m.id.toLowerCase().startsWith(p + "/"));
|
|
@@ -1243,6 +1248,26 @@ Error: ${errMsg}` }],
|
|
|
1243
1248
|
|
|
1244
1249
|
// src/tools/music.ts
|
|
1245
1250
|
import { z as z5 } from "zod";
|
|
1251
|
+
|
|
1252
|
+
// src/utils/http.ts
|
|
1253
|
+
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
1254
|
+
const controller = new AbortController();
|
|
1255
|
+
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
1256
|
+
id.unref?.();
|
|
1257
|
+
try {
|
|
1258
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
1259
|
+
} finally {
|
|
1260
|
+
clearTimeout(id);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
function isTimeoutError(err) {
|
|
1264
|
+
const name = err instanceof Error ? err.name : "";
|
|
1265
|
+
if (name === "AbortError" || name === "TimeoutError") return true;
|
|
1266
|
+
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
1267
|
+
return msg.includes("abort") || msg.includes("timeout") || msg.includes("timed out") || msg.includes("did not complete within");
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/tools/music.ts
|
|
1246
1271
|
import { privateKeyToAccount } from "viem/accounts";
|
|
1247
1272
|
import {
|
|
1248
1273
|
createPaymentPayload,
|
|
@@ -1372,7 +1397,7 @@ Error: ${errMsg}` }],
|
|
|
1372
1397
|
isError: true
|
|
1373
1398
|
};
|
|
1374
1399
|
}
|
|
1375
|
-
if (
|
|
1400
|
+
if (isTimeoutError(err)) {
|
|
1376
1401
|
return {
|
|
1377
1402
|
content: [{ type: "text", text: `Music generation timed out. This can happen during peak load \u2014 please try again.
|
|
1378
1403
|
Error: ${errMsg}` }],
|
|
@@ -1387,15 +1412,6 @@ Error: ${errMsg}` }],
|
|
|
1387
1412
|
}
|
|
1388
1413
|
);
|
|
1389
1414
|
}
|
|
1390
|
-
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
1391
|
-
const controller = new AbortController();
|
|
1392
|
-
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
1393
|
-
try {
|
|
1394
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
1395
|
-
} finally {
|
|
1396
|
-
clearTimeout(id);
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
1415
|
|
|
1400
1416
|
// src/tools/speech.ts
|
|
1401
1417
|
import { z as z6 } from "zod";
|
|
@@ -1514,7 +1530,7 @@ Returns a hosted audio URL \u2014 download immediately if you need to keep the f
|
|
|
1514
1530
|
}
|
|
1515
1531
|
const privateKey = getOrCreateWalletKey();
|
|
1516
1532
|
const account = privateKeyToAccount2(privateKey);
|
|
1517
|
-
const resp402 = await
|
|
1533
|
+
const resp402 = await fetchWithTimeout(endpoint, {
|
|
1518
1534
|
method: "POST",
|
|
1519
1535
|
headers: { "Content-Type": "application/json" },
|
|
1520
1536
|
body: JSON.stringify(body)
|
|
@@ -1540,7 +1556,7 @@ Returns a hosted audio URL \u2014 download immediately if you need to keep the f
|
|
|
1540
1556
|
extra: details.extra
|
|
1541
1557
|
}
|
|
1542
1558
|
);
|
|
1543
|
-
const resp = await
|
|
1559
|
+
const resp = await fetchWithTimeout(endpoint, {
|
|
1544
1560
|
method: "POST",
|
|
1545
1561
|
headers: {
|
|
1546
1562
|
"Content-Type": "application/json",
|
|
@@ -1593,7 +1609,7 @@ Error: ${errMsg}` }],
|
|
|
1593
1609
|
isError: true
|
|
1594
1610
|
};
|
|
1595
1611
|
}
|
|
1596
|
-
if (
|
|
1612
|
+
if (isTimeoutError(err)) {
|
|
1597
1613
|
return {
|
|
1598
1614
|
content: [{ type: "text", text: `Speech generation timed out \u2014 please try again.
|
|
1599
1615
|
Error: ${errMsg}` }],
|
|
@@ -1610,7 +1626,7 @@ Error: ${errMsg}` }],
|
|
|
1610
1626
|
}
|
|
1611
1627
|
async function listVoices() {
|
|
1612
1628
|
try {
|
|
1613
|
-
const resp = await
|
|
1629
|
+
const resp = await fetchWithTimeout(`${BLOCKRUN_API2}/v1/audio/voices`, { method: "GET" }, VOICES_TIMEOUT);
|
|
1614
1630
|
if (resp.ok) {
|
|
1615
1631
|
const payload = await resp.json();
|
|
1616
1632
|
const voices = payload.data || [];
|
|
@@ -1637,15 +1653,6 @@ Any raw ElevenLabs voice_id also works.` }],
|
|
|
1637
1653
|
structuredContent: { voices: VOICE_ALIASES }
|
|
1638
1654
|
};
|
|
1639
1655
|
}
|
|
1640
|
-
async function fetchWithTimeout2(url, options, timeoutMs) {
|
|
1641
|
-
const controller = new AbortController();
|
|
1642
|
-
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
1643
|
-
try {
|
|
1644
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
1645
|
-
} finally {
|
|
1646
|
-
clearTimeout(id);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
1656
|
|
|
1650
1657
|
// src/tools/video.ts
|
|
1651
1658
|
import { z as z7 } from "zod";
|
|
@@ -1749,7 +1756,7 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
1749
1756
|
if (image_url) body.image_url = image_url;
|
|
1750
1757
|
if (real_face_asset_id) body.real_face_asset_id = real_face_asset_id;
|
|
1751
1758
|
if (duration_seconds !== void 0) body.duration_seconds = duration_seconds;
|
|
1752
|
-
const resp402 = await
|
|
1759
|
+
const resp402 = await fetchWithTimeout(submitUrl, {
|
|
1753
1760
|
method: "POST",
|
|
1754
1761
|
headers: { "Content-Type": "application/json" },
|
|
1755
1762
|
body: JSON.stringify(body)
|
|
@@ -1777,7 +1784,7 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
1777
1784
|
extra: details.extra
|
|
1778
1785
|
}
|
|
1779
1786
|
);
|
|
1780
|
-
const submitResp = await
|
|
1787
|
+
const submitResp = await fetchWithTimeout(submitUrl, {
|
|
1781
1788
|
method: "POST",
|
|
1782
1789
|
headers: {
|
|
1783
1790
|
"Content-Type": "application/json",
|
|
@@ -1802,7 +1809,7 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
1802
1809
|
let completed = null;
|
|
1803
1810
|
while (Date.now() - startedAt < TOTAL_BUDGET_MS) {
|
|
1804
1811
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1805
|
-
const pollResp = await
|
|
1812
|
+
const pollResp = await fetchWithTimeout(pollAbsoluteUrl, {
|
|
1806
1813
|
method: "GET",
|
|
1807
1814
|
headers: { "PAYMENT-SIGNATURE": paymentPayload }
|
|
1808
1815
|
}, 9e4);
|
|
@@ -1866,7 +1873,7 @@ Error: ${errMsg}` }],
|
|
|
1866
1873
|
isError: true
|
|
1867
1874
|
};
|
|
1868
1875
|
}
|
|
1869
|
-
if (
|
|
1876
|
+
if (isTimeoutError(err)) {
|
|
1870
1877
|
return {
|
|
1871
1878
|
content: [{ type: "text", text: `Video generation timed out. The upstream async job didn't complete in time \u2014 please try again.
|
|
1872
1879
|
Error: ${errMsg}` }],
|
|
@@ -1881,15 +1888,6 @@ Error: ${errMsg}` }],
|
|
|
1881
1888
|
}
|
|
1882
1889
|
);
|
|
1883
1890
|
}
|
|
1884
|
-
async function fetchWithTimeout3(url, options, timeoutMs) {
|
|
1885
|
-
const controller = new AbortController();
|
|
1886
|
-
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
1887
|
-
try {
|
|
1888
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
1889
|
-
} finally {
|
|
1890
|
-
clearTimeout(id);
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
1891
|
|
|
1894
1892
|
// src/tools/realface.ts
|
|
1895
1893
|
import { z as z8 } from "zod";
|
|
@@ -1901,19 +1899,10 @@ import {
|
|
|
1901
1899
|
} from "@blockrun/llm";
|
|
1902
1900
|
var BLOCKRUN_API4 = "https://blockrun.ai/api";
|
|
1903
1901
|
var ENROLLMENT_PRICE_USD = 0.01;
|
|
1904
|
-
async function fetchWithTimeout4(url, options, timeoutMs) {
|
|
1905
|
-
const controller = new AbortController();
|
|
1906
|
-
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
1907
|
-
try {
|
|
1908
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
1909
|
-
} finally {
|
|
1910
|
-
clearTimeout(id);
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1913
1902
|
async function payAndPostJson(url, reqBody, fallbackDescription) {
|
|
1914
1903
|
const privateKey = getOrCreateWalletKey();
|
|
1915
1904
|
const account = privateKeyToAccount4(privateKey);
|
|
1916
|
-
const resp402 = await
|
|
1905
|
+
const resp402 = await fetchWithTimeout(url, {
|
|
1917
1906
|
method: "POST",
|
|
1918
1907
|
headers: { "Content-Type": "application/json" },
|
|
1919
1908
|
body: reqBody
|
|
@@ -1939,7 +1928,7 @@ async function payAndPostJson(url, reqBody, fallbackDescription) {
|
|
|
1939
1928
|
extra: details.extra
|
|
1940
1929
|
}
|
|
1941
1930
|
);
|
|
1942
|
-
const resp = await
|
|
1931
|
+
const resp = await fetchWithTimeout(url, {
|
|
1943
1932
|
method: "POST",
|
|
1944
1933
|
headers: {
|
|
1945
1934
|
"Content-Type": "application/json",
|
|
@@ -1988,7 +1977,7 @@ Privacy: BlockRun does not store face/liveness data \u2014 only the asset id, na
|
|
|
1988
1977
|
}
|
|
1989
1978
|
const body = { name };
|
|
1990
1979
|
if (group_id) body.groupId = group_id;
|
|
1991
|
-
const resp = await
|
|
1980
|
+
const resp = await fetchWithTimeout(`${BLOCKRUN_API4}/v1/realface/init`, {
|
|
1992
1981
|
method: "POST",
|
|
1993
1982
|
headers: { "Content-Type": "application/json" },
|
|
1994
1983
|
body: JSON.stringify(body)
|
|
@@ -2037,7 +2026,7 @@ QR opened for scanning (${qrPath}).`;
|
|
|
2037
2026
|
if (!group_id) {
|
|
2038
2027
|
return { content: [{ type: "text", text: formatError('group_id is required for action:"status".') }], isError: true };
|
|
2039
2028
|
}
|
|
2040
|
-
const resp = await
|
|
2029
|
+
const resp = await fetchWithTimeout(`${BLOCKRUN_API4}/v1/realface/status?groupId=${encodeURIComponent(group_id)}`, {
|
|
2041
2030
|
method: "GET"
|
|
2042
2031
|
}, 3e4);
|
|
2043
2032
|
const data = await resp.json().catch(() => ({}));
|
|
@@ -2067,8 +2056,8 @@ QR opened for scanning (${qrPath}).`;
|
|
|
2067
2056
|
if (action === "list") {
|
|
2068
2057
|
const account = privateKeyToAccount4(getOrCreateWalletKey());
|
|
2069
2058
|
const [rfResp, vpResp] = await Promise.all([
|
|
2070
|
-
|
|
2071
|
-
|
|
2059
|
+
fetchWithTimeout(`${BLOCKRUN_API4}/v1/wallet/${account.address}/realfaces`, { method: "GET" }, 3e4),
|
|
2060
|
+
fetchWithTimeout(`${BLOCKRUN_API4}/v1/wallet/${account.address}/portraits`, { method: "GET" }, 3e4).catch(() => null)
|
|
2072
2061
|
]);
|
|
2073
2062
|
const data = await rfResp.json().catch(() => ({}));
|
|
2074
2063
|
if (!rfResp.ok) {
|
|
@@ -2165,7 +2154,7 @@ Enroll one: blockrun_realface action:"init" name:"\u2026" (real person) or actio
|
|
|
2165
2154
|
const account = privateKeyToAccount4(privateKey);
|
|
2166
2155
|
const enrollUrl = `${BLOCKRUN_API4}/v1/realface/enroll`;
|
|
2167
2156
|
const reqBody = JSON.stringify({ name, image_url, group_id });
|
|
2168
|
-
const resp402 = await
|
|
2157
|
+
const resp402 = await fetchWithTimeout(enrollUrl, {
|
|
2169
2158
|
method: "POST",
|
|
2170
2159
|
headers: { "Content-Type": "application/json" },
|
|
2171
2160
|
body: reqBody
|
|
@@ -2191,7 +2180,7 @@ Enroll one: blockrun_realface action:"init" name:"\u2026" (real person) or actio
|
|
|
2191
2180
|
extra: details.extra
|
|
2192
2181
|
}
|
|
2193
2182
|
);
|
|
2194
|
-
const resp = await
|
|
2183
|
+
const resp = await fetchWithTimeout(enrollUrl, {
|
|
2195
2184
|
method: "POST",
|
|
2196
2185
|
headers: {
|
|
2197
2186
|
"Content-Type": "application/json",
|
|
@@ -3075,18 +3064,12 @@ function initializeMcpServer(server) {
|
|
|
3075
3064
|
"blockrun://models",
|
|
3076
3065
|
{ description: "Available AI models with pricing", mimeType: "application/json" },
|
|
3077
3066
|
async () => {
|
|
3078
|
-
const
|
|
3079
|
-
if (!modelCache.models) {
|
|
3080
|
-
modelCache.models = "listAllModels" in llm ? await llm.listAllModels() : await llm.listModels();
|
|
3081
|
-
setTimeout(() => {
|
|
3082
|
-
modelCache.models = null;
|
|
3083
|
-
}, 5 * 60 * 1e3);
|
|
3084
|
-
}
|
|
3067
|
+
const models = await loadModels(getClient(), modelCache);
|
|
3085
3068
|
return {
|
|
3086
3069
|
contents: [{
|
|
3087
3070
|
uri: "blockrun://models",
|
|
3088
3071
|
mimeType: "application/json",
|
|
3089
|
-
text: JSON.stringify(
|
|
3072
|
+
text: JSON.stringify(models, null, 2)
|
|
3090
3073
|
}]
|
|
3091
3074
|
};
|
|
3092
3075
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.5",
|
|
4
4
|
"mcpName": "io.github.BlockRunAI/blockrun-mcp",
|
|
5
5
|
"description": "BlockRun MCP Server - Give your AI agent web search, deep research, prediction markets, crypto data, X/Twitter intelligence. Paid via x402 micropayments.",
|
|
6
6
|
"type": "module",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@solana/web3.js": "^1.98.4",
|
|
52
52
|
"open": "^11.0.0",
|
|
53
53
|
"qrcode": "^1.5.4",
|
|
54
|
+
"rpc-websockets": "9.3.0",
|
|
54
55
|
"sharp": "^0.34.5",
|
|
55
56
|
"viem": "^2.21.0",
|
|
56
57
|
"zod": "^4.3.5"
|