Skip to main content
Glama
README.md
# kushbitx-mcp-agent

A **real agent-directed integration** for [`@kushbitx/sdk`](https://www.npmjs.com/package/@kushbitx/sdk) — built for the [KushBitx bounty issue #1](https://github.com/kushBitxHQ/kushbitx-sdk/issues/1).

The model decides which SDK tool to call and in what order. It is not a fixed-sequence demo script: the agent receives three tool schemas, emits `tool_calls`, reads the results, and chooses when to stop. The same three capabilities are also exposed as an MCP stdio server so any MCP host can drive them.

## What changed in this revision

This revision answers the three points in the maintainer's technical review:

| Review point | How it is addressed |
| --- | --- |
| "Use an actual AI agent runtime — the current `agent.mjs` is a deterministic MCP client that calls three tools in a fixed sequence." | `agent/agent.mjs` is now an [OI]-compatible **tool-calling agent loop**. The model receives the tool schemas and decides the calls. Evidence of a real model-directed run: [`evidence/agent-run.md`](evidence/agent-run.md) + [`evidence/agent-transcript.json`](evidence/agent-transcript.json) |
| "Add automated tests — `npm test` currently exits with 'No test specified.'" | `npm test` now runs **18 tests** (`node --test`), covering the tools, input validation, upstream 5xx failures, unexpected/missing HTTP 402 challenges, the retry boundary, and a guard asserting no signing or payment path is exposed |
| "Provide fresh verification evidence … reproducible from a clean clone." | README rewritten; `evidence/agent-run.md` regenerated from the post-change run; the reproduce commands below are the exact ones used |

## Security posture

| Guarantee | How it is enforced |
| --- | --- |
| No private key is ever requested, read, stored, or logged | No key argument exists in any tool schema; `viem`/signers are not dependencies. A test asserts no key material appears in the tool surface |
| No payment is ever signed or executed | The x402 tool stops at the HTTP 402 challenge and returns it verbatim |
| No signing, payment, recovery, or policy-mutation tool is exposed | Only three read-only tools are registered. **A test asserts the handlers never call `submitPaidCheck`, `restoreReport`, `prepareRecovery`, `createSpendPolicy`, `updateSpendPolicy`, `requestSpendDecision`, or `approveSpendDecision`** |
| SpendGuard is never claimed to enforce anything | Descriptions, the agent's system prompt, and the run summary all state the verdict is **advisory** and that enforcement belongs to the signing/execution layer |
| Unexpected responses surface as failures | A non-402 status, a missing challenge, or an unknown service throws; a test asserts each case |

## Layout

```
agent/
  tools.mjs          # three tool schemas + SDK-backed handlers (the single source of truth)
  agent.mjs          # [OI]-compatible tool-calling AGENT LOOP (the model chooses the calls)
src/
  server.mjs         # MCP stdio server exposing the same three tools
  retry.mjs          # bounded retry for transient upstream signals only
test/
  tools.test.mjs     # tool layer: happy paths, validation, failures, retry, no-signing guard
  server.test.mjs    # MCP adapter contract + error-result behaviour
evidence/
  agent-run.md       # sanitized transcript of a real agent-directed run
  agent-transcript.json
```

## Tools exposed

| Tool | Free? | Purpose |
| --- | --- | --- |
| `preview_token` | ✅ | Inspect basic Base token market data for an address |
| `evaluate_spend` | ✅ | Evaluate a proposed USDC spend against a policy **before** money moves (advisory) |
| `get_payment_challenge` | ✅ | Discover the x402 payment requirements for a paid service (stops at 402) |

## Requirements

- Node.js **22 or later** (tested on v22.23.1)
- No wallet, no funds, and no API key to KushBitx are required for the free path

## Setup

```bash
git clone https://github.com/krpx0341/kushbitx-mcp-agent
cd kushbitx-mcp-agent
npm install
```

## Run the tests

```bash
npm test
```

Expected: `# tests 18 / # pass 18 / # fail 0`. All tests are offline — the SDK's `fetchFn` injection seam is used, so no network or credentials are needed.

## Run the agent

The agent needs an [OI]-compatible chat-completions endpoint. Point it at any
provider that supports tool calling:

```bash
export OPENAI_BASE_URL="https://your-endpoint/v1"
export OPENAI_API_KEY="your-key"
export AGENT_MODEL="your-model"
npm run agent
```

To capture the full tool-call transcript:

```bash
export AGENT_TRANSCRIPT_OUT="./evidence/agent-transcript.json"
npm run agent
```

The agent prints every tool call with its arguments and result, then a summary.
It exits non-zero if the three-tool checklist was not completed, so CI can catch
a regression.

### Using the MCP server from another host

```jsonc
{
  "mcpServers": {
    "kushbitx": {
      "command": "node",
      "args": ["/absolute/path/to/kushbitx-mcp-agent/src/server.mjs"]
    }
  }
}
```

## Verified output

From the committed run — full detail in [`evidence/agent-run.md`](evidence/agent-run.md):

```
======================================================================
Summary
======================================================================
turns used        : 2
tool calls        : 3
distinct tools    : preview_token, evaluate_spend, get_payment_challenge
tool errors       : 0

No private key was requested, read, or stored. No payment was signed.
SpendGuard output is advisory; enforcement belongs to the signing layer.
```

SpendGuard returned `decision: HUMAN_APPROVAL` with `advisory: true` and
`executionAuthorized: false`. The x402 challenge decoded to
`x402Version: 2`, `scheme: exact`, `network: eip155:8453`,
`amount: "250000"` (0.25 USDC). Nothing was signed and nothing was paid.

## Notes and observations

- **Upstream flakiness on the free preview.** During testing on 2026-09-19 `POST /api/token-preview` returned HTTP `503` (`{"error":"Market data is temporarily unavailable..."}`) intermittently — roughly one call in three — while `/api/spendguard/evaluate` and `/api/token-risk` stayed healthy. `src/retry.mjs` retries only that transient signal, bounded; a genuine failure is still surfaced as an error. Flagging in case the market-data dependency needs a look.
- **`evaluateSpend` validates progressively**, revealing required fields one at a time. The accepted shape is `{ agentId, requestId, amount, chain: 'base', asset: 'USDC', recipient, service?, policy }`, where `policy` requires `maxPerTransaction`, `remainingDailyBudget`, `requireHumanAbove`, `maxRepeats`, `allowedRecipients`, and `blockUnknownRecipients`.
- **Reproducibility.** A clean clone plus `npm install` is enough: `npm test` proves the tool layer offline, `npm run agent` proves the model-directed path against a live endpoint.

## Sanitization

The repository contains only public data: the well-known USDC contract address on Base, the SDK's own published `payTo` address from the x402 challenge, and BaseScan-visible values. The API key for the model endpoint is supplied at runtime via `OPENAI_API_KEY` and is **not** committed, logged, or printed. No private key, seed phrase, personal wallet address, or personal data appears anywhere in this repository.

## License

Apache-2.0, matching the upstream SDK.