kushbitx-mcp-agent
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@kushbitx-mcp-agentCheck the current Base token market data and see if my SpendGuard policy would approve this spend."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
kushbitx-mcp-agent
An AI-agent integration for @kushbitx/sdk, built for the
$50 USDC integration bounty in kushBitxHQ/kushbitx-sdk#1.
The model decides what to call. There is no fixed sequence: the agent loop appends the model's tool calls, executes them, feeds the results back, and repeats until the model stops asking for tools or a SpendGuard decision stops the run. The same three capabilities are also exposed as an MCP stdio server.
Nothing here can sign a payment or move funds. The paid path stops at reading an x402 challenge out
of a 402 response: no signature is created, no transaction is sent, and no private key is ever read.
What it demonstrates
Capability | Endpoint | Cost | Used for |
|
| free | Live Base token market data (no wallet) |
|
| free | Policy evaluation before money moves (advisory) |
|
| free to inspect | Reads the |
Related MCP server: Base Intel MCP
Quick start
Node.js 22 or later.
npm install
cp .env.example .env # then set your LLM key, or export DEEPSEEK_API_KEY
npm run start # run the agent end to end
npm test # offline suite (no network, no credentials)
npm run mcp # run the MCP stdio serverThe LLM is any OpenAI-compatible chat-completions endpoint with tool calling. The default is
deepseek-chat; set LLM_BASE_URL / LLM_MODEL to point elsewhere.
Environment
Variable | Required | Meaning |
| for | LLM key. Alternatively |
| no | Default |
| no | Default |
| no | Route SDK traffic through a proxy, e.g. |
| no |
|
| required by | The live suites dial |
MCP host configuration
{
"mcpServers": {
"kushbitx": { "command": "node", "args": ["mcp-server.mjs"] }
}
}Files
Path | Purpose |
| The tool-calling loop, the dispatch table and the chat-completions caller. |
| Tool schemas plus a thin mapping layer over the published SDK. |
| The same three capabilities over MCP stdio. |
| Proxy transports: |
| Resolves the LLM key from the environment or a credentials file; never logs it. |
| End-to-end run and CLI entry point; writes sanitized evidence. |
| Offline suite: the agent loop, the toolkit mapping, input shaping and the x402 decode. |
| The argv-leak regression: a stub child records its own argv and stdin. |
| The credentials parser: quoting, block boundaries, env precedence. |
| Live suite: drives the real MCP server over the official stdio transport. |
| Cross-platform launcher for the live suites ( |
| Adversarial review probe: injection, edge cases, contract drift. |
| Manual helper that prints what the child process actually saw. |
Test report
Offline suite — no network, no credentials, the SDK is driven through its fetchFn seam:
$ npm test
✔ toolkit maps a real SDK preview response into the reported shape
✔ toolkit rejects a malformed token address before any request
✔ toolkit reports the x402 challenge without signing or paying
✔ toolkit surfaces an unknown paid service as an error
✔ agent follows the model's tool order — forward
✔ agent follows the model's tool order — reversed, proving order is not hardcoded
✔ agent ends immediately when the model needs no tools
✔ a non-APPROVE spend decision stops the run without signing or paying
✔ a tool error is reported to the model, not thrown
✔ an unknown tool name is reported back to the model
✔ maxSteps bounds a model that never stops calling tools
✔ normalizeSpendInput applies policy defaults and keeps the caller allowlist
✔ buildPaidInput shapes per-service payloads
✔ every tool schema declares a name and an object schema
✔ the child process argv carries no secret (the leak this fixes)
✔ the stub proves the secret survived the round trip
✔ the transport source spawns a child but passes it no arguments carrying data
✔ every other transport in the repo avoids child processes entirely
✔ parseRawResponse keeps the last HTTP block and its headers
✔ transport selection: explicit modes win, auto is the fallback wrapper
✔ auto falls back to the native tunnel when curl is missing entirely
✔ auto falls back per-request when the curl exec fails without a response
✔ the native fallback tunnel works end to end (no setup needed without curl)
ℹ tests 36 ℹ pass 35 ℹ fail 0 ℹ skipped 1Live suite — the real MCP server against the hosted endpoints, through the proxy transport.
Requires KUSHBITX_PROXY (see the environment table): without it these checks get 403
from Cloudflare in this environment.
$ npm run test:live
ℹ tests 16 ℹ pass 16 ℹ fail 0Sanitized end-to-end run
npm start executed the live flow. The model chose the order itself, producing:
$ node main.mjs
stopped : model-finished
tools used : preview_token -> discover_payment_challenge -> evaluate_spend
steps : 3 | elapsed: 11693ms
0. preview_token token=USDC priceUsd=null (source.stale=true)
1. discover_payment_challenge x402 v2 exact eip155:8453 amount=250000 timeout=300s signed=false paid=false
2. evaluate_spend decision=APPROVE findings=0 executionAuthorized=falseFinal answer (abridged — this is verbatim from the run above; npm start reproduces it and writes the
full sanitized trajectory to evidence/agent-run.json, which is git-ignored like any run artifact):
**Token checked:** USDC on Base (0x8335…2913) — Aerodrome USDC/USDbC, price $1.000021,
liquidity $146,020.43; source DexScreener, flagged stale at 182s.
**Spend decision:** APPROVE (advisory only; executionAuthorized: false)
• 1.00 USDC, policy max/tx 5.00, daily 20.00, human approval above 2.00, unknown recipients blocked
• Findings: none.
**x402 terms (token-risk, /api/token-risk):** version 2, scheme exact, network eip155:8453 (Base),
amount 250000 base units = 0.25 USDC, timeout 300s, extra {name: "USD Coin", version: "2"}.
**Confirmation:** nothing was signed and nothing was paid (signed: false, paid: false).Security model
No private key is read, stored, or requested anywhere in this repository. There is no code path that signs a payment or sends a transaction.
The paid capability is limited to reading the
402challenge;signedandpaidare returned asfalseby construction and asserted in both suites.Addresses are redacted (
0x8335…2913) in the committed evidence; the full values are the public USDC-on-Base and x402 recipient constants already published in the SDK README andagent.mjs.The LLM key is read from the environment (or a credentials file) at runtime and is never logged.
Network note
On some networks the Cloudflare edge in front of kushbitx.com answers 403 to the machine's default
egress (cf-ray …-HKG in my case), and the hosted endpoints answer 403 to a request sent from Node's
own TLS stack through a proxy that curl succeeds with on the same host — the block page, not the API,
is what rejects it. So when a proxy is configured, requests are sent through curl -K -:
KUSHBITX_PROXY=http://127.0.0.1:7897 npm startThe whole configuration — including any Authorization header — is written to curl's stdin, never to
its argument list. An earlier revision passed the header as curl -H "authorization: …", which put
the model API key in the child's argv where /proc/<pid>/cmdline or ps can read it; that code is gone
from this repo. The property is now pinned by tests that run a stub child process and assert what it
actually saw:
child argv : ["-sS","-K","-"]
secret in argv : no
secret in stdin : yes (expected)
url in argv : no
proxy in argv : noReproduce with node test/fixtures/verify-argv-leak.mjs. With KUSHBITX_PROXY unset the code uses the
global fetch and spawns no child process at all, so a normal environment pays nothing for this.
License
Apache-2.0, matching the SDK.
Why auto prefers curl
The proxy transport is selectable:
KUSHBITX_TRANSPORT=auto (default) curl -K -, with a real fallback: the native
tunnel is used when the curl probe fails, and
per-request when a curl exec yields no response
KUSHBITX_TRANSPORT=curl the stdin-only curl transport, no fallback
KUSHBITX_TRANSPORT=native in-process CONNECT tunnel, no child process
KUSHBITX_TRANSPORT=auto-nocurl native, without probing for curlThree cases reach the fallback and are covered by tests: curl missing from PATH, a curl exec that fails without producing a response, and the forced modes above. Once a fallback has happened the transport stays on native, so a host without curl pays the failed exec at most once.
Measured on this host through the same proxy, same endpoint:
curl (OpenSSL) -> HTTP 200
node (native tunnel) -> HTTP 403 (Cloudflare block page)So the native tunnel is a portability fallback, not an equivalent transport: it is what
runs on a host without curl, and on a network where the origin accepts Node's TLS
fingerprint it behaves identically. KUSHBITX_TRANSPORT=native forces it for testing;
KUSHBITX_TRANSPORT=auto-nocurl selects it without probing for curl.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only on-chain intelligence for AI agents on Base: balances, tokens, gas, tx status.
Read-only on-chain intelligence for AI agents on Base: balances, tokens, gas, tx status.
Market data and web intelligence for AI agents, paid per call in USDC on Base via x402.
Pay-per-call Base and Polygon onchain data over x402 for AI agents.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to access crypto/web3 data across 5 chains with pay-per-call billing in USDC via x402, no API key required, and built-in spend caps.3642 npmMIT
- AlicenseNot gradedqualityBmaintenanceRead-only on-chain intelligence for AI agents on Base, providing tools to read balances, token metadata, gas, and transaction status live from chain without API keys.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to resolve tokens, get quotes, check for honeypots/rug pulls, build swaps, and retrieve receipts via x402 micropayments.1MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to inspect the public NFH protocol corpus, verify census status, and prepare bounded Ethereum wallet intents for claims and non-custodial market actions while never signing or submitting transactions.1-