@blockrun/mcp 0.1.0 → 0.2.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 +72 -84
- package/dist/index.js +361 -283
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,81 +1,82 @@
|
|
|
1
1
|
# @blockrun/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## The Problem
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Want to use GPT-5, Gemini, or DeepSeek in Claude Code? Today you need to:
|
|
6
|
+
|
|
7
|
+
1. Create accounts with 5+ AI providers
|
|
8
|
+
2. Manage 5+ API keys and billing systems
|
|
9
|
+
3. Pay $20-100/month minimums per provider
|
|
10
|
+
4. Configure each provider separately
|
|
11
|
+
|
|
12
|
+
**That's too much friction.**
|
|
13
|
+
|
|
14
|
+
## The Solution
|
|
15
|
+
|
|
16
|
+
BlockRun MCP gives you access to 30+ AI models with:
|
|
17
|
+
|
|
18
|
+
- **Zero API keys** - No accounts needed with OpenAI, Google, etc.
|
|
19
|
+
- **One wallet** - Single USDC balance for all providers
|
|
20
|
+
- **Pay-per-use** - No minimums, $5 gets you started
|
|
21
|
+
- **One command** - Install and go
|
|
6
22
|
|
|
7
23
|
```bash
|
|
8
24
|
claude mcp add blockrun npx @blockrun/mcp
|
|
9
25
|
```
|
|
10
26
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
| Feature | Other Solutions | BlockRun MCP |
|
|
14
|
-
|---------|-----------------|--------------|
|
|
15
|
-
| **API Keys** | Need 5+ keys (OpenAI, Anthropic, Google...) | **None needed** |
|
|
16
|
-
| **Billing** | Manage 5+ subscriptions | **One wallet, unified balance** |
|
|
17
|
-
| **Setup** | Complex config per provider | **One command, auto-wallet** |
|
|
18
|
-
| **Models** | Usually 1 provider | **30+ models, 6 providers** |
|
|
19
|
-
| **Payment** | Monthly subscriptions | **Pay only what you use** |
|
|
20
|
-
| **Minimum** | $20-100/month per provider | **$0 minimum, start with $5** |
|
|
27
|
+
> **Alternative:** Prefer Python? Try the [BlockRun Skill](https://github.com/BlockRunAI/claude-code-blockrun-agent) (`pip install blockrun-llm`) - same features, different integration style.
|
|
21
28
|
|
|
22
29
|
## Quick Start
|
|
23
30
|
|
|
24
|
-
### 1. Install
|
|
31
|
+
### 1. Install
|
|
25
32
|
|
|
26
33
|
```bash
|
|
27
|
-
# Add to Claude Code
|
|
28
34
|
claude mcp add blockrun npx @blockrun/mcp
|
|
29
35
|
```
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
A wallet is automatically created for you.
|
|
32
38
|
|
|
33
39
|
### 2. Get Your Wallet Address
|
|
34
40
|
|
|
35
|
-
In Claude Code, run:
|
|
36
|
-
```
|
|
37
|
-
Use blockrun_setup to get my wallet address
|
|
38
41
|
```
|
|
42
|
+
You: blockrun setup
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Use blockrun_wallet to show my wallet info
|
|
44
|
+
Claude: Your wallet address is 0x...
|
|
45
|
+
Send USDC on Base network to fund it.
|
|
43
46
|
```
|
|
44
47
|
|
|
45
48
|
### 3. Fund Your Wallet
|
|
46
49
|
|
|
47
50
|
Send USDC to your wallet address on **Base** network. Even $5 gets you hundreds of requests.
|
|
48
51
|
|
|
49
|
-
**Funding Options:**
|
|
50
|
-
|
|
51
52
|
| Method | Steps |
|
|
52
53
|
|--------|-------|
|
|
53
54
|
| **From Coinbase** | Send → USDC → Select "Base" network → Paste your address |
|
|
54
|
-
| **Bridge** |
|
|
55
|
-
| **Buy Direct** |
|
|
55
|
+
| **Bridge** | [bridge.base.org](https://bridge.base.org) → Bridge USDC to Base |
|
|
56
|
+
| **Buy Direct** | [Coinbase Onramp](https://www.coinbase.com/onramp) → Buy USDC on Base |
|
|
56
57
|
|
|
57
58
|
### 4. Start Using
|
|
58
59
|
|
|
60
|
+
Just ask naturally:
|
|
61
|
+
|
|
59
62
|
```
|
|
60
|
-
You:
|
|
63
|
+
You: blockrun ask GPT-5 to explain quantum computing
|
|
64
|
+
|
|
65
|
+
You: blockrun chat with Claude Opus about this error
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
Quantum computing is a type of computation that harnesses...
|
|
67
|
+
You: blockrun generate an image of a mountain sunset
|
|
64
68
|
```
|
|
65
69
|
|
|
66
|
-
##
|
|
70
|
+
## Usage Examples
|
|
67
71
|
|
|
68
|
-
###
|
|
69
|
-
Chat with any AI model.
|
|
72
|
+
### Chat with Any Model
|
|
70
73
|
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
temperature: 0.7 // Optional (default: 1)
|
|
78
|
-
})
|
|
74
|
+
```
|
|
75
|
+
blockrun ask GPT-5 what causes aurora borealis
|
|
76
|
+
|
|
77
|
+
blockrun chat with Claude Opus about optimizing this algorithm
|
|
78
|
+
|
|
79
|
+
blockrun ask Gemini Pro to review this code for security issues
|
|
79
80
|
```
|
|
80
81
|
|
|
81
82
|
**Popular Models:**
|
|
@@ -85,60 +86,47 @@ blockrun_chat({
|
|
|
85
86
|
- `google/gemini-2.5-pro` - Great for long context (1M tokens)
|
|
86
87
|
- `deepseek/deepseek-chat` - Very affordable
|
|
87
88
|
|
|
88
|
-
###
|
|
89
|
-
|
|
89
|
+
### Smart Model Selection
|
|
90
|
+
|
|
91
|
+
Let BlockRun pick the best model for your needs:
|
|
90
92
|
|
|
91
|
-
```javascript
|
|
92
|
-
blockrun_smart({
|
|
93
|
-
mode: "balanced", // Required: fast | balanced | powerful | cheap | reasoning
|
|
94
|
-
message: "Hello!" // Required
|
|
95
|
-
})
|
|
96
93
|
```
|
|
94
|
+
blockrun smart fast: what's 2+2
|
|
95
|
+
|
|
96
|
+
blockrun smart powerful: analyze this complex codebase
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|------|-------------|----------|------|
|
|
100
|
-
| `fast` | Gemini Flash, GPT-4o-mini | Quick responses | $ |
|
|
101
|
-
| `balanced` | GPT-4o, Claude Sonnet | Daily tasks | $$ |
|
|
102
|
-
| `powerful` | GPT-5.2, Claude Opus, o3 | Complex work | $$$$ |
|
|
103
|
-
| `cheap` | Gemini Flash, DeepSeek | Budget-conscious | $ |
|
|
104
|
-
| `reasoning` | o3, o1, DeepSeek Reasoner | Logic & math | $$$ |
|
|
105
|
-
|
|
106
|
-
### `blockrun_models`
|
|
107
|
-
List all available models with pricing.
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
blockrun_models({
|
|
111
|
-
category: "chat", // Optional: all, chat, reasoning, image, embedding
|
|
112
|
-
provider: "openai" // Optional: filter by provider
|
|
113
|
-
})
|
|
98
|
+
blockrun smart cheap: summarize this text
|
|
114
99
|
```
|
|
115
100
|
|
|
116
|
-
|
|
117
|
-
|
|
101
|
+
| Mode | Models Used | Best For |
|
|
102
|
+
|------|-------------|----------|
|
|
103
|
+
| `fast` | Gemini Flash, GPT-4o-mini | Quick responses |
|
|
104
|
+
| `balanced` | GPT-4o, Claude Sonnet | Daily tasks |
|
|
105
|
+
| `powerful` | GPT-5.2, Claude Opus, o3 | Complex work |
|
|
106
|
+
| `cheap` | Gemini Flash, DeepSeek | Budget-conscious |
|
|
107
|
+
| `reasoning` | o3, o1, DeepSeek Reasoner | Logic & math |
|
|
108
|
+
|
|
109
|
+
### Generate Images
|
|
118
110
|
|
|
119
|
-
```javascript
|
|
120
|
-
blockrun_image({
|
|
121
|
-
prompt: "A sunset over mountains", // Required
|
|
122
|
-
model: "openai/dall-e-3", // Optional
|
|
123
|
-
size: "1024x1024", // Optional: 1024x1024, 1792x1024, 1024x1792
|
|
124
|
-
quality: "hd" // Optional: standard, hd
|
|
125
|
-
})
|
|
126
111
|
```
|
|
112
|
+
blockrun generate an image of a cyberpunk cityscape
|
|
127
113
|
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
blockrun create a watercolor painting of mountains
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### List Available Models
|
|
130
118
|
|
|
131
|
-
```javascript
|
|
132
|
-
blockrun_wallet({})
|
|
133
|
-
// Returns: address, network, balance link, funding options
|
|
134
119
|
```
|
|
120
|
+
blockrun list models
|
|
135
121
|
|
|
136
|
-
|
|
137
|
-
|
|
122
|
+
blockrun show OpenAI models with pricing
|
|
123
|
+
```
|
|
138
124
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
125
|
+
### Wallet Management
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
blockrun setup # First-time setup instructions
|
|
129
|
+
blockrun wallet # Check your wallet address
|
|
142
130
|
```
|
|
143
131
|
|
|
144
132
|
## Supported Models & Pricing
|
|
@@ -262,16 +250,16 @@ claude mcp add blockrun npx @blockrun/mcp --env BLOCKRUN_WALLET_KEY=0x...
|
|
|
262
250
|
## Troubleshooting
|
|
263
251
|
|
|
264
252
|
### "Payment was rejected"
|
|
265
|
-
Your wallet needs funding.
|
|
253
|
+
Your wallet needs funding. Say `blockrun setup` to get your address and funding instructions.
|
|
266
254
|
|
|
267
255
|
### "Wallet key required"
|
|
268
256
|
The MCP couldn't find or create a wallet. Check that `~/.blockrun/` directory is writable.
|
|
269
257
|
|
|
270
258
|
### Model not responding
|
|
271
|
-
Some models have rate limits. Try `
|
|
259
|
+
Some models have rate limits. Try `blockrun smart cheap` or `blockrun smart fast` to use alternative models.
|
|
272
260
|
|
|
273
261
|
### Check wallet balance
|
|
274
|
-
|
|
262
|
+
Say `blockrun wallet` or visit: `https://basescan.org/address/YOUR_ADDRESS`
|
|
275
263
|
|
|
276
264
|
## Configuration
|
|
277
265
|
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import {
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import {
|
|
7
|
-
CallToolRequestSchema,
|
|
8
|
-
ListToolsRequestSchema
|
|
9
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { z } from "zod";
|
|
10
7
|
import { LLMClient } from "@blockrun/llm";
|
|
11
8
|
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
12
9
|
import * as fs from "fs";
|
|
@@ -65,6 +62,23 @@ function getClient() {
|
|
|
65
62
|
}
|
|
66
63
|
return client;
|
|
67
64
|
}
|
|
65
|
+
function getWalletInfo() {
|
|
66
|
+
const llm = getClient();
|
|
67
|
+
const address = llm.getWalletAddress();
|
|
68
|
+
return {
|
|
69
|
+
address,
|
|
70
|
+
network: "Base",
|
|
71
|
+
chainId: 8453,
|
|
72
|
+
currency: "USDC",
|
|
73
|
+
isNew: walletWasCreated,
|
|
74
|
+
basescanUrl: `https://basescan.org/address/${address}`,
|
|
75
|
+
fundingOptions: {
|
|
76
|
+
coinbase: "Send USDC, select 'Base' network",
|
|
77
|
+
bridge: "https://bridge.base.org",
|
|
78
|
+
buy: "https://www.coinbase.com/onramp"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
68
82
|
function getWalletSetupInstructions() {
|
|
69
83
|
if (!walletAddress) {
|
|
70
84
|
getClient();
|
|
@@ -116,9 +130,13 @@ SECURITY NOTE:
|
|
|
116
130
|
================================================================================
|
|
117
131
|
`;
|
|
118
132
|
}
|
|
119
|
-
var
|
|
133
|
+
var server = new McpServer({
|
|
134
|
+
name: "blockrun-mcp",
|
|
135
|
+
version: "0.2.0"
|
|
136
|
+
});
|
|
137
|
+
server.registerTool(
|
|
138
|
+
"blockrun_chat",
|
|
120
139
|
{
|
|
121
|
-
name: "blockrun_chat",
|
|
122
140
|
description: `Chat with any AI model via BlockRun. Supports 30+ models including GPT-5, Claude Opus 4, Gemini 3, and more.
|
|
123
141
|
Pay-per-request with x402 micropayments - no API keys needed.
|
|
124
142
|
|
|
@@ -131,34 +149,34 @@ Popular models:
|
|
|
131
149
|
|
|
132
150
|
Use blockrun_models to see all available models with pricing.`,
|
|
133
151
|
inputSchema: {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
},
|
|
140
|
-
message: {
|
|
141
|
-
type: "string",
|
|
142
|
-
description: "Your message to the AI"
|
|
143
|
-
},
|
|
144
|
-
system: {
|
|
145
|
-
type: "string",
|
|
146
|
-
description: "Optional system prompt to set context/behavior"
|
|
147
|
-
},
|
|
148
|
-
max_tokens: {
|
|
149
|
-
type: "number",
|
|
150
|
-
description: "Maximum tokens in response (default: 1024)"
|
|
151
|
-
},
|
|
152
|
-
temperature: {
|
|
153
|
-
type: "number",
|
|
154
|
-
description: "Creativity level 0-2 (default: 1)"
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
required: ["model", "message"]
|
|
152
|
+
model: z.string().describe("Model ID (e.g., 'anthropic/claude-sonnet-4', 'openai/gpt-4o'). Use blockrun_models to list all."),
|
|
153
|
+
message: z.string().describe("Your message to the AI"),
|
|
154
|
+
system: z.string().optional().describe("Optional system prompt to set context/behavior"),
|
|
155
|
+
max_tokens: z.number().optional().default(1024).describe("Maximum tokens in response"),
|
|
156
|
+
temperature: z.number().optional().default(1).describe("Creativity level 0-2")
|
|
158
157
|
}
|
|
159
158
|
},
|
|
159
|
+
async ({ model, message, system, max_tokens, temperature }) => {
|
|
160
|
+
try {
|
|
161
|
+
const llm = getClient();
|
|
162
|
+
const response = await llm.chat(model, message, {
|
|
163
|
+
system,
|
|
164
|
+
maxTokens: max_tokens,
|
|
165
|
+
temperature
|
|
166
|
+
});
|
|
167
|
+
return { content: [{ type: "text", text: response }] };
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
170
|
+
return {
|
|
171
|
+
content: [{ type: "text", text: formatError(errorMessage) }],
|
|
172
|
+
isError: true
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
server.registerTool(
|
|
178
|
+
"blockrun_smart",
|
|
160
179
|
{
|
|
161
|
-
name: "blockrun_smart",
|
|
162
180
|
description: `Smart model routing - automatically picks the best model based on your needs.
|
|
163
181
|
|
|
164
182
|
Modes:
|
|
@@ -170,49 +188,112 @@ Modes:
|
|
|
170
188
|
|
|
171
189
|
Example: blockrun_smart({ mode: "fast", message: "Hello" })`,
|
|
172
190
|
inputSchema: {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
type: "string",
|
|
182
|
-
description: "Your message to the AI"
|
|
183
|
-
},
|
|
184
|
-
system: {
|
|
185
|
-
type: "string",
|
|
186
|
-
description: "Optional system prompt"
|
|
187
|
-
},
|
|
188
|
-
max_tokens: {
|
|
189
|
-
type: "number",
|
|
190
|
-
description: "Maximum tokens in response (default: 1024)"
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
required: ["mode", "message"]
|
|
191
|
+
mode: z.enum(["fast", "balanced", "powerful", "cheap", "reasoning"]).describe("Routing mode"),
|
|
192
|
+
message: z.string().describe("Your message to the AI"),
|
|
193
|
+
system: z.string().optional().describe("Optional system prompt"),
|
|
194
|
+
max_tokens: z.number().optional().default(1024).describe("Maximum tokens in response")
|
|
195
|
+
},
|
|
196
|
+
outputSchema: {
|
|
197
|
+
model_used: z.string().describe("The model that was used"),
|
|
198
|
+
response: z.string().describe("The AI response")
|
|
194
199
|
}
|
|
195
200
|
},
|
|
201
|
+
async ({ mode, message, system, max_tokens }) => {
|
|
202
|
+
const models = MODEL_TIERS[mode];
|
|
203
|
+
let lastError = null;
|
|
204
|
+
for (const model of models) {
|
|
205
|
+
try {
|
|
206
|
+
const llm = getClient();
|
|
207
|
+
const response = await llm.chat(model, message, {
|
|
208
|
+
system,
|
|
209
|
+
maxTokens: max_tokens
|
|
210
|
+
});
|
|
211
|
+
const result = { model_used: model, response };
|
|
212
|
+
return {
|
|
213
|
+
content: [{ type: "text", text: `[Used: ${model}]
|
|
214
|
+
|
|
215
|
+
${response}` }],
|
|
216
|
+
structuredContent: result
|
|
217
|
+
};
|
|
218
|
+
} catch (error) {
|
|
219
|
+
lastError = error;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const errorMessage = lastError?.message || "All models failed";
|
|
224
|
+
return {
|
|
225
|
+
content: [{ type: "text", text: formatError(errorMessage) }],
|
|
226
|
+
isError: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
server.registerTool(
|
|
231
|
+
"blockrun_models",
|
|
196
232
|
{
|
|
197
|
-
name: "blockrun_models",
|
|
198
233
|
description: "List all available AI models with pricing. Use this to discover models and compare costs.",
|
|
199
234
|
inputSchema: {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
235
|
+
category: z.enum(["all", "chat", "reasoning", "image", "embedding"]).optional().default("all").describe("Filter by category"),
|
|
236
|
+
provider: z.string().optional().describe("Filter by provider (e.g., 'openai', 'anthropic', 'google')")
|
|
237
|
+
},
|
|
238
|
+
outputSchema: {
|
|
239
|
+
count: z.number().describe("Number of models returned"),
|
|
240
|
+
models: z.array(z.object({
|
|
241
|
+
id: z.string(),
|
|
242
|
+
name: z.string().optional(),
|
|
243
|
+
inputPrice: z.number().optional(),
|
|
244
|
+
outputPrice: z.number().optional()
|
|
245
|
+
})).describe("List of available models")
|
|
212
246
|
}
|
|
213
247
|
},
|
|
248
|
+
async ({ category, provider }) => {
|
|
249
|
+
const llm = getClient();
|
|
250
|
+
if (!cachedModels) {
|
|
251
|
+
cachedModels = await llm.listModels();
|
|
252
|
+
setTimeout(() => {
|
|
253
|
+
cachedModels = null;
|
|
254
|
+
}, 5 * 60 * 1e3);
|
|
255
|
+
}
|
|
256
|
+
let models = cachedModels;
|
|
257
|
+
if (provider) {
|
|
258
|
+
const p = provider.toLowerCase();
|
|
259
|
+
models = models.filter((m) => m.id.toLowerCase().startsWith(p + "/"));
|
|
260
|
+
}
|
|
261
|
+
if (category && category !== "all") {
|
|
262
|
+
if (category === "image") {
|
|
263
|
+
models = models.filter(
|
|
264
|
+
(m) => m.id.includes("dall-e") || m.id.includes("flux") || m.id.includes("banana")
|
|
265
|
+
);
|
|
266
|
+
} else if (category === "reasoning") {
|
|
267
|
+
models = models.filter(
|
|
268
|
+
(m) => m.id.includes("/o1") || m.id.includes("/o3") || m.id.includes("reasoner")
|
|
269
|
+
);
|
|
270
|
+
} else if (category === "embedding") {
|
|
271
|
+
models = models.filter((m) => m.id.includes("embed"));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const lines = models.map((m) => {
|
|
275
|
+
const input = m.inputPrice ? `$${m.inputPrice}/M in` : "";
|
|
276
|
+
const output = m.outputPrice ? `$${m.outputPrice}/M out` : "";
|
|
277
|
+
const pricing = [input, output].filter(Boolean).join(", ");
|
|
278
|
+
return `- ${m.id}: ${m.name || ""} ${pricing ? `(${pricing})` : ""}`;
|
|
279
|
+
});
|
|
280
|
+
const structuredModels = models.map((m) => ({
|
|
281
|
+
id: m.id,
|
|
282
|
+
name: m.name,
|
|
283
|
+
inputPrice: m.inputPrice,
|
|
284
|
+
outputPrice: m.outputPrice
|
|
285
|
+
}));
|
|
286
|
+
return {
|
|
287
|
+
content: [{ type: "text", text: `Available models (${models.length}):
|
|
288
|
+
|
|
289
|
+
${lines.join("\n")}` }],
|
|
290
|
+
structuredContent: { count: models.length, models: structuredModels }
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
server.registerTool(
|
|
295
|
+
"blockrun_image",
|
|
214
296
|
{
|
|
215
|
-
name: "blockrun_image",
|
|
216
297
|
description: `Generate images using AI models. Supports DALL-E 3, Flux, and Nano Banana.
|
|
217
298
|
|
|
218
299
|
Models:
|
|
@@ -220,264 +301,261 @@ Models:
|
|
|
220
301
|
- together/flux-schnell: Fast generation ($0.02/image)
|
|
221
302
|
- google/nano-banana: Experimental Google model`,
|
|
222
303
|
inputSchema: {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
enum: ["openai/dall-e-3", "together/flux-schnell", "google/nano-banana"]
|
|
233
|
-
},
|
|
234
|
-
size: {
|
|
235
|
-
type: "string",
|
|
236
|
-
description: "Image size (default: 1024x1024)",
|
|
237
|
-
enum: ["1024x1024", "1792x1024", "1024x1792"]
|
|
238
|
-
},
|
|
239
|
-
quality: {
|
|
240
|
-
type: "string",
|
|
241
|
-
description: "Quality level for DALL-E 3 (default: standard)",
|
|
242
|
-
enum: ["standard", "hd"]
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
required: ["prompt"]
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
name: "blockrun_wallet",
|
|
250
|
-
description: "Get information about your BlockRun wallet address. Shows address, network, and quick funding options.",
|
|
251
|
-
inputSchema: {
|
|
252
|
-
type: "object",
|
|
253
|
-
properties: {}
|
|
304
|
+
prompt: z.string().describe("Description of the image to generate"),
|
|
305
|
+
model: z.enum(["openai/dall-e-3", "together/flux-schnell", "google/nano-banana"]).optional().default("openai/dall-e-3").describe("Image model"),
|
|
306
|
+
size: z.enum(["1024x1024", "1792x1024", "1024x1792"]).optional().default("1024x1024").describe("Image size"),
|
|
307
|
+
quality: z.enum(["standard", "hd"]).optional().default("standard").describe("Quality level for DALL-E 3")
|
|
308
|
+
},
|
|
309
|
+
outputSchema: {
|
|
310
|
+
url: z.string().describe("URL of the generated image"),
|
|
311
|
+
prompt: z.string().describe("The prompt used"),
|
|
312
|
+
model: z.string().describe("The model used")
|
|
254
313
|
}
|
|
255
314
|
},
|
|
256
|
-
{
|
|
257
|
-
|
|
258
|
-
|
|
315
|
+
async ({ prompt, model, size, quality }) => {
|
|
316
|
+
const apiUrl = "https://blockrun.ai/api/v1/images/generations";
|
|
317
|
+
const body = {
|
|
318
|
+
model,
|
|
319
|
+
prompt,
|
|
320
|
+
size,
|
|
321
|
+
quality,
|
|
322
|
+
n: 1
|
|
323
|
+
};
|
|
324
|
+
const response = await fetch(apiUrl, {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: { "Content-Type": "application/json" },
|
|
327
|
+
body: JSON.stringify(body)
|
|
328
|
+
});
|
|
329
|
+
if (response.status === 402) {
|
|
330
|
+
return {
|
|
331
|
+
content: [{ type: "text", text: `Image generation requires payment. Please ensure your wallet has USDC on Base.
|
|
259
332
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
- Pricing information
|
|
264
|
-
- Security details`,
|
|
265
|
-
inputSchema: {
|
|
266
|
-
type: "object",
|
|
267
|
-
properties: {}
|
|
333
|
+
To generate "${prompt}" with ${model}, the approximate cost is $0.04-0.08 per image.` }],
|
|
334
|
+
isError: true
|
|
335
|
+
};
|
|
268
336
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
system: args.system,
|
|
275
|
-
maxTokens: args.max_tokens,
|
|
276
|
-
temperature: args.temperature
|
|
277
|
-
});
|
|
278
|
-
return response;
|
|
279
|
-
}
|
|
280
|
-
async function handleSmartRoute(args) {
|
|
281
|
-
const models = MODEL_TIERS[args.mode];
|
|
282
|
-
if (!models) {
|
|
283
|
-
throw new Error(`Invalid mode: ${args.mode}. Use: fast, balanced, powerful, cheap, or reasoning`);
|
|
284
|
-
}
|
|
285
|
-
let lastError = null;
|
|
286
|
-
for (const model of models) {
|
|
287
|
-
try {
|
|
288
|
-
const response = await handleChat({
|
|
289
|
-
model,
|
|
290
|
-
message: args.message,
|
|
291
|
-
system: args.system,
|
|
292
|
-
max_tokens: args.max_tokens
|
|
293
|
-
});
|
|
294
|
-
return `[Used: ${model}]
|
|
295
|
-
|
|
296
|
-
${response}`;
|
|
297
|
-
} catch (error) {
|
|
298
|
-
lastError = error;
|
|
299
|
-
continue;
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: "text", text: formatError(`Image generation failed: ${response.status}`) }],
|
|
340
|
+
isError: true
|
|
341
|
+
};
|
|
300
342
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
setTimeout(() => {
|
|
309
|
-
cachedModels = null;
|
|
310
|
-
}, 5 * 60 * 1e3);
|
|
311
|
-
}
|
|
312
|
-
let models = cachedModels;
|
|
313
|
-
if (args.provider) {
|
|
314
|
-
const provider = args.provider.toLowerCase();
|
|
315
|
-
models = models.filter((m) => m.id.toLowerCase().startsWith(provider + "/"));
|
|
316
|
-
}
|
|
317
|
-
if (args.category && args.category !== "all") {
|
|
318
|
-
const category = args.category.toLowerCase();
|
|
319
|
-
if (category === "image") {
|
|
320
|
-
models = models.filter(
|
|
321
|
-
(m) => m.id.includes("dall-e") || m.id.includes("flux") || m.id.includes("banana")
|
|
322
|
-
);
|
|
323
|
-
} else if (category === "reasoning") {
|
|
324
|
-
models = models.filter(
|
|
325
|
-
(m) => m.id.includes("/o1") || m.id.includes("/o3") || m.id.includes("reasoner")
|
|
326
|
-
);
|
|
327
|
-
} else if (category === "embedding") {
|
|
328
|
-
models = models.filter((m) => m.id.includes("embed"));
|
|
343
|
+
const data = await response.json();
|
|
344
|
+
const imageUrl = data.data?.[0]?.url;
|
|
345
|
+
if (!imageUrl) {
|
|
346
|
+
return {
|
|
347
|
+
content: [{ type: "text", text: formatError("No image URL in response") }],
|
|
348
|
+
isError: true
|
|
349
|
+
};
|
|
329
350
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const input = m.inputPrice ? `$${m.inputPrice}/M in` : "";
|
|
333
|
-
const output = m.outputPrice ? `$${m.outputPrice}/M out` : "";
|
|
334
|
-
const pricing = [input, output].filter(Boolean).join(", ");
|
|
335
|
-
return `- ${m.id}: ${m.name || ""} ${pricing ? `(${pricing})` : ""}`;
|
|
336
|
-
});
|
|
337
|
-
return `Available models (${models.length}):
|
|
338
|
-
|
|
339
|
-
${lines.join("\n")}`;
|
|
340
|
-
}
|
|
341
|
-
async function handleImageGeneration(args) {
|
|
342
|
-
const model = args.model || "openai/dall-e-3";
|
|
343
|
-
const llm = getClient();
|
|
344
|
-
const apiUrl = "https://blockrun.ai/api/v1/images/generations";
|
|
345
|
-
const body = {
|
|
346
|
-
model,
|
|
347
|
-
prompt: args.prompt,
|
|
348
|
-
size: args.size || "1024x1024",
|
|
349
|
-
quality: args.quality || "standard",
|
|
350
|
-
n: 1
|
|
351
|
-
};
|
|
352
|
-
const response = await fetch(apiUrl, {
|
|
353
|
-
method: "POST",
|
|
354
|
-
headers: {
|
|
355
|
-
"Content-Type": "application/json"
|
|
356
|
-
},
|
|
357
|
-
body: JSON.stringify(body)
|
|
358
|
-
});
|
|
359
|
-
if (response.status === 402) {
|
|
360
|
-
return `Image generation requires payment. Please ensure your wallet has USDC on Base.
|
|
361
|
-
|
|
362
|
-
To generate "${args.prompt}" with ${model}, the approximate cost is $0.04-0.08 per image.`;
|
|
363
|
-
}
|
|
364
|
-
if (!response.ok) {
|
|
365
|
-
throw new Error(`Image generation failed: ${response.status}`);
|
|
366
|
-
}
|
|
367
|
-
const data = await response.json();
|
|
368
|
-
const imageUrl = data.data?.[0]?.url;
|
|
369
|
-
if (!imageUrl) {
|
|
370
|
-
throw new Error("No image URL in response");
|
|
371
|
-
}
|
|
372
|
-
return `Image generated successfully!
|
|
351
|
+
return {
|
|
352
|
+
content: [{ type: "text", text: `Image generated successfully!
|
|
373
353
|
|
|
374
354
|
URL: ${imageUrl}
|
|
375
355
|
|
|
376
|
-
Prompt: ${
|
|
377
|
-
Model: ${model}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
356
|
+
Prompt: ${prompt}
|
|
357
|
+
Model: ${model}` }],
|
|
358
|
+
structuredContent: { url: imageUrl, prompt, model }
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
server.registerTool(
|
|
363
|
+
"blockrun_wallet",
|
|
364
|
+
{
|
|
365
|
+
description: "Get information about your BlockRun wallet address. Shows address, network, and quick funding options.",
|
|
366
|
+
inputSchema: {},
|
|
367
|
+
outputSchema: {
|
|
368
|
+
address: z.string().describe("Wallet address"),
|
|
369
|
+
network: z.string().describe("Network name"),
|
|
370
|
+
chainId: z.number().describe("Chain ID"),
|
|
371
|
+
currency: z.string().describe("Currency"),
|
|
372
|
+
isNew: z.boolean().describe("Whether this is a newly created wallet"),
|
|
373
|
+
basescanUrl: z.string().describe("Link to view on Basescan")
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
async () => {
|
|
377
|
+
const info = getWalletInfo();
|
|
378
|
+
const isNewWallet = info.isNew;
|
|
379
|
+
let text = `BlockRun Wallet Information
|
|
384
380
|
============================
|
|
385
381
|
|
|
386
|
-
Address: ${address}
|
|
387
|
-
Network:
|
|
388
|
-
Currency:
|
|
382
|
+
Address: ${info.address}
|
|
383
|
+
Network: ${info.network} (Chain ID: ${info.chainId})
|
|
384
|
+
Currency: ${info.currency}
|
|
389
385
|
|
|
390
|
-
View on Basescan:
|
|
386
|
+
View on Basescan: ${info.basescanUrl}
|
|
391
387
|
`;
|
|
392
|
-
|
|
393
|
-
|
|
388
|
+
if (isNewWallet) {
|
|
389
|
+
text += `
|
|
394
390
|
STATUS: NEW WALLET - NEEDS FUNDING
|
|
395
391
|
${getWalletSetupInstructions()}`;
|
|
396
|
-
|
|
397
|
-
|
|
392
|
+
} else {
|
|
393
|
+
text += `
|
|
398
394
|
HOW TO ADD FUNDS:
|
|
399
395
|
-----------------
|
|
400
396
|
Send USDC to the address above on Base network.
|
|
401
397
|
|
|
402
398
|
Quick options:
|
|
403
|
-
1. From Coinbase:
|
|
404
|
-
2. Bridge:
|
|
405
|
-
3. Buy:
|
|
399
|
+
1. From Coinbase: ${info.fundingOptions.coinbase}
|
|
400
|
+
2. Bridge: ${info.fundingOptions.bridge}
|
|
401
|
+
3. Buy: ${info.fundingOptions.buy}
|
|
406
402
|
|
|
407
403
|
Full instructions: Run blockrun_setup tool
|
|
408
404
|
`;
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
content: [{ type: "text", text }],
|
|
408
|
+
structuredContent: {
|
|
409
|
+
address: info.address,
|
|
410
|
+
network: info.network,
|
|
411
|
+
chainId: info.chainId,
|
|
412
|
+
currency: info.currency,
|
|
413
|
+
isNew: info.isNew,
|
|
414
|
+
basescanUrl: info.basescanUrl
|
|
415
|
+
}
|
|
416
|
+
};
|
|
409
417
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
getClient();
|
|
414
|
-
return getWalletSetupInstructions();
|
|
415
|
-
}
|
|
416
|
-
var server = new Server(
|
|
418
|
+
);
|
|
419
|
+
server.registerTool(
|
|
420
|
+
"blockrun_setup",
|
|
417
421
|
{
|
|
418
|
-
|
|
419
|
-
|
|
422
|
+
description: `Get detailed wallet setup and funding instructions. Use this for first-time setup or if you need help adding funds to your wallet.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
- Your wallet address
|
|
426
|
+
- Step-by-step funding instructions (Coinbase, bridge, direct purchase)
|
|
427
|
+
- Pricing information
|
|
428
|
+
- Security details`,
|
|
429
|
+
inputSchema: {}
|
|
420
430
|
},
|
|
431
|
+
async () => {
|
|
432
|
+
getClient();
|
|
433
|
+
return { content: [{ type: "text", text: getWalletSetupInstructions() }] };
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
server.registerResource(
|
|
437
|
+
"wallet",
|
|
438
|
+
"blockrun://wallet",
|
|
421
439
|
{
|
|
422
|
-
|
|
423
|
-
|
|
440
|
+
description: "Your BlockRun wallet address and status",
|
|
441
|
+
mimeType: "application/json"
|
|
442
|
+
},
|
|
443
|
+
async () => {
|
|
444
|
+
const info = getWalletInfo();
|
|
445
|
+
return {
|
|
446
|
+
contents: [{
|
|
447
|
+
uri: "blockrun://wallet",
|
|
448
|
+
mimeType: "application/json",
|
|
449
|
+
text: JSON.stringify(info, null, 2)
|
|
450
|
+
}]
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
server.registerResource(
|
|
455
|
+
"models",
|
|
456
|
+
"blockrun://models",
|
|
457
|
+
{
|
|
458
|
+
description: "List of all available AI models with pricing",
|
|
459
|
+
mimeType: "application/json"
|
|
460
|
+
},
|
|
461
|
+
async () => {
|
|
462
|
+
const llm = getClient();
|
|
463
|
+
if (!cachedModels) {
|
|
464
|
+
cachedModels = await llm.listModels();
|
|
465
|
+
setTimeout(() => {
|
|
466
|
+
cachedModels = null;
|
|
467
|
+
}, 5 * 60 * 1e3);
|
|
424
468
|
}
|
|
469
|
+
return {
|
|
470
|
+
contents: [{
|
|
471
|
+
uri: "blockrun://models",
|
|
472
|
+
mimeType: "application/json",
|
|
473
|
+
text: JSON.stringify(cachedModels, null, 2)
|
|
474
|
+
}]
|
|
475
|
+
};
|
|
425
476
|
}
|
|
426
477
|
);
|
|
427
|
-
server.
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
switch (name) {
|
|
435
|
-
case "blockrun_chat":
|
|
436
|
-
result = await handleChat(args);
|
|
437
|
-
break;
|
|
438
|
-
case "blockrun_smart":
|
|
439
|
-
result = await handleSmartRoute(args);
|
|
440
|
-
break;
|
|
441
|
-
case "blockrun_models":
|
|
442
|
-
result = await handleListModels(args);
|
|
443
|
-
break;
|
|
444
|
-
case "blockrun_image":
|
|
445
|
-
result = await handleImageGeneration(args);
|
|
446
|
-
break;
|
|
447
|
-
case "blockrun_wallet":
|
|
448
|
-
result = handleWalletInfo();
|
|
449
|
-
break;
|
|
450
|
-
case "blockrun_setup":
|
|
451
|
-
result = handleSetup();
|
|
452
|
-
break;
|
|
453
|
-
default:
|
|
454
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
478
|
+
server.registerPrompt(
|
|
479
|
+
"quick_chat",
|
|
480
|
+
{
|
|
481
|
+
description: "Start a quick chat with a recommended model",
|
|
482
|
+
argsSchema: {
|
|
483
|
+
message: z.string().describe("Your message"),
|
|
484
|
+
style: z.enum(["concise", "detailed", "creative"]).optional().default("concise").describe("Response style")
|
|
455
485
|
}
|
|
486
|
+
},
|
|
487
|
+
async ({ message, style }) => {
|
|
488
|
+
const systemPrompts = {
|
|
489
|
+
concise: "Be concise and direct. Give short, focused answers.",
|
|
490
|
+
detailed: "Provide thorough, comprehensive answers with examples.",
|
|
491
|
+
creative: "Be creative and imaginative in your responses."
|
|
492
|
+
};
|
|
456
493
|
return {
|
|
457
|
-
|
|
494
|
+
messages: [
|
|
495
|
+
{
|
|
496
|
+
role: "user",
|
|
497
|
+
content: {
|
|
498
|
+
type: "text",
|
|
499
|
+
text: `[System: ${systemPrompts[style || "concise"]}]
|
|
500
|
+
|
|
501
|
+
${message}`
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
]
|
|
458
505
|
};
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
server.registerPrompt(
|
|
509
|
+
"code_review",
|
|
510
|
+
{
|
|
511
|
+
description: "Get a code review from a powerful model",
|
|
512
|
+
argsSchema: {
|
|
513
|
+
code: z.string().describe("The code to review"),
|
|
514
|
+
language: z.string().optional().describe("Programming language"),
|
|
515
|
+
focus: z.enum(["bugs", "performance", "style", "all"]).optional().default("all").describe("What to focus on")
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
async ({ code, language, focus }) => {
|
|
519
|
+
const focusInstructions = {
|
|
520
|
+
bugs: "Focus on potential bugs, errors, and edge cases.",
|
|
521
|
+
performance: "Focus on performance issues and optimization opportunities.",
|
|
522
|
+
style: "Focus on code style, readability, and best practices.",
|
|
523
|
+
all: "Review for bugs, performance, and style."
|
|
524
|
+
};
|
|
525
|
+
return {
|
|
526
|
+
messages: [
|
|
527
|
+
{
|
|
528
|
+
role: "user",
|
|
529
|
+
content: {
|
|
530
|
+
type: "text",
|
|
531
|
+
text: `Please review this ${language || ""} code. ${focusInstructions[focus || "all"]}
|
|
532
|
+
|
|
533
|
+
\`\`\`${language || ""}
|
|
534
|
+
${code}
|
|
535
|
+
\`\`\``
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
);
|
|
542
|
+
function formatError(message) {
|
|
543
|
+
const isPaymentError = message.toLowerCase().includes("payment") || message.toLowerCase().includes("402") || message.toLowerCase().includes("balance") || message.toLowerCase().includes("insufficient");
|
|
544
|
+
let errorText = `Error: ${message}`;
|
|
545
|
+
if (isPaymentError) {
|
|
546
|
+
errorText += `
|
|
465
547
|
|
|
466
548
|
This error usually means your wallet needs funding.
|
|
467
549
|
Run the blockrun_setup tool to get your wallet address and funding instructions.
|
|
468
550
|
|
|
469
551
|
Quick fix: Send USDC to your wallet on Base network.`;
|
|
470
|
-
}
|
|
471
|
-
return {
|
|
472
|
-
content: [{ type: "text", text: errorText }],
|
|
473
|
-
isError: true
|
|
474
|
-
};
|
|
475
552
|
}
|
|
476
|
-
|
|
553
|
+
return errorText;
|
|
554
|
+
}
|
|
477
555
|
async function main() {
|
|
478
556
|
const transport = new StdioServerTransport();
|
|
479
557
|
await server.connect(transport);
|
|
480
|
-
console.error("BlockRun MCP Server started");
|
|
558
|
+
console.error("BlockRun MCP Server started (v0.1.0)");
|
|
481
559
|
}
|
|
482
560
|
main().catch((error) => {
|
|
483
561
|
console.error("Fatal error:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "BlockRun MCP Server - Access 30+ AI models via x402 micropayments. No API keys needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -43,9 +43,10 @@
|
|
|
43
43
|
"url": "https://github.com/blockrunai/blockrun-mcp/issues"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
47
46
|
"@blockrun/llm": "^0.1.1",
|
|
48
|
-
"
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
48
|
+
"viem": "^2.21.0",
|
|
49
|
+
"zod": "^4.3.5"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@types/node": "^20.0.0",
|