@blockrun/mcp 0.9.1 → 0.11.0
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 +31 -6
- package/dist/index.js +89 -42
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -45,6 +45,27 @@ After BlockRun, it can. Each query costs fractions of a cent, billed from a loca
|
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
+
## Showcase
|
|
49
|
+
|
|
50
|
+
Posters generated through `blockrun_image` with `openai/gpt-image-2`. Each is a single API call routed through BlockRun, paid in USDC on Base.
|
|
51
|
+
|
|
52
|
+
### Latest — GPT-5.5 now live on BlockRun
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="assets/posters/gpt-5-5-launch.png" width="640" alt="gpt-5.5 — now live on BlockRun. Pay per call. No subscription. No keys.">
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
### Gallery
|
|
59
|
+
|
|
60
|
+
| | | |
|
|
61
|
+
|:---:|:---:|:---:|
|
|
62
|
+
| <img src="assets/posters/cornell-2026-popular-booth.png" width="280" alt="Thank you, Cornell — BlockRun at the Cornell Blockchain Conference 2026, packed booth"> | <img src="assets/posters/cornell-2026.png" width="280" alt="Thank you, Cornell — BlockRun at the Cornell Blockchain Conference 2026"> | <img src="skills/image-prompting/example-100t-poster.jpg" width="280" alt="100 Trillion Tokens served — synthwave milestone poster"> |
|
|
63
|
+
| **Cornell Blockchain Conference 2026** — packed booth recap | **Cornell Blockchain Conference 2026** — quiet variant | **100 Trillion Tokens** — milestone synthwave poster |
|
|
64
|
+
|
|
65
|
+
Prompts and a worked example for these are in [`skills/image-prompting/SKILL.md`](skills/image-prompting/SKILL.md).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
48
69
|
## Install
|
|
49
70
|
|
|
50
71
|
**Claude Code (recommended)**
|
|
@@ -83,7 +104,7 @@ Run `blockrun_wallet` to see your address. Send USDC on Base.
|
|
|
83
104
|
| Coinbase | Send → USDC → Base network → paste address |
|
|
84
105
|
| Bridge from Ethereum | [bridge.base.org](https://bridge.base.org) |
|
|
85
106
|
|
|
86
|
-
$5 covers ~5,000 market queries, ~500 Exa searches,
|
|
107
|
+
$5 covers ~5,000 market queries, ~500 Exa searches, ~250 image generations, or ~30 Seedance 1.5-pro clips (5s).
|
|
87
108
|
|
|
88
109
|
---
|
|
89
110
|
|
|
@@ -91,14 +112,18 @@ $5 covers ~5,000 market queries, ~500 Exa searches, or ~250 image generations.
|
|
|
91
112
|
|
|
92
113
|
| Tool | Data source | Cost |
|
|
93
114
|
|------|-------------|------|
|
|
115
|
+
| `blockrun_chat` | 55+ LLMs (GPT, Claude, Gemini, DeepSeek, Kimi K2.6, GLM, NVIDIA free tier, ...) with `mode` tier routing | per token |
|
|
116
|
+
| `blockrun_image` | DALL-E 3, GPT Image 1/2, Grok Imagine, Flux, CogView-4, Nano Banana — generation + editing | $0.015–0.12 |
|
|
117
|
+
| `blockrun_video` | xAI Grok Imagine Video + ByteDance Seedance 1.5/2.0/2.0-fast | $0.03–0.30/sec |
|
|
118
|
+
| `blockrun_music` | MiniMax music generation | per track |
|
|
119
|
+
| `blockrun_price` | Pyth-backed realtime + OHLC — crypto / FX / commodity (free), 12 stock markets (paid) | free or $0.001/call |
|
|
94
120
|
| `blockrun_markets` | Polymarket, Kalshi, dFlow, Binance Futures | $0.001/query |
|
|
121
|
+
| `blockrun_x` | X/Twitter — profiles, tweets, followers, mentions, search (AttentionVC) | per call |
|
|
95
122
|
| `blockrun_exa` | Neural web search (Exa) — research, competitors, papers, URL content | $0.01/query |
|
|
96
|
-
| `blockrun_search` |
|
|
97
|
-
| `blockrun_twitter` | X/Twitter — profiles, tweets, trends, Grok sentiment | per token |
|
|
123
|
+
| `blockrun_search` | Grok Live Search — web + news with citations | ~$0.025 per source |
|
|
98
124
|
| `blockrun_dex` | Live DEX prices via DexScreener | free |
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `blockrun_wallet` | Balance, spending, agent budgets | free |
|
|
125
|
+
| `blockrun_models` | Live catalogue of every LLM/image/video/music model + pricing | free |
|
|
126
|
+
| `blockrun_wallet` | Balance, spending, agent budgets, setup QR | free |
|
|
102
127
|
|
|
103
128
|
---
|
|
104
129
|
|
package/dist/index.js
CHANGED
|
@@ -117,8 +117,8 @@ var MODEL_TIERS = {
|
|
|
117
117
|
powerful: ["openai/gpt-5.4-pro", "anthropic/claude-opus-4.7", "anthropic/claude-opus-4.6", "openai/o3", "openai/gpt-5.4"],
|
|
118
118
|
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"],
|
|
119
119
|
reasoning: ["openai/o3", "openai/o1", "openai/o3-mini", "deepseek/deepseek-reasoner", "moonshot/kimi-k2.6", "openai/gpt-5.3-codex"],
|
|
120
|
-
free: ["nvidia/
|
|
121
|
-
coding: ["zai/glm-5", "openai/gpt-5.3-codex", "moonshot/kimi-k2.6", "nvidia/qwen3-coder-480b", "
|
|
120
|
+
free: ["nvidia/qwen3-next-80b-a3b-thinking", "nvidia/mistral-small-4-119b", "nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "nvidia/qwen3-coder-480b", "nvidia/llama-4-maverick", "nvidia/gpt-oss-20b", "nvidia/glm-4.7"],
|
|
121
|
+
coding: ["zai/glm-5", "openai/gpt-5.3-codex", "moonshot/kimi-k2.6", "nvidia/qwen3-coder-480b", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4"],
|
|
122
122
|
glm: ["zai/glm-5", "zai/glm-5-turbo", "nvidia/glm-4.7"]
|
|
123
123
|
};
|
|
124
124
|
|
|
@@ -611,13 +611,14 @@ Generation models:
|
|
|
611
611
|
- xai/grok-imagine-image ($0.02) \u2014 xAI Grok Imagine, stylized, fast
|
|
612
612
|
- xai/grok-imagine-image-pro ($0.07) \u2014 xAI Grok Imagine Pro, higher quality
|
|
613
613
|
- openai/gpt-image-1 ($0.02-0.04) \u2014 GPT native image generation
|
|
614
|
+
- openai/gpt-image-2 ($0.06-0.12) \u2014 ChatGPT Images 2.0, reasoning-driven, multilingual text rendering + character consistency
|
|
614
615
|
- openai/dall-e-3 ($0.04-0.08) \u2014 High quality, prompt adherence
|
|
615
616
|
- google/nano-banana ($0.05) \u2014 Google image model
|
|
616
|
-
Edit models: openai/gpt-image-1 (default for edits)`,
|
|
617
|
+
Edit models: openai/gpt-image-1, openai/gpt-image-2 (default for edits)`,
|
|
617
618
|
inputSchema: {
|
|
618
619
|
prompt: z4.string().describe("Image description or edit instructions"),
|
|
619
620
|
action: z4.enum(["generate", "edit"]).optional().default("generate").describe("generate: create from text; edit: transform existing image"),
|
|
620
|
-
model: z4.enum(["zai/cogview-4", "openai/dall-e-3", "together/flux-schnell", "google/nano-banana", "openai/gpt-image-1", "xai/grok-imagine-image", "xai/grok-imagine-image-pro"]).optional().describe("Model to use (default: dall-e-3 for generate, gpt-image-
|
|
621
|
+
model: z4.enum(["zai/cogview-4", "openai/dall-e-3", "together/flux-schnell", "google/nano-banana", "openai/gpt-image-1", "openai/gpt-image-2", "xai/grok-imagine-image", "xai/grok-imagine-image-pro"]).optional().describe("Model to use (default: dall-e-3 for generate, gpt-image-2 for edit). xai/grok-imagine-image is stylized and fast; xai/grok-imagine-image-pro is higher quality; gpt-image-2 is the newest edit-capable model with stronger instruction following."),
|
|
621
622
|
image: z4.string().optional().describe("Source image for edit action: base64-encoded image or URL"),
|
|
622
623
|
size: z4.enum(["1024x1024", "1792x1024", "1024x1792"]).optional().default("1024x1024"),
|
|
623
624
|
quality: z4.enum(["standard", "hd"]).optional().default("standard")
|
|
@@ -635,7 +636,7 @@ Edit models: openai/gpt-image-1 (default for edits)`,
|
|
|
635
636
|
};
|
|
636
637
|
}
|
|
637
638
|
response = await imgClient.edit(prompt, image, {
|
|
638
|
-
model: model || "openai/gpt-image-
|
|
639
|
+
model: model || "openai/gpt-image-2",
|
|
639
640
|
size
|
|
640
641
|
});
|
|
641
642
|
} else {
|
|
@@ -825,41 +826,46 @@ import {
|
|
|
825
826
|
extractPaymentDetails as extractPaymentDetails2
|
|
826
827
|
} from "@blockrun/llm";
|
|
827
828
|
var BLOCKRUN_API2 = "https://blockrun.ai/api";
|
|
828
|
-
var
|
|
829
|
+
var TOTAL_BUDGET_MS = 3e5;
|
|
830
|
+
var POLL_INTERVAL_MS = 5e3;
|
|
829
831
|
function registerVideoTool(server) {
|
|
830
832
|
server.registerTool(
|
|
831
833
|
"blockrun_video",
|
|
832
834
|
{
|
|
833
|
-
description: `Generate short AI videos via BlockRun x402.
|
|
835
|
+
description: `Generate short AI videos via BlockRun x402 (async, client-polled).
|
|
834
836
|
|
|
835
|
-
|
|
837
|
+
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.
|
|
836
838
|
|
|
837
|
-
|
|
839
|
+
Models:
|
|
840
|
+
- xai/grok-imagine-video ($0.05/sec, 8s default -> $0.42/clip) \u2014 stylized, fast
|
|
841
|
+
- bytedance/seedance-1.5-pro ($0.03/sec, 720p, 5s default up to 10s) \u2014 cheapest
|
|
842
|
+
- bytedance/seedance-2.0-fast ($0.15/sec, ~60-80s gen) \u2014 sweet-spot price/quality
|
|
843
|
+
- bytedance/seedance-2.0 ($0.30/sec, 720p Pro) \u2014 highest quality
|
|
838
844
|
|
|
839
845
|
Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GCS so URLs don't expire).`,
|
|
840
846
|
inputSchema: {
|
|
841
847
|
prompt: z6.string().describe("Text description of the video to generate. E.g. 'a red apple slowly spinning on a wooden table', 'a hummingbird hovering near a red flower, ultra slow motion'"),
|
|
842
848
|
image_url: z6.string().url().optional().describe("Optional seed image URL for image-to-video generation"),
|
|
843
|
-
duration_seconds: z6.number().int().min(1).max(60).optional().describe("Duration to bill for (defaults to the model's 8s
|
|
844
|
-
model: z6.enum(["xai/grok-imagine-video"]).optional().default("xai/grok-imagine-video").describe("Video model to use")
|
|
849
|
+
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)."),
|
|
850
|
+
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")
|
|
845
851
|
}
|
|
846
852
|
},
|
|
847
853
|
async ({ prompt, image_url, duration_seconds, model }) => {
|
|
848
854
|
try {
|
|
849
855
|
const privateKey = getOrCreateWalletKey();
|
|
850
856
|
const account = privateKeyToAccount2(privateKey);
|
|
851
|
-
const
|
|
857
|
+
const submitUrl = `${BLOCKRUN_API2}/v1/videos/generations`;
|
|
852
858
|
const body = { model, prompt };
|
|
853
859
|
if (image_url) body.image_url = image_url;
|
|
854
860
|
if (duration_seconds !== void 0) body.duration_seconds = duration_seconds;
|
|
855
|
-
const resp402 = await fetchWithTimeout2(
|
|
861
|
+
const resp402 = await fetchWithTimeout2(submitUrl, {
|
|
856
862
|
method: "POST",
|
|
857
863
|
headers: { "Content-Type": "application/json" },
|
|
858
864
|
body: JSON.stringify(body)
|
|
859
865
|
}, 15e3);
|
|
860
866
|
if (resp402.status !== 402) {
|
|
861
|
-
const
|
|
862
|
-
throw new Error(`Expected 402, got ${resp402.status}: ${JSON.stringify(
|
|
867
|
+
const data = await resp402.json();
|
|
868
|
+
throw new Error(`Expected 402, got ${resp402.status}: ${JSON.stringify(data)}`);
|
|
863
869
|
}
|
|
864
870
|
const prHeader = resp402.headers.get("payment-required") || resp402.headers.get("PAYMENT-REQUIRED");
|
|
865
871
|
if (!prHeader) throw new Error("No PAYMENT-REQUIRED header in 402 response");
|
|
@@ -872,50 +878,91 @@ Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GC
|
|
|
872
878
|
details.amount,
|
|
873
879
|
details.network || "eip155:8453",
|
|
874
880
|
{
|
|
875
|
-
resourceUrl: details.resource?.url ||
|
|
881
|
+
resourceUrl: details.resource?.url || submitUrl,
|
|
876
882
|
resourceDescription: details.resource?.description || "BlockRun Video Generation",
|
|
877
|
-
|
|
883
|
+
// Bump to 10 min so the signed authorization stays valid through the
|
|
884
|
+
// async polling window. Default (~5 min) is tight when upstream is slow.
|
|
885
|
+
maxTimeoutSeconds: Math.max(details.maxTimeoutSeconds || 0, 600),
|
|
878
886
|
extra: details.extra
|
|
879
887
|
}
|
|
880
888
|
);
|
|
881
|
-
const
|
|
889
|
+
const submitResp = await fetchWithTimeout2(submitUrl, {
|
|
882
890
|
method: "POST",
|
|
883
891
|
headers: {
|
|
884
892
|
"Content-Type": "application/json",
|
|
885
893
|
"PAYMENT-SIGNATURE": paymentPayload
|
|
886
894
|
},
|
|
887
895
|
body: JSON.stringify(body)
|
|
888
|
-
},
|
|
889
|
-
if (
|
|
896
|
+
}, 3e4);
|
|
897
|
+
if (submitResp.status === 402) {
|
|
890
898
|
throw new Error("Payment rejected. Check your wallet balance.");
|
|
891
899
|
}
|
|
892
|
-
if (!
|
|
893
|
-
const errBody = await
|
|
894
|
-
throw new Error(`API error ${
|
|
900
|
+
if (!submitResp.ok && submitResp.status !== 202) {
|
|
901
|
+
const errBody = await submitResp.json().catch(() => ({ error: "Submit failed" }));
|
|
902
|
+
throw new Error(`API error ${submitResp.status}: ${JSON.stringify(errBody)}`);
|
|
903
|
+
}
|
|
904
|
+
const submitData = await submitResp.json();
|
|
905
|
+
if (!submitData.id || !submitData.poll_url) {
|
|
906
|
+
throw new Error(`Submit response missing id/poll_url: ${JSON.stringify(submitData)}`);
|
|
907
|
+
}
|
|
908
|
+
const pollAbsoluteUrl = submitData.poll_url.startsWith("http") ? submitData.poll_url : `${BLOCKRUN_API2.replace(/\/api$/, "")}${submitData.poll_url}`;
|
|
909
|
+
const startedAt = Date.now();
|
|
910
|
+
let lastStatus = submitData.status || "queued";
|
|
911
|
+
let completed = null;
|
|
912
|
+
while (Date.now() - startedAt < TOTAL_BUDGET_MS) {
|
|
913
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
914
|
+
const pollResp = await fetchWithTimeout2(pollAbsoluteUrl, {
|
|
915
|
+
method: "GET",
|
|
916
|
+
headers: { "PAYMENT-SIGNATURE": paymentPayload }
|
|
917
|
+
}, 9e4);
|
|
918
|
+
const pollData = await pollResp.json().catch(() => ({}));
|
|
919
|
+
lastStatus = pollData.status || lastStatus;
|
|
920
|
+
if (pollResp.status === 202 && (lastStatus === "queued" || lastStatus === "in_progress")) {
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
if (lastStatus === "failed") {
|
|
924
|
+
throw new Error(`Upstream generation failed: ${pollData.error || "unknown"}. No payment taken.`);
|
|
925
|
+
}
|
|
926
|
+
if (pollResp.ok && lastStatus === "completed") {
|
|
927
|
+
const clip = pollData.data?.[0];
|
|
928
|
+
if (!clip?.url) throw new Error("Completed poll missing video URL");
|
|
929
|
+
completed = {
|
|
930
|
+
url: clip.url,
|
|
931
|
+
source_url: clip.source_url,
|
|
932
|
+
duration_seconds: clip.duration_seconds,
|
|
933
|
+
request_id: clip.request_id,
|
|
934
|
+
backed_up: clip.backed_up,
|
|
935
|
+
modelReturned: pollData.model,
|
|
936
|
+
txHash: pollResp.headers.get("X-Payment-Receipt") || pollResp.headers.get("x-payment-receipt") || void 0
|
|
937
|
+
};
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
if (!pollResp.ok && pollResp.status !== 202 && pollResp.status !== 504) {
|
|
941
|
+
throw new Error(`Poll error ${pollResp.status}: ${JSON.stringify(pollData)}`);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
if (!completed) {
|
|
945
|
+
throw new Error(`Video generation did not complete within ${Math.round(TOTAL_BUDGET_MS / 1e3)}s (last status: ${lastStatus}). No payment was taken.`);
|
|
895
946
|
}
|
|
896
|
-
const data = await resp.json();
|
|
897
|
-
const clip = data.data?.[0];
|
|
898
|
-
if (!clip?.url) throw new Error("No video URL in response");
|
|
899
|
-
const txHash = resp.headers.get("X-Payment-Receipt") || resp.headers.get("x-payment-receipt");
|
|
900
947
|
const lines = [
|
|
901
948
|
`\u{1F3AC} Video ready!`,
|
|
902
|
-
`URL: ${
|
|
903
|
-
`Duration: ${
|
|
904
|
-
`Model: ${
|
|
905
|
-
...
|
|
906
|
-
...
|
|
907
|
-
...txHash ? [`Tx: ${txHash}`] : []
|
|
949
|
+
`URL: ${completed.url}`,
|
|
950
|
+
`Duration: ${completed.duration_seconds ? `${completed.duration_seconds}s` : "8s"}`,
|
|
951
|
+
`Model: ${completed.modelReturned || model}`,
|
|
952
|
+
...completed.backed_up ? [`Backed up to BlockRun storage (URL is permanent)`] : completed.source_url ? [`Source URL: ${completed.source_url}`] : [],
|
|
953
|
+
...completed.request_id ? [`Request ID: ${completed.request_id}`] : [],
|
|
954
|
+
...completed.txHash ? [`Tx: ${completed.txHash}`] : []
|
|
908
955
|
];
|
|
909
956
|
return {
|
|
910
957
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
911
958
|
structuredContent: {
|
|
912
|
-
url:
|
|
913
|
-
...
|
|
914
|
-
duration_seconds:
|
|
915
|
-
model:
|
|
916
|
-
...
|
|
917
|
-
...
|
|
918
|
-
...txHash ? { txHash } : {}
|
|
959
|
+
url: completed.url,
|
|
960
|
+
...completed.source_url ? { source_url: completed.source_url } : {},
|
|
961
|
+
duration_seconds: completed.duration_seconds,
|
|
962
|
+
model: completed.modelReturned || model,
|
|
963
|
+
...completed.request_id ? { request_id: completed.request_id } : {},
|
|
964
|
+
...completed.backed_up !== void 0 ? { backed_up: completed.backed_up } : {},
|
|
965
|
+
...completed.txHash ? { txHash: completed.txHash } : {}
|
|
919
966
|
}
|
|
920
967
|
};
|
|
921
968
|
} catch (err) {
|
|
@@ -927,9 +974,9 @@ Error: ${errMsg}` }],
|
|
|
927
974
|
isError: true
|
|
928
975
|
};
|
|
929
976
|
}
|
|
930
|
-
if (errMsg.includes("abort") || errMsg.includes("timeout") || errMsg.includes("Timeout") || errMsg.includes("timed out")) {
|
|
977
|
+
if (errMsg.includes("abort") || errMsg.includes("timeout") || errMsg.includes("Timeout") || errMsg.includes("timed out") || errMsg.includes("did not complete within")) {
|
|
931
978
|
return {
|
|
932
|
-
content: [{ type: "text", text: `Video generation timed out.
|
|
979
|
+
content: [{ type: "text", text: `Video generation timed out. The upstream async job didn't complete in time \u2014 please try again.
|
|
933
980
|
Error: ${errMsg}` }],
|
|
934
981
|
isError: true
|
|
935
982
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
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",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"url": "https://github.com/blockrunai/blockrun-mcp/issues"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@blockrun/llm": "^1.
|
|
47
|
+
"@blockrun/llm": "^1.9.0",
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49
49
|
"open": "^11.0.0",
|
|
50
50
|
"qrcode": "^1.5.4",
|