exfer-mcp
MCP server for the Exfer blockchain — gives an AI agent (Claude Code, Claude Desktop, Cursor, any MCP host) a typed wallet it can actually use: balances, payments, signed price quotes, and HTLC settlement on mainnet.
What it's for, proven: two agents settling a real service on mainnet, end to end — a signed EXFER-QUOTE, an on-chain payment that binds datum = quote_id, then atomic delivery the instant the chain proves it to depth. No per-transaction approval, no escrow operator, no human releasing the goods. See exfer-honor/examples/mainnet-loop.
⚠️ The agent can spend this wallet on its own — there is no per-transaction human approval. Unlike a normal wallet (where you click "confirm" on each send), anything that can reach this MCP server — your agent, or a prompt-injection of it — can move the funds. Keep only a float you're OK losing, and/or set spend caps (
WALLETD_SPEND_CAP_PER_TX,WALLETD_SPEND_CAP_PER_PERIOD+WALLETD_SPEND_CAP_PERIOD_SECS, in exfers).
Set it up
Two ways — they end the same place. Either way, you restart your MCP host once at the end: servers load at startup, so a host (or an agent inside one) can't connect to a server it just registered in the same session. That's normal, not a failure.
Hand it to your coding agent
Paste the block below to your agent (Claude Code, Cursor, Codex, or Claude Desktop with a terminal). It verifies the package, pre-warms the download, registers the server, then tells you how to do the one restart.
Set up the exfer MCP server for me. It's a young project that gives an AI agent a spendable Exfer-mainnet wallet with no per-transaction approval, so be careful and stop before any funding step. Check provenance first: package
exfer-mcpon PyPI, repogithub.com/exfer-stack/exfer-mcp; in managed mode it downloads theexfer-walletdbinary fromexfer-stack/exfer-walletdreleases and runs it only if the SHA-256 matches a digest baked into the package. (github.com/ahuman-exfer/exferis the separate Exfer blockchain repo — not this MCP.) Frequent recent releases are expected for a young project; pin the version below. Everything before funding is read-only.
- Install
uvif it's missing (it providesuvx): macOS/Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh; Windowsirm https://astral.sh/uv/install.ps1 | iex.- Pre-warm first — this is what prevents a host startup-timeout. Run
uvx exfer-mcp==0.6.0 --prewarm. It caches the package and downloads + checksum-verifies thewalletdbinary, then exits — no secrets, nothing to fund. Wait forwalletd binary ready. (First run can take ~1 min on a slow link; that's the download you're moving off the host's startup path.)- Register an MCP server named
exfer: commanduvx, args["exfer-mcp==0.6.0"], envWALLETD_KEYSTORE_PASSPHRASE= a fresh secret fromuv run --no-project python -c "import secrets; print(secrets.token_urlsafe(24))". Inject it directly so the literal never appears in this chat. Claude Code:claude mcp add exfer -e WALLETD_KEYSTORE_PASSPHRASE="$(uv run --no-project python -c 'import secrets; print(secrets.token_urlsafe(24))')" -- uvx exfer-mcp==0.6.0. Claude Desktop / Cursor / Codex: put that block undermcpServersin the host config — for Codex (~/.codex/config.toml) also addstartup_timeout_sec = 120under[mcp_servers.exfer]. To confirm it registered, check the config simply has the env key — do NOT runclaude mcp getormcp list -v; they print the passphrase straight back into this chat.- Stop and tell me to restart. You can't hot-reload MCP servers into your own running session, so don't try to call any
exfer_*tool yet. Tell me exactly how to reload for my host — Claude Code: quit and relaunch (or/mcp→ reconnectexfer); Codex / Cursor / Claude Desktop: fully quit and reopen — then wait for me to come back.- After I've restarted, call
exfer_get_block_height(a height means it's live; the first call takes ~15s while it creates the keystore) and then give me a receive address viaexfer_generate_address.- Recovery phrase: first run writes 24 words to
<WALLETD_DATADIR>/RECOVERY_PHRASE.txt(mode 0600; default~/.exfer-walletd-mcp, Windows%USERPROFILE%\.exfer-walletd-mcp). On Windows 0600 is POSIX-only, so make sure that file isn't in a synced/backed-up folder. Tell me to copy it offline and delete the file — don't print it here. Losing it and the passphrase makes the wallet unrecoverable.
Or do it yourself
1. Install uv (it provides uvx): macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh; Windows irm https://astral.sh/uv/install.ps1 | iex.
2. Pre-warm — caches the package + the SHA-256-verified walletd binary off the host's startup path (no secrets):
uvx exfer-mcp==0.6.0 --prewarm
3. Pick a keystore passphrase (you choose it; it's stored in the host config and unlocks/creates the wallet). A strong random one: uv run --no-project python -c "import secrets; print(secrets.token_urlsafe(24))".
4. Register the server (managed mode — passphrase only):
- Claude Code:
claude mcp add exfer -e WALLETD_KEYSTORE_PASSPHRASE='<passphrase>' -- uvx exfer-mcp==0.6.0 - Claude Desktop / Cursor / Codex: add under
mcpServersin the host config (Codex: alsostartup_timeout_sec = 120):"exfer": { "command": "uvx", "args": ["exfer-mcp==0.6.0"], "env": { "WALLETD_KEYSTORE_PASSPHRASE": "<passphrase>" } }
5. Restart / reload the MCP host, then call exfer_get_block_height (a height = live) and exfer_generate_address (your receive address).
6. Back up the recovery phrase at ~/.exfer-walletd-mcp/RECOVERY_PHRASE.txt (mode 0600): copy it offline, then delete the file. It plus the passphrase are the only way to recover the wallet.
(Pin the version — uvx otherwise resolves+caches whatever is latest. pip install exfer-mcp also works; Python ≥ 3.10, pulls the exfer SDK + mcp + psutil.)
If a shell/host doesn't forward the trailing
--prewarmflag to the tool, setEXFER_MCP_PREWARM=1in the environment instead — it triggers the same prewarm-and-exit and is typo-proof.
Configure
exfer-mcp needs an exfer-walletd wallet daemon (it holds the keys and signs/broadcasts). Setting WALLETD_URL is the mode switch:
Managed (zero-setup) — recommended
Leave WALLETD_URL unset. exfer-mcp spawns + supervises its own walletd against Exfer's public mainnet node + indexer, and obtains the walletd binary automatically: EXFER_WALLETD_BIN → exfer-walletd on PATH → else it downloads the prebuilt binary for your platform and verifies it against a SHA-256 baked into this exfer-mcp release (not a co-located checksum) before running it, re-checking on every run (cached 0o700 in ~/.cache/exfer-mcp/walletd/). You only provide a passphrase:
{
"mcpServers": {
"exfer": {
"command": "uvx",
"args": ["exfer-mcp==0.6.0"],
"env": { "WALLETD_KEYSTORE_PASSPHRASE": "<a strong passphrase>" }
}
}
}
First run creates a seeded keystore and prints its 24-word recovery phrase to stderr once — that's the only backup. Keystore + datadir live in WALLETD_DATADIR (default ~/.exfer-walletd-mcp) and persist across restarts.
Claude Code one-liner:
claude mcp add exfer -e WALLETD_KEYSTORE_PASSPHRASE='<passphrase>' -- uvx exfer-mcp==0.6.0
External — connect to a walletd you run
Set WALLETD_URL + WALLETD_AUTH_TOKEN (and WALLETD_FINGERPRINT for https:// with a self-signed cert):
{
"mcpServers": {
"exfer": {
"command": "uvx",
"args": ["exfer-mcp==0.6.0"],
"env": {
"WALLETD_URL": "http://127.0.0.1:7448",
"WALLETD_AUTH_TOKEN": "<walletd token>"
}
}
}
}
Environment reference
| Variable | Mode | Default | Meaning |
|---|---|---|---|
WALLETD_KEYSTORE_PASSPHRASE |
managed (required) | — | unlocks / creates the managed keystore |
EXFER_WALLETD_BIN |
managed (optional) | auto: PATH or download | path to a walletd binary (skips auto-download) |
EXFER_WALLETD_VERSION |
managed (optional) | pinned | walletd release to auto-download |
WALLETD_DATADIR |
managed (optional) | ~/.exfer-walletd-mcp |
keystore + tokens; give each concurrent session its own |
EXFER_NODE_RPC / EXFER_INDEXER_RPC |
managed (optional) | public mainnet | upstream node(s) / indexer ("" indexer = disable) |
EXFER_ENABLE_SWAP |
managed (optional) | off | 1 turns on the cross-chain on-ramp (swap_* / bsc_* tools) using the community pool default. Off by default — swap moves real cross-chain funds |
EXFER_SWAP_POOL / EXFER_SWAP_POOL_CA |
managed (optional) | community pool | point the swap at your own pool URL + its CA (PEM). Overrides the default; a custom pool never uses the bundled CA |
WALLETD_URL + WALLETD_AUTH_TOKEN |
external (required) | — | walletd URL + bearer token |
WALLETD_FINGERPRINT |
external (optional) | — | sha256:<hex> for self-signed TLS |
Running multiple agent sessions at once? Managed mode is one wallet per datadir — give each session a distinct
WALLETD_DATADIR, or run one shared walletd and connect every session in external mode.
What you get (35 tools)
- Wallet & chain:
generate_address,list_addresses,get_balance,get_block_height - Payments:
simulate_transfer(dry-run fee),transfer,wait_for_tx,wait_for_payment(push, no polling),payment_uri_encode/_decode - Identity & price quotes:
sign_message/verify_message,quote_issue/quote_verify(signed EXFER-QUOTE credentials) - Conditional payment:
htlc_lock/_claim/_reclaim/_status/_list(atomic, hash-time-locked settlement) - History:
get_address_history(indexer-backed raw activity) - Self-funding (earn):
earn,earn_probe,earn_status,earn_stop— mine EXFER to your own address with spare CPU/GPU. EXFER is mineable, so an agent can acquire its own starting capital from compute alone (no human, bank, KYC, or pre-funded account). Zero-setup: the prebuilt CPU miner is auto-downloaded and digest-verified on first use (GPU is opt-in via a self-built--features cudabinary atEXFER_AGENT_MINER_BIN).earn_probetests whether a pool actually accepts your shares and recommends one, so you don't mine blind. - On-ramp (cross-chain swap, opt-in):
bsc_get_address,bsc_get_balance,swap_pool_info,swap_get_quote,swap_execute,swap_status,swap_list,swap_refund— fund the wallet's BSC address with USDT/BNB and atomically swap into EXFER (and back), so an agent can on-ramp without a human acquiring EXFER for it. Off unlessEXFER_ENABLE_SWAP=1(it moves real cross-chain funds); see the env reference. - Meta:
check_update(is a newer exfer-mcp on PyPI? read-only, no wallet access)
The intended spend flow is simulate → confirm with the user → transfer → wait — the agent always knows the fee before committing, and the human decides. Note CPU mining at mainnet difficulty is largely symbolic; real earnings want a GPU or a low-difficulty network.
Updating
exfer-mcp never updates itself — silently pulling new code or a new key-handling binary is a supply-chain risk, so an update is always a deliberate step.
- Check: call
exfer_check_update(or ask your agent "is there an exfer-mcp update?"). It reports the latest version, whether your version was yanked (a security recall), and the exact update command — read-only, no wallet access, works even if walletd is down. The server also checks ~once a day on startup and notes a newer/yanked release on stderr. Opt out withEXFER_MCP_NO_UPDATE_CHECK=1. - Update: bump the pinned version, optionally run
uvx exfer-mcp==<new> --prewarm(a new release may pull a newwalletdbinary — pre-fetching it keeps the next startup off the timeout path), then reload your host — re-add withuvx exfer-mcp==<new>(Claude Code) or changeargsin the config file. (Unpinneduvx exfer-mcp:uvx --refresh exfer-mcp. uv tool / pipx:uv tool upgrade/pipx upgrade.) Your wallet keys are never touched by an update. - Your wallet survives updates. An update swaps the Python code + the (re-verified) walletd binary only. Your keystore, seed,
RECOVERY_PHRASE.txt, and tokens inWALLETD_DATADIRare never read, moved, or deleted — they live in a separate directory from the disposable binary cache (~/.cache/exfer-mcp).
Safety
WALLETD_AUTH_TOKEN/WALLETD_KEYSTORE_PASSPHRASEand theWALLETD_DATADIRcontents are wallet secrets — full spend authority. The managed walletd binds loopback-only, and exfer-mcp redacts bearer tokens from forwarded logs.- No per-call human gate is built in (that's the host's job). Bound the blast radius with walletd spend caps, or keep only a small float.
- Auto-downloaded walletd binaries are run only after their SHA-256 matches a digest baked into this exfer-mcp release — re-verified on every run, not just first download. The trust anchor is the PyPI package's Trusted-Publishing provenance, not the mutable GitHub release (a co-located
SHA256SUMSwould be worthless against a release/account compromise). A mismatch or an unpinned walletd version is refused;EXFER_WALLETD_BINoverrides with a binary you built/trust.
License
MIT
Metadata
Release files for exfer-mcp 0.7.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| exfer_mcp-0.7.1.tar.gz | 87.8 kB | With provenance | Details for exfer_mcp-0.7.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| exfer_mcp-0.7.1-py3-none-any.whl | Python 3 | none | any | Details for exfer_mcp-0.7.1-py3-none-any.whl |
Total release size: 166.1 kB
Release files / exfer_mcp-0.7.1.tar.gz
| Download URL | exfer_mcp-0.7.1.tar.gz |
|---|---|
| Size | 87.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f81c76d69294a51989f238b05c58928a006151cd91394428474769baaa79085
|
|
BLAKE2b-256 checksum How to use checksums |
abe172218f83536f134864b8d37f856220722ad936391cf6e4a250177e9ab76b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.
Transparency logRelease files / exfer_mcp-0.7.1-py3-none-any.whl
| Download URL | exfer_mcp-0.7.1-py3-none-any.whl |
|---|---|
| Size | 78.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
323565eb7a1fef097ff212c871a94916c70df85611d2f7a56190402859b24718
|
|
BLAKE2b-256 checksum How to use checksums |
ebf4df77845492e8c8ff654c08ddc497c8811e8419d655a06c6253fa30812a2b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.
Transparency logSecurity for exfer-mcp 0.7.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for exfer_mcp-0.7.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.