@blockrun/mcp 0.6.7 → 0.6.9
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 +2 -2
- package/dist/index.js +182 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
**Real-time data for Claude — markets, research, X/Twitter, crypto. No API keys. Pay per call.**
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
claude mcp add blockrun npx @blockrun/mcp
|
|
10
|
+
claude mcp add blockrun npx -y @blockrun/mcp@latest
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Wallet auto-created. Fund with $5 USDC. Ask Claude anything.
|
|
@@ -49,7 +49,7 @@ After BlockRun, it can. Each query costs fractions of a cent, billed from a loca
|
|
|
49
49
|
|
|
50
50
|
**Claude Code (recommended)**
|
|
51
51
|
```bash
|
|
52
|
-
claude mcp add blockrun npx @blockrun/mcp
|
|
52
|
+
claude mcp add blockrun npx -y @blockrun/mcp@latest
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
**Claude Desktop** — add to `claude_desktop_config.json`:
|
package/dist/index.js
CHANGED
|
@@ -653,8 +653,148 @@ Error: ${errMsg}` }],
|
|
|
653
653
|
);
|
|
654
654
|
}
|
|
655
655
|
|
|
656
|
-
// src/tools/
|
|
656
|
+
// src/tools/music.ts
|
|
657
657
|
import { z as z5 } from "zod";
|
|
658
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
659
|
+
import {
|
|
660
|
+
createPaymentPayload,
|
|
661
|
+
parsePaymentRequired,
|
|
662
|
+
extractPaymentDetails
|
|
663
|
+
} from "@blockrun/llm";
|
|
664
|
+
var BLOCKRUN_API = "https://blockrun.ai/api";
|
|
665
|
+
var MUSIC_TIMEOUT = 2e5;
|
|
666
|
+
function registerMusicTool(server) {
|
|
667
|
+
server.registerTool(
|
|
668
|
+
"blockrun_music",
|
|
669
|
+
{
|
|
670
|
+
description: `Generate music tracks via BlockRun x402.
|
|
671
|
+
|
|
672
|
+
Generates a full-length ~3 minute MP3 track. Takes 1-3 minutes to complete.
|
|
673
|
+
|
|
674
|
+
Models: minimax/music-2.5+ ($0.1575), minimax/music-2.5 ($0.1575)
|
|
675
|
+
|
|
676
|
+
Returns a time-limited CDN URL \u2014 download immediately if you need to keep the file.`,
|
|
677
|
+
inputSchema: {
|
|
678
|
+
prompt: z5.string().describe("Music style, mood, or description. E.g. 'upbeat synthwave with neon pads', 'chill lo-fi beats', 'epic orchestral film score'"),
|
|
679
|
+
instrumental: z5.boolean().optional().default(true).describe("Generate without vocals (default: true)"),
|
|
680
|
+
lyrics: z5.string().optional().describe("Custom lyrics. Cannot be used with instrumental: true"),
|
|
681
|
+
model: z5.enum(["minimax/music-2.5+", "minimax/music-2.5"]).optional().default("minimax/music-2.5+").describe("Music model to use")
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
async ({ prompt, instrumental, lyrics, model }) => {
|
|
685
|
+
try {
|
|
686
|
+
if (instrumental && lyrics?.trim()) {
|
|
687
|
+
return {
|
|
688
|
+
content: [{ type: "text", text: formatError("Cannot specify lyrics when instrumental is true") }],
|
|
689
|
+
isError: true
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
const privateKey = getOrCreateWalletKey();
|
|
693
|
+
const account = privateKeyToAccount(privateKey);
|
|
694
|
+
const url = `${BLOCKRUN_API}/v1/audio/generations`;
|
|
695
|
+
const body = { model, prompt, instrumental };
|
|
696
|
+
if (lyrics?.trim()) body.lyrics = lyrics.trim();
|
|
697
|
+
const resp402 = await fetchWithTimeout(url, {
|
|
698
|
+
method: "POST",
|
|
699
|
+
headers: { "Content-Type": "application/json" },
|
|
700
|
+
body: JSON.stringify(body)
|
|
701
|
+
}, 15e3);
|
|
702
|
+
if (resp402.status !== 402) {
|
|
703
|
+
const data2 = await resp402.json();
|
|
704
|
+
throw new Error(`Expected 402, got ${resp402.status}: ${JSON.stringify(data2)}`);
|
|
705
|
+
}
|
|
706
|
+
const prHeader = resp402.headers.get("payment-required") || resp402.headers.get("PAYMENT-REQUIRED");
|
|
707
|
+
if (!prHeader) throw new Error("No PAYMENT-REQUIRED header in 402 response");
|
|
708
|
+
const paymentRequired = parsePaymentRequired(prHeader);
|
|
709
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
710
|
+
const paymentPayload = await createPaymentPayload(
|
|
711
|
+
privateKey,
|
|
712
|
+
account.address,
|
|
713
|
+
details.recipient,
|
|
714
|
+
details.amount,
|
|
715
|
+
details.network || "eip155:8453",
|
|
716
|
+
{
|
|
717
|
+
resourceUrl: details.resource?.url || url,
|
|
718
|
+
resourceDescription: details.resource?.description || "BlockRun Music Generation",
|
|
719
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
720
|
+
extra: details.extra
|
|
721
|
+
}
|
|
722
|
+
);
|
|
723
|
+
const resp = await fetchWithTimeout(url, {
|
|
724
|
+
method: "POST",
|
|
725
|
+
headers: {
|
|
726
|
+
"Content-Type": "application/json",
|
|
727
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
728
|
+
},
|
|
729
|
+
body: JSON.stringify(body)
|
|
730
|
+
}, MUSIC_TIMEOUT);
|
|
731
|
+
if (resp.status === 402) {
|
|
732
|
+
throw new Error("Payment rejected. Check your wallet balance.");
|
|
733
|
+
}
|
|
734
|
+
if (!resp.ok) {
|
|
735
|
+
const errBody = await resp.json().catch(() => ({ error: "Request failed" }));
|
|
736
|
+
throw new Error(`API error ${resp.status}: ${JSON.stringify(errBody)}`);
|
|
737
|
+
}
|
|
738
|
+
const data = await resp.json();
|
|
739
|
+
const track = data.data?.[0];
|
|
740
|
+
if (!track?.url) throw new Error("No track URL in response");
|
|
741
|
+
const txHash = resp.headers.get("X-Payment-Receipt") || resp.headers.get("x-payment-receipt");
|
|
742
|
+
const lines = [
|
|
743
|
+
`\u{1F3B5} Track ready!`,
|
|
744
|
+
`URL: ${track.url}`,
|
|
745
|
+
`Duration: ${track.duration_seconds ? `${track.duration_seconds}s` : "~3 min"}`,
|
|
746
|
+
`Model: ${data.model || model}`,
|
|
747
|
+
...track.lyrics ? [`Lyrics: ${track.lyrics.slice(0, 200)}${track.lyrics.length > 200 ? "..." : ""}`] : [],
|
|
748
|
+
...txHash ? [`Tx: ${txHash}`] : [],
|
|
749
|
+
``,
|
|
750
|
+
`Note: This URL expires in ~24h. Download it now if you need to keep the file.`
|
|
751
|
+
];
|
|
752
|
+
return {
|
|
753
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
754
|
+
structuredContent: {
|
|
755
|
+
url: track.url,
|
|
756
|
+
duration_seconds: track.duration_seconds,
|
|
757
|
+
model: data.model || model,
|
|
758
|
+
...track.lyrics ? { lyrics: track.lyrics } : {},
|
|
759
|
+
...txHash ? { txHash } : {}
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
} catch (err) {
|
|
763
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
764
|
+
if (errMsg.includes("balance") || errMsg.includes("payment") || errMsg.includes("402") || errMsg.includes("rejected")) {
|
|
765
|
+
return {
|
|
766
|
+
content: [{ type: "text", text: `Music generation requires payment. Run blockrun_wallet with action: "setup" for funding instructions.
|
|
767
|
+
Error: ${errMsg}` }],
|
|
768
|
+
isError: true
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (errMsg.includes("abort") || errMsg.includes("timeout") || errMsg.includes("Timeout")) {
|
|
772
|
+
return {
|
|
773
|
+
content: [{ type: "text", text: `Music generation timed out. This can happen during peak load \u2014 please try again.
|
|
774
|
+
Error: ${errMsg}` }],
|
|
775
|
+
isError: true
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
return {
|
|
779
|
+
content: [{ type: "text", text: formatError(`Music generation failed: ${errMsg}`) }],
|
|
780
|
+
isError: true
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
787
|
+
const controller = new AbortController();
|
|
788
|
+
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
789
|
+
try {
|
|
790
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
791
|
+
} finally {
|
|
792
|
+
clearTimeout(id);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// src/tools/search.ts
|
|
797
|
+
import { z as z6 } from "zod";
|
|
658
798
|
function registerSearchTool(server) {
|
|
659
799
|
server.registerTool(
|
|
660
800
|
"blockrun_search",
|
|
@@ -666,11 +806,11 @@ Pricing: ~$0.01/search
|
|
|
666
806
|
|
|
667
807
|
Returns a summary with cited sources.`,
|
|
668
808
|
inputSchema: {
|
|
669
|
-
query:
|
|
670
|
-
sources:
|
|
671
|
-
max_results:
|
|
672
|
-
from_date:
|
|
673
|
-
to_date:
|
|
809
|
+
query: z6.string().describe("Search query"),
|
|
810
|
+
sources: z6.array(z6.enum(["web", "x", "news"])).optional().describe("Sources to search (default: web + x + news)"),
|
|
811
|
+
max_results: z6.number().optional().default(10).describe("Max results per source (1-20)"),
|
|
812
|
+
from_date: z6.string().optional().describe("Start date filter (YYYY-MM-DD)"),
|
|
813
|
+
to_date: z6.string().optional().describe("End date filter (YYYY-MM-DD)")
|
|
674
814
|
}
|
|
675
815
|
},
|
|
676
816
|
async ({ query, sources, max_results, from_date, to_date }) => {
|
|
@@ -698,7 +838,7 @@ Returns a summary with cited sources.`,
|
|
|
698
838
|
}
|
|
699
839
|
|
|
700
840
|
// src/tools/exa.ts
|
|
701
|
-
import { z as
|
|
841
|
+
import { z as z7 } from "zod";
|
|
702
842
|
function registerExaTool(server) {
|
|
703
843
|
server.registerTool(
|
|
704
844
|
"blockrun_exa",
|
|
@@ -711,14 +851,14 @@ Actions:
|
|
|
711
851
|
- contents: Fetch full Markdown text from URLs, ready for LLM context ($0.002/URL)
|
|
712
852
|
- similar: Find pages semantically similar to a given URL ($0.01/call)`,
|
|
713
853
|
inputSchema: {
|
|
714
|
-
action:
|
|
715
|
-
query:
|
|
716
|
-
url:
|
|
717
|
-
urls:
|
|
718
|
-
num_results:
|
|
719
|
-
category:
|
|
720
|
-
include_domains:
|
|
721
|
-
exclude_domains:
|
|
854
|
+
action: z7.enum(["search", "answer", "contents", "similar"]).describe("Action to perform"),
|
|
855
|
+
query: z7.string().optional().describe("Natural language query (for search/answer)"),
|
|
856
|
+
url: z7.string().optional().describe("Reference URL to find similar pages (for similar action)"),
|
|
857
|
+
urls: z7.array(z7.string()).optional().describe("URLs to fetch content from (for contents action, up to 100)"),
|
|
858
|
+
num_results: z7.number().optional().describe("Number of results to return (default: 10)"),
|
|
859
|
+
category: z7.string().optional().describe("Category filter: 'news', 'research paper', 'company', 'tweet', 'github', 'pdf'"),
|
|
860
|
+
include_domains: z7.array(z7.string()).optional().describe("Only search within these domains"),
|
|
861
|
+
exclude_domains: z7.array(z7.string()).optional().describe("Exclude these domains from results")
|
|
722
862
|
}
|
|
723
863
|
},
|
|
724
864
|
async ({ action, query, url, urls, num_results, category, include_domains, exclude_domains }) => {
|
|
@@ -771,7 +911,7 @@ Actions:
|
|
|
771
911
|
}
|
|
772
912
|
|
|
773
913
|
// src/tools/markets.ts
|
|
774
|
-
import { z as
|
|
914
|
+
import { z as z8 } from "zod";
|
|
775
915
|
function registerMarketsTool(server) {
|
|
776
916
|
server.registerTool(
|
|
777
917
|
"blockrun_markets",
|
|
@@ -786,9 +926,9 @@ Example paths:
|
|
|
786
926
|
|
|
787
927
|
$0.001/call.`,
|
|
788
928
|
inputSchema: {
|
|
789
|
-
path:
|
|
790
|
-
params:
|
|
791
|
-
body:
|
|
929
|
+
path: z8.string().describe("Endpoint path, e.g. 'polymarket/events', 'kalshi/markets/KXBTC-25MAR14'"),
|
|
930
|
+
params: z8.record(z8.string(), z8.string()).optional().describe("Query parameters for GET requests"),
|
|
931
|
+
body: z8.any().optional().describe("JSON body for POST queries (triggers pmQuery)")
|
|
792
932
|
}
|
|
793
933
|
},
|
|
794
934
|
async ({ path: path2, params, body }) => {
|
|
@@ -811,7 +951,7 @@ $0.001/call.`,
|
|
|
811
951
|
}
|
|
812
952
|
|
|
813
953
|
// src/tools/dex.ts
|
|
814
|
-
import { z as
|
|
954
|
+
import { z as z9 } from "zod";
|
|
815
955
|
function registerDexTool(server) {
|
|
816
956
|
server.registerTool(
|
|
817
957
|
"blockrun_dex",
|
|
@@ -828,10 +968,10 @@ Examples:
|
|
|
828
968
|
blockrun_dex({ token: "So11...xxx" }) -> Get specific token data
|
|
829
969
|
blockrun_dex({ symbol: "PEPE" }) -> Search by symbol`,
|
|
830
970
|
inputSchema: {
|
|
831
|
-
query:
|
|
832
|
-
token:
|
|
833
|
-
symbol:
|
|
834
|
-
chain:
|
|
971
|
+
query: z9.string().optional().describe("Search query (token name, symbol, or address)"),
|
|
972
|
+
token: z9.string().optional().describe("Token address for direct lookup"),
|
|
973
|
+
symbol: z9.string().optional().describe("Token symbol to search"),
|
|
974
|
+
chain: z9.string().optional().describe("Filter by chain (ethereum, solana, base, etc.)")
|
|
835
975
|
}
|
|
836
976
|
},
|
|
837
977
|
async ({ query, token, symbol, chain }) => {
|
|
@@ -899,6 +1039,7 @@ function initializeMcpServer(server) {
|
|
|
899
1039
|
registerChatTool(server, budget);
|
|
900
1040
|
registerModelsTool(server, modelCache);
|
|
901
1041
|
registerImageTool(server);
|
|
1042
|
+
registerMusicTool(server);
|
|
902
1043
|
registerSearchTool(server);
|
|
903
1044
|
registerExaTool(server);
|
|
904
1045
|
registerMarketsTool(server);
|
|
@@ -939,15 +1080,30 @@ function initializeMcpServer(server) {
|
|
|
939
1080
|
}
|
|
940
1081
|
|
|
941
1082
|
// src/index.ts
|
|
1083
|
+
var VERSION = "0.6.8";
|
|
1084
|
+
async function checkForUpdate() {
|
|
1085
|
+
try {
|
|
1086
|
+
const resp = await fetch("https://registry.npmjs.org/@blockrun/mcp/latest", {
|
|
1087
|
+
signal: AbortSignal.timeout(3e3)
|
|
1088
|
+
});
|
|
1089
|
+
const data = await resp.json();
|
|
1090
|
+
if (data.version && data.version !== VERSION) {
|
|
1091
|
+
console.error(`[BlockRun] Update available: v${VERSION} \u2192 v${data.version}`);
|
|
1092
|
+
console.error(`[BlockRun] Run: claude mcp add blockrun npx -y @blockrun/mcp@latest`);
|
|
1093
|
+
}
|
|
1094
|
+
} catch {
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
942
1097
|
async function main() {
|
|
943
1098
|
const server = new McpServer({
|
|
944
1099
|
name: "blockrun-mcp",
|
|
945
|
-
version:
|
|
1100
|
+
version: VERSION
|
|
946
1101
|
});
|
|
947
1102
|
initializeMcpServer(server);
|
|
948
1103
|
const transport = new StdioServerTransport();
|
|
949
1104
|
await server.connect(transport);
|
|
950
|
-
console.error(
|
|
1105
|
+
console.error(`BlockRun MCP Server started (v${VERSION}) \u2014 stdio transport`);
|
|
1106
|
+
checkForUpdate();
|
|
951
1107
|
}
|
|
952
1108
|
main().catch((error) => {
|
|
953
1109
|
console.error("Fatal error:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
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",
|