Add hermes-finance-plugin MCP server with approval workflows. Changes: - mcp/servers.json: register hermes-finance-plugin MCP server - config.yaml: extend approvals with finance policy (threshold $10, daily cap $100) - docs/finance-integration.md: full integration guide - mcp/setup.sh: add Node.js + plugin installation - bin/test-finance-payment.py: dry-run demo and smoke test script Supported networks: Sepolia, Base Sepolia, Base, Ethereum. Approval: payments >$10 require second signature; $100 daily cap per agent. Security: private key via env, append-only audit logs, revocation path. Closes #965
7.6 KiB
USDC/x402 Payment Integration — Finance Plugin
Ticket: #965
Plugin: hermes-finance-plugin
Type: MCP Server (stdio transport)
Status: Integrated
Overview
The hermes-finance-plugin is an MCP server that exposes USDC/x402 payment tools to Timmy. It enables agents to:
- Send USDC on Ethereum L1 and L2s (Ethereum, Base, Base Sepolia, Sepolia)
- Enforce per-transaction and daily approval limits
- Log all payment attempts for audit
- Support multi-step approval workflows for high-value transfers
This integration configures the plugin as a sidecar MCP server in timmy-config, wires approval policies into config.yaml, and provides sandbox testing instructions.
Supported Networks & Wallet Requirements
Networks
| Network | Chain ID | x402 Enabled | Faucet |
|---|---|---|---|
| Sepolia (testnet) | 11155111 | ✅ | https://sepoliafaucet.com |
| Base Sepolia | 84532 | ✅ | https://faucet.base.org |
| Base Mainnet | 8453 | ✅ | N/A (real funds) |
| Ethereum Mainnet | 1 | ✅ | N/A (real funds) |
Wallet Requirements
- Private key stored in
FINANCE_PRIVATE_KEYenv var (no 0x prefix) - RPC endpoint in
FINANCE_RPC_URL(Infura, Alchemy, or public RPC) - USDC balance — ensure sufficient funds + gas on chosen network
- x402 marketplace support — recipient must support x402 payment requests
Approval Workflow Steps
1. Agent Requests Payment
Agent calls payment_send MCP tool with:
{
"to": "0x...",
"amount_usd": 25.50,
"network": "sepolia",
"reason": "API service fee"
}
2. Threshold Evaluation
Plugin compares amount_usd against FINANCE_APPROVAL_THRESHOLD_USD (default: $10):
- ≤ $10 → auto-approved, transaction proceeds
- > $10 → requires second signature (manual approval step)
3. Approval Routing
For amounts > $10, the plugin:
- Logs approval request to
~/.hermes/logs/finance_approvals.jsonl - Sends approval request via configured notifier (see
config.yaml→notifications) - Waits for explicit
payment_approveorpayment_rejectsignal - Proceeds only after approval or times out after 24h
4. Daily Cap Enforcement
The plugin maintains a rolling 24h spend ledger per agent in ~/.hermes/logs/finance_spend.jsonl. If an agent's total since yesterday exceeds FINANCE_DAILY_CAP_USD (default: $100), all payment requests are rejected until the window slides.
Rate Limiting & Daily Caps
Rate limiting: Built into the x402 protocol itself — each payment request is EIP-712 signed and non-replayable.
Daily caps: Per-agent accounting enforced client-side by the plugin. Ledger location:
~/.hermes/logs/finance_spend.jsonl
Sample ledger entry:
{
"timestamp": "2026-04-29T12:34:56Z",
"agent_id": "allegro",
"tx_hash": "0xabc123...",
"amount_usd": 25.00,
"network": "sepolia",
"to": "0xrecipient...",
"status": "completed"
}
Configuring Approval Policies
Add the following to config.yaml under approvals::
approvals:
mode: manual
finance:
threshold_usd: 10 # Payments > $10 require second signature
daily_cap_usd: 100 # Daily limit per agent
require_second_signature: true
enabled_networks:
- sepolia
- base-sepolia
- base
- ethereum
Configurable via environment variables (take precedence):
FINANCE_THRESHOLD_USDFINANCE_DAILY_CAP_USDFINANCE_REQUIRE_SECOND_SIGNATURE(true/false)
Setup & Installation
Prerequisites
- Node.js ≥ 18 (for npx)
- npm or yarn
- Access to a funded testnet wallet (Sepolia or Base Sepolia)
One-line Install
cd ~/.timmy/timmy-config/mcp
bash setup.sh
The setup.sh script:
- Verifies Node.js installation
- Installs
hermes-finance-pluginvia npm - Validates environment variables
- Runs a smoke test with
--dry-run
Environment Variables
Set these in ~/.zshrc or ~/.bashrc:
# Network selection (sepolia | base-sepolia | base | ethereum)
export FINANCE_NETWORK=sepolia
# Private key (no 0x prefix, keep secret!)
export FINANCE_PRIVATE_KEY=abc123...
# RPC endpoint (Infura/Alchemy/public)
export FINANCE_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
# Approval policy (optional — overrides config.yaml)
export FINANCE_DAILY_CAP_USD=100
export FINANCE_APPROVAL_THRESHOLD_USD=10
Never commit private keys. Use .env files or system keychain.
Testing the Plugin
Dry-Run (no funds)
~/.hermes/bin/test-finance-payment.py --dry-run --amount 25 --to 0xRecipient
Expected output:
[DRY-RUN] Would send $25.00 USDC on sepolia to 0xRecipient
[CHECK] Amount > $10 → requires manual approval
[APPROVAL] Request logged to ~/.hermes/logs/finance_approvals.jsonl
Live Test (Sepolia testnet)
# 1. Get Sepolia ETH & USDC from faucets
# - https://sepoliafaucet.com (ETH)
# - USDC: https://www.usdcfaucet.com (sepolia)
# 2. Run real transaction
~/.hermes/bin/test-finance-payment.py \
--amount 5.00 \
--to 0xYourTestAddress \
--network sepolia
Expected result:
- Transaction hash appears in output
- Transaction visible on sepolia.etherscan.io
- Approval log entry appears if amount > $10
Verification Deliverables
After sandbox testing, produce:
-
Testnet transaction hash
Example:0x4f3a...c2d1from Sepolia Etherscan -
Config snippet showing policy
Save output of:grep -A5 'approvals:' ~/.timmy/timmy-config/config.yaml -
Screenshot of approval log entry
tail -1 ~/.hermes/logs/finance_approvals.jsonl | jq . -
Risks and mitigations note (see below)
Security Considerations
Key Storage
- Risk: Private key compromise → total fund loss
- Mitigation:
- Store keys in macOS Keychain or
pass(Unix password manager) - Use dedicated burner wallet for each agent
- Never check keys into git; enforce via
pre-commithooks - Rotate keys monthly
- Store keys in macOS Keychain or
Revocation
- Risk: Compromised key cannot be revoked on-chain (EVM)
- Mitigation:
- Use smart-contract wallets (Safe, Argent) with owner rotation
- Emergency
finance_revokeMCP tool immediately disables plugin - Maintain hot/cold wallet split — daily cap limits exposure
Audit Trail
- Risk: Tampered logs hide malicious activity
- Mitigation:
- Append-only
finance_spend.jsonlandfinance_approvals.jsonlwith daily hash chaining - Ship logs to remote SIEM (Splunk/Graylog) via secure syslog
- Weekly attestation:
git commitlogs to immutable storage (S3 with WORM) - All approval decisions require cryptographic signature from approver
- Append-only
Additional Safeguards
- Enable
tirithsecurity guard inconfig.yaml - Enforce
security.redact_secrets: trueto avoid private-key logging - Run plugin in isolated network namespace (optional)
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
npx: command not found |
Node.js not installed | brew install node |
ENOENT: hermes-finance-plugin |
npm package not found | npm install -g hermes-finance-plugin |
PRIVATE_KEY not set |
Env var missing | export FINANCE_PRIVATE_KEY=... |
insufficient funds |
Testnet wallet empty | Visit faucets above |
approval timeout |
No manual approver | Set FINANCE_REQUIRE_SECOND_SIGNATURE=false for test |
References
- x402 spec: https://github.com/coinbase/x402
- USDC on Sepolia: https://docs.circle.com/usdc-misc/testnet
- EIP-712 signatures: https://eips.ethereum.org/EIPS/eip-712