@pendle/boros-mcp
v0.3.0
Published
MCP server for Boros — Pendle's interest rate derivatives trading platform
Maintainers
Readme
@pendle/boros-mcp
MCP server that lets your AI assistant trade interest rate derivatives on Boros — Pendle's funding rate swap platform on Arbitrum.
Ask things like "current 3-month BTC perp funding rate?", "open 0.5 ETH long on the 30-day market at 8% APR", "show open positions and unrealized PnL".
- 44 tools: market data, account state, trading, wallet, AMM
- Delegated agent key — LLM signs trades with an ephemeral key you authorize once; main wallet stays cold
- Simulate-then-execute — every order previewed before chain submit
- Cross-margin and isolated-margin
- Wallet ops always re-prompt your real browser wallet
Install
Node ≥ 18. Ships a boros-mcp binary.
npx -y @pendle/boros-mcp
# or
yarn global add @pendle/boros-mcp && boros-mcpFrom source (only if hacking on it):
git clone https://github.com/pendle-finance/boros-mcp
cd boros-mcp && yarn install && yarn buildConfigure your client
The server speaks MCP over stdio, so any compliant client can launch it. Pick the one you use.
Claude Code
One command (recommended):
claude mcp add boros -- npx -y @pendle/boros-mcpAdd --scope user for global (all projects) instead of the default project scope. Verify with claude mcp list.
Claude Desktop
Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"boros": {
"command": "npx",
"args": ["-y", "@pendle/boros-mcp"]
}
}
}Restart the app to load the server.
Codex CLI
Edit ~/.codex/config.toml:
[mcp_servers.boros]
command = "npx"
args = ["-y", "@pendle/boros-mcp"]Gemini CLI
Edit ~/.gemini/settings.json (or your project's .gemini/settings.json):
{
"mcpServers": {
"boros": {
"command": "npx",
"args": ["-y", "@pendle/boros-mcp"]
}
}
}opencode
Edit ~/.config/opencode/opencode.json (or opencode.json at the project root):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"boros": {
"type": "local",
"command": ["npx", "-y", "@pendle/boros-mcp"],
"enabled": true
}
}
}Built from source
Replace the command/args block in any of the configs above with:
"command": "node",
"args": ["/absolute/path/to/boros-mcp/dist/index.js"]Other MCP clients
Run npx -y @pendle/boros-mcp (or boros-mcp if globally installed) and point your client at it over stdio transport.
How approvals work — read this first
Boros MCP is not a pure JSON-RPC MCP. Alongside the stdio MCP channel it spins up a small HTTP server on 127.0.0.1:<random-port> to broker browser-side wallet signatures. Necessary because Boros wallet operations require signatures from your real wallet, which lives in the browser, not in the LLM.
Two classes of action
| Class | Tools | Signing key | Browser involved? |
|---|---|---|---|
| Trading & AMM | place_order, place_orders, close_position, cancel_orders, add_liquidity, remove_liquidity, cash_transfer, … | Agent key (delegated, on-disk) | No — fully autonomous |
| Wallet & agent lifecycle | setup_agent, revoke_agent, deposit, withdraw, cancel_withdraw, vault_pay_treasury | Your main wallet | Yes — browser callback |
Localhost callback flow
When you run e.g. "deposit 100 USDC into Boros":
- Tool call returns a localhost URL with a one-time token:
http://127.0.0.1:<ephemeral-port>/deposit?token=<uuid>. Server auto-opens it; URL is also echoed to stderr ([boros-mcp] Opening browser: …) so you can paste manually. - Page prompts your browser wallet (MetaMask, Rabby, …) to sign and broadcast the tx. Private key never leaves the browser.
- After confirmation, page POSTs
txHashback to the same localhost port. - Server verifies the receipt on-chain: tx hit
ROUTER_ADDRESS, function selector is in the per-action allowlist, signed-from address matches your registered wallet. Only then does the tool call resolve success to the LLM.
If verification fails (wrong contract, wrong selector, wrong signer), the tool call errors and nothing further happens.
First-run agent setup
On first use, ask "set up a Boros agent". The server:
- Generates a fresh Ethereum keypair (the agent key) in-process.
- Opens an
/approve-agentpage where you connect your real wallet and sign one EIP-712 typed message (not a transaction — no gas paid;send-txs-botrelays the approval on-chain). - Once the relay tx confirms, encrypts the agent key with AES-256-GCM (scrypt-derived KDF, optional password) and stores it at
~/.boros-mcp/agent.enc.
Subsequent trades signed locally by the delegated agent — no browser, no popups. Wallet operations always re-prompt the browser.
The agent is bounded on-chain to ~12 trade/AMM router selectors — it cannot withdraw, transfer to other wallets, change account managers, or approve other agents. Default expiry 30 days (expiryDays overrides, 1–365). Revoke via "revoke my Boros agent" (also a wallet-flow action).
Why this matters for client config
- Server must run as a long-lived child process of the MCP client (which
claude mcp addand the configs above all do). Not a one-shot RPC server — the in-memorypendingActionsmap is what makes the localhost callback safe (token → action lookup with TTL). - Port is ephemeral (OS-assigned per startup). Do not firewall a fixed port; do not expose. Server only binds
127.0.0.1. - If your MCP client is sandboxed without browser/loopback access (e.g. remote container), wallet-signing tools will not work. Trading-only flows still function once an agent is provisioned from a non-sandboxed environment.
Environment variables
All optional.
| Variable | Default | Purpose |
|---|---|---|
| ARBITRUM_RPC | https://arb1.arbitrum.io/rpc | Arbitrum RPC endpoint |
| BOROS_MCP_PRETTY | unset | Set to 1 to pretty-print JSON tool responses (debug; ~30–40% more tokens) |
Security model
- Agent key lives only on your machine, encrypted at rest under a scrypt-derived key (optional password, AES-256-GCM)
- Wallet operations (deposit / withdraw / agent setup / revoke / vault treasury) never use the agent key — always re-prompt your real wallet via the localhost callback
- Trade calldata verified against the simulated parameters before signing (selector allowlist + intent verification)
- Browser-callback transactions verified on-chain after submission: receipt status, target contract (
ROUTER_ADDRESS), function selector (per-action allowlist), and signer address must all match. A malicious page cannot resolve a deposit by pointing at an unrelated successful tx. - HTTP server only listens on
127.0.0.1, on an OS-assigned ephemeral port chosen fresh each launch (no stable port to bookmark or expose). The chosen URL is logged to stderr at startup and embedded in every signing-page link returned by tools. - One-time tokens scope each pending action (deposit, withdraw, agent approval, …) to a single browser callback. Tokens kept in memory only, invalidated on use or process exit.
Links
- Source & issues: https://github.com/pendle-finance/boros-mcp
- Boros app: https://boros.finance
- Pendle: https://pendle.finance
- MCP: https://modelcontextprotocol.io
Boros documentation
The server also surfaces these via the boros_glossary tool (docs field) so the model knows where to read more:
- Introduction: https://docs.pendle.finance/boros-dev/Introduction
- Lite paper: https://docs.pendle.finance/boros-dev/LitePaper
- FAQ: https://docs.pendle.finance/boros-dev/FAQ
- Settlement: https://docs.pendle.finance/boros-dev/Mechanics/Settlement
- Indicators: https://docs.pendle.finance/boros-dev/Backend/indicators
- Historical data: https://docs.pendle.finance/boros-dev/Backend/historical-data
- Glossary: https://docs.pendle.finance/boros-dev/Backend/glossary
- Bulk historical data archive: https://historical-data.boros.finance — OHLCV, trades, order book, settlement and underlying-funding history as ZIP-compressed NDJSON (
/files.jsonmanifest), refreshed every 2–3 days. For long-range/offline analysis beyond what the liveget_market_*tools return per call.
License
MIT
