MCP server
Install @hodle/mcp — a stdio MCP server that exposes the Hodle Platform API as tools for Claude Code, Cursor, Codex, and Hermes.
@hodle/mcp is a self-hosted Model Context Protocol
server. It runs on your machine over stdio, wraps the public Hodle REST API in typed
tools, and never sends your API key anywhere except Authorization: Bearer headers on
requests it makes to the Hodle API itself.
Environment variables
| Variable | Required | Default | Notes |
|---|---|---|---|
HODLE_API_KEY | Yes | — | Missing key fails at startup with a clear message. Never accepted as a tool argument. |
HODLE_API_URL | No | https://sandbox-api.hodle.com.br | Sandbox-first: set it explicitly to point at https://api.hodle.com.br. |
HODLE_MCP_ALLOW_WRITES | No | false (unset) | Set to true to register the write tools. Off by default. |
HODLE_WALLET_PIN | Only for payout/transfer | — | The end user's wallet PIN. Read from the environment on purpose, never a tool argument — see below. |
HODLE_PROTECTED_SYMMETRIC_KEY | Only for payout/transfer | — | From POST /api/wallet/keys. Same handling as the PIN. |
Add the MCP server
Add it with the CLI:
claude mcp add hodle \
-e HODLE_API_KEY=YOUR_API_KEY \
-e HODLE_API_URL=https://sandbox-api.hodle.com.br \
-e HODLE_MCP_ALLOW_WRITES=false \
-- npx -y @hodle/mcpOr drop this into your project's .mcp.json:
{
"mcpServers": {
"hodle": {
"command": "npx",
"args": ["-y", "@hodle/mcp"],
"env": {
"HODLE_API_KEY": "YOUR_API_KEY",
"HODLE_API_URL": "https://sandbox-api.hodle.com.br",
"HODLE_MCP_ALLOW_WRITES": "false"
}
}
}
}Add this to ~/.cursor/mcp.json (or your project's .cursor/mcp.json):
{
"mcpServers": {
"hodle": {
"command": "npx",
"args": ["-y", "@hodle/mcp"],
"env": {
"HODLE_API_KEY": "YOUR_API_KEY",
"HODLE_API_URL": "https://sandbox-api.hodle.com.br",
"HODLE_MCP_ALLOW_WRITES": "false"
}
}
}
}Reload Cursor's MCP settings from Settings → MCP after saving.
Add this to ~/.codex/config.toml:
[mcp_servers.hodle]
command = "npx"
args = ["-y", "@hodle/mcp"]
[mcp_servers.hodle.env]
HODLE_API_KEY = "YOUR_API_KEY"
HODLE_API_URL = "https://sandbox-api.hodle.com.br"
HODLE_MCP_ALLOW_WRITES = "false"Restart Codex CLI to pick up the new server.
Add this to ~/.hermes/config.yaml:
mcpServers:
hodle:
command: npx
args: ["-y", "@hodle/mcp"]
env:
HODLE_API_KEY: YOUR_API_KEY
HODLE_API_URL: https://sandbox-api.hodle.com.br
HODLE_MCP_ALLOW_WRITES: "false"Then run /reload-mcp in a Hermes chat to pick it up without restarting.
Tools
Every tool call talks to the same host as HODLE_API_URL — sandbox by default. Read
tools are always registered. Write tools are registered only when
HODLE_MCP_ALLOW_WRITES=true, and every write tool requires confirm: true on the call
itself — a call without it is refused before any HTTP request is made, and it tells you
exactly what it would have done.
| Tool | Gated | Wraps |
|---|---|---|
hodle_quote | Read | POST /api/quote — Quote |
hodle_kyc_get | Read | GET /api/kyc — KYC |
hodle_account_statement | Read | GET /api/account/statement — Account statement |
hodle_wallet_get | Read | GET /api/wallet — Wallet get |
hodle_payout_status | Read | GET /api/wallet/payout/{transactionId} — Wallet payout |
hodle_subaccount_list | Read | GET /api/subaccount |
hodle_subaccount_get | Read | GET /api/subaccount/{subAccountId} |
hodle_wallet_payout | Write | POST /api/wallet/payout — Wallet payout |
hodle_wallet_transfer | Write | POST /api/wallet/transfer — Wallet transfer |
hodle_deposit_asset | Write | POST /api/deposit/asset — Deposit asset |
hodle_lightning_invoice | Write | POST /api/lightning/invoice — Lightning invoice |
hodle_subaccount_create | Write | POST /api/subaccount |
hodle_kyc_create | Write | POST /api/kyc (hosted flow) — KYC |
Use it
Once the server is wired in, ask your agent to use it directly — no extra prompting needed beyond naming what you want:
Get a quote for converting R$500 (PIX) into USDC on Base.The agent calls hodle_quote and reads back the priced amount and fees.
What the gates do and do not do
Be precise about what protects you here, because the two gates protect different things and neither one is a human approving a payment:
HODLE_MCP_ALLOW_WRITESis the real boundary. Leave it unset and the write tools are never registered — the agent cannot see them, cannot call them, and no prompt can talk it into using a tool that does not exist.confirm: trueis a deliberateness check, not human approval. The agent sets that field, not you. It stops a value-moving call from happening by accident or as a half-formed guess, and the refusal tells you exactly what would have run — but an agent that has decided to pay can setconfirm: trueon its own.
The human-in-the-loop step is your MCP client's own tool-approval prompt (Claude Code,
Cursor, and Codex each ask before running a tool). Keep that approval on for the write
tools. If you are running an agent unattended, leave HODLE_MCP_ALLOW_WRITES unset and
give the server a sandbox key.
walletPin and protectedSymmetricKey are not tool arguments. A tool argument is
text the model writes, so a PIN passed that way would travel through the model's context
and land in your agent's transcript and the provider's logs. The server reads both from
HODLE_WALLET_PIN and HODLE_PROTECTED_SYMMETRIC_KEY instead, exactly like the API key,
and both money tools refuse with a clear message when they are not set. Anything the API
echoes back is scrubbed of those values before it reaches the agent. Never paste an end
user's PIN into a chat session.
One consequence worth knowing up front: the server holds one credential pair, so
hodle_wallet_payout refuses a call that sets subAccountId. A subaccount payout needs
that subaccount's own PIN and key, and quietly sending the main account's would be wrong.
Run per-subaccount payouts from your own integration code, where you can hold the right
credentials per user — see Wallet payout.
When a write call times out
Write calls get a 60s timeout; reads get 15s. If a write times out or the connection
drops, the tool returns outcomeUnknown: true and says so in plain words, because the
operation may already have been accepted on the server. A repeated POST is not
deduplicated by the API, so a blind retry can pay the same Pix twice. Check state first —
hodle_payout_status for a payout, hodle_account_statement otherwise — and only then
decide whether to call again.
Next steps
- Turn on
HODLE_MCP_ALLOW_WRITES=trueonly once you've tested the read path in sandbox. - Install the
hodle-apiagent skill alongside the MCP server so the agent also has the two end-to-end flows, KYC gating, and webhook verification in its context — the MCP server is the hands, the skill is the map. - Read the full API reference for every field the tools accept.