Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest
|---|---|---|---|
| **Claude Code** | ✅ Verified · 2.1.251 · 2026-08-30 | ✅ | `claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest` |
| **Codex CLI** | ✅ Verified · 0.142.5 · 2026-08-30 | ❌ | `codex mcp add blockrun -- npx -y @blockrun/mcp@latest` |
| **OpenClaw** | 🟡 In use · 2026.5.2 (from a local build; the `npx` form below is not yet verified) | — not documented | `openclaw mcp set blockrun '{"command":"npx","args":["-y","@blockrun/mcp@latest"]}'` |
| **OpenClaw** | ✅ Verified · 2026.8.2 · 2026-09-02 | ⚠️ surface-dependent; see below | `openclaw mcp set blockrun '{"command":"npx","args":["-y","@blockrun/mcp@latest"]}'` |
| **Claude Desktop** | 📝 Documented | ⚠️ renders; OK reports *cancel* → proceeds | `claude_desktop_config.json` — JSON below |
| **Cursor** | 📝 Documented | ✅ | `~/.cursor/mcp.json` — JSON below |
| **VS Code (Copilot)** | 📝 Documented | ✅ | `code --add-mcp '{"name":"blockrun","command":"npx","args":["-y","@blockrun/mcp@latest"]}'` |
Expand All @@ -141,6 +141,15 @@ claude mcp add blockrun -s user -- npx -y @blockrun/mcp@latest

Any other MCP client that can spawn a stdio server works the same way: `command: npx`, `args: ["-y", "@blockrun/mcp@latest"]`. With nvm/Homebrew Node on a JSON-configured client, put the absolute path from `which npx` in `command`. Spend-dialog sources and what "proceeds without asking" means: [`docs/spend-confirmation.md`](docs/spend-confirmation.md).

**OpenClaw:** the published `npx` package was verified end-to-end on 2026.8.2: all 20 tools were projected, free calls worked, and paid x402 calls settled. Add a hard session cap while installing:

```bash
openclaw mcp set blockrun '{"command":"npx","args":["-y","@blockrun/mcp@latest"],"env":{"BLOCKRUN_BUDGET_LIMIT":"2"}}'
openclaw mcp doctor blockrun --probe
```

Spend confirmation depends on the OpenClaw runtime and chat surface. Its Codex harness supports MCP form elicitation, but an unmappable prompt is returned as an explicit decline; in the WebChat → Codex route tested here, `BLOCKRUN_CONFIRM_SPEND=on` declined paid calls without presenting an actionable dialog. Keep confirmation off on that route and rely on `BLOCKRUN_BUDGET_LIMIT` plus OpenClaw's own tool-approval mode.

<details>
<summary><strong>JSON for Claude Desktop, Cursor, Windsurf</strong></summary>

