@blockrun/mcp 0.15.1 → 0.16.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/index.js +135 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
PriceClient,
|
|
16
16
|
SolanaLLMClient,
|
|
17
17
|
getOrCreateWallet,
|
|
18
|
+
getOrCreateSolanaWallet,
|
|
18
19
|
loadSolanaWallet,
|
|
19
20
|
getPaymentLinks,
|
|
20
21
|
formatWalletCreatedMessage,
|
|
@@ -53,6 +54,30 @@ function getChain() {
|
|
|
53
54
|
}
|
|
54
55
|
return "base";
|
|
55
56
|
}
|
|
57
|
+
var CHAIN_FILE = path.join(BLOCKRUN_DIR, ".chain");
|
|
58
|
+
function resetChainCaches() {
|
|
59
|
+
_evmClient = null;
|
|
60
|
+
_solanaClient = null;
|
|
61
|
+
_imageClient = null;
|
|
62
|
+
_priceClient = null;
|
|
63
|
+
_freePriceClient = null;
|
|
64
|
+
}
|
|
65
|
+
function setChain(chain) {
|
|
66
|
+
fs.mkdirSync(BLOCKRUN_DIR, { recursive: true });
|
|
67
|
+
fs.writeFileSync(CHAIN_FILE, chain, { mode: 384 });
|
|
68
|
+
resetChainCaches();
|
|
69
|
+
}
|
|
70
|
+
async function ensureBothWallets() {
|
|
71
|
+
const evm = ensureEvmWallet();
|
|
72
|
+
const sol = await getOrCreateSolanaWallet();
|
|
73
|
+
if (sol.isNew) {
|
|
74
|
+
console.error(formatWalletCreatedMessage(sol.address));
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
base: { address: evm.address, isNew: evm.isNew },
|
|
78
|
+
solana: { address: sol.address, isNew: sol.isNew }
|
|
79
|
+
};
|
|
80
|
+
}
|
|
56
81
|
function ensureEvmWallet() {
|
|
57
82
|
if (!_evmWalletInfo) {
|
|
58
83
|
_evmWalletInfo = getOrCreateWallet();
|
|
@@ -66,11 +91,14 @@ function getOrCreateWalletKey() {
|
|
|
66
91
|
const info = ensureEvmWallet();
|
|
67
92
|
return info.privateKey;
|
|
68
93
|
}
|
|
94
|
+
function buildSolanaClient() {
|
|
95
|
+
const privateKey = process.env.SOLANA_WALLET_KEY || loadSolanaWallet() || void 0;
|
|
96
|
+
return new SolanaLLMClient(privateKey ? { privateKey } : void 0);
|
|
97
|
+
}
|
|
69
98
|
function getClient() {
|
|
70
99
|
if (getChain() === "solana") {
|
|
71
100
|
if (!_solanaClient) {
|
|
72
|
-
|
|
73
|
-
_solanaClient = new SolanaLLMClient(privateKey ? { privateKey } : void 0);
|
|
101
|
+
_solanaClient = buildSolanaClient();
|
|
74
102
|
}
|
|
75
103
|
return _solanaClient;
|
|
76
104
|
}
|
|
@@ -126,15 +154,14 @@ async function getWalletInfo() {
|
|
|
126
154
|
fundingUrl: links.blockrun
|
|
127
155
|
};
|
|
128
156
|
}
|
|
129
|
-
async function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
} catch {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
157
|
+
async function getSolanaUsdcBalance() {
|
|
158
|
+
try {
|
|
159
|
+
return await buildSolanaClient().getBalance();
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
137
162
|
}
|
|
163
|
+
}
|
|
164
|
+
async function getBaseUsdcBalance(address) {
|
|
138
165
|
const USDC_ADDRESS2 = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
139
166
|
const BASE_RPC_URLS = [
|
|
140
167
|
"https://mainnet.base.org",
|
|
@@ -162,6 +189,9 @@ async function getUsdcBalance(address) {
|
|
|
162
189
|
}
|
|
163
190
|
return null;
|
|
164
191
|
}
|
|
192
|
+
async function getChainBalance(chain, address) {
|
|
193
|
+
return chain === "solana" ? getSolanaUsdcBalance() : getBaseUsdcBalance(address);
|
|
194
|
+
}
|
|
165
195
|
|
|
166
196
|
// src/tools/wallet.ts
|
|
167
197
|
import { z } from "zod";
|
|
@@ -182,7 +212,7 @@ var QR_FILE = path2.join(WALLET_DIR, "qr.png");
|
|
|
182
212
|
var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
183
213
|
var BASE_CHAIN_ID = "8453";
|
|
184
214
|
var MODEL_TIERS = {
|
|
185
|
-
fast: ["google/gemini-2.5-flash", "google/gemini-3.1-flash-lite", "openai/gpt-5-mini", "deepseek/deepseek-chat", "google/gemini-3-flash-preview"],
|
|
215
|
+
fast: ["google/gemini-3.5-flash", "google/gemini-2.5-flash", "google/gemini-3.1-flash-lite", "openai/gpt-5-mini", "deepseek/deepseek-chat", "google/gemini-3-flash-preview"],
|
|
186
216
|
balanced: ["openai/gpt-5.4", "anthropic/claude-sonnet-4.6", "google/gemini-2.5-pro", "moonshot/kimi-k2.6", "openai/gpt-5.3", "google/gemini-3.1-pro"],
|
|
187
217
|
powerful: ["openai/gpt-5.4-pro", "anthropic/claude-opus-4.7", "anthropic/claude-opus-4.6", "openai/o3", "openai/gpt-5.4"],
|
|
188
218
|
cheap: ["zai/glm-5", "zai/glm-5-turbo", "nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "google/gemini-2.5-flash", "deepseek/deepseek-chat", "openai/gpt-5.4-nano"],
|
|
@@ -324,10 +354,14 @@ Call this FIRST if any other blockrun_* tool returns a payment/balance error.
|
|
|
324
354
|
Call this to check your current USDC balance before expensive operations.
|
|
325
355
|
Call this to set spending limits before spawning child agents.
|
|
326
356
|
|
|
357
|
+
The server holds TWO wallets \u2014 one on Base, one on Solana \u2014 but pays on ONE
|
|
358
|
+
active chain at a time. status shows both addresses/balances and which is active.
|
|
359
|
+
|
|
327
360
|
Actions:
|
|
328
|
-
- status (default):
|
|
329
|
-
- setup: Get funding instructions + QR code (call this when balance is 0)
|
|
330
|
-
- qr: Open QR code in system viewer
|
|
361
|
+
- status (default): Both wallet addresses + USDC balances, active chain, session spending
|
|
362
|
+
- setup: Get funding instructions + QR code for the ACTIVE chain (call this when balance is 0)
|
|
363
|
+
- qr: Open QR code (active chain) in system viewer
|
|
364
|
+
- chain + chain:"base"|"solana": Switch the active payment chain (omit chain: to just see the current one)
|
|
331
365
|
|
|
332
366
|
Budget controls:
|
|
333
367
|
- budget + budget_action:"set" + budget_amount:1.00 \u2192 Set global spend cap
|
|
@@ -345,14 +379,15 @@ Usage pattern for multi-agent systems:
|
|
|
345
379
|
|
|
346
380
|
Do NOT call this for actual AI queries \u2014 use blockrun_chat for that.`,
|
|
347
381
|
inputSchema: {
|
|
348
|
-
action: z.enum(["status", "setup", "qr", "budget", "delegate", "revoke", "report"]).optional().default("status").describe("What to do"),
|
|
382
|
+
action: z.enum(["status", "setup", "qr", "chain", "budget", "delegate", "revoke", "report"]).optional().default("status").describe("What to do"),
|
|
383
|
+
chain: z.enum(["base", "solana"]).optional().describe("Target chain for action='chain'. Omit to view the current active chain."),
|
|
349
384
|
budget_action: z.enum(["set", "check", "clear"]).optional().describe("Budget action (for action='budget')"),
|
|
350
385
|
budget_amount: z.number().optional().describe("Budget limit in USD (for budget_action='set')"),
|
|
351
386
|
agent_id: z.string().optional().describe("Agent identifier for delegate/revoke/report actions"),
|
|
352
387
|
agent_limit: z.number().optional().describe("Budget limit in USD for this agent (required for delegate action)")
|
|
353
388
|
}
|
|
354
389
|
},
|
|
355
|
-
async ({ action, budget_action, budget_amount, agent_id, agent_limit }) => {
|
|
390
|
+
async ({ action, chain: targetChain, budget_action, budget_amount, agent_id, agent_limit }) => {
|
|
356
391
|
if (action === "budget") {
|
|
357
392
|
const budgetAct = budget_action || "check";
|
|
358
393
|
if (budgetAct === "set") {
|
|
@@ -428,6 +463,35 @@ Pass agent_id: "${agent_id}" in any blockrun_* tool call to track and enforce th
|
|
|
428
463
|
structuredContent: { global: { limit: budget.limit, spent: budget.spent, calls: budget.calls }, agents: agentRows }
|
|
429
464
|
};
|
|
430
465
|
}
|
|
466
|
+
if (action === "chain") {
|
|
467
|
+
const both2 = await ensureBothWallets();
|
|
468
|
+
if (targetChain && targetChain !== getChain()) {
|
|
469
|
+
setChain(targetChain);
|
|
470
|
+
}
|
|
471
|
+
const active = getChain();
|
|
472
|
+
const activeWallet = active === "solana" ? both2.solana : both2.base;
|
|
473
|
+
const activeBalance2 = await getChainBalance(active, activeWallet.address);
|
|
474
|
+
const balStr = activeBalance2 !== null ? `$${activeBalance2.toFixed(6)} USDC` : "balance unavailable";
|
|
475
|
+
const switched = targetChain ? `Switched active chain \u2192 ${active.toUpperCase()}.` : `Active chain: ${active.toUpperCase()}.`;
|
|
476
|
+
const text2 = `${switched}
|
|
477
|
+
|
|
478
|
+
Active (${active}): ${activeWallet.address}
|
|
479
|
+
Balance: ${balStr}${activeBalance2 !== null && activeBalance2 < 1 ? " (low \u2014 fund this address)" : ""}
|
|
480
|
+
Base: ${both2.base.address}
|
|
481
|
+
Solana: ${both2.solana.address}
|
|
482
|
+
|
|
483
|
+
All blockrun_* calls now pay on ${active}. Note: image generation, price, video,
|
|
484
|
+
music and RealFace are Base-only \u2014 switch back with chain:"base" for those.`;
|
|
485
|
+
return {
|
|
486
|
+
content: [{ type: "text", text: text2 }],
|
|
487
|
+
structuredContent: {
|
|
488
|
+
activeChain: active,
|
|
489
|
+
base: both2.base.address,
|
|
490
|
+
solana: both2.solana.address,
|
|
491
|
+
activeBalance: activeBalance2
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
}
|
|
431
495
|
const info = await getWalletInfo();
|
|
432
496
|
const address = info.address;
|
|
433
497
|
const chain = getChain();
|
|
@@ -525,24 +589,38 @@ SECURITY: Private key stored at ~/.blockrun/.session (never leaves your machine)
|
|
|
525
589
|
================================================================================`;
|
|
526
590
|
return { content: [{ type: "text", text: text2 }] };
|
|
527
591
|
}
|
|
528
|
-
const
|
|
529
|
-
const
|
|
530
|
-
|
|
592
|
+
const both = await ensureBothWallets();
|
|
593
|
+
const [baseBal, solBal] = await Promise.all([
|
|
594
|
+
getChainBalance("base", both.base.address),
|
|
595
|
+
getChainBalance("solana", both.solana.address)
|
|
596
|
+
]);
|
|
597
|
+
const activeBalance = chain === "solana" ? solBal : baseBal;
|
|
598
|
+
const fmt = (b) => b !== null ? `$${b.toFixed(6)} USDC` : "unavailable";
|
|
531
599
|
const explorerLabel = chain === "solana" ? "Solscan" : "Basescan";
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
${
|
|
600
|
+
const mark = (c) => c === chain ? "\u2192" : " ";
|
|
601
|
+
const text = `Active chain: ${chain.toUpperCase()} (switch with action:"chain" chain:"base"|"solana")
|
|
602
|
+
|
|
603
|
+
${mark("base")} Base: ${both.base.address}
|
|
604
|
+
${fmt(baseBal)}${baseBal !== null && baseBal < 1 ? " (low)" : ""}
|
|
605
|
+
${mark("solana")} Solana: ${both.solana.address}
|
|
606
|
+
${fmt(solBal)}${solBal !== null && solBal < 1 ? " (low)" : ""}
|
|
607
|
+
|
|
608
|
+
Paying on ${chain} | View active: ${info.explorerUrl}${info.isNew ? "\nNEW WALLET on active chain \u2014 run action:'setup' for funding instructions" : ""}`;
|
|
536
609
|
return {
|
|
537
610
|
content: [{ type: "text", text }],
|
|
538
611
|
structuredContent: {
|
|
612
|
+
activeChain: chain,
|
|
539
613
|
address: info.address,
|
|
540
|
-
balance,
|
|
614
|
+
balance: activeBalance,
|
|
541
615
|
network: info.network,
|
|
542
616
|
chainId: info.chainId,
|
|
543
617
|
isNew: info.isNew,
|
|
544
618
|
explorerUrl: info.explorerUrl,
|
|
545
|
-
explorerLabel
|
|
619
|
+
explorerLabel,
|
|
620
|
+
wallets: {
|
|
621
|
+
base: { address: both.base.address, balance: baseBal },
|
|
622
|
+
solana: { address: both.solana.address, balance: solBal }
|
|
623
|
+
}
|
|
546
624
|
}
|
|
547
625
|
};
|
|
548
626
|
}
|
|
@@ -865,7 +943,7 @@ Edit models: openai/gpt-image-1, openai/gpt-image-2 (default for edits)`,
|
|
|
865
943
|
try {
|
|
866
944
|
if (getChain() !== "base") {
|
|
867
945
|
return {
|
|
868
|
-
content: [{ type: "text", text: formatError("blockrun_image currently settles on Base only. Switch BlockRun to Base (for example:
|
|
946
|
+
content: [{ type: "text", text: formatError("blockrun_image currently settles on Base only. Switch BlockRun to Base (for example: run blockrun_wallet with action:chain chain:base) and fund the Base wallet with USDC.") }],
|
|
869
947
|
isError: true
|
|
870
948
|
};
|
|
871
949
|
}
|
|
@@ -979,7 +1057,7 @@ Returns a time-limited CDN URL \u2014 download immediately if you need to keep t
|
|
|
979
1057
|
try {
|
|
980
1058
|
if (getChain() !== "base") {
|
|
981
1059
|
return {
|
|
982
|
-
content: [{ type: "text", text: formatError("blockrun_music currently settles on Base only. Switch BlockRun to Base (for example:
|
|
1060
|
+
content: [{ type: "text", text: formatError("blockrun_music currently settles on Base only. Switch BlockRun to Base (for example: run blockrun_wallet with action:chain chain:base) and fund the Base wallet with USDC.") }],
|
|
983
1061
|
isError: true
|
|
984
1062
|
};
|
|
985
1063
|
}
|
|
@@ -1116,7 +1194,8 @@ var VIDEO_PRICE_PER_SECOND = {
|
|
|
1116
1194
|
"xai/grok-imagine-video": 0.05,
|
|
1117
1195
|
"bytedance/seedance-1.5-pro": 0.092,
|
|
1118
1196
|
"bytedance/seedance-2.0-fast": 0.238,
|
|
1119
|
-
"bytedance/seedance-2.0": 0.298
|
|
1197
|
+
"bytedance/seedance-2.0": 0.298,
|
|
1198
|
+
"azure/sora-2": 0.1
|
|
1120
1199
|
};
|
|
1121
1200
|
var VIDEO_PRICE_PER_SECOND_IMAGE = {
|
|
1122
1201
|
"bytedance/seedance-2.0-fast": 0.14,
|
|
@@ -1130,7 +1209,9 @@ var VIDEO_DEFAULT_DURATION = {
|
|
|
1130
1209
|
"xai/grok-imagine-video": 8,
|
|
1131
1210
|
"bytedance/seedance-1.5-pro": 5,
|
|
1132
1211
|
"bytedance/seedance-2.0-fast": 5,
|
|
1133
|
-
"bytedance/seedance-2.0": 5
|
|
1212
|
+
"bytedance/seedance-2.0": 5,
|
|
1213
|
+
"azure/sora-2": 4
|
|
1214
|
+
// Sora 2 accepts only 4 / 8 / 12s
|
|
1134
1215
|
};
|
|
1135
1216
|
function registerVideoTool(server, budget) {
|
|
1136
1217
|
server.registerTool(
|
|
@@ -1141,6 +1222,7 @@ function registerVideoTool(server, budget) {
|
|
|
1141
1222
|
Turns a text prompt (and optional seed image) into a short MP4 clip. The tool submits the job, then polls until the video is ready (typical total wall-time 60-180s; 5 min hard cap). Payment is settled only when upstream returns a finished video \u2014 if the job fails or we give up, you are not charged.
|
|
1142
1223
|
|
|
1143
1224
|
Models (Seedance defaults bumped to 720p + synced audio on the gateway):
|
|
1225
|
+
- azure/sora-2 ($0.10/sec, 720p + synced audio, text-to-video) \u2014 OpenAI Sora 2 via Azure AI Foundry. duration_seconds must be 4, 8, or 12 (4s default -> ~$0.42/clip). No image_url / RealFace.
|
|
1144
1226
|
- xai/grok-imagine-video ($0.05/sec, 8s default -> $0.42/clip) \u2014 stylized, fast
|
|
1145
1227
|
- bytedance/seedance-1.5-pro (~$0.092/sec, 720p + audio t2v, 5s default up to 10s) \u2014 cheapest Seedance, token-priced upstream
|
|
1146
1228
|
- bytedance/seedance-2.0-fast (~$0.238/sec text \xB7 ~$0.140/sec image-to-video, 720p + audio, ~60-80s gen) \u2014 sweet-spot price/quality; supports BytePlus RealFace assets
|
|
@@ -1154,7 +1236,7 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
1154
1236
|
image_url: z6.string().url().optional().describe("Optional seed image URL for image-to-video generation"),
|
|
1155
1237
|
real_face_asset_id: z6.string().regex(/^ta_[A-Za-z0-9]+$/, "token360 asset id like 'ta_xxxx'").optional().describe("BytePlus RealFace asset id (from blockrun_realface enroll/list) to generate video of a specific real person. Seedance 2.0 / 2.0-fast only. Mutually exclusive with image_url."),
|
|
1156
1238
|
duration_seconds: z6.number().int().min(1).max(60).optional().describe("Duration to bill for (defaults to the model's default \u2014 8s for xAI, 5s for Seedance; Seedance supports up to 10s)."),
|
|
1157
|
-
model: z6.enum(["xai/grok-imagine-video", "bytedance/seedance-1.5-pro", "bytedance/seedance-2.0-fast", "bytedance/seedance-2.0"]).optional().default("xai/grok-imagine-video").describe("Video model to use"),
|
|
1239
|
+
model: z6.enum(["azure/sora-2", "xai/grok-imagine-video", "bytedance/seedance-1.5-pro", "bytedance/seedance-2.0-fast", "bytedance/seedance-2.0"]).optional().default("xai/grok-imagine-video").describe("Video model to use"),
|
|
1158
1240
|
agent_id: z6.string().optional().describe("Agent identifier for budget tracking and enforcement.")
|
|
1159
1241
|
}
|
|
1160
1242
|
},
|
|
@@ -1162,7 +1244,7 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
1162
1244
|
try {
|
|
1163
1245
|
if (getChain() !== "base") {
|
|
1164
1246
|
return {
|
|
1165
|
-
content: [{ type: "text", text: formatError("blockrun_video currently settles on Base only. Switch BlockRun to Base (for example:
|
|
1247
|
+
content: [{ type: "text", text: formatError("blockrun_video currently settles on Base only. Switch BlockRun to Base (for example: run blockrun_wallet with action:chain chain:base) and fund the Base wallet with USDC.") }],
|
|
1166
1248
|
isError: true
|
|
1167
1249
|
};
|
|
1168
1250
|
}
|
|
@@ -1503,7 +1585,7 @@ Enroll one: blockrun_realface action:"init" name:"\u2026".` }],
|
|
|
1503
1585
|
}
|
|
1504
1586
|
if (action === "enroll") {
|
|
1505
1587
|
if (getChain() !== "base") {
|
|
1506
|
-
return { content: [{ type: "text", text: formatError("blockrun_realface enroll settles on Base only. Switch BlockRun to Base (
|
|
1588
|
+
return { content: [{ type: "text", text: formatError("blockrun_realface enroll settles on Base only. Switch BlockRun to Base (run blockrun_wallet with action:chain chain:base) and fund the Base wallet with USDC.") }], isError: true };
|
|
1507
1589
|
}
|
|
1508
1590
|
if (!name || !image_url || !group_id) {
|
|
1509
1591
|
return { content: [{ type: "text", text: formatError("enroll requires name, image_url, and group_id (from init, after the group is active).") }], isError: true };
|
|
@@ -1605,6 +1687,20 @@ Error: ${errMsg}` }],
|
|
|
1605
1687
|
|
|
1606
1688
|
// src/tools/search.ts
|
|
1607
1689
|
import { z as z8 } from "zod";
|
|
1690
|
+
|
|
1691
|
+
// src/utils/body.ts
|
|
1692
|
+
function coerceBody(body) {
|
|
1693
|
+
if (typeof body !== "string") return body;
|
|
1694
|
+
const trimmed = body.trim();
|
|
1695
|
+
if (trimmed === "") return {};
|
|
1696
|
+
try {
|
|
1697
|
+
return JSON.parse(trimmed);
|
|
1698
|
+
} catch {
|
|
1699
|
+
return body;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// src/tools/search.ts
|
|
1608
1704
|
var SEARCH_PRICE_PER_SOURCE = 0.025;
|
|
1609
1705
|
var SEARCH_DEFAULT_MAX_RESULTS = 10;
|
|
1610
1706
|
function estimateSearchCost(body) {
|
|
@@ -1633,6 +1729,7 @@ Full request shape + worked examples in the \`search\` skill (\`skills/search/SK
|
|
|
1633
1729
|
},
|
|
1634
1730
|
async ({ path: path5, body, agent_id }) => {
|
|
1635
1731
|
try {
|
|
1732
|
+
body = coerceBody(body);
|
|
1636
1733
|
const estimatedCost = estimateSearchCost(body);
|
|
1637
1734
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
|
1638
1735
|
if (!budgetCheck.allowed) {
|
|
@@ -1690,6 +1787,7 @@ Full request/response shapes + worked research workflows in the \`exa-research\`
|
|
|
1690
1787
|
},
|
|
1691
1788
|
async ({ path: path5, body, agent_id }) => {
|
|
1692
1789
|
try {
|
|
1790
|
+
body = coerceBody(body);
|
|
1693
1791
|
const estimatedCost = estimateExaCost(path5, body);
|
|
1694
1792
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
|
1695
1793
|
if (!budgetCheck.allowed) {
|
|
@@ -1788,6 +1886,7 @@ Pass query params via 'params' (GET). Use 'body' only for POST endpoints (e.g. p
|
|
|
1788
1886
|
},
|
|
1789
1887
|
async ({ path: path5, params, body, agent_id }) => {
|
|
1790
1888
|
try {
|
|
1889
|
+
body = coerceBody(body);
|
|
1791
1890
|
const estimatedCost = estimateMarketCost(path5, body);
|
|
1792
1891
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
|
1793
1892
|
if (!budgetCheck.allowed) {
|
|
@@ -1880,7 +1979,7 @@ Examples:
|
|
|
1880
1979
|
const paid = isPaidPriceCall(action, category);
|
|
1881
1980
|
if (paid && getChain() !== "base") {
|
|
1882
1981
|
return {
|
|
1883
|
-
content: [{ type: "text", text: formatError("Paid stock price/history calls currently settle on Base only. Switch BlockRun to Base (for example:
|
|
1982
|
+
content: [{ type: "text", text: formatError("Paid stock price/history calls currently settle on Base only. Switch BlockRun to Base (for example: run blockrun_wallet with action:chain chain:base) and fund the Base wallet with USDC.") }],
|
|
1884
1983
|
isError: true
|
|
1885
1984
|
};
|
|
1886
1985
|
}
|
|
@@ -2050,6 +2149,7 @@ Full action shapes + GPU type details in the \`modal\` skill.`,
|
|
|
2050
2149
|
},
|
|
2051
2150
|
async ({ path: path5, body, agent_id }) => {
|
|
2052
2151
|
try {
|
|
2152
|
+
body = coerceBody(body);
|
|
2053
2153
|
const cleanPath = path5.replace(/^\/+/, "").replace(/^v1\/modal\//, "");
|
|
2054
2154
|
const estimatedCost = estimateModalCost(cleanPath);
|
|
2055
2155
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
|
@@ -2115,6 +2215,7 @@ Voice call flow + voice preset details + full body shapes in the \`phone\` skill
|
|
|
2115
2215
|
},
|
|
2116
2216
|
async ({ path: path5, body, agent_id }) => {
|
|
2117
2217
|
try {
|
|
2218
|
+
body = coerceBody(body);
|
|
2118
2219
|
const cleanPath = path5.replace(/^\/+/, "").replace(/^v1\//, "");
|
|
2119
2220
|
const estimatedCost = estimatePhoneCost(cleanPath, body !== void 0);
|
|
2120
2221
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
|
@@ -2212,6 +2313,7 @@ Each Surf endpoint pre-validates required params before settling \u2014 you get
|
|
|
2212
2313
|
},
|
|
2213
2314
|
async ({ path: path5, params, body, agent_id }) => {
|
|
2214
2315
|
try {
|
|
2316
|
+
body = coerceBody(body);
|
|
2215
2317
|
const cleanPath = path5.replace(/^\/+/, "").replace(/^v1\/surf\//, "").replace(/^api\/v1\/surf\//, "");
|
|
2216
2318
|
const estimatedCost = estimateSurfCost(cleanPath);
|
|
2217
2319
|
const budgetCheck = checkBudget(budget, agent_id, estimatedCost);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
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",
|