@blockrun/mcp 0.8.0 → 0.9.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.
Files changed (3) hide show
  1. package/README.md +6 -3
  2. package/dist/index.js +263 -22
  3. package/package.json +2 -2
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 -y @blockrun/mcp@latest
10
+ claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest
11
11
  ```
12
12
 
13
13
  Wallet auto-created. Fund with $5 USDC. Ask Claude anything.
@@ -49,9 +49,12 @@ 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 -y @blockrun/mcp@latest
52
+ claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest
53
53
  ```
54
54
 
55
+ The `-s user` flag installs globally (available in every project). The `--` separator
56
+ ensures `-y` is passed to `npx`, not parsed by `claude mcp add`.
57
+
55
58
  **Claude Desktop** — add to `claude_desktop_config.json`:
56
59
  ```json
57
60
  {
@@ -66,7 +69,7 @@ claude mcp add blockrun npx -y @blockrun/mcp@latest
66
69
 
67
70
  **Hosted (no install, always latest)**
68
71
  ```bash
69
- claude mcp add --transport http blockrun https://mcp.blockrun.ai/mcp
72
+ claude mcp add blockrun -s user --transport http https://mcp.blockrun.ai/mcp
70
73
  ```
71
74
 
72
75
  ---
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
+ import { readFileSync } from "fs";
4
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
7
 
@@ -8,6 +9,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
8
9
  import {
9
10
  LLMClient,
10
11
  ImageClient,
12
+ PriceClient,
11
13
  getOrCreateWallet,
12
14
  getPaymentLinks,
13
15
  formatWalletCreatedMessage,
@@ -15,6 +17,7 @@ import {
15
17
  } from "@blockrun/llm";
16
18
  var _client = null;
17
19
  var _imageClient = null;
20
+ var _priceClient = null;
18
21
  var _walletInfo = null;
19
22
  function ensureWallet() {
20
23
  if (!_walletInfo) {
@@ -43,6 +46,13 @@ function getImageClient() {
43
46
  }
44
47
  return _imageClient;
45
48
  }
49
+ function getPriceClient() {
50
+ if (!_priceClient) {
51
+ const privateKey = getOrCreateWalletKey();
52
+ _priceClient = new PriceClient({ privateKey });
53
+ }
54
+ return _priceClient;
55
+ }
46
56
  function getWalletInfo() {
47
57
  const info = ensureWallet();
48
58
  const links = getPaymentLinks(info.address);
@@ -103,12 +113,12 @@ var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
103
113
  var BASE_CHAIN_ID = "8453";
104
114
  var MODEL_TIERS = {
105
115
  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"],
116
+ 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"],
117
+ powerful: ["openai/gpt-5.4-pro", "anthropic/claude-opus-4.7", "anthropic/claude-opus-4.6", "openai/o3", "openai/gpt-5.4"],
108
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"],
109
- reasoning: ["openai/o3", "openai/o1", "openai/o3-mini", "deepseek/deepseek-reasoner", "openai/gpt-5.3-codex"],
119
+ reasoning: ["openai/o3", "openai/o1", "openai/o3-mini", "deepseek/deepseek-reasoner", "moonshot/kimi-k2.6", "openai/gpt-5.3-codex"],
110
120
  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", "nvidia/glm-4.7"],
111
- coding: ["zai/glm-5", "openai/gpt-5.3-codex", "nvidia/qwen3-coder-480b", "nvidia/devstral-2-123b", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4"],
121
+ coding: ["zai/glm-5", "openai/gpt-5.3-codex", "moonshot/kimi-k2.6", "nvidia/qwen3-coder-480b", "nvidia/devstral-2-123b", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4"],
112
122
  glm: ["zai/glm-5", "zai/glm-5-turbo", "nvidia/glm-4.7"]
113
123
  };
114
124
 
@@ -1099,8 +1109,235 @@ $0.001/call.`,
1099
1109
  );
