Agents
MCP server
The same service, for AI agents. MCP is the protocol an agent uses to discover tools and call them; this server publishes 33 of them, plus a few resources and two guided prompts. Under the hood it is JSON-RPC 2.0 over HTTP, one POST per call, no sessions.
Connect#
The endpoint is https://sandbox.whire.ai/mcp. Send your key as X-API-Key (not needed while the sandbox runs with authentication off).
| Client | How |
|---|---|
| MCP Inspector | npx @modelcontextprotocol/inspector → Add server → streamable-http → the URL → Settings → Custom Headers → X-API-Key |
| Claude Code | claude mcp add --transport http whire https://sandbox.whire.ai/mcp --header "X-API-Key: $KEY" |
| A client with no URL field | npx mcp-remote https://sandbox.whire.ai/mcp --header "X-API-Key: $KEY" |
| Your own code | any MCP SDK, transport streamable-http |
From code:
claude mcp add --transport http whire https://sandbox.whire.ai/mcp --header "X-API-Key: $KEY"
# then, in a session:
# "Sign up Merchant B.V. as a payer and authorize 50 EUR to Acme under mandate SHOP-001"from whire import WhireClient
async with WhireClient(api_key="your-api-key", environment="sandbox") as client:
tools = await client.mcp.list_tools()
print([tool.name for tool in tools])
receipt = await client.mcp.call_tool("authorize_payment", {
"mandateId": "...", "amount": 50, "beneficiaryId": "...",
})
print(receipt["decision"])from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
URL = "https://sandbox.whire.ai/mcp"
HEADERS = {"X-API-Key": "your-api-key"}
async with streamablehttp_client(URL, headers=HEADERS) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([tool.name for tool in tools.tools])
result = await session.call_tool("authorize_payment", {
"mandateId": "...", "amount": 50, "beneficiaryId": "...",
})
print(result.structuredContent["decision"])import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(
new StreamableHTTPClientTransport(new URL("https://sandbox.whire.ai/mcp"), {
requestInit: { headers: { "X-API-Key": "your-api-key" } },
})
);
const { tools } = await client.listTools();
console.log(tools.map((tool) => tool.name));
const result = await client.callTool({
name: "authorize_payment",
arguments: { mandateId: "...", amount: 50, beneficiaryId: "..." },
});
console.log(result.structuredContent);import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Authorize 50 EUR to Acme Supplies under mandate SHOP-001 and tell me the decision.",
options: {
mcpServers: {
whire: { type: "http", url: "https://sandbox.whire.ai/mcp", headers: { "X-API-Key": process.env.WHIRE_KEY! } },
},
allowedTools: ["mcp__whire__authorize_payment", "mcp__whire__list_payment_mandates"],
},
})) {
if (message.type === "result") console.log(message.result);
}Building an agent on OpenAI or Anthropic? The agent toolkit serves these same tools to any function-calling model, with a confirmation step before money moves.
Or by hand — every call is one JSON-RPC message:
POST /mcp
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }POST /mcp
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "authorize_payment",
"arguments": { "mandateId": "…", "amount": 50, "beneficiaryId": "…" } } }Two headers are required by the transport: Content-Type: application/json and Accept: application/json, text/event-stream. Replies are plain JSON; GET and DELETE answer 405 because there is nothing to stream and no session to end.
Tools#
Every tool returns structured JSON (structuredContent) as well as text, and carries a JSON schema for its arguments — that is what the agent's model reads.
Payers — the customer whose money moves
| Tool | Does |
|---|---|
register_payer |
sign up a payer; opens pending_verification |
activate_payer_account |
record that verification passed; the payer may now sign mandates |
suspend_payer_account |
no new mandates; existing ones stay until revoked |
add_funding_source, set_default_funding_source |
the accounts a payer can be debited from |
get_payer, list_payers |
read |
Authorization — the decision
| Tool | Does |
|---|---|
authorize_payment |
may this payment proceed under this mandate? Returns a signed receipt |
verify_authorization_receipt |
check a receipt: signature, expiry, decision |
get_capabilities |
can this deployment authorize, settle, and is settlement simulated |
Beneficiaries — who can be paid
| Tool | Does |
|---|---|
validate_iban |
format and checksum |
create_beneficiary, get_beneficiary |
a payee by IBAN |
register_user, add_payment_method, set_default_payment_method, get_user, list_users, create_beneficiary_for_user |
people with several ways to be paid |
Mandates — the standing authorization (Mandates)
| Tool | Does |
|---|---|
create_payment_mandate |
sign one: payee, per-payment cap, total cap, window |
validate_payment_mandate |
run the ten checks against a possible payment |
revoke_payment_mandate |
stop it |
list_payment_mandates |
read |
Payouts — the lifecycle
| Tool | Does |
|---|---|
create_payout_draft |
a payout under a mandate |
submit_payout_for_review |
to KYC; with a provider configured the decision arrives on its own |
record_provider_event |
a provider decision, when you play the provider |
confirm_payout |
human confirmation |
execute_payout |
send it through the rail; refuses when there is none |
get_payout_status, list_payouts |
read, with history |
Simulation and x402
| Tool | Does |
|---|---|
get_simulation |
the simulated rail's scenarios, delay and accounts |
quote_x402_resource |
read a 402 price; commits nothing |
pay_x402_resource |
pay a 402-gated URL under a mandate (x402) |
The two x402 payer tools are offered only on a deployment that can settle; without a rail the list is 31.
Resources and prompts#
| Resource | Holds |
|---|---|
config://provider |
capabilities and the settlement rail |
policy://limits |
the mandate rules this service enforces |
payout://{payoutId}, mandate://{mandateId} |
any record by id |
Two prompts, run_agent_payout_flow and run_payment_mandate_flow, walk a client through the payout lifecycle and the mandate checks step by step.
A typical agent flow#
The mandate is what limits the agent: it can only authorize what the payer signed for. execute_payout and pay_x402_resource are marked as destructive in their tool metadata, so a well-behaved agent asks a human before calling them.
Same data as the REST API#
The MCP server and the REST API share one store. A payer signed up over REST is visible to list_payers a moment later, and the other way round.