@blockrun/mcp 0.7.2 → 0.8.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/dist/index.js +177 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -597,15 +597,17 @@ Actions:
|
|
|
597
597
|
- edit: Transform an existing image using img2img
|
|
598
598
|
|
|
599
599
|
Generation models:
|
|
600
|
-
- zai/cogview-4 ($0.
|
|
600
|
+
- zai/cogview-4 ($0.015) \u2014 Zhipu CogView-4, photorealistic, great for detailed scenes
|
|
601
|
+
- xai/grok-imagine-image ($0.02) \u2014 xAI Grok Imagine, stylized, fast
|
|
602
|
+
- xai/grok-imagine-image-pro ($0.07) \u2014 xAI Grok Imagine Pro, higher quality
|
|
603
|
+
- openai/gpt-image-1 ($0.02-0.04) \u2014 GPT native image generation
|
|
601
604
|
- openai/dall-e-3 ($0.04-0.08) \u2014 High quality, prompt adherence
|
|
602
|
-
-
|
|
603
|
-
- google/nano-banana \u2014 Google image model
|
|
605
|
+
- google/nano-banana ($0.05) \u2014 Google image model
|
|
604
606
|
Edit models: openai/gpt-image-1 (default for edits)`,
|
|
605
607
|
inputSchema: {
|
|
606
608
|
prompt: z4.string().describe("Image description or edit instructions"),
|
|
607
609
|
action: z4.enum(["generate", "edit"]).optional().default("generate").describe("generate: create from text; edit: transform existing image"),
|
|
608
|
-
model: z4.enum(["zai/cogview-4", "openai/dall-e-3", "together/flux-schnell", "google/nano-banana", "openai/gpt-image-1"]).optional().describe("Model to use (default: dall-e-3 for generate, gpt-image-1 for edit).
|
|
610
|
+
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-1 for edit). xai/grok-imagine-image is stylized and fast; xai/grok-imagine-image-pro is higher quality."),
|
|
609
611
|
image: z4.string().optional().describe("Source image for edit action: base64-encoded image or URL"),
|
|
610
612
|
size: z4.enum(["1024x1024", "1792x1024", "1024x1792"]).optional().default("1024x1024"),
|
|
611
613
|
quality: z4.enum(["standard", "hd"]).optional().default("standard")
|
|
@@ -804,8 +806,144 @@ async function fetchWithTimeout(url, options, timeoutMs) {
|
|
|
804
806
|
}
|
|
805
807
|
}
|
|
806
808
|
|
|
807
|
-
// src/tools/
|
|
809
|
+
// src/tools/video.ts
|
|
808
810
|
import { z as z6 } from "zod";
|
|
811
|
+
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
812
|
+
import {
|
|
813
|
+
createPaymentPayload as createPaymentPayload2,
|
|
814
|
+
parsePaymentRequired as parsePaymentRequired2,
|
|
815
|
+
extractPaymentDetails as extractPaymentDetails2
|
|
816
|
+
} from "@blockrun/llm";
|
|
817
|
+
var BLOCKRUN_API2 = "https://blockrun.ai/api";
|
|
818
|
+
var VIDEO_TIMEOUT = 3e5;
|
|
819
|
+
function registerVideoTool(server) {
|
|
820
|
+
server.registerTool(
|
|
821
|
+
"blockrun_video",
|
|
822
|
+
{
|
|
823
|
+
description: `Generate short AI videos via BlockRun x402.
|
|
824
|
+
|
|
825
|
+
Uses xAI's Grok Imagine Video to turn a text prompt (and optional seed image) into an 8-second MP4 clip. The call blocks until the video is ready (30-120s typical).
|
|
826
|
+
|
|
827
|
+
Model: xai/grok-imagine-video ($0.05/sec, 8s default -> $0.42/clip)
|
|
828
|
+
|
|
829
|
+
Returns a permanent blockrun-hosted MP4 URL (the gateway mirrors the asset to GCS so URLs don't expire).`,
|
|
830
|
+
inputSchema: {
|
|
831
|
+
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'"),
|
|
832
|
+
image_url: z6.string().url().optional().describe("Optional seed image URL for image-to-video generation"),
|
|
833
|
+
duration_seconds: z6.number().int().min(1).max(60).optional().describe("Duration to bill for (defaults to the model's 8s default). Must not exceed max_duration_seconds."),
|
|
834
|
+
model: z6.enum(["xai/grok-imagine-video"]).optional().default("xai/grok-imagine-video").describe("Video model to use")
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
async ({ prompt, image_url, duration_seconds, model }) => {
|
|
838
|
+
try {
|
|
839
|
+
const privateKey = getOrCreateWalletKey();
|
|
840
|
+
const account = privateKeyToAccount2(privateKey);
|
|
841
|
+
const url = `${BLOCKRUN_API2}/v1/videos/generations`;
|
|
842
|
+
const body = { model, prompt };
|
|
843
|
+
if (image_url) body.image_url = image_url;
|
|
844
|
+
if (duration_seconds !== void 0) body.duration_seconds = duration_seconds;
|
|
845
|
+
const resp402 = await fetchWithTimeout2(url, {
|
|
846
|
+
method: "POST",
|
|
847
|
+
headers: { "Content-Type": "application/json" },
|
|
848
|
+
body: JSON.stringify(body)
|
|
849
|
+
}, 15e3);
|
|
850
|
+
if (resp402.status !== 402) {
|
|
851
|
+
const data2 = await resp402.json();
|
|
852
|
+
throw new Error(`Expected 402, got ${resp402.status}: ${JSON.stringify(data2)}`);
|
|
853
|
+
}
|
|
854
|
+
const prHeader = resp402.headers.get("payment-required") || resp402.headers.get("PAYMENT-REQUIRED");
|
|
855
|
+
if (!prHeader) throw new Error("No PAYMENT-REQUIRED header in 402 response");
|
|
856
|
+
const paymentRequired = parsePaymentRequired2(prHeader);
|
|
857
|
+
const details = extractPaymentDetails2(paymentRequired);
|
|
858
|
+
const paymentPayload = await createPaymentPayload2(
|
|
859
|
+
privateKey,
|
|
860
|
+
account.address,
|
|
861
|
+
details.recipient,
|
|
862
|
+
details.amount,
|
|
863
|
+
details.network || "eip155:8453",
|
|
864
|
+
{
|
|
865
|
+
resourceUrl: details.resource?.url || url,
|
|
866
|
+
resourceDescription: details.resource?.description || "BlockRun Video Generation",
|
|
867
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
868
|
+
extra: details.extra
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
const resp = await fetchWithTimeout2(url, {
|
|
872
|
+
method: "POST",
|
|
873
|
+
headers: {
|
|
874
|
+
"Content-Type": "application/json",
|
|
875
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
876
|
+
},
|
|
877
|
+
body: JSON.stringify(body)
|
|
878
|
+
}, VIDEO_TIMEOUT);
|
|
879
|
+
if (resp.status === 402) {
|
|
880
|
+
throw new Error("Payment rejected. Check your wallet balance.");
|
|
881
|
+
}
|
|
882
|
+
if (!resp.ok) {
|
|
883
|
+
const errBody = await resp.json().catch(() => ({ error: "Request failed" }));
|
|
884
|
+
throw new Error(`API error ${resp.status}: ${JSON.stringify(errBody)}`);
|
|
885
|
+
}
|
|
886
|
+
const data = await resp.json();
|
|
887
|
+
const clip = data.data?.[0];
|
|
888
|
+
if (!clip?.url) throw new Error("No video URL in response");
|
|
889
|
+
const txHash = resp.headers.get("X-Payment-Receipt") || resp.headers.get("x-payment-receipt");
|
|
890
|
+
const lines = [
|
|
891
|
+
`\u{1F3AC} Video ready!`,
|
|
892
|
+
`URL: ${clip.url}`,
|
|
893
|
+
`Duration: ${clip.duration_seconds ? `${clip.duration_seconds}s` : "8s"}`,
|
|
894
|
+
`Model: ${data.model || model}`,
|
|
895
|
+
...clip.backed_up ? [`Backed up to BlockRun storage (URL is permanent)`] : clip.source_url ? [`Source URL: ${clip.source_url}`] : [],
|
|
896
|
+
...clip.request_id ? [`Request ID: ${clip.request_id}`] : [],
|
|
897
|
+
...txHash ? [`Tx: ${txHash}`] : []
|
|
898
|
+
];
|
|
899
|
+
return {
|
|
900
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
901
|
+
structuredContent: {
|
|
902
|
+
url: clip.url,
|
|
903
|
+
...clip.source_url ? { source_url: clip.source_url } : {},
|
|
904
|
+
duration_seconds: clip.duration_seconds,
|
|
905
|
+
model: data.model || model,
|
|
906
|
+
...clip.request_id ? { request_id: clip.request_id } : {},
|
|
907
|
+
...clip.backed_up !== void 0 ? { backed_up: clip.backed_up } : {},
|
|
908
|
+
...txHash ? { txHash } : {}
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
} catch (err) {
|
|
912
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
913
|
+
if (errMsg.includes("balance") || errMsg.includes("payment") || errMsg.includes("402") || errMsg.includes("rejected")) {
|
|
914
|
+
return {
|
|
915
|
+
content: [{ type: "text", text: `Video generation requires payment. Run blockrun_wallet with action: "setup" for funding instructions.
|
|
916
|
+
Error: ${errMsg}` }],
|
|
917
|
+
isError: true
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
if (errMsg.includes("abort") || errMsg.includes("timeout") || errMsg.includes("Timeout") || errMsg.includes("timed out")) {
|
|
921
|
+
return {
|
|
922
|
+
content: [{ type: "text", text: `Video generation timed out. xAI's async job didn't complete in time \u2014 please try again.
|
|
923
|
+
Error: ${errMsg}` }],
|
|
924
|
+
isError: true
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
return {
|
|
928
|
+
content: [{ type: "text", text: formatError(`Video generation failed: ${errMsg}`) }],
|
|
929
|
+
isError: true
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
async function fetchWithTimeout2(url, options, timeoutMs) {
|
|
936
|
+
const controller = new AbortController();
|
|
937
|
+
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
938
|
+
try {
|
|
939
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
940
|
+
} finally {
|
|
941
|
+
clearTimeout(id);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// src/tools/search.ts
|
|
946
|
+
import { z as z7 } from "zod";
|
|
809
947
|
function registerSearchTool(server) {
|
|
810
948
|
server.registerTool(
|
|
811
949
|
"blockrun_search",
|
|
@@ -817,11 +955,11 @@ Pricing: ~$0.01/search
|
|
|
817
955
|
|
|
818
956
|
Returns a summary with cited sources.`,
|
|
819
957
|
inputSchema: {
|
|
820
|
-
query:
|
|
821
|
-
sources:
|
|
822
|
-
max_results:
|
|
823
|
-
from_date:
|
|
824
|
-
to_date:
|
|
958
|
+
query: z7.string().describe("Search query"),
|
|
959
|
+
sources: z7.array(z7.enum(["web", "x", "news"])).optional().describe("Sources to search (default: web + x + news)"),
|
|
960
|
+
max_results: z7.number().optional().default(10).describe("Max results per source (1-20)"),
|
|
961
|
+
from_date: z7.string().optional().describe("Start date filter (YYYY-MM-DD)"),
|
|
962
|
+
to_date: z7.string().optional().describe("End date filter (YYYY-MM-DD)")
|
|
825
963
|
}
|
|
826
964
|
},
|
|
827
965
|
async ({ query, sources, max_results, from_date, to_date }) => {
|
|
@@ -849,7 +987,7 @@ Returns a summary with cited sources.`,
|
|
|
849
987
|
}
|
|
850
988
|
|
|
851
989
|
// src/tools/exa.ts
|
|
852
|
-
import { z as
|
|
990
|
+
import { z as z8 } from "zod";
|
|
853
991
|
function registerExaTool(server) {
|
|
854
992
|
server.registerTool(
|
|
855
993
|
"blockrun_exa",
|
|
@@ -862,14 +1000,14 @@ Actions:
|
|
|
862
1000
|
- contents: Fetch full Markdown text from URLs, ready for LLM context ($0.002/URL)
|
|
863
1001
|
- similar: Find pages semantically similar to a given URL ($0.01/call)`,
|
|
864
1002
|
inputSchema: {
|
|
865
|
-
action:
|
|
866
|
-
query:
|
|
867
|
-
url:
|
|
868
|
-
urls:
|
|
869
|
-
num_results:
|
|
870
|
-
category:
|
|
871
|
-
include_domains:
|
|
872
|
-
exclude_domains:
|
|
1003
|
+
action: z8.enum(["search", "answer", "contents", "similar"]).describe("Action to perform"),
|
|
1004
|
+
query: z8.string().optional().describe("Natural language query (for search/answer)"),
|
|
1005
|
+
url: z8.string().optional().describe("Reference URL to find similar pages (for similar action)"),
|
|
1006
|
+
urls: z8.array(z8.string()).optional().describe("URLs to fetch content from (for contents action, up to 100)"),
|
|
1007
|
+
num_results: z8.number().optional().describe("Number of results to return (default: 10)"),
|
|
1008
|
+
category: z8.string().optional().describe("Category filter: 'news', 'research paper', 'company', 'tweet', 'github', 'pdf'"),
|
|
1009
|
+
include_domains: z8.array(z8.string()).optional().describe("Only search within these domains"),
|
|
1010
|
+
exclude_domains: z8.array(z8.string()).optional().describe("Exclude these domains from results")
|
|
873
1011
|
}
|
|
874
1012
|
},
|
|
875
1013
|
async ({ action, query, url, urls, num_results, category, include_domains, exclude_domains }) => {
|
|
@@ -922,7 +1060,7 @@ Actions:
|
|
|
922
1060
|
}
|
|
923
1061
|
|
|
924
1062
|
// src/tools/markets.ts
|
|
925
|
-
import { z as
|
|
1063
|
+
import { z as z9 } from "zod";
|
|
926
1064
|
function registerMarketsTool(server) {
|
|
927
1065
|
server.registerTool(
|
|
928
1066
|
"blockrun_markets",
|
|
@@ -937,9 +1075,9 @@ Example paths:
|
|
|
937
1075
|
|
|
938
1076
|
$0.001/call.`,
|
|
939
1077
|
inputSchema: {
|
|
940
|
-
path:
|
|
941
|
-
params:
|
|
942
|
-
body:
|
|
1078
|
+
path: z9.string().describe("Endpoint path, e.g. 'polymarket/events', 'kalshi/markets/KXBTC-25MAR14'"),
|
|
1079
|
+
params: z9.record(z9.string(), z9.string()).optional().describe("Query parameters for GET requests"),
|
|
1080
|
+
body: z9.any().optional().describe("JSON body for POST queries (triggers pmQuery)")
|
|
943
1081
|
}
|
|
944
1082
|
},
|
|
945
1083
|
async ({ path: path3, params, body }) => {
|
|
@@ -962,7 +1100,7 @@ $0.001/call.`,
|
|
|
962
1100
|
}
|
|
963
1101
|
|
|
964
1102
|
// src/tools/dex.ts
|
|
965
|
-
import { z as
|
|
1103
|
+
import { z as z10 } from "zod";
|
|
966
1104
|
function registerDexTool(server) {
|
|
967
1105
|
server.registerTool(
|
|
968
1106
|
"blockrun_dex",
|
|
@@ -979,10 +1117,10 @@ Examples:
|
|
|
979
1117
|
blockrun_dex({ token: "So11...xxx" }) -> Get specific token data
|
|
980
1118
|
blockrun_dex({ symbol: "PEPE" }) -> Search by symbol`,
|
|
981
1119
|
inputSchema: {
|
|
982
|
-
query:
|
|
983
|
-
token:
|
|
984
|
-
symbol:
|
|
985
|
-
chain:
|
|
1120
|
+
query: z10.string().optional().describe("Search query (token name, symbol, or address)"),
|
|
1121
|
+
token: z10.string().optional().describe("Token address for direct lookup"),
|
|
1122
|
+
symbol: z10.string().optional().describe("Token symbol to search"),
|
|
1123
|
+
chain: z10.string().optional().describe("Filter by chain (ethereum, solana, base, etc.)")
|
|
986
1124
|
}
|
|
987
1125
|
},
|
|
988
1126
|
async ({ query, token, symbol, chain }) => {
|
|
@@ -1043,7 +1181,7 @@ ${lines.join("\n\n")}` }],
|
|
|
1043
1181
|
}
|
|
1044
1182
|
|
|
1045
1183
|
// src/tools/modal.ts
|
|
1046
|
-
import { z as
|
|
1184
|
+
import { z as z11 } from "zod";
|
|
1047
1185
|
var MODAL_GPU_TYPES = ["T4", "L4", "A10G", "A100", "A100-80GB", "H100"];
|
|
1048
1186
|
function registerModalTool(server) {
|
|
1049
1187
|
server.registerTool(
|
|
@@ -1063,17 +1201,17 @@ Pricing:
|
|
|
1063
1201
|
- create: $0.01
|
|
1064
1202
|
- exec/status/terminate: $0.001 each`,
|
|
1065
1203
|
inputSchema: {
|
|
1066
|
-
action:
|
|
1204
|
+
action: z11.enum(["create", "exec", "status", "terminate"]).describe(
|
|
1067
1205
|
"Sandbox action to perform"
|
|
1068
1206
|
),
|
|
1069
|
-
sandbox_id:
|
|
1070
|
-
command:
|
|
1071
|
-
image:
|
|
1072
|
-
timeout:
|
|
1073
|
-
cpu:
|
|
1074
|
-
memory:
|
|
1075
|
-
gpu:
|
|
1076
|
-
setup_commands:
|
|
1207
|
+
sandbox_id: z11.string().optional().describe("Sandbox ID returned by a previous create"),
|
|
1208
|
+
command: z11.array(z11.string()).optional().describe('Command array for exec, for example ["python", "-c", "print(2+2)"]'),
|
|
1209
|
+
image: z11.string().optional().describe("Container image for create (default: python:3.11)"),
|
|
1210
|
+
timeout: z11.number().optional().describe("Timeout in seconds for create or exec"),
|
|
1211
|
+
cpu: z11.number().optional().describe("CPU cores for create"),
|
|
1212
|
+
memory: z11.number().optional().describe("Memory in MB for create"),
|
|
1213
|
+
gpu: z11.enum(MODAL_GPU_TYPES).optional().describe("Optional GPU type for create"),
|
|
1214
|
+
setup_commands: z11.array(z11.string()).optional().describe("Shell commands to run during sandbox setup")
|
|
1077
1215
|
}
|
|
1078
1216
|
},
|
|
1079
1217
|
async ({ action, sandbox_id, command, image, timeout, cpu, memory, gpu, setup_commands }) => {
|
|
@@ -1138,6 +1276,7 @@ function initializeMcpServer(server) {
|
|
|
1138
1276
|
registerModelsTool(server, modelCache);
|
|
1139
1277
|
registerImageTool(server);
|
|
1140
1278
|
registerMusicTool(server);
|
|
1279
|
+
registerVideoTool(server);
|
|
1141
1280
|
registerSearchTool(server);
|
|
1142
1281
|
registerExaTool(server);
|
|
1143
1282
|
registerMarketsTool(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|