Expand Down
3 changes: 3 additions & 0 deletions docs/spend-confirmation.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ client. Verified against each client's own documentation on 2026-08-29:
| **Cursor** | ✅ Yes | Elicitation is listed as **Supported** in Cursor's MCP feature table. |
| **VS Code (GitHub Copilot)** | ✅ Yes | Elicitation support landed in VS Code 1.102; URL-mode elicitation in 1.107. |
| **Claude Desktop** | ⚠️ Partial | Observed while building this feature: a form dialog renders, but confirming it reports `cancel` rather than `accept`, so the call proceeds. Only an explicit **Decline** stops the charge. |
| **OpenClaw** | ⚠️ Surface-dependent | Codex harness form elicitation is supported, but unmappable prompts are explicitly declined. On OpenClaw 2026.8.2 WebChat → Codex, this prompt returned `decline` without an actionable dialog, so paid calls stopped. Use the hard budget and OpenClaw tool approvals on that route. |
| **Windsurf** | ❌ No | Windsurf documents support for tools, resources and prompts only. |
| **Codex CLI** | ❌ Not documented | OpenAI's MCP docs list tool calling and server instructions; elicitation is not mentioned. |
| **Gemini CLI** | ❌ Not documented | Tools, resources and prompts are documented; elicitation is not. |
Expand All @@ -123,6 +124,8 @@ Sources: [Claude Code MCP docs](https://code.claude.com/docs/en/mcp) ·
[Cursor MCP docs](https://cursor.com/docs/context/mcp) ·
[VS Code 1.102](https://code.visualstudio.com/updates/v1_102) /
[1.107 release notes](https://code.visualstudio.com/updates/v1_107) ·
[OpenClaw MCP docs](https://docs.openclaw.ai/cli/mcp) /
[Codex harness runtime](https://docs.openclaw.ai/plugins/codex-harness-runtime) ·
[Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp) ·
[Codex MCP docs](https://developers.openai.com/codex/mcp) ·
[Gemini CLI MCP docs](https://geminicli.com/docs/tools/mcp-server/).
Expand Down
6 changes: 3 additions & 3 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export const BASE_RPC_URLS = [
// gemini-3.5-flash-lite ($0.3/$2.5, live-probed 2026-08-12),
// gemini-3.1-flash-lite ($0.25/$1.5), gemini-2.5-pro, gemini-2.5-flash,
// gemini-2.5-flash-lite — all 1M context
// DeepSeek (3): deepseek-v4-pro ($0.435/$0.87, 1M, reasoning + coding),
// DeepSeek (3): deepseek-v4-pro ($1.32/$3.96, 1M, reasoning + coding;
// repriced by the gateway and re-probed 2026-09-02),
// deepseek-chat, deepseek-reasoner ($0.14/$0.28 on Base since DeepSeek's
// 2026-08-07 cut; sol still quotes $0.2/$0.4 — see the drift note above)
// Moonshot (1): kimi-k3 ($3/$15, 1M, vision + reasoning + coding)
Expand Down Expand Up @@ -213,7 +214,7 @@ export const CHAT_PRICE_PER_MTOKEN: Record<string, { input: number; output: numb
"zai/glm-5.1": { input: 1.4, output: 4.4 },
"zai/glm-5-turbo": { input: 1.2, output: 4 },
"zai/glm-5": { input: 1, output: 3.2 },
"deepseek/deepseek-v4-pro": { input: 0.435, output: 0.87 },
"deepseek/deepseek-v4-pro": { input: 1.32, output: 3.96 },
"deepseek/deepseek-chat": { input: 0.14, output: 0.28 },
"deepseek/deepseek-reasoner": { input: 0.14, output: 0.28 },
"minimax/minimax-m3": { input: 0.3, output: 1.2 },
Expand Down Expand Up @@ -381,4 +382,3 @@ export const BASE_TOKENS: Record<string, string> = {
DAI: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
cbETH: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22",
};

8 changes: 4 additions & 4 deletions test/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test("estimateChatCost keeps genuinely-free paths at $0", () => {
// loop can fall through to any of them — so coding ($5/$25) legitimately
// reserves less than balanced ($5/$30).
//
// Amounts below are live unpaid 402 quotes, 2026-08-13, 100k-char prompt,
// Amounts below are live unpaid 402 quotes, last refreshed 2026-09-02, 100k-char prompt,
// max_tokens 1024. Re-probe with `npm run verify:prices` (which now carries one
// row per tier) rather than adjusting them to match a failing build.
const LIVE_CHARGE_100K: Array<[string | undefined, string | undefined, number]> = [
Expand All @@ -53,7 +53,7 @@ const LIVE_CHARGE_100K: Array<[string | undefined, string | undefined, number]>
[undefined, "openai/gpt-5.6-terra", 0.098269],
[undefined, "google/gemini-3.5-flash", 0.073951],
[undefined, "zai/glm-5", 0.049346],
[undefined, "deepseek/deepseek-v4-pro", 0.021977],
[undefined, "deepseek/deepseek-v4-pro", 0.064790],
// Tier routing: the charge is that of the member the loop settles on, so each
// tier is pinned against its most expensive member's live quote.
["powerful", undefined, 1.460020], // gpt-5.4-pro
Expand All @@ -62,10 +62,10 @@ const LIVE_CHARGE_100K: Array<[string | undefined, string | undefined, number]>
["coding", undefined, 0.243655], // claude-opus-5
["fast", undefined, 0.073951], // gemini-3.5-flash
["glm", undefined, 0.049346], // glm-5.x
["cheap", undefined, 0.021977], // deepseek-v4-pro
["cheap", undefined, 0.064790], // deepseek-v4-pro
];

test("estimateChatCost never reserves less than the gateway charges (live 402, 2026-08-13)", () => {
test("estimateChatCost never reserves less than the gateway charges (live 402, refreshed 2026-09-02)", () => {
for (const [mode, model, charged] of LIVE_CHARGE_100K) {
const reserved = estimateChatCost(1024, mode, model, undefined, 100_000);
assert.ok(
Expand Down