A Model Context Protocol (MCP) server that provides AI assistants with access to the Blink Bitcoin and Lightning Network API.
- Lightning Network: Create and pay invoices, send to Lightning addresses
- On-Chain Bitcoin: Generate addresses, send transactions, estimate fees
- Stablesats (USD): Full support for USD-denominated wallets
- Intraledger Transfers: Free instant transfers between Blink users
- Webhooks: Register callbacks for payment notifications
- Real-time Subscriptions: Monitor invoice status and account updates
- Price Data: Get real-time and historical Bitcoin prices
- L402 Consumer: Discover, pay for, and cache tokens for L402-gated APIs
- L402 Producer: Create Lightning paywalls and verify payment tokens
- L402 Discovery: Search l402.directory and 402index.io for paid APIs
- Node.js 18+
- A Blink wallet account (dashboard.blink.sv)
- A Blink API key
git clone https://github.com/yourusername/blink-mcp.git
cd blink-mcp
npm install
npm run build- Log in to your Blink wallet at dashboard.blink.sv
- Go to Settings > API Keys
- Click Create API Key
- Select the permissions you need:
- Read: View balances, transactions, and account info
- Receive: Create invoices and addresses to receive payments
- Write: Send payments and modify account settings
- Copy the generated API key
Set the following environment variables:
# Required: Your Blink API key
export BLINK_API_KEY=blink_xxxxxxxxxxxxx
# Optional: Network to use (default: mainnet)
export BLINK_NETWORK=mainnet # or 'staging' for testnetAdd to your Claude Desktop configuration (~/.config/claude/claude_desktop_config.json on Linux/Mac or %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"blink": {
"command": "node",
"args": ["/path/to/blink-mcp/dist/index.js"],
"env": {
"BLINK_API_KEY": "your_api_key_here"
}
}
}
}Or if installed globally via npm:
{
"mcpServers": {
"blink": {
"command": "blink-mcp",
"env": {
"BLINK_API_KEY": "your_api_key_here"
}
}
}
}The server uses stdio transport. Run it with:
BLINK_API_KEY=your_key node dist/index.js| Tool | Description |
|---|---|
get_account_info |
Get current user account information |
get_wallets |
List all wallets with balances |
get_wallet_balance |
Get balance of a specific wallet |
get_transactions |
Get transaction history (paginated) |
get_transaction_by_id |
Get specific transaction details |
get_account_limits |
View withdrawal and transfer limits |
set_default_wallet |
Set default wallet (BTC or USD) |
set_display_currency |
Set display currency preference |
get_realtime_price |
Get current Bitcoin price |
get_price_history |
Get historical price data |
convert_currency |
Convert between fiat and Bitcoin |
get_supported_currencies |
List supported currencies |
lookup_user_wallet |
Find wallet by Blink username |
check_username_available |
Check username availability |
set_username |
Set/update your username |
get_authorization_scopes |
View API key permissions |
get_network_info |
Get Lightning node info |
| Tool | Description |
|---|---|
create_invoice |
Create BTC Lightning invoice |
create_invoice_usd |
Create USD-denominated invoice |
create_invoice_no_amount |
Create open (any amount) invoice |
cancel_invoice |
Cancel unpaid invoice |
get_invoice_status |
Check invoice status by hash |
get_invoice_status_by_request |
Check status by bolt11 |
pay_invoice |
Pay a Lightning invoice |
pay_invoice_with_amount |
Pay open invoice with amount |
pay_lightning_address |
Send to Lightning address |
pay_lnurl |
Pay via LNURL |
estimate_lightning_fee |
Estimate payment fee |
estimate_lightning_fee_no_amount |
Estimate fee for open invoice |
| Tool | Description |
|---|---|
create_onchain_address |
Generate new receiving address |
get_current_onchain_address |
Get current address |
send_onchain |
Send BTC on-chain |
send_onchain_all |
Sweep entire balance |
send_onchain_usd |
Send from USD wallet on-chain |
estimate_onchain_fee |
Estimate BTC transaction fee |
estimate_onchain_fee_usd |
Estimate USD wallet fee |
| Tool | Description |
|---|---|
send_to_wallet |
Send BTC to wallet ID (free, instant) |
send_to_wallet_usd |
Send USD to wallet ID |
send_to_username |
Send to Blink username |
| Tool | Description |
|---|---|
list_webhooks |
List registered webhooks |
add_webhook |
Register webhook endpoint |
remove_webhook |
Remove webhook |
subscribe_invoice_status |
Subscribe to invoice updates |
subscribe_invoice_status_by_hash |
Subscribe by payment hash |
subscribe_account_updates |
Subscribe to all account events |
subscribe_price_updates |
Subscribe to price changes |
list_subscriptions |
List active subscriptions |
cancel_subscription |
Cancel a subscription |
cancel_all_subscriptions |
Cancel all subscriptions |
| Tool | Description |
|---|---|
l402_discover |
Probe a URL for L402 payment requirements (no payment) |
l402_pay |
Access an L402-protected URL, paying automatically via Blink |
l402_store |
Manage the L402 token cache (~/.blink/l402-tokens.json) |
l402_challenge_create |
Create an L402 payment challenge (invoice + signed macaroon) |
l402_payment_verify |
Verify an L402 payment token (preimage + HMAC signature + caveats) |
l402_search |
Search L402 service directories (l402.directory or 402index.io) |
User: What's my Bitcoin balance?
Assistant: [Uses get_wallets tool]
Your BTC wallet has 50,000 sats and your USD wallet has $12.50.
User: Create an invoice for 10,000 sats
Assistant: [Uses create_invoice tool]
Here's your Lightning invoice for 10,000 sats:
lnbc100u1p...
User: Send 1000 sats to user@blink.sv
Assistant: [Uses pay_lightning_address tool]
Payment of 1,000 sats sent successfully to user@blink.sv!
User: Let me know when invoice lnbc... is paid
Assistant: [Uses subscribe_invoice_status tool]
I'm now monitoring the invoice. I'll notify you when it's paid.
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run in development mode
npm run dev
# Type checking
npm run typecheck
# Linting
npm run lintsrc/
├── index.ts # MCP server entry point
├── client.ts # Blink GraphQL client
├── types.ts # TypeScript type definitions
├── graphql/
│ └── operations.ts # GraphQL queries, mutations, subscriptions
└── tools/
├── wallet.ts # Wallet and account tools
├── lightning.ts # Lightning Network tools
├── onchain.ts # On-chain Bitcoin tools
├── intraledger.ts # Blink-to-Blink transfer tools
├── webhooks.ts # Webhook and subscription tools
└── l402.ts # L402 consumer, producer, and discovery tools
This MCP server wraps the Blink GraphQL API. For detailed API documentation, visit:
- Blink Agent Playbook: Canonical AI agent API reference — order of operations, safety constraints, and verification checklist.
- Blink Developer Docs
- Blink API Playground
- llms.txt: Machine-readable discovery metadata for AI agents.
- API Key Security: Never commit your API key to version control
- Permission Scoping: Use the minimum required permissions for your use case
- Write Operations: Be cautious with write permissions as they allow sending funds
- Environment Variables: Store API keys in environment variables, not in config files
Because this server holds a Blink API key and exposes tools that move funds, an agent processing untrusted content (a web page, email, invoice memo, etc.) could be steered into making a payment via indirect prompt injection. To mitigate this, every money-moving tool passes through a central spend guard before it executes, enforcing (in order): recipient allowlist → per-transaction cap → rolling 24h budget → human confirmation.
The guard is safe-by-default: with no configuration, all spend tools require explicit confirmation before running.
| Variable | Default | Effect |
|---|---|---|
BLINK_REQUIRE_CONFIRMATION |
true |
Require confirmation before any spend |
BLINK_APPROVAL_MODE |
fail-closed |
Fallback when the client can't do elicitation: fail-closed or stderr-code |
BLINK_MAX_PAYMENT_SATS |
(none) | Per-transaction cap in sats (authoritative for all spends, incl. l402_pay) |
BLINK_DAILY_BUDGET_SATS |
(none) | Rolling 24h spend cap in sats (durable across restarts) |
BLINK_RECIPIENT_ALLOWLIST |
(none) | Allowed recipients (ln addr / username / btc addr / wallet id) |
BLINK_WEBHOOK_ALLOWLIST |
(none) | Allowed webhook callback hostnames |
BLINK_L402_MAX_SATS |
1000 |
Mandatory default cap for l402_pay |
BLINK_L402_HOST_ALLOWLIST |
(none) | Required for L402 network access; fail-closed when unset |
Confirmation flow. When the MCP client supports elicitation, the guard prompts inline and blocks until the user accepts — this is the preferred, injection-safe path.
For clients without elicitation support, a token returned through the tool
channel is not a human boundary (a prompt-injected loop could simply echo it
back), so there is no such token. Instead BLINK_APPROVAL_MODE controls the
fallback:
fail-closed(default): the spend is refused.stderr-code: the server prints a one-time approval code to its console (stderr) — which the model cannot read — and the human operator re-issues the tool call withapproval_code="<code>". The code never enters model context, so injection alone cannot obtain it.
Amount enforcement. BLINK_MAX_PAYMENT_SATS and BLINK_DAILY_BUDGET_SATS
are enforced for every spend tool. Fixed-amount Lightning invoices are decoded
from the bolt11 before payment so pay_invoice is subject to the same caps and
budget as amount-carrying tools. For l402_pay, whose amount is only known
after fetching the invoice, the caps are re-checked after decoding and before
payment. The 24h budget is debited only on a successful payment (failed
attempts never burn budget) and is persisted to a 0600 ledger at
~/.blink/spend-ledger.json so it survives restarts.
Sweeps and undecodable amounts. When a per-transaction cap or daily budget
is configured, send_onchain_all (full-balance sweep) and any pay_invoice
whose bolt11 amount cannot be decoded are refused — the amount cannot be
verified against the cap, so the guard fails closed rather than bypassing it.
With no caps configured, these still require confirmation.
L402 hardening. l402_pay enforces a mandatory spend cap
(max_amount_sats or BLINK_L402_MAX_SATS) plus the global caps above, and
refuses invoices whose amount cannot be decoded. Server-side L402 fetches
require BLINK_L402_HOST_ALLOWLIST (fail-closed when unset), are HTTPS-only,
reject private/loopback/link-local addresses, and re-validate every redirect
hop — mitigating DNS-rebinding SSRF without socket pinning. Cached L402 tokens
are stored 0600, and l402_store get masks payment secrets unless called
with reveal: true.
Webhooks. add_webhook requires an HTTPS URL and, when
BLINK_WEBHOOK_ALLOWLIST is set, a listed hostname.
Make sure you've set the BLINK_API_KEY environment variable with your API key.
Your API key may not have the required permissions. Check your key's scopes in the Blink wallet settings.
Real-time subscriptions require a stable connection. Check your network and firewall settings.
MIT
Contributions are welcome! Please open an issue or submit a pull request.