Kura
A local, human-approved crypto wallet for AI agents on Base/Arc — it reads wallet state and pays x402 APIs, but every payment needs the user's password in the Kura app.
get_wallet_status — read-only: wallet state, active account address, and all accounts (no password).
get_balances — USDC and gas-token balances on the active network (
ethabsent on Arc, where gas is USDC).get_history — recent transaction attempts newest-first with statuses (sent, blocked, settled, reverted, expired, received, unknown), up to 200.
lookup_agent — read an ERC-8004 agent's on-chain record and compare its registered wallet/domain against a given
pay_to/resource.request_payment — ask the user to approve a USDC/ETH transfer via a password popup (5-min timeout); limits, autopay rules, and emergency lock enforced.
x402_fetch — call a paid x402 URL (GET/POST/etc. with headers/JSON body); on 402, get approval and retry the identical request, returning text/JSON or saving binary files.
x402_resubmit — re-send the on-chain proof of a self-broadcast payment to retrieve content without paying again.
Kura (蔵 — a storehouse that guards your treasures)
A local EVM wallet for AI agents. On a Mac, when an AI like Claude makes an internet payment (x402), this is the wallet where a human approves it with a password.
Not a human wallet (like MetaMask) — it's for AI agents
Not a cloud SaaS — it runs locally only. Keys never leave this computer.
AI requests a payment → a human approves with a password → it executes
The chain is Base (Ethereum L2, near-zero fees). Default is the testnet (Base Sepolia)
At a glance
[ AI 앱 (Claude Code / 데스크톱) ]
│ MCP로 "결제해줘" 요청
▼
[ Kura 데스크톱 앱 ] ← 승인 팝업 → 사람이 비밀번호 입력
│ 서명 (키는 이 앱 안에서만)
▼
[ Base 체인 / x402 페이실리테이터 ] ← 실제 결제The password is only ever entered in the Kura app's input field. It never goes into chat windows, MCP, or config files.
Related MCP server: cardzero-mcp
Installation
Apple Silicon Mac (macOS 11 or later)
(A) Homebrew
brew install --cask dinggi5/tap/kura(B) Download the DMG directly
Download Kura_<version>_aarch64.dmg from Releases, open it, and drag Kura into the Applications folder.
Since this is an app you're entrusting with your keys, I've written down the exact commands for verifying that the app you received is really the one I built in SECURITY.md.
(C) Build from source
Prerequisites: Rust, Node.js (20.19+ or 22.12+ — required by Vite 7), macOS.
git clone https://github.com/dinggi5/kura.git
cd kura
git checkout v0.1.1 # 배포본과 같은 소스. 빼면 개발 중인 최신 코드가 받아져요
npm ci # package-lock.json 그대로 설치 (install 은 버전이 올라갈 수 있어요)
# 개발 모드로 바로 실행
npm run tauri dev
# 앱으로 빌드해 /Applications에 설치
npm run tauri build -- --bundles app --no-sign
ditto src-tauri/target/release/bundle/macos/Kura.app /Applications/Kura.app
open /Applications/Kura.appUpdates
The app updates itself.
Go to Settings → About to check the version and changelog, then click Install now and restart.
Only the check is automatic — installation always requires you to click it.
Downloaded files are installed only after their signature is verified (signature verification cannot be disabled). Details are in the "Updates" section of SECURITY.md.
If you don't want the automatic update-check traffic, turn off Settings → About → Check on startup.
Uninstalling
⚠️ Uninstalling the app does not delete your wallet. Keys, settings, and transaction history live in ~/.jigap outside the app, so removing just the app leaves them intact — I did this on purpose so you don't accidentally lose your assets (even brew uninstall --zap won't remove them).
# 앱만 제거 (지갑은 남음 — 나중에 다시 설치하면 그대로 이어서 써요)
brew uninstall --cask dinggi5/tap/kura # 또는 /Applications/Kura.app 을 휴지통으로To completely erase the wallet too on this Mac, follow this order:
First make sure you have the 12-word recovery phrase in hand. You can view it again via the key button in the app's header.
If there's a balance left, move it to another wallet.
Quit Kura completely (right-click the menu bar icon → Quit). If it's running, it writes a state file to
~/.jigapevery few seconds, so a deleted folder will reappear right away.Also quit any AI tools (like Claude Code) that have the Kura MCP attached.
If you had auto-start enabled, turn it off or run
rm ~/Library/LaunchAgents/Kura.plist(this file remains if you delete the app via Trash. If you uninstall withbrew uninstall --cask, it goes away with it).Then run
rm -rf ~/.jigap
Running that final rm -rf ~/.jigap without the 12 words means no one can ever recover that wallet's assets.
First run
Kura lives in the menu bar. When you launch it, a storehouse icon (◻︎) appears in the menu bar at the top of your screen, and the window only drops down when you click that icon. Clicking elsewhere closes it, and the app stays in the background waiting for AI payment requests. To quit completely, right-click the icon → Quit. (On first launch when no wallet exists yet, the window opens by itself.)
Create a wallet — set a password (8+ characters) that you'll enter for every transfer. Your key is encrypted and stored with this password (
~/.jigap/wallet.enc).Back up the seed — 12 words are shown. This is the real proof of ownership of your assets, so write them down on paper or in a password manager. Even if you forget your password, the 12 words alone can recover it: quit the app, first make sure you have the 12 words in hand, then delete
~/.jigap/wallet.encand relaunch the app — you can restore it via Import on the first screen (you can also put them into any other standard BIP-39 wallet). However, deleting this file without the 12 words means losing your assets forever.Welcome tour — walks you through funding, AI connection, and safety features. You can revisit it anytime from the ⓘ Help in the header.
Funding (USDC)
To make payments, your wallet needs USDC (digital dollars).
Tap Receive in the app to see your address and QR code.
When sending from an exchange or another wallet, be sure to select the Base network. Sending on another network will lose your funds.
On the testnet (default), it's not real money. Use the Faucet button on the receive screen to get free test coins and practice.
ETH is optional — for x402 payments, the facilitator pays the fee, so you can have 0 ETH. You only need a little ETH for gas when sending directly via the app's Send (Base fees are around a cent). Funding with USDC alone is enough.
Connecting AI (Claude)
Register the Kura server in your AI app's MCP settings to connect. Once connected, a "Claude connected" badge appears on the main screen. Since 0.1.2, the MCP server is built into the app, so you can connect without cloning the source or installing Rust.
The easiest way — the "AI Connect" screen in the app
Click the "AI not connected" badge at the top of the main screen to open the connection screen.
Claude Desktop — click the "Connect" button and an extension install window appears in Claude. Just click 'Install' and you're done.
Claude Code — registered with one click (the app runs
claude mcp addfor you). From the nextclaudelaunch, it's connected from any folder.
Below is how to do the same thing by hand.
Claude Desktop — one extension file is all you need
Download kura-<version>.mcpb from the releases page and double-click it — Claude Desktop will ask to install it. (Or go to Claude Settings → Extensions → Choose file.)
The extension contains no executable — it only has a launcher that verifies the signature of the signed and notarized MCP server inside the installed Kura.app and then runs it. So you need to install the Kura app first.
Claude Code · other MCP apps
Register the in-app binary with its absolute path:
claude mcp add --scope user kura -- /Applications/Kura.app/Contents/MacOS/kura-mcp(--scope user is the option that makes it available everywhere, not just "this folder". If you only want it in one project, you can omit it.)
For other MCP apps, write it in the settings like this:
{
"mcpServers": {
"kura": {
"command": "/Applications/Kura.app/Contents/MacOS/kura-mcp"
}
}
}If you're developing from source
The repo root already has .mcp.json. Running claude in this folder picks it up automatically (the first time it asks whether to use the server — approve it). This path is for development, rebuilding with cargo run every time — if you're using an installed build, registering the app path above is the right approach.
Tools the AI can use: get_wallet_status · get_balances · get_history (read-only) · request_payment (payment request → approval popup in the app) · x402_fetch (calls a URL that requires 402 payment).
If you change the MCP tools, restart the AI app for it to take effect (the server is loaded once at session start).
How a payment flows
The AI requests a payment.
The Kura window appears showing how much, to where (it pops up automatically even if the window was hidden).
Enter the password and approve.
The payment executes and the result goes back to the AI. If you don't approve within 5 minutes, it's automatically rejected.
Security model
Password approval — by default, every payment requires password approval (if autonomous payments are enabled, exceptions apply only under the conditions below). Keys are stored encrypted (Argon2id + AES-256-GCM) and are only decrypted at payment time, then wiped immediately (if an autonomous payment session is enabled, they're kept in memory only while unlocked).
Limits — set how much can be sent per transaction / per day in settings (default: 5 USDC single, 20 USDC daily). Anything over is blocked.
Emergency lock — turning on the shield button in the header immediately blocks all transfers.
Trusted addresses · autonomous payments — for automatic approval without a password, session unlock + small limits + trusted address must all be satisfied. Otherwise, a password is always required.
Transaction history — records all outgoing transfers, blocked attempts, and signatures.
Local-first — keys (
~/.jigap/) live outside the repo and never get committed to git.No analytics, no font CDN — the app connects to the internet on its own for only three things: ①the RPC server used for balance lookups and transfers ②x402 addresses requested by the AI ③update checks (GitHub). Usage data is never sent anywhere, and fonts are bundled in the app, so the UI renders fine offline too.
Update checks can be disabled — on launch it asks GitHub whether a new version exists (your IP and current version are logged there). Turning off Settings → About → Check on startup removes even this traffic. Whether the check is on or off, installation only proceeds when you click it — nothing ever changes silently.
For developers
You can also drive the same wallet from the CLI kura (it shares the MCP server and core logic). It's already inside the installed app, so one line on your PATH and you're set:
sudo mkdir -p /usr/local/bin
sudo ln -sf /Applications/Kura.app/Contents/MacOS/kura-cli /usr/local/bin/kura
kura statusTo run from source:
cargo run --manifest-path ./kura-mcp/Cargo.toml --bin kura -- status
cargo run --manifest-path ./kura-mcp/Cargo.toml --bin kura -- balance
cargo run --manifest-path ./kura-mcp/Cargo.toml --bin kura -- history --limit 10
cargo run --manifest-path ./kura-mcp/Cargo.toml --bin kura -- pay <주소> <금액> --token usdc
cargo run --manifest-path ./kura-mcp/Cargo.toml --bin kura -- fetch <URL>pay/fetch never take a password via the CLI — the Kura app must be running, and a human enters the password in the approval popup.
Tests:
(cd src-tauri && cargo test) # 백엔드(지갑·암호화·한도·송금)
(cd kura-mcp && cargo test) # MCP/CLI 어댑터
npx tsc --noEmit && npx vite build # 프론트The procedure for producing a release build (signed, notarized DMG) is in docs/RELEASE.md. It needs an Apple Developer account and a one-time setup, and after that it's one line:
./scripts/release.shTech stack
Desktop | Tauri (Rust + web frontend) |
Frontend | React + Tailwind CSS, Framer Motion, Lucide, Pretendard |
Chain | Base / alloy-rs |
Payments | x402 (EIP-3009 off-chain signatures) |
AI connect | MCP server (rmcp) |
Structure: [Rust core (src-tauri)] ← MCP / CLI adapters (kura-mcp). Only the GUI process has key access (signing) — that's the last line of defense.
License · status
MIT license — since this is code that handles keys and money, I believe it should be something you can read, verify, and modify yourself.
If you find a vulnerability, please report it through the private channel in SECURITY.md before filing an issue. The same document also lists what Kura cannot protect against.
The bundled Pretendard font is under the SIL Open Font License 1.1 (full text).
The number one user is myself — a wallet for Korean developers and creators on Apple Silicon Macs who pay with local LLMs/Claude. It's still an early 0.1.x version, so I recommend learning on the default testnet first and only putting what you can afford to lose on mainnet.
Available Tools
7 toolsget_balancesBalancesARead-only
Reads the active account's USDC (for payments) and gas-token balances on the active network (Base mainnet, Arc mainnet, Base Sepolia, or Arc testnet, per the user's setting). The eth field is the gas balance and is ABSENT on chains where gas is paid in USDC itself (Arc) — there the USDC balance already covers gas, so never add the two together. Errors if there is no wallet.
Inputs: no named parameters.
get_historyHistoryARead-only
Returns the active account's recent transaction attempts, newest first. status is one of sent, blocked, failed, signed (x402 signed, awaiting settlement), settled (x402 settled, settle_tx is the settlement tx), settle_failed, unknown (a signed transaction was submitted but the wallet couldn't confirm the chain received it — detail is its tx hash; it may have gone through, so never resend on the strength of this entry alone; the wallet app later rechecks it on-chain and turns it into sent or reverted), reverted (mined but reverted on-chain — no money moved, only gas), expired (an x402 signature that was never used before it expired — no money moved), or received (money that came in — to is the sender, detail the tx hash; both are empty for ETH a contract sent; found on-chain by the wallet app while it runs, back to 90 days). Use limit to cap how many come back (default 20).
Inputs: limit.
get_wallet_statusWallet statusARead-only
Returns the wallet's state and address. state is encrypted (normal), legacy, or none. address is the ACTIVE account's address; accounts lists every account in the wallet (index, address, label) and account is the active index. Balances, history, and payment requests all use the active account, and only the user can switch accounts, in the wallet app. No password needed — read only.
Inputs: no named parameters.
lookup_agentLook up an agent (ERC-8004)ARead-only
Reads an agent's ERC-8004 record from the registry on the active network (read-only, on-chain only — the wallet never fetches the agent's website). Give it agent_id, the agent's number in the Identity Registry. Returns: registered, owner, wallet (the registered agentWallet), token_uri and the uri_domain read from it, declared_name (what the record calls itself), and feedback_clients (how many addresses left feedback). Pass pay_to and/or resource to also get a comparison: whether the address equals the registered wallet and whether the resource's domain equals the domain listed on-chain. IMPORTANT: registration is permissionless — anyone can register any name, domain, or wallet, and anyone can leave feedback. Being registered is NOT proof of safety. Only a mismatch is a strong signal, and only when the agent number came from a source you trust (the service's own docs), not from the payment response itself.
Inputs: agent_id (required), pay_to, resource.
request_paymentRequest a paymentADestructive
Asks the user to make a payment. The wallet app opens an approval window, and the payment is only sent once the user approves it with their password (it waits up to 5 minutes). The one exception is autopay, which the user turns on themselves — only then can a payment be approved automatically, and only within an unlocked session, a small limit, and a trusted address. Arguments: to (recipient address), amount (decimal string), token (USDC by default, or ETH), memo (what the payment is for — the user reads it to decide, so always fill it in), and optionally agent_id (the recipient's ERC-8004 number, if a service told you one — the wallet then shows the user whether the address matches that agent's registered wallet). Per-payment and daily limits and the emergency lock are enforced by the app. Never send a password as an argument — the user types it in the app. Returns: status, tx_hash, detail, and an explorer link. status is approved (the chain accepted the transfer), rejected or failed (nothing was sent — safe to ask again), or unknown: the user approved but the wallet couldn't confirm whether the transfer reached the chain (tx_hash is set when known). unknown means it MAY have been sent — never ask again on your own; tell the user and have them check the history or the tx.
Inputs: to (required), amount (required), memo, token, +1 more.
x402_fetchFetch a paid URL (x402)ADestructive
Calls an x402 paid API or URL. It sends the request first — GET by default, or the given method (POST, PUT, PATCH, DELETE) with optional headers and a JSON object body; if the server answers 402 Payment Required, it asks the user to approve the required payment (exact scheme, the active network, that chain's USDC) in the wallet app, then sends the SAME request (same method, headers and body) again with the payment header and returns the content. If no payment is required (no 402), it just returns the response. Redirects are not followed once a payment header is attached (nor at all when method, headers or body are given) — a redirect comes back as an error with the new address. Text and JSON come back in body. Binary responses (images, PDF, audio) are saved to a file whose path is in saved_file (with content_type); a PNG/JPEG/GIF/WebP image up to 3 MB is also attached as an image. Text longer than 100,000 characters is cut in body and kept whole in saved_file. If saving takes too long (macOS asking for Downloads access), the result comes back first and saving_file names where the file will appear. Settlement takes one of two shapes, chosen by the server's requirement: a facilitator settles the signed EIP-3009 authorization (no gas from this wallet), or — where gas is paid in USDC itself and the server asks for eip3009-client-broadcast — the wallet broadcasts the transfer itself, so the price AND its gas leave this balance. Approval works exactly as in request_payment (password by default; automatic only when the user has turned autopay on), and the app enforces per-payment and daily limits and the emergency lock. Never send a password as an argument. Arguments: url (required), method, headers, body (JSON object), memo (what the payment is for — the user reads it to decide), agent_id. Returns: payment, paid, status, http_status, body, and amount/pay_to/settlement when paid; on a chain where the wallet broadcasts the payment itself, tx and explorer point at that transaction (both are empty on the facilitator-settled path, where settlement_tx/settlement_explorer carry the transaction the seller reports in its receipt — the seller's word, not checked on-chain by the wallet). IMPORTANT — decide on payment, which says where the money is: "none" = nothing was paid, trying again is safe (declined, no 402, or "reverted": the chain rejected the transfer and only gas was spent); "confirmed" = the money left the wallet; "unknown" = it MAY have left (status pending/unknown, or settlement_failed on the facilitator path, where the server's refusal doesn't prove the facilitator didn't settle). For confirmed and unknown without content, asking again can pay a second time — stop and tell the user, showing the tx (when a tx came back without content, x402_resubmit re-sends its proof without paying again). paid is kept for older callers and is simply payment != "none". Read notice when present, and never retry on an HTTP status alone: after the money moved the server may answer with a fresh 402 challenge that reads as if the payment never happened.
Inputs: url (required), body, memo, method, +2 more.
x402_resubmitResubmit an x402 payment proofAIdempotent
Resubmits the on-chain proof of an x402 payment this wallet already broadcast itself, to get the content it paid for. Use it when x402_fetch returned a tx without content (status pending, unknown or undelivered, or settlement_failed with a tx). No new money moves and no approval is asked: the wallet re-sends the same proof (the tx plus the saved challenge values) to the same URL. It first checks the tx on-chain — if it isn't mined yet you get status pending (wait and call again), if it reverted you get reverted (payment none: nothing was paid, so paying again is a new decision). Sellers keep proofs acceptable only for a while (the reference server: 10 minutes), so a late resubmit can be refused — that is settlement_failed with a notice; do not pay again then, tell the user and show the tx. Proofs are kept for 7 days. Returns the same shape as x402_fetch.
Inputs: tx (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Most tools are clearly distinct (request_payment, get_wallet_status, get_balances, get_history, lookup_agent). The only partial overlaps are request_payment vs x402_fetch (both trigger payments) and x402_fetch vs x402_resubmit, though the descriptions clearly delineate direct transfer vs paid API call vs proof resubmission without new money.
Consistent snake_case verb_noun pattern (request_payment, get_wallet_status, get_balances, get_history, lookup_agent), with x402_fetch and x402_resubmit using a coherent namespace prefix. Minor deviation from pure verb_noun but overall predictable.
7 tools is well-scoped for a wallet/payment server, with each tool earning its place. No redundant or filler tools.
Covers the core wallet lifecycle: payments, status/accounts, balances, history, x402 paid fetches with resubmission, and agent registry lookup. Minor gaps like account-switching (explicitly user-only) or explicit cancellation are reasonable omissions, but no major workflow dead ends.
Maintenance
Related MCP Connectors
Self-custodial USDC wallet on Base for AI agents: on-chain caps, Face ID, one-tap pause.
Crypto wallet for AI agents: balances, payments, swaps and trading with owner controls.
Encrypted, pay-per-use persistent memory storage for AI agents, gated by x402 payments on Base.
Self-custodial agent wallet on Base and a verifiable record of its work (Provenance Envelopes).
Related MCP Servers
AlicenseAqualityDmaintenanceProvides a non-custodial USDC wallet on Base for AI agents, with human-in-the-loop approval for every payment.411 npmMIT- AlicenseAqualityDmaintenanceGives AI agents a smart-contract wallet on Base (USDC) with 10 stdio tools: create wallets, send USDC payments, pay x402-protected HTTP resources, and run ERC-8183 escrow Jobs for A2A service delivery.1010 npmMIT
- AlicenseAqualityBmaintenanceA budget-bound x402 payment wallet for AI agents: it autonomously pays HTTP 402 payment-gated URLs across every major chain (EVM, Solana, and many non-EVM families). Self-custodial and backendless, your key, your RPC, with spend caps enforced before any on-chain send.810MIT

token4u-mcpofficial
AlicenseAqualityCmaintenanceEnables AI agents to call LLM APIs via x402 micropayments in USDC on Base network, manage a local wallet, and query consumption records.355 npmMIT