From f7d589ce21467023e9d3b8da0efa346583ba1d05 Mon Sep 17 00:00:00 2001 From: up2itnow0822 <220628848+up2itnow0822@users.noreply.github.com> Date: Tue, 24 Mar 2026 12:24:25 -0500 Subject: [PATCH 1/3] feat: add agent-payment-x402 skill for autonomous agent payments Adds a skill for x402 payment execution with MCP integration: - Per-task and per-session spending controls - Non-custodial wallet management (ERC-4337) - Pairs with mcp-server-patterns and cost-aware-llm-pipeline skills - Production reference: merged into NVIDIA NeMo Agent Toolkit (PR #17) - npm package: agentwallet-sdk --- skills/agent-payment-x402/SKILL.md | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 skills/agent-payment-x402/SKILL.md diff --git a/skills/agent-payment-x402/SKILL.md b/skills/agent-payment-x402/SKILL.md new file mode 100644 index 00000000..0dab98d0 --- /dev/null +++ b/skills/agent-payment-x402/SKILL.md @@ -0,0 +1,83 @@ +--- +name: agent-payment-x402 +description: Add x402 payment execution to AI agents — per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents need to pay for APIs, services, or other agents. +origin: community +--- + +# Agent Payment Execution (x402) + +Enable AI agents to make autonomous payments with built-in spending controls. Uses the x402 HTTP payment protocol and MCP tools so agents can pay for external services, APIs, or other agents without custodial risk. + +## When to Use + +Use when: your agent needs to pay for an API call, purchase a service, settle with another agent, enforce per-task spending limits, or manage a non-custodial wallet. Pairs naturally with cost-aware-llm-pipeline and mcp-server-patterns skills. + +## Core Concepts + +### x402 Protocol +x402 extends HTTP 402 (Payment Required) into a machine-negotiable flow. When a server returns `402`, the agent's payment tool automatically negotiates price, checks budget, signs a transaction, and retries — no human in the loop. + +### Spending Controls +Every payment tool call enforces a `SpendingPolicy`: +- **Per-task budget** — max spend for a single agent action +- **Per-session budget** — cumulative limit across an entire session +- **Allowlisted recipients** — restrict which addresses/services the agent can pay +- **Rate limits** — max transactions per minute/hour + +### Non-Custodial Wallets +Agents hold their own keys via ERC-4337 smart accounts. The orchestrator sets policy; the agent can only spend within bounds. No pooled funds, no custodial risk. + +## MCP Integration + +The payment layer exposes standard MCP tools that slot into any Claude Code or agent harness setup: + +```json +{ + "mcpServers": { + "agentpay": { + "command": "npx", + "args": ["-y", "agentwallet-sdk"] + } + } +} +``` + +### Available Tools + +| Tool | Purpose | +|------|---------| +| `get_balance` | Check agent wallet balance | +| `send_payment` | Send payment to address or ENS | +| `check_spending` | Query remaining budget | +| `set_policy` | Configure spending limits | +| `list_transactions` | Audit trail of all payments | + +## Example: Pay-Per-API-Call Agent + +```typescript +// In your CLAUDE.md or agent config: +// 1. Add agentpay MCP server (see above) +// 2. Set spending policy in your skill/hook: + +// Hook: pre-tool check +if (toolName === "web_search" && apiCost > 0) { + const budget = await mcp.call("agentpay", "check_spending"); + if (budget.remaining < apiCost) { + return { error: "Budget exceeded for this task" }; + } +} +``` + +## Best Practices + +- **Set budgets before delegation**: When spawning sub-agents, attach a SpendingPolicy. Never give an agent unlimited spend. +- **Audit trails**: Use `list_transactions` in post-task hooks to log what was spent and why. +- **Fail closed**: If the payment tool is unreachable, block the paid action — don't fall back to unmetered access. +- **Pair with security-review**: Payment tools are high-privilege. Apply the same scrutiny as shell access. +- **Test with testnets first**: Use Base Sepolia for development; switch to Base mainnet for production. + +## Production Reference + +- **npm**: [`agentwallet-sdk`](https://www.npmjs.com/package/agentwallet-sdk) +- **Merged into NVIDIA NeMo Agent Toolkit**: [PR #17](https://github.com/NVIDIA/NeMo-Agent-Toolkit-Examples/pull/17) — x402 payment tool for NVIDIA's agent examples +- **Protocol spec**: [x402.org](https://x402.org) From e57ad5c33d5203cddda975a08827ef4f9ad67d2c Mon Sep 17 00:00:00 2001 From: up2itnow0822 <220628848+up2itnow0822@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:25:14 -0500 Subject: [PATCH 2/3] fix: address all automated review feedback on code example Security model: - Remove set_policy from agent-callable tools table; document as orchestrator-only to prevent self-privilege escalation - Pin agentwallet-sdk@6.0.0 in MCP config with pre-install guidance (npx without -y hangs in non-interactive MCP startup) - Whitelist only required env vars (PATH, NODE_ENV, WALLET_PRIVATE_KEY) instead of forwarding entire process.env to subprocess Code example (complete rewrite): - Add StdioClientTransport import and client.connect() for runnable code - Wrap in async main() for CJS/ESM compatibility (top-level await) - Verify set_policy result via isError before delegating - Five distinct fail-closed error paths in preToolCheck: 1. Invalid apiCost input (NaN/Infinity bypass prevention) 2. Transport/connectivity failure 3. Tool-level error (isError: true, e.g., auth failure) 4. Unexpected response format (missing/non-finite remaining) 5. Budget exceeded (clear amounts in message) - Use Number.isFinite() for both apiCost and remaining validation Documentation: - Rename headings per CONTRIBUTING.md format - Replace broken mcp-server-patterns cross-ref with security-review - Add 'Pin your dependencies' to Best Practices - Add security note about supply-chain risk --- skills/agent-payment-x402/SKILL.md | 126 +++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 17 deletions(-) diff --git a/skills/agent-payment-x402/SKILL.md b/skills/agent-payment-x402/SKILL.md index 0dab98d0..c90d505d 100644 --- a/skills/agent-payment-x402/SKILL.md +++ b/skills/agent-payment-x402/SKILL.md @@ -10,9 +10,9 @@ Enable AI agents to make autonomous payments with built-in spending controls. Us ## When to Use -Use when: your agent needs to pay for an API call, purchase a service, settle with another agent, enforce per-task spending limits, or manage a non-custodial wallet. Pairs naturally with cost-aware-llm-pipeline and mcp-server-patterns skills. +Use when: your agent needs to pay for an API call, purchase a service, settle with another agent, enforce per-task spending limits, or manage a non-custodial wallet. Pairs naturally with cost-aware-llm-pipeline and security-review skills. -## Core Concepts +## How It Works ### x402 Protocol x402 extends HTTP 402 (Payment Required) into a machine-negotiable flow. When a server returns `402`, the agent's payment tool automatically negotiates price, checks budget, signs a transaction, and retries — no human in the loop. @@ -25,52 +25,144 @@ Every payment tool call enforces a `SpendingPolicy`: - **Rate limits** — max transactions per minute/hour ### Non-Custodial Wallets -Agents hold their own keys via ERC-4337 smart accounts. The orchestrator sets policy; the agent can only spend within bounds. No pooled funds, no custodial risk. +Agents hold their own keys via ERC-4337 smart accounts. The orchestrator sets policy before delegation; the agent can only spend within bounds. No pooled funds, no custodial risk. ## MCP Integration -The payment layer exposes standard MCP tools that slot into any Claude Code or agent harness setup: +The payment layer exposes standard MCP tools that slot into any Claude Code or agent harness setup. + +> **Security note**: Always pin the package version. This tool manages private keys — unpinned `npx` installs introduce supply-chain risk. ```json { "mcpServers": { "agentpay": { "command": "npx", - "args": ["-y", "agentwallet-sdk"] + "args": ["agentwallet-sdk@6.0.0"] } } } ``` -### Available Tools +### Available Tools (agent-callable) | Tool | Purpose | |------|---------| | `get_balance` | Check agent wallet balance | | `send_payment` | Send payment to address or ENS | | `check_spending` | Query remaining budget | -| `set_policy` | Configure spending limits | | `list_transactions` | Audit trail of all payments | -## Example: Pay-Per-API-Call Agent +> **Note**: Spending policy is set by the **orchestrator** before delegating to the agent — not by the agent itself. This prevents agents from escalating their own spending limits. Configure policy via `set_policy` in your orchestration layer or pre-task hook, never as an agent-callable tool. + +## Examples + +### Budget enforcement in an MCP client + +When building an orchestrator that calls the agentpay MCP server, enforce budgets before dispatching paid tool calls. + +> **Prerequisites**: Install the package before adding the MCP config — `npx` without `-y` will prompt for confirmation in non-interactive environments, causing the server to hang: `npm install -g agentwallet-sdk@6.0.0` ```typescript -// In your CLAUDE.md or agent config: -// 1. Add agentpay MCP server (see above) -// 2. Set spending policy in your skill/hook: +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; -// Hook: pre-tool check -if (toolName === "web_search" && apiCost > 0) { - const budget = await mcp.call("agentpay", "check_spending"); - if (budget.remaining < apiCost) { - return { error: "Budget exceeded for this task" }; +async function main() { + // 1. Validate credentials before constructing the transport. + // A missing key must fail immediately — never let the subprocess start without auth. + const walletKey = process.env.WALLET_PRIVATE_KEY; + if (!walletKey) { + throw new Error("WALLET_PRIVATE_KEY is not set — refusing to start payment server"); + } + + // Connect to the agentpay MCP server via stdio transport. + // Whitelist only the env vars the server needs — never forward all of process.env + // to a third-party subprocess that manages private keys. + const transport = new StdioClientTransport({ + command: "npx", + args: ["agentwallet-sdk@6.0.0"], + env: { + PATH: process.env.PATH ?? "", + NODE_ENV: process.env.NODE_ENV ?? "production", + WALLET_PRIVATE_KEY: walletKey, + }, + }); + const agentpay = new Client({ name: "orchestrator", version: "1.0.0" }); + await agentpay.connect(transport); + + // 2. Set spending policy before delegating to the agent. + // Always verify success — a silent failure means no controls are active. + const policyResult = await agentpay.callTool({ + name: "set_policy", + arguments: { + per_task_budget: 0.50, + per_session_budget: 5.00, + allowlisted_recipients: ["api.example.com"], + }, + }); + if (policyResult.isError) { + throw new Error( + `Failed to set spending policy — do not delegate: ${JSON.stringify(policyResult.content)}` + ); + } + + // 3. Use preToolCheck before any paid action + await preToolCheck(agentpay, 0.01); +} + +// Pre-tool hook: fail-closed budget enforcement with four distinct error paths. +async function preToolCheck(agentpay: Client, apiCost: number): Promise { + // Path 1: Reject invalid input (NaN/Infinity bypass the < comparison) + if (!Number.isFinite(apiCost) || apiCost < 0) { + throw new Error(`Invalid apiCost: ${apiCost} — action blocked`); + } + + // Path 2: Transport/connectivity failure + let result; + try { + result = await agentpay.callTool({ name: "check_spending" }); + } catch (err) { + throw new Error(`Payment service unreachable — action blocked: ${err}`); + } + + // Path 3: Tool returned an error (e.g., auth failure, wallet not initialised) + if (result.isError) { + throw new Error( + `check_spending failed — action blocked: ${JSON.stringify(result.content)}` + ); + } + + // Path 4: Parse and validate the response shape + let remaining: number; + try { + const parsed = JSON.parse( + (result.content as Array<{ text: string }>)[0].text + ); + if (!Number.isFinite(parsed?.remaining)) { + throw new TypeError("missing or non-finite 'remaining' field"); + } + remaining = parsed.remaining; + } catch (err) { + throw new Error( + `check_spending returned unexpected format — action blocked: ${err}` + ); + } + + // Path 5: Budget exceeded + if (remaining < apiCost) { + throw new Error( + `Budget exceeded: need $${apiCost} but only $${remaining} remaining` + ); } } + +main().catch(console.error); ``` ## Best Practices -- **Set budgets before delegation**: When spawning sub-agents, attach a SpendingPolicy. Never give an agent unlimited spend. +- **Set budgets before delegation**: When spawning sub-agents, attach a SpendingPolicy via your orchestration layer. Never give an agent unlimited spend. +- **Pin your dependencies**: Always specify an exact version in your MCP config (e.g., `agentwallet-sdk@6.0.0`). Verify package integrity before deploying to production. - **Audit trails**: Use `list_transactions` in post-task hooks to log what was spent and why. - **Fail closed**: If the payment tool is unreachable, block the paid action — don't fall back to unmetered access. - **Pair with security-review**: Payment tools are high-privilege. Apply the same scrutiny as shell access. From 95a1435f61407973059f504ba0436e036ae0b2ac Mon Sep 17 00:00:00 2001 From: AI Agent Economy <220628848+up2itnow0822@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:43:59 -0500 Subject: [PATCH 3/3] Update skills/agent-payment-x402/SKILL.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- skills/agent-payment-x402/SKILL.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/skills/agent-payment-x402/SKILL.md b/skills/agent-payment-x402/SKILL.md index c90d505d..08319c63 100644 --- a/skills/agent-payment-x402/SKILL.md +++ b/skills/agent-payment-x402/SKILL.md @@ -156,7 +156,10 @@ async function preToolCheck(agentpay: Client, apiCost: number): Promise { } } -main().catch(console.error); +main().catch((err) => { + console.error(err); + process.exitCode = 1; +}); ``` ## Best Practices