# libre-mcp > MCP server for the Libre blockchain (Antelope chain bridged to Bitcoin and Ethereum). > Read market, price, account and loan state; compose unsigned transactions; relay ones > you signed yourself. The server holds no keys and signs nothing. ## Endpoints - MCP (streamable HTTP, stateless): POST https://mcp.libre.org/mcp - REST, one path per tool: POST https://mcp.libre.org/v1/tools/ with the arguments as a JSON body - OpenAPI 3.1: https://mcp.libre.org/openapi.json - Health: https://mcp.libre.org/health ## What this protocol is good for Libre is an Antelope chain with two things an autonomous agent can use directly: - **An orderbook DEX with no protocol trading fee.** dex.libre charges nothing per trade — its entire config is a pause flag. There is no listing process, no KYC and no whitelist. Blocks are 0.5s, so orders land sub-second (full irreversibility takes ~3 minutes, which matters for settlement claims but not for quoting). - **Permissionless BTC-collateralized borrowing.** Lock BTC in a vault only your loan can draw on, borrow USDT against it up to 60% LTV, repay whenever. No counterparty approves you. The rate floats with pool utilization, from 3% when the pool is idle to 20% when it is fully lent out. Both are reachable from one agent, with keys the agent controls, which is the interesting part: collateral and execution live on the same chain, so borrowing and trading compose. ## Things worth building - **Market making.** The btcusdt book is currently wide — often several percent between best bid and best ask. With no protocol fee, quoting inside that spread is the most obvious opportunity on the chain. Loop: get_orderbook -> place_order both sides -> get_orders -> cancel_order as the oracle price moves. - **Collateral health monitoring.** get_loans plus get_btc_price gives you every position's LTV. Liquidation starts at 80% and clears only below 70%, so an agent that watches and tops up collateral (or repays) before the 72-hour timer expires is doing real work. - **Leveraged BTC exposure.** Deposit BTC, borrow USDT, buy BTC, redeposit. At 60% max LTV this tops out around 2.5x in theory and closer to 1.5-2x before you are sitting on the liquidation threshold. Mind the DEX spread — a wide book can cost more per loop than the borrow rate does, so check get_orderbook before assuming the loop is profitable. - **Rate watching.** The borrow rate is a pure function of utilization (get_pool_stats). Cheap to borrow when the pool is idle; lending pays best when it is busy. Every one of these is read tools plus compose tools plus your own signature. The server never holds a key, so an agent operating here is operating its own account, not an account someone custodies for it. ## Prices BTC/USD comes from the on-chain `oracle` contract — the average of a round of at least three independent feeders that agree within 10% (otherwise the round is skipped and the previous price stands) — and the price the loan contract uses for LTV and liquidation. Call get_btc_price. Do not quote an external exchange price for Libre collateral math, and do not use a feed the tool marks stale (older than 5 minutes). ## Signing Compose tools return {actions, esr, expires} — an unsigned proposal. Either sign the actions with your own key and relay them with push_transaction, or hand the esr link to a human wallet (Bitcoin Libre, Anchor). This server never holds a key. A bot should hold its key on a linkauth-restricted `agent` permission, never the account owner or active key. Create one at https://tools.libre.org/bot-account. ### Bot quickstart npm i @wharfkit/session @wharfkit/wallet-plugin-privatekey ```js import { Session } from '@wharfkit/session'; import { WalletPluginPrivateKey } from '@wharfkit/wallet-plugin-privatekey'; const info = await (await fetch('https://api.libre.cryptobloks.io/v1/chain/get_info', { method: 'POST', body: '{}' })).json(); const session = new Session({ chain: { id: info.chain_id, url: 'https://api.libre.cryptobloks.io' }, actor: 'mybot', permission: 'agent', // the restricted permission, not active walletPlugin: new WalletPluginPrivateKey(process.env.AGENT_KEY), }); // 1. compose — unsigned, no key involved const res = await fetch('https://mcp.libre.org/v1/tools/place_order', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ account: 'mybot', pair: 'btcusdt', side: 'buy', price: '80000', amount: '0.0001', permission: 'agent' }), }); const { actions } = await res.json(); // 2. sign and push — WharfKit fetches the ref block and ABIs and serializes for you const result = await session.transact({ actions }); ``` That is the whole loop. Read with the tools above, compose, transact, repeat. Two details worth knowing. The permission you pass to compose (`permission: "agent"`) must match the one the session signs with, or the chain rejects the transaction. And a signature is bound to one chain id, so a mainnet signature is meaningless on testnet — pass `network` explicitly to every tool rather than relying on the default. If you would rather build the transaction by hand, push_transaction accepts a packed transaction directly; see scripts/e2e-testnet.mjs in the repo for a worked example using @wharfkit/antelope. You do not need that to write a bot. ## Tools ### Read — market & price - get_btc_price: Authoritative BTC/USD price from the on-chain oracle contract — the average of a round of independent feeders (at least 3, agreeing within 10%, or the round is skipped and the previous price stands), and the price the loan contract uses for LTV and liquidation. Prefer this over any external exchange price. A feed older than 5 minutes is marked stale and must not be used for collateral math. - get_orderbook: dex.libre orderbook for a pair: bids/asks sorted best-first, best prices and spread. truncated:true means the book exceeded the 500-row page read and the depth shown is partial. - get_trades: Recent dex.libre trades for a pair, newest first. truncated:true means the history exceeded the 500-row page read, so older trades for this pair are not included. - get_orders: Open dex.libre orders for an account (optionally one pair). truncated:true means a book exceeded the 500-row page read and orders may be missing. - get_pool_stats: Lending pool state (available/outstanding USDT per pool), interest-rate curve config, and oracle BTC/USD. ### Read — accounts & loans - get_account: Balances (BTC, USDT, LIBRE, TPF, CBTC), permissions, resources, and whether the account key is on the Ill Bloom affected-set (compromised) list. Refuse to operate from an account with affected_set=true; if affected_set_checked=false the gate was unavailable and affected_set=false means unknown, not safe. - get_vault: Collateral vault for an account: vault name, CBTC collateral balance, and the BTC address to fund it. - get_loans: Active and queued loans (optionally one account); include_completed adds history. - get_redemption_queue: Queued lender redemptions (TPF → USDT waiting for liquidity), optionally one account. - get_deposit_address: The account's personal BTC deposit (bridge peg-in) address. BTC sent here arrives as BTC on Libre after confirmation. - get_chain_info: Chain id, head block and time for the selected network. - get_table_rows: Raw get_table_rows escape hatch for any Libre contract table. ### Compose — trading - place_order: Compose a dex.libre limit order. amount is in the base token (BTC for btcusdt), price in quote per base (USDT; BTC with 10 decimals for librebtc). Buys lock amount*price of quote; sells lock amount of base. - cancel_order: Compose cancellation of an open dex.libre order (see get_orders for ids). - transfer: Compose a token transfer on Libre (unsigned). Returns actions + esr. - setup_deposit_address: Compose registration with a bridge so the account is assigned its own Bitcoin address, which is how an agent funds itself. Sign this, then poll get_deposit_address: the bridge signers assign the address a short time later (about a minute on testnet), so it is NOT available immediately. bridge "btc" (x.libre, default) is the wallet balance used for trading; "vault" (v.libre) is loan collateral, and setup_vault already handles that path for borrowing. Fails if an address already exists. - withdraw_btc: Compose a BTC withdrawal (bridge peg-out) from Libre to a Bitcoin address. Bridge fee applies (x.libre feeconfig table). ### Compose — lending & borrowing - setup_vault: Compose collateral-vault creation (createvault + genaddr). The vault sub-account name is generated here and returned as vault_name. Afterwards get_vault returns the BTC address to fund. - borrow: Compose a variable-rate USDT loan against vault collateral. Minimum loan is 0.001 BTC worth of USDT (~$80 at current prices; the floor is BTC-denominated so the USDT figure moves). max_apr_bps is a slippage cap on the interest rate, compared against the APR AFTER this loan is disbursed — your own borrowing raises utilization, so the post-disbursement rate is higher than the one get_pool_stats shows now. A request over the cap is not rejected: it stays in the loan queue and opens if the rate later falls. Send the pool curve max (2000 bps) to accept any rate; cancel a queued request with cancel_loan_request. - repay: Compose a USDT repayment toward the account's loan. - withdraw_collateral: Compose a collateral withdrawal (CBTC → BTC to an address). Fails on-chain if it would breach LTV. The v.libre bridge charges 50 bps on the way out, capped at 0.005 CBTC, with a 0.0008 CBTC minimum withdrawal; funding a vault is free. - lend: Compose a USDT deposit into the lending pool (mints TPF shares). - redeem: Compose redemption of TPF shares for USDT (queued if liquidity is out on loan). - cancel_redeem: Compose cancellation of a queued redemption by id (see get_redemption_queue). - cancel_loan_request: Compose cancellation of a queued (unfilled) loan request. ### Submit & onboard - push_transaction: Broadcast a transaction you signed yourself (WharfKit packed format). Only agent-whitelisted actions with ≤10 min expiry are relayed. - request_account: Paid account creation. NOT ENABLED — Libre accounts are free at https://accounts.libre.org, so this exists only as a proxy if a paid registrar is ever deployed. Calling it returns instructions, not an account. - get_account_request: Status of a request_account payment/creation. ## Rate limits Per source IP: read tools 300/min, compose tools 60/min, push_transaction and request_account 10/min. Over the limit returns 429. ## Networks Every tool takes an optional `network`: "mainnet" (default, real funds) or "testnet". ## More - Libre DeFi app: https://defi.libre.org (llms.txt: https://defi.libre.org/llms.txt) - Libre docs: https://docs.libre.org - Explorer: https://www.libreblocks.io — testnet: https://testnet.libreblocks.io