Cross-chain swaps are tedious by design.
Open a browser. Connect a wallet. Approve a token. Copy addresses between tabs. Sign again. Wait for confirmations. Hope nothing breaks midway through the flow.
I got tired of it. So I asked a different question:
What if the entire experience — quote, approval, signing, broadcasting, settlement — happened from a single terminal command?
swap 0.0005 wBTC to BTC
That's the goal I set. Here's how I built it, what I learned, and where it's going.
The Real Insight (Read This First)
Most blockchain tooling is built for UIs. REST APIs, ABIs, wallet popups — all of it assumes a human is clicking through a browser.
But AI systems don't click. They call tools, compose workflows, and orchestrate steps.
The insight that drove this entire project:
Modern AI works best when infrastructure is designed for it — not retrofitted around it.
Instead of wrapping another UI around Garden Finance's swap infrastructure, I made the AI system itself the interface. That one decision changed everything about how I structured the architecture.
The Final Experience
Inside Claude Code, you type:
swap 0.0005 wBTC to BTC on mainnet
Claude responds:
Using saved configuration:
• RPC URL: https://mainnet.infura.io/v3/...
• Bitcoin destination: bc1p...
Quote:
Sending: 0.0005 wBTC
Receiving: 0.00048712 BTC
Solver: hashira
Confirm? (yes/no)
After confirmation, the entire workflow executes automatically:
- ERC-20 approval
- Initiate transaction
- Order polling every 5 seconds
- Bitcoin redemption tracking through to final settlement
No browser. No tab switching. No manual signing prompts. Just the terminal.
System Architecture
The project is a four-layer AI-native infrastructure stack:
AI Client Layer
(Claude Code / Cursor)
↓
Orchestration Layer
(Claude Code Skill)
↓
Capability Layer
(Garden MCP Server)
↓
Protocol/API Layer
(Garden Finance API)
Each layer has exactly one job:
| Layer | Responsibility |
| Claude Code / Cursor | Natural language interface |
| Claude Skill | Workflow orchestration |
| Garden MCP | AI-consumable protocol capabilities |
| Garden Finance API | Swap infrastructure |
The separation turned out to be the most important architectural decision in the project.
The MCP layer exposes capabilities. The skill layer orchestrates workflows. Sensitive operations stay local. Nothing bleeds across boundaries.
Part 1 — The Garden MCP Server
The first thing I built was an MCP server that wraps Garden Finance's swap infrastructure and makes it natively consumable by AI systems.
The key design decision: expose semantic tools, not protocol primitives.
Instead of making Claude deal with raw API endpoints and low-level transaction construction, the MCP server exposes high-level tools that model user intent:
| Tool | Description |
get_quote | Get a swap quote between assets |
create_order | Submit a cross-chain swap order |
get_order_status | Poll an order until completion |
get_all_user_orders | Fetch wallet order history |
get_assets | List supported assets |
get_chains | List supported chains |
get_liquidity | Fetch real-time liquidity |
LLMs perform significantly better when tools represent capabilities and semantic actions instead of low-level protocol primitives. That single design choice made the orchestration layer dramatically more reliable.
Hosted Endpoints
The MCP server runs remotely over HTTP — no local setup required. Connecting it to Claude Code is a single command:
# Mainnet
claude mcp add --transport http garden-mainnet [mainnet-endpoint]/mcp
# Testnet
claude mcp add --transport http garden-testnet [testnet-endpoint]/mcp
Or manually via .claude/settings.json:
{
"mcpServers": {
"garden-mainnet": {
"type": "http",
"url": "[mainnet-endpoint]/mcp"
},
"garden-testnet": {
"type": "http",
"url": "[testnet-endpoint]/mcp"
}
}
}
The same server works with Claude Code, Cursor, and any other MCP-compatible client without modification.
Server Architecture
The server uses MCP Streamable HTTP transport in stateless mode — each request spins up a fresh server instance:
MCP Client (Claude Code, Cursor, ...)
│
▼
garden-mcp
(Express + StreamableHTTPServerTransport)
│
▼
Garden Finance API
Stateless mode works perfectly here because all tools are pure API proxies with no session requirements. It also gives horizontal scalability, simpler deployments, and predictable execution for free.
Part 2 — The Claude Code Skill
The second component is the orchestration layer: a Claude Code skill that handles the full swap workflow end-to-end.
Claude Code skills are structured execution workflows that activate automatically based on user intent. This one triggers for prompts like:
swap wBTC to BTC
bridge my BTC to Ethereum
swap 0.001 BTC to wBTC
The skill itself contains no protocol logic. Instead, it coordinates:
- MCP tool calls for quote discovery and order creation
- Local TypeScript signing scripts (more on why below)
- Shell commands and polling loops
- Keychain-based secret management
Automatic MCP Registration
One onboarding detail I wanted to get right: the skill automatically checks whether the Garden MCP tools are registered, and registers them silently if not:
claude mcp list 2>/dev/null | grep -q garden-mainnet || \
claude mcp add --transport http garden-mainnet [endpoint]
If missing, Claude registers the MCP server and asks the user to restart. Almost all manual setup friction is gone.
The Trust Boundary That Matters
One thing intentionally stays outside MCP: transaction signing.
Private keys should never leave the local machine. So all signing happens through small local TypeScript scripts executed with Bun:
get-address.ts — derive EVM address from private key
btc-get-address.ts — derive Bitcoin Taproot address
sign-and-initiate.ts — ERC-20 approval + initiate transaction
btc-send.ts — fund Bitcoin HTLC
The orchestration layer pipes MCP responses directly into these local scripts:
cat /tmp/garden-order.json | (
cd ~/.claude/skills/garden &&
GARDEN_PRIVATE_KEY=$(security find-generic-password -a garden -s garden-pk -w) \
ETH_RPC_URL=<ETH_RPC_URL> \
bun run scripts/sign-and-initiate.ts
)
This creates a clean, explicit trust boundary:
| Component | Responsibility |
| MCP Server | Remote capabilities |
| Claude Skill | Workflow orchestration |
| Local Scripts | Signing and broadcasting |
| macOS Keychain | Secret storage |
The private key never appears in Claude's conversation context.
Keychain Integration
The first version required entering a private key every session. Terrible UX and unnecessary risk.
The skill now integrates directly with macOS Keychain. Stored values include the private key, Ethereum RPC URL, and Bitcoin destination address. Each signing script fetches secrets directly from Keychain at execution time — never from the conversation, never from environment variables Claude can see.
The Full Swap Flow
When you type swap 0.0005 wBTC to BTC, here's what actually happens:
- Verify MCP availability (register automatically if missing)
- Load credentials from Keychain
- Resolve any missing configuration
- Derive wallet addresses locally
- Fetch swap quote through MCP
- Present quote and confirm with user
- Create swap order via MCP
- Sign and broadcast initiation locally
- Poll order status every 5 seconds
- Return final redeem transaction hash
The same flow handles BTC → wBTC, mainnet, and testnet through the same conversational interface.
Testnet Swaps
We ran a full suite of testnet swaps across both directions:
- wBTC → BTC on Sepolia + Bitcoin testnet
- BTC → wBTC on Bitcoin testnet + Sepolia
The flows are completed end-to-end, including ERC-20 approval, HTLC funding, solver initiation, and redemption tracking. Keychain secret storage, automatic MCP registration, and polling logic all behaved correctly under real swap conditions.
We're continuing to use the testnet environment for internal validation before making this publicly available. Once the signing scripts are hardened and the skill is stable across edge cases, and also after we handle all the security issues that could crop up, we'll open it up.
Why MCP Is the Right Abstraction Here
After building this, MCP's value as an abstraction layer became obvious.
Instead of giving Claude a raw REST API and asking it to figure out request construction, authentication, and error handling — MCP provides:
- Structured capabilities with typed inputs
- Semantic tool names that match user intent
- Deterministic execution surfaces Claude can reason about reliably
The result feels less like "chatting with a bot" and more like programmable infrastructure that happens to accept natural language.
What's Next
A few things on the roadmap:
- Windows Credential Manager support
- Linux secret-service integration
- Ledger hardware wallet support
- Streaming swap status updates
- More Garden asset pairs
- Multi-wallet support
- Autonomous swap execution flows
The architecture already composes cleanly enough to support all of them.
Closing Thought
The most interesting thing I built here wasn't the swap itself.
It was the realization that AI-native infrastructure looks fundamentally different from web-native infrastructure. Not because the underlying protocols change — but because the interface layer does.
When the AI is the interface, you stop building UIs and start building capabilities. The distinction sounds subtle. It isn't.