@blockrun/mcp 0.6.6 → 0.6.7

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.
Files changed (2) hide show
  1. package/dist/index.js +82 -149
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,70 +5,29 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
 
7
7
  // src/utils/wallet.ts
8
- import { LLMClient, ImageClient } from "@blockrun/llm";
9
- import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
10
- import * as fs from "fs";
11
-
12
- // src/utils/constants.ts
13
- import * as path from "path";
14
- import * as os from "os";
15
- var WALLET_DIR = path.join(os.homedir(), ".blockrun");
16
- var WALLET_FILE = path.join(WALLET_DIR, ".session");
17
- var QR_FILE = path.join(WALLET_DIR, "qr.png");
18
- var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
19
- var BASE_CHAIN_ID = "8453";
20
- var BASE_RPC_URLS = [
21
- "https://mainnet.base.org",
22
- "https://base.llamarpc.com",
23
- "https://1rpc.io/base"
24
- ];
25
- var MODEL_TIERS = {
26
- fast: ["google/gemini-2.5-flash", "google/gemini-3.1-flash-lite", "openai/gpt-5-mini", "deepseek/deepseek-chat", "google/gemini-3-flash-preview"],
27
- balanced: ["openai/gpt-5.4", "anthropic/claude-sonnet-4.6", "google/gemini-2.5-pro", "openai/gpt-5.3", "google/gemini-3.1-pro"],
28
- powerful: ["openai/gpt-5.4-pro", "anthropic/claude-opus-4.6", "anthropic/claude-opus-4.5", "openai/o3", "openai/gpt-5.4"],
29
- cheap: ["nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "google/gemini-2.5-flash", "deepseek/deepseek-chat", "openai/gpt-5.4-nano"],
30
- reasoning: ["openai/o3", "openai/o1", "openai/o3-mini", "deepseek/deepseek-reasoner", "openai/gpt-5.3-codex"],
31
- free: ["nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "nvidia/nemotron-ultra-253b", "nvidia/nemotron-super-49b", "nvidia/qwen3-coder-480b", "nvidia/llama-4-maverick", "nvidia/gpt-oss-20b"],
32
- coding: ["openai/gpt-5.3-codex", "nvidia/qwen3-coder-480b", "nvidia/devstral-2-123b", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4"]
33
- };
34
-
35
- // src/utils/wallet.ts
36
- var _walletWasCreated = false;
37
- var _walletAddress = null;
8
+ import {
9
+ LLMClient,
10
+ ImageClient,
11
+ getOrCreateWallet,
12
+ getPaymentLinks,
13
+ formatWalletCreatedMessage,
14
+ formatNeedsFundingMessage
15
+ } from "@blockrun/llm";
38
16
  var _client = null;
39
17
  var _imageClient = null;
40
- function getOrCreateWalletKey() {
41
- const envKey = process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY;
42
- if (envKey) {
43
- const account2 = privateKeyToAccount(envKey);
44
- _walletAddress = account2.address;
45
- return envKey;
46
- }
47
- if (fs.existsSync(WALLET_FILE)) {
48
- try {
49
- const savedKey = fs.readFileSync(WALLET_FILE, "utf-8").trim();
50
- if (savedKey.startsWith("0x") && savedKey.length === 66) {
51
- const account2 = privateKeyToAccount(savedKey);
52
- _walletAddress = account2.address;
53
- return savedKey;
54
- }
55
- } catch {
18
+ var _walletInfo = null;
19
+ function ensureWallet() {
20
+ if (!_walletInfo) {
21
+ _walletInfo = getOrCreateWallet();
22
+ if (_walletInfo.isNew) {
23
+ console.error(formatWalletCreatedMessage(_walletInfo.address));
56
24
  }
57
25
  }
58
- const newKey = generatePrivateKey();
59
- const account = privateKeyToAccount(newKey);
60
- _walletAddress = account.address;
61
- _walletWasCreated = true;
62
- try {
63
- if (!fs.existsSync(WALLET_DIR)) {
64
- fs.mkdirSync(WALLET_DIR, { recursive: true, mode: 448 });
65
- }
66
- fs.writeFileSync(WALLET_FILE, newKey, { mode: 384 });
67
- console.error(`[BlockRun] New wallet created and saved to ${WALLET_FILE}`);
68
- } catch (err) {
69
- console.error(`[BlockRun] Warning: Could not save wallet to file: ${err}`);
70
- }
71
- return newKey;
26
+ return _walletInfo;
27
+ }
28
+ function getOrCreateWalletKey() {
29
+ const info = ensureWallet();
30
+ return info.privateKey;
72
31
  }
73
32
  function getClient() {
74
33
  if (!_client) {
@@ -85,28 +44,29 @@ function getImageClient() {
85
44
  return _imageClient;
86
45
  }
87
46
  function getWalletInfo() {
88
- const llm = getClient();
89
- const address = llm.getWalletAddress();
47
+ const info = ensureWallet();
48
+ const links = getPaymentLinks(info.address);
90
49
  return {
91
- address,
50
+ address: info.address,
92
51
  network: "Base",
93
52
  chainId: 8453,
94
53
  currency: "USDC",
95
- isNew: _walletWasCreated,
96
- basescanUrl: `https://basescan.org/address/${address}`
54
+ isNew: info.isNew,
55
+ basescanUrl: links.basescan,
56
+ fundingUrl: links.blockrun
97
57
  };
98
58
  }
99
59
  async function getUsdcBalance(address) {
60
+ const USDC_ADDRESS2 = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
61
+ const BASE_RPC_URLS = [
62
+ "https://mainnet.base.org",
63
+ "https://base.llamarpc.com",
64
+ "https://1rpc.io/base"
65
+ ];
100
66
  const data = {
101
67
  jsonrpc: "2.0",
102
68
  method: "eth_call",
103
- params: [
104
- {
105
- to: USDC_ADDRESS,
106
- data: `0x70a08231000000000000000000000000${address.slice(2)}`
107
- },
108
- "latest"
109
- ],
69
+ params: [{ to: USDC_ADDRESS2, data: `0x70a08231000000000000000000000000${address.slice(2)}` }, "latest"],
110
70
  id: 1
111
71
  };
112
72
  for (const rpcUrl of BASE_RPC_URLS) {
@@ -117,9 +77,7 @@ async function getUsdcBalance(address) {
117
77
  body: JSON.stringify(data)
118
78
  });
119
79
  const result = await response.json();
120
- if (result.result) {
121
- return parseInt(result.result, 16) / 1e6;
122
- }
80
+ if (result.result) return parseInt(result.result, 16) / 1e6;
123
81
  } catch {
124
82
  continue;
125
83
  }
@@ -133,15 +91,35 @@ import { z } from "zod";
133
91
  // src/utils/qr.ts
134
92
  import QRCode from "qrcode";
135
93
  import open from "open";
136
- import * as fs2 from "fs";
94
+ import * as fs from "fs";
95
+
96
+ // src/utils/constants.ts
97
+ import * as path from "path";
98
+ import * as os from "os";
99
+ var WALLET_DIR = path.join(os.homedir(), ".blockrun");
100
+ var WALLET_FILE = path.join(WALLET_DIR, ".session");
101
+ var QR_FILE = path.join(WALLET_DIR, "qr.png");
102
+ var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
103
+ var BASE_CHAIN_ID = "8453";
104
+ var MODEL_TIERS = {
105
+ fast: ["google/gemini-2.5-flash", "google/gemini-3.1-flash-lite", "openai/gpt-5-mini", "deepseek/deepseek-chat", "google/gemini-3-flash-preview"],
106
+ balanced: ["openai/gpt-5.4", "anthropic/claude-sonnet-4.6", "google/gemini-2.5-pro", "openai/gpt-5.3", "google/gemini-3.1-pro"],
107
+ powerful: ["openai/gpt-5.4-pro", "anthropic/claude-opus-4.6", "anthropic/claude-opus-4.5", "openai/o3", "openai/gpt-5.4"],
108
+ cheap: ["nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "google/gemini-2.5-flash", "deepseek/deepseek-chat", "openai/gpt-5.4-nano"],
109
+ reasoning: ["openai/o3", "openai/o1", "openai/o3-mini", "deepseek/deepseek-reasoner", "openai/gpt-5.3-codex"],
110
+ free: ["nvidia/gpt-oss-120b", "nvidia/deepseek-v3.2", "nvidia/nemotron-ultra-253b", "nvidia/nemotron-super-49b", "nvidia/qwen3-coder-480b", "nvidia/llama-4-maverick", "nvidia/gpt-oss-20b"],
111
+ coding: ["openai/gpt-5.3-codex", "nvidia/qwen3-coder-480b", "nvidia/devstral-2-123b", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4"]
112
+ };
113
+
114
+ // src/utils/qr.ts
137
115
  function getEip681Uri(address, amountUsdc = 1) {
138
116
  const amountWei = Math.floor(amountUsdc * 1e6);
139
117
  return `ethereum:${USDC_ADDRESS}@${BASE_CHAIN_ID}/transfer?address=${address}&uint256=${amountWei}`;
140
118
  }
141
119
  async function generateQrPng(address) {
142
120
  const eip681Uri = getEip681Uri(address);
143
- if (!fs2.existsSync(WALLET_DIR)) {
144
- fs2.mkdirSync(WALLET_DIR, { recursive: true, mode: 448 });
121
+ if (!fs.existsSync(WALLET_DIR)) {
122
+ fs.mkdirSync(WALLET_DIR, { recursive: true, mode: 448 });
145
123
  }
146
124
  await QRCode.toFile(QR_FILE, eip681Uri, {
147
125
  type: "png",
@@ -675,52 +653,8 @@ Error: ${errMsg}` }],
675
653
  );
676
654
  }
677
655
 
678
- // src/tools/twitter.ts
679
- import { z as z5 } from "zod";
680
- function registerTwitterTool(server, budget) {
681
- server.registerTool(
682
- "blockrun_twitter",
683
- {
684
- description: `Search real-time X/Twitter via Grok. Use for trending topics, @handles, breaking news.`,
685
- inputSchema: {
686
- query: z5.string().describe("Search query (can include @handles, topics)"),
687
- max_results: z5.number().optional().default(10).describe("Max results (1-25)")
688
- }
689
- },
690
- async ({ query, max_results }) => {
691
- const budgetCheck = checkBudget(budget);
692
- if (!budgetCheck.allowed) {
693
- return {
694
- content: [{ type: "text", text: `Budget limit reached ($${budget.spent.toFixed(4)} of $${budget.limit?.toFixed(2)}). Use blockrun_wallet with action: "budget" to adjust.` }],
695
- isError: true
696
- };
697
- }
698
- try {
699
- const llm = getClient();
700
- const response = await llm.chat("xai/grok-3", query, {
701
- system: `Real-time X/Twitter search. Focus on recent posts, key accounts, engagement. Max results: ${max_results}`,
702
- search: true
703
- });
704
- recordSpending(budget, 2e-3);
705
- return {
706
- content: [{ type: "text", text: `[X/Twitter via Grok]
707
-
708
- ${response}` }],
709
- structuredContent: { query, model: "xai/grok-3", response }
710
- };
711
- } catch (error) {
712
- const errorMessage = error instanceof Error ? error.message : String(error);
713
- return {
714
- content: [{ type: "text", text: formatError(errorMessage) }],
715
- isError: true
716
- };
717
- }
718
- }
719
- );
720
- }
721
-
722
656
  // src/tools/search.ts
723
- import { z as z6 } from "zod";
657
+ import { z as z5 } from "zod";
724
658
  function registerSearchTool(server) {
725
659
  server.registerTool(
726
660
  "blockrun_search",
@@ -732,11 +666,11 @@ Pricing: ~$0.01/search
732
666
 
733
667
  Returns a summary with cited sources.`,
734
668
  inputSchema: {
735
- query: z6.string().describe("Search query"),
736
- sources: z6.array(z6.enum(["web", "x", "news"])).optional().describe("Sources to search (default: web + x + news)"),
737
- max_results: z6.number().optional().default(10).describe("Max results per source (1-20)"),
738
- from_date: z6.string().optional().describe("Start date filter (YYYY-MM-DD)"),
739
- to_date: z6.string().optional().describe("End date filter (YYYY-MM-DD)")
669
+ query: z5.string().describe("Search query"),
670
+ sources: z5.array(z5.enum(["web", "x", "news"])).optional().describe("Sources to search (default: web + x + news)"),
671
+ max_results: z5.number().optional().default(10).describe("Max results per source (1-20)"),
672
+ from_date: z5.string().optional().describe("Start date filter (YYYY-MM-DD)"),
673
+ to_date: z5.string().optional().describe("End date filter (YYYY-MM-DD)")
740
674
  }
741
675
  },
742
676
  async ({ query, sources, max_results, from_date, to_date }) => {
@@ -764,7 +698,7 @@ Returns a summary with cited sources.`,
764
698
  }
765
699
 
766
700
  // src/tools/exa.ts
767
- import { z as z7 } from "zod";
701
+ import { z as z6 } from "zod";
768
702
  function registerExaTool(server) {
769
703
  server.registerTool(
770
704
  "blockrun_exa",
@@ -777,14 +711,14 @@ Actions:
777
711
  - contents: Fetch full Markdown text from URLs, ready for LLM context ($0.002/URL)
778
712
  - similar: Find pages semantically similar to a given URL ($0.01/call)`,
779
713
  inputSchema: {
780
- action: z7.enum(["search", "answer", "contents", "similar"]).describe("Action to perform"),
781
- query: z7.string().optional().describe("Natural language query (for search/answer)"),
782
- url: z7.string().optional().describe("Reference URL to find similar pages (for similar action)"),
783
- urls: z7.array(z7.string()).optional().describe("URLs to fetch content from (for contents action, up to 100)"),
784
- num_results: z7.number().optional().describe("Number of results to return (default: 10)"),
785
- category: z7.string().optional().describe("Category filter: 'news', 'research paper', 'company', 'tweet', 'github', 'pdf'"),
786
- include_domains: z7.array(z7.string()).optional().describe("Only search within these domains"),
787
- exclude_domains: z7.array(z7.string()).optional().describe("Exclude these domains from results")
714
+ action: z6.enum(["search", "answer", "contents", "similar"]).describe("Action to perform"),
715
+ query: z6.string().optional().describe("Natural language query (for search/answer)"),
716
+ url: z6.string().optional().describe("Reference URL to find similar pages (for similar action)"),
717
+ urls: z6.array(z6.string()).optional().describe("URLs to fetch content from (for contents action, up to 100)"),
718
+ num_results: z6.number().optional().describe("Number of results to return (default: 10)"),
719
+ category: z6.string().optional().describe("Category filter: 'news', 'research paper', 'company', 'tweet', 'github', 'pdf'"),
720
+ include_domains: z6.array(z6.string()).optional().describe("Only search within these domains"),
721
+ exclude_domains: z6.array(z6.string()).optional().describe("Exclude these domains from results")
788
722
  }
789
723
  },
790
724
  async ({ action, query, url, urls, num_results, category, include_domains, exclude_domains }) => {
@@ -837,7 +771,7 @@ Actions:
837
771
  }
838
772
 
839
773
  // src/tools/markets.ts
840
- import { z as z8 } from "zod";
774
+ import { z as z7 } from "zod";
841
775
  function registerMarketsTool(server) {
842
776
  server.registerTool(
843
777
  "blockrun_markets",
@@ -852,9 +786,9 @@ Example paths:
852
786
 
853
787
  $0.001/call.`,
854
788
  inputSchema: {
855
- path: z8.string().describe("Endpoint path, e.g. 'polymarket/events', 'kalshi/markets/KXBTC-25MAR14'"),
856
- params: z8.record(z8.string(), z8.string()).optional().describe("Query parameters for GET requests"),
857
- body: z8.any().optional().describe("JSON body for POST queries (triggers pmQuery)")
789
+ path: z7.string().describe("Endpoint path, e.g. 'polymarket/events', 'kalshi/markets/KXBTC-25MAR14'"),
790
+ params: z7.record(z7.string(), z7.string()).optional().describe("Query parameters for GET requests"),
791
+ body: z7.any().optional().describe("JSON body for POST queries (triggers pmQuery)")
858
792
  }
859
793
  },
860
794
  async ({ path: path2, params, body }) => {
@@ -877,7 +811,7 @@ $0.001/call.`,
877
811
  }
878
812
 
879
813
  // src/tools/dex.ts
880
- import { z as z9 } from "zod";
814
+ import { z as z8 } from "zod";
881
815
  function registerDexTool(server) {
882
816
  server.registerTool(
883
817
  "blockrun_dex",
@@ -894,10 +828,10 @@ Examples:
894
828
  blockrun_dex({ token: "So11...xxx" }) -> Get specific token data
895
829
  blockrun_dex({ symbol: "PEPE" }) -> Search by symbol`,
896
830
  inputSchema: {
897
- query: z9.string().optional().describe("Search query (token name, symbol, or address)"),
898
- token: z9.string().optional().describe("Token address for direct lookup"),
899
- symbol: z9.string().optional().describe("Token symbol to search"),
900
- chain: z9.string().optional().describe("Filter by chain (ethereum, solana, base, etc.)")
831
+ query: z8.string().optional().describe("Search query (token name, symbol, or address)"),
832
+ token: z8.string().optional().describe("Token address for direct lookup"),
833
+ symbol: z8.string().optional().describe("Token symbol to search"),
834
+ chain: z8.string().optional().describe("Filter by chain (ethereum, solana, base, etc.)")
901
835
  }
902
836
  },
903
837
  async ({ query, token, symbol, chain }) => {
@@ -965,7 +899,6 @@ function initializeMcpServer(server) {
965
899
  registerChatTool(server, budget);
966
900
  registerModelsTool(server, modelCache);
967
901
  registerImageTool(server);
968
- registerTwitterTool(server, budget);
969
902
  registerSearchTool(server);
970
903
  registerExaTool(server);
971
904
  registerMarketsTool(server);
@@ -1009,12 +942,12 @@ function initializeMcpServer(server) {
1009
942
  async function main() {
1010
943
  const server = new McpServer({
1011
944
  name: "blockrun-mcp",
1012
- version: "0.6.5"
945
+ version: "0.6.6"
1013
946
  });
1014
947
  initializeMcpServer(server);
1015
948
  const transport = new StdioServerTransport();
1016
949
  await server.connect(transport);
1017
- console.error("BlockRun MCP Server started (v0.6.5) \u2014 stdio transport");
950
+ console.error("BlockRun MCP Server started (v0.6.6) \u2014 stdio transport");
1018
951
  }
1019
952
  main().catch((error) => {
1020
953
  console.error("Fatal error:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/mcp",
3
- "version": "0.6.6",
3
+ "version": "0.6.7",
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",