Give your agent a bank.
One MCP endpoint. A dedicated account with an IBAN, cards, payments, payouts and a ledger, under a policy the agent can't change.
https://mcp.navoka.com
transport: MCP over HTTP (streamable)
auth: OAuth 2.1 + PKCE
scopes: ledger:read policy:read cards:issue
payments:write payouts:writehttps://mcp.navoka.comThe endpoint.
https://mcp.navoka.com
transport: MCP over HTTP (streamable)
auth: OAuth 2.1 + PKCE (holder authorizes once; agent session receives a scoped token)
scopes: ledger:read policy:read cards:issue payments:write payouts:writehttps://mcp.navoka.comClaude Code
claude mcp add --transport http navoka https://mcp.navoka.comAny MCP client
add the URL; on first call the holder is sent to authorize.
ChatGPT / Claude / Grok
consumer paths on Connect.
The holder authorizes. The agent works inside what the holder allowed. There is no API key that grants more than the policy.Isolation
The tools.
| Capability | Does | Amounts | Held when |
|---|---|---|---|
get_balance | Balance and available budget by currency | — | never |
get_policy | Read the holder's policy (limits, allowlist, mode) | — | never |
issue_card | Issue a debit card to the agent (or read its existing one); returns a token reference, never a PAN. Every authorization on it is checked against the policy | — | never (the policy is enforced at authorization) |
pay_invoice | Parse or accept an invoice and pay by ACH / SEPA / Faster Payments | {value, currency} | new payee · above threshold · over ceiling |
send | Transfer to a person or business; rail chosen or auto (ach, sepa_instant, fps, swift, usdc, eurc, push_to_card) | {value, currency} | new payee · above threshold · country not allowed |
payout | Batch payment from a list or sheet; one approval for the batch | per-line | new payees · batch above threshold · monthly cap |
get_ledger | Rows with what, rule, approver, reason, line_id, timestamps | — | never |
get_line | Status of one line_id: held · approved · declined · settled | — | never |
set_policy | Holder-only. Refused from an agent session; attempt is logged. | — | always, for agents |
Every write tool takes
reason(string, required).It's stored on the ledger row verbatim and is what the holder reads at approval and in a dispute.
Every write tool returns a
line_idand astatus.heldis a normal outcome, not an error. Pollget_lineor subscribe to the webhook.
The policy.
The mandate as JSON. Written by the holder, readable by the agent, enforced at the account — not in your prompt.
{
"policy_id": "pol_7f3a",
"currency": "EUR",
"monthly_budget": { "value": 500.00, "currency": "EUR" },
"approve_above": { "value": 250.00, "currency": "EUR" },
"per_transaction_ceiling": { "value": 600.00, "currency": "EUR" },
"velocity": { "count_per_day": 10, "value_per_day": { "value": 800.00, "currency": "EUR" } },
"allowlist": {
"merchants": ["amazon.es", "booking.com", "farfetch.com", "spotify.com", "netflix.com"],
"payees": ["pay_iberdrola", "pay_anna_reid", "pay_studio_marr"]
},
"countries": ["ES", "GB", "US", "AE"],
"mcc": { "allow": ["5411", "4722", "5734", "4900"], "deny": ["7995", "6011"] },
"mode": "run_inside_limit",
"card": { "id": "card_4412", "status": "active" },
"kill_switch": false
}Anything the agent requests is evaluated against this at the account. A request outside it returns status: held with reason_code (new_payee, above_threshold, merchant_not_allowed, country_not_allowed, mcc_denied, velocity, budget_exceeded) — never a silent failure.Limits and approvals
The same call, two views.
{
"tool": "pay_invoice",
"payee": "Studio Marr",
"iban": "ES91••••4402",
"amount": { "value": 1250.00, "currency": "EUR" },
"reference": "INV-2041",
"reason": "Invoice INV-2041, due 15 Oct",
"policy_id": "pol_7f3a"
}{ "line_id": "ln_01J9K2…", "status": "held", "reason_code": ["new_payee", "above_threshold"] }{ "line_id": "ln_01J9K2…", "status": "approved", "approver": "holder", "approved_at": "2026-10-01T09:41:12Z", "rail": "sepa_instant" }No PAN, no full IBAN in either view. The token and the vault handle that.Security
Held, approved, declined.
heldevaluated, outside policy, waiting for the holder. Your agent should tell the user why (the
reason_codeis human-readable) and stop. Don't retry; don't split the amount to get under the threshold — velocity and budget catch it, and it's logged.approvedthe holder tapped. Execution follows;
settledwhen the rail confirms.declinednothing left the account; no authorization was made.
frozenkill switch. All write tools return
frozenuntil the holder unpauses.
Webhook: line.held, line.approved, line.declined, line.settled, policy.updated, account.frozen.Sandbox
Sandbox.
https://mcp.sandbox.navoka.com
# same tools, synthetic rails, instant settlement
# test holder auto-approves after 5 s
# or never, with: X-Navoka-Test-Hold: always
# test cards decline on merchant: decline.testhttps://mcp.sandbox.navoka.comhttps://mcp.sandbox.navoka.com — same tools, synthetic rails, instant settlement, a test holder who auto-approves after 5 seconds (or never, with X-Navoka-Test-Hold: always). Test cards decline on merchant decline.test. No KYC, no real money.
Isolation.
One agent, one VM.
Each agent runs in its own isolated virtual machine with its own encrypted storage.
Token, never PAN.
The agent's debit card is provisioned as a network token;
issue_cardreturns a token reference, never card data. The policy is applied at every authorization on it.Policy at the account.
Enforcement doesn't depend on your prompt or your client. A jailbroken agent still gets
held.
Full pageSecurity
Fees.
Sandbox is free. Rail fees are returned on every write call before execution (quote field) so your agent can show them to the holder.
Questions.
How do I give my agent a bank account via MCP?
Is this an API or an MCP server?
api.navoka.com/v1. Either way the policy is enforced at the account, so the client you use doesn't change what's allowed.What happens when my agent asks for something outside the policy?
status: held with a readable reason_code — new payee, above threshold, merchant not allowed, country not allowed, category denied, velocity, budget exceeded. Nothing has moved. The holder sees the same line with Approve and Decline. Your agent should explain and wait, not retry or split the amount; both are caught and logged.Can my agent change the policy if the user asks it to?
set_policy is holder-only and is refused from an agent session; the attempt is logged. The user changes limits on the limits screen or in the chat with an explicit confirmation bound to their identity. This is deliberate: a policy the agent could edit is a policy a prompt injection could edit.Does my agent ever see a card number or a full IBAN?
issue_card returns a token reference and the card's status; the PAN is provisioned to the network token from the issuer's vault and never enters your process. IBANs are masked in every response. Receipts and ledger rows carry the payee name, amount, rule, approver and reason — enough to reconcile, nothing to leak.Is there a sandbox and what does it cost?
quote before execution, so your agent can show them to the holder.Get an endpoint.
Sandbox in minutes. Production when the holder says so.