1100
1110
  }
1101
1111
 
1102
- // src/tools/dex.ts
1112
+ // src/tools/price.ts
1103
1113
  import { z as z10 } from "zod";
1114
+ var CATEGORY = z10.enum(["crypto", "fx", "commodity", "usstock", "stocks"]);
1115
+ var MARKET = z10.enum([
1116
+ "us",
1117
+ "hk",
1118
+ "jp",
1119
+ "kr",
1120
+ "gb",
1121
+ "de",
1122
+ "fr",
1123
+ "nl",
1124
+ "ie",
1125
+ "lu",
1126
+ "cn",
1127
+ "ca"
1128
+ ]);
1129
+ var RESOLUTION = z10.enum(["1", "5", "15", "60", "240", "D", "W", "M"]);
1130
+ var SESSION = z10.enum(["pre", "post", "on"]);
1131
+ var ACTION = z10.enum(["price", "history", "list"]);
1132
+ function registerPriceTool(server) {
1133
+ server.registerTool(
1134
+ "blockrun_price",
1135
+ {
1136
+ description: `Realtime quotes and OHLC history for crypto, FX, commodities and 12 global stock markets (Pyth-backed).
1137
+
1138
+ - action="price" \u2014 realtime quote for a symbol
1139
+ - action="history" \u2014 OHLC bars between from/to (unix seconds)
1140
+ - action="list" \u2014 discovery: list available symbols (free)
1141
+
1142
+ Pricing:
1143
+ - crypto / fx / commodity: FREE across price, history and list
1144
+ - stocks / usstock: $0.001 per price or history call (list free)
1145
+
1146
+ Stocks markets: us, hk, jp, kr, gb, de, fr, nl, ie, lu, cn, ca (required when category="stocks").
1147
+
1148
+ Examples:
1149
+ - { action: "price", category: "crypto", symbol: "BTC-USD" }
1150
+ - { action: "price", category: "stocks", symbol: "AAPL", market: "us" }
1151
+ - { action: "history", category: "crypto", symbol: "ETH-USD", resolution: "D", from: 1700000000, to: 1710000000 }
1152
+ - { action: "list", category: "crypto", query: "sol" }`,
1153
+ inputSchema: {
1154
+ action: ACTION.describe("Which endpoint to hit: price, history, or list."),
1155
+ category: CATEGORY.describe("Market category."),
1156
+ symbol: z10.string().optional().describe("Ticker (required for price+history). e.g. BTC-USD, AAPL, EUR-USD."),
1157
+ market: MARKET.optional().describe("Stock market code \u2014 required when category='stocks'."),
1158
+ session: SESSION.optional().describe("Equity session hint (pre/post/on); ignored for non-equity."),
1159
+ resolution: RESOLUTION.optional().describe("Bar resolution for history (default D)."),
1160
+ from: z10.number().optional().describe("History window start (unix seconds)."),
1161
+ to: z10.number().optional().describe("History window end (unix seconds)."),
1162
+ query: z10.string().optional().describe("Free-text filter for list."),
1163
+ limit: z10.number().optional().describe("Max items for list (default 100, max 2000).")
1164
+ }
1165
+ },
1166
+ async ({ action, category, symbol, market, session, resolution, from, to, query, limit }) => {
1167
+ try {
1168
+ const priceClient = getPriceClient();
1169
+ if (action === "price") {
1170
+ if (!symbol) throw new Error("symbol is required for action='price'");
1171
+ const result2 = await priceClient.price(category, symbol, {
1172
+ market,
1173
+ session
1174
+ });
1175
+ return {
1176
+ content: [{ type: "text", text: JSON.stringify(result2, null, 2) }],
1177
+ structuredContent: result2
1178
+ };
1179
+ }
1180
+ if (action === "history") {
1181
+ if (!symbol) throw new Error("symbol is required for action='history'");
1182
+ if (!from) throw new Error("from (unix seconds) is required for action='history'");
1183
+ const result2 = await priceClient.history(category, symbol, {
1184
+ market,
1185
+ session,
1186
+ resolution: resolution ?? "D",
1187
+ from,
1188
+ to
1189
+ });
1190
+ return {
1191
+ content: [{ type: "text", text: JSON.stringify(result2, null, 2) }],
1192
+ structuredContent: result2
1193
+ };
1194
+ }
1195
+ const result = await priceClient.listSymbols(category, {
1196
+ market,
1197
+ query,
1198
+ limit
1199
+ });
1200
+ return {
1201
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
1202
+ structuredContent: result
1203
+ };
1204
+ } catch (err) {
1205
+ const msg = err instanceof Error ? err.message : String(err);
1206
+ return {
1207
+ content: [{ type: "text", text: formatError(msg) }],
1208
+ isError: true
1209
+ };
1210
+ }
1211
+ }
1212
+ );
1213
+ }
1214
+
1215
+ // src/tools/twitter.ts
1216
+ import { z as z11 } from "zod";
1217
+ var ACTION2 = z11.enum([
1218
+ "user_lookup",
1219
+ "user_info",
1220
+ "followers",
1221
+ "followings",
1222
+ "verified_followers",
1223
+ "user_tweets",
1224
+ "user_mentions",
1225
+ "tweet_lookup",
1226
+ "tweet_replies",
1227
+ "tweet_thread",
1228
+ "search"
1229
+ ]);
1230
+ function registerTwitterTool(server) {
1231
+ server.registerTool(
1232
+ "blockrun_x",
1233
+ {
1234
+ description: `Structured X/Twitter data via AttentionVC partner API.
1235
+
1236
+ Actions:
1237
+ - user_lookup (usernames: string | string[])
1238
+ - user_info (username)
1239
+ - followers (username, cursor?)
1240
+ - followings (username, cursor?)
1241
+ - verified_followers (user_id, cursor?)
1242
+ - user_tweets (username, includeReplies?, cursor?)
1243
+ - user_mentions (username, sinceTime?, untilTime?, cursor?)
1244
+ - tweet_lookup (tweet_ids: string | string[])
1245
+ - tweet_replies (tweet_id, cursor?, queryType?)
1246
+ - tweet_thread (tweet_id, cursor?)
1247
+ - search (query, queryType?, cursor?)
1248
+
1249
+ Paid per request via x402; prices scale with the endpoint (e.g. user_lookup ~ $0.02, followers ~ $0.05/page).`,
1250
+ inputSchema: {
1251
+ action: ACTION2,
1252
+ usernames: z11.union([z11.string(), z11.array(z11.string())]).optional(),
1253
+ username: z11.string().optional(),
1254
+ user_id: z11.string().optional(),
1255
+ tweet_id: z11.string().optional(),
1256
+ tweet_ids: z11.union([z11.string(), z11.array(z11.string())]).optional(),
1257
+ query: z11.string().optional(),
1258
+ queryType: z11.enum(["Latest", "Top", "Default"]).optional(),
1259
+ cursor: z11.string().optional(),
1260
+ sinceTime: z11.string().optional(),
1261
+ untilTime: z11.string().optional(),
1262
+ includeReplies: z11.boolean().optional()
1263
+ }
1264
+ },
1265
+ async (args) => {
1266
+ try {
1267
+ const llm = getClient();
1268
+ const a = args.action;
1269
+ const require2 = (value, name) => {
1270
+ if (value === void 0 || value === null || value === "") {
1271
+ throw new Error(`${name} is required for action='${a}'`);
1272
+ }
1273
+ return value;
1274
+ };
1275
+ let result;
1276
+ switch (a) {
1277
+ case "user_lookup":
1278
+ result = await llm.xUserLookup(require2(args.usernames, "usernames"));
1279
+ break;
1280
+ case "user_info":
1281
+ result = await llm.xUserInfo(require2(args.username, "username"));
1282
+ break;
1283
+ case "followers":
1284
+ result = await llm.xFollowers(require2(args.username, "username"), args.cursor);
1285
+ break;
1286
+ case "followings":
1287
+ result = await llm.xFollowings(require2(args.username, "username"), args.cursor);
1288
+ break;
1289
+ case "verified_followers":
1290
+ result = await llm.xVerifiedFollowers(require2(args.user_id, "user_id"), args.cursor);
1291
+ break;
1292
+ case "user_tweets":
1293
+ result = await llm.xUserTweets(
1294
+ require2(args.username, "username"),
1295
+ args.includeReplies,
1296
+ args.cursor
1297
+ );
1298
+ break;
1299
+ case "user_mentions":
1300
+ result = await llm.xUserMentions(
1301
+ require2(args.username, "username"),
1302
+ args.sinceTime,
1303
+ args.untilTime,
1304
+ args.cursor
1305
+ );
1306
+ break;
1307
+ case "tweet_lookup":
1308
+ result = await llm.xTweetLookup(require2(args.tweet_ids, "tweet_ids"));
1309
+ break;
1310
+ case "tweet_replies":
1311
+ result = await llm.xTweetReplies(
1312
+ require2(args.tweet_id, "tweet_id"),
1313
+ args.queryType,
1314
+ args.cursor
1315
+ );
1316
+ break;
1317
+ case "tweet_thread":
1318
+ result = await llm.xTweetThread(require2(args.tweet_id, "tweet_id"), args.cursor);
1319
+ break;
1320
+ case "search":
1321
+ result = await llm.xSearch(require2(args.query, "query"), args.queryType, args.cursor);
1322
+ break;
1323
+ }
1324
+ return {
1325
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
1326
+ structuredContent: result
1327
+ };
1328
+ } catch (err) {
1329
+ const msg = err instanceof Error ? err.message : String(err);
1330
+ return {
1331
+ content: [{ type: "text", text: formatError(msg) }],
1332
+ isError: true
1333
+ };
1334
+ }
1335
+ }
1336
+ );
1337
+ }
1338
+
1339
+ // src/tools/dex.ts
1340
+ import { z as z12 } from "zod";
1104
1341
  function registerDexTool(server) {
1105
1342
  server.registerTool(
1106
1343
  "blockrun_dex",
@@ -1117,10 +1354,10 @@ Examples:
1117
1354
  blockrun_dex({ token: "So11...xxx" }) -> Get specific token data
1118
1355
  blockrun_dex({ symbol: "PEPE" }) -> Search by symbol`,
1119
1356
  inputSchema: {
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.)")
1357
+ query: z12.string().optional().describe("Search query (token name, symbol, or address)"),
1358
+ token: z12.string().optional().describe("Token address for direct lookup"),
1359
+ symbol: z12.string().optional().describe("Token symbol to search"),
1360
+ chain: z12.string().optional().describe("Filter by chain (ethereum, solana, base, etc.)")
1124
1361
  }
1125
1362
  },
1126
1363
  async ({ query, token, symbol, chain }) => {
@@ -1181,7 +1418,7 @@ ${lines.join("\n\n")}` }],
1181
1418
  }
1182
1419
 
1183
1420
  // src/tools/modal.ts
1184
- import { z as z11 } from "zod";
1421
+ import { z as z13 } from "zod";
1185
1422
  var MODAL_GPU_TYPES = ["T4", "L4", "A10G", "A100", "A100-80GB", "H100"];
1186
1423
  function registerModalTool(server) {
1187
1424
  server.registerTool(
@@ -1201,17 +1438,17 @@ Pricing:
1201
1438
  - create: $0.01
1202
1439
  - exec/status/terminate: $0.001 each`,
1203
1440
  inputSchema: {
1204
- action: z11.enum(["create", "exec", "status", "terminate"]).describe(
1441
+ action: z13.enum(["create", "exec", "status", "terminate"]).describe(
1205
1442
  "Sandbox action to perform"
1206
1443
  ),
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")
1444
+ sandbox_id: z13.string().optional().describe("Sandbox ID returned by a previous create"),
1445
+ command: z13.array(z13.string()).optional().describe('Command array for exec, for example ["python", "-c", "print(2+2)"]'),
1446
+ image: z13.string().optional().describe("Container image for create (default: python:3.11)"),
1447
+ timeout: z13.number().optional().describe("Timeout in seconds for create or exec"),
1448
+ cpu: z13.number().optional().describe("CPU cores for create"),
1449
+ memory: z13.number().optional().describe("Memory in MB for create"),
1450
+ gpu: z13.enum(MODAL_GPU_TYPES).optional().describe("Optional GPU type for create"),
1451
+ setup_commands: z13.array(z13.string()).optional().describe("Shell commands to run during sandbox setup")
1215
1452
  }
1216
1453
  },
1217
1454
  async ({ action, sandbox_id, command, image, timeout, cpu, memory, gpu, setup_commands }) => {
@@ -1280,6 +1517,8 @@ function initializeMcpServer(server) {
1280
1517
  registerSearchTool(server);
1281
1518
  registerExaTool(server);
1282
1519
  registerMarketsTool(server);
1520
+ registerPriceTool(server);
1521
+ registerTwitterTool(server);
1283
1522
  registerDexTool(server);
1284
1523
  registerModalTool(server);
1285
1524
  server.registerResource(
@@ -1392,7 +1631,7 @@ function warnOnLeakedKeys() {
1392
1631
  console.error(" 3. Reconnect using the local package (signs locally, key");
1393
1632
  console.error(" never leaves your machine):");
1394
1633
  console.error(" claude mcp remove blockrun");
1395
- console.error(" claude mcp add blockrun npx -y @blockrun/mcp@latest");
1634
+ console.error(" claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest");
1396
1635
  console.error("");
1397
1636
  console.error(" Details: https://github.com/BlockRunAI/blockrun-mcp-server/issues/1");
1398
1637
  console.error("");
@@ -1400,7 +1639,9 @@ function warnOnLeakedKeys() {
1400
1639
  }
1401
1640
 
1402
1641
  // src/index.ts
1403
- var VERSION = "0.7.2";
1642
+ var { version: VERSION } = JSON.parse(
1643
+ readFileSync(new URL("../package.json", import.meta.url), "utf-8")
1644
+ );
1404
1645
  async function checkForUpdate() {
1405
1646
  try {
1406
1647
  const resp = await fetch("https://registry.npmjs.org/@blockrun/mcp/latest", {
@@ -1409,7 +1650,7 @@ async function checkForUpdate() {
1409
1650
  const data = await resp.json();
1410
1651
  if (data.version && data.version !== VERSION) {
1411
1652
  console.error(`[BlockRun] Update available: v${VERSION} \u2192 v${data.version}`);
1412
- console.error(`[BlockRun] Run: claude mcp add blockrun npx -y @blockrun/mcp@latest`);
1653
+ console.error(`[BlockRun] Run: claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest`);
1413
1654
  }
1414
1655
  } catch {
1415
1656
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/mcp",
3
- "version": "0.8.0",
3
+ "version": "0.9.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",
@@ -44,7 +44,7 @@
44
44
  "url": "https://github.com/blockrunai/blockrun-mcp/issues"
45
45
  },
46
46
  "dependencies": {
47
- "@blockrun/llm": "^1.5.0",
47
+ "@blockrun/llm": "^1.8.0",
48
48
  "@modelcontextprotocol/sdk": "^1.0.0",
49
49
  "open": "^11.0.0",
50
50
  "qrcode": "^1.5.4",