Skip to content
Blog

Exposing Your Payment Gateway as an MCP Tool Server

MCP lets agents call tools — and payments are the scariest tools you can expose. Here is how to structure an MCP tool server over your payment gateway with two-phase approval, idempotency, and least privilege.

Published on • October 13, 2026

AI Assistant

The Model Context Protocol makes it trivially easy to hand an agent a tool: define a JSON Schema, expose a handler, and any MCP client — Claude, your internal ops agent, a CI bot — can call it. Hand that agent your payment gateway and you have automated the most irreversible operation in your business.

This post is about doing it anyway, deliberately: what an MCP payment server looks like, where the spec’s security requirements bite, and how to structure tools so an agent can pay but almost never should, without a human in the loop.

The MCP surface, in one screen

MCP runs on JSON-RPC 2.0. A tools-capable server implements two methods:

  • tools/list — returns tool names, descriptions, and inputSchemas (JSON Schema).
  • tools/call — takes a tool name plus arguments; returns content, or a protocol-level error.

A minimal payment server’s tool list might be:

ToolKindPurpose
list_transactionsreadSearch payments by customer, date, status
get_transactionreadFetch one payment with full detail
create_refund_intentwrite (staged)Compute a refund; do not execute
execute_refundwrite (irreversible)Execute an approved refund intent
list_customersreadLook up customer IDs

Read tools first is not decoration. The MCP tools specification defines tool annotations — readOnlyHint, destructiveHint, idempotentHint, openWorldHint — precisely so clients can present the right affordances and users can reason about calls. Mark every read tool readOnlyHint: true, and mark irreversible writes destructiveHint: true so the host UI can demand confirmation.

The core design move: two-phase writes

Never expose a single refund(payment_id, amount) tool to an agent. Split it:

{
  "name": "create_refund_intent",
  "description": "Validate and price a refund WITHOUT executing it. Returns an intent_id for human approval.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "payment_id": { "type": "string" },
      "amount_cents": { "type": "integer" },
      "reason": { "type": "string" }
    },
    "required": ["payment_id", "amount_cents", "reason"]
  },
  "annotations": { "readOnlyHint": true }
}

The intent step validates everything — payment exists, amount within policy, refundable window open — and returns a short-lived intent_id plus a human-readable summary. The execute step takes only the intent:

{
  "name": "execute_refund",
  "inputSchema": {
    "type": "object",
    "properties": {
      "intent_id": { "type": "string" },
      "idempotency_key": { "type": "string" }
    },
    "required": ["intent_id", "idempotency_key"]
  },
  "annotations": { "readOnlyHint": false, "destructiveHint": true, "idempotentHint": true }
}

This mirrors what payment gateways themselves do with confirmation flows, and it exploits the MCP client’s natural rhythm: the agent plans, a human sees the intent summary in the approval UI, and only then does money move. If your gateway supports idempotency keys natively — Stripe, Adyen, and most modern providers do — thread them through so a retried execute_refund cannot double-pay.

Auth: your existing auth, not a new one

The spec is blunt about this: MCP servers must implement existing authentication and authorization rather than inventing parallel identity schemes, enforce least privilege, and log every tool call for audit. Concretely for payments:

  • Never ship a long-lived gateway secret to the host. The server holds the gateway credentials; the agent only ever sees your tool surface.
  • Bind the MCP session to a real user or service identity. An ops agent acting on behalf of “alice@acme.com” inherits Alice’s refund limits.
  • Encode policy in the server, not the prompt. “Agents may refund up to $50, max three per day” is a server-side check with a per-identity token bucket — a prompt instruction is a suggestion, a server check is a control.
  • Audit log everything: caller identity, tool, arguments, intent summary, final outcome. The MCP spec calls for auditability of tool invocations; for payments this is your incident-response lifeline.

Transport: stdio for local, HTTP for teams

For a developer’s local setup — an agent on a laptop reaching a gateway sandbox — stdio transport is simplest: the host spawns your server as a subprocess. For a shared production server, use the Streamable HTTP transport behind TLS, with the same token-based auth your other internal services use. Keep the gateway’s own network restrictions in place: the payment server should be able to reach only the gateway and your database.

Descriptions are the interface

Agents choose tools by reading descriptions, so write them like API docs for a tired engineer:

  • Bad: "Refunds a payment."
  • Good: "Refund a completed payment. Use only after create_refund_intent returned an intent_id that a human approved. Does not validate policy — validation happens at intent creation."

State the side effects, the prerequisites, and what the tool does not do. Vague descriptions are how an agent calls execute_refund with a made-up intent id at 2 a.m.

A checklist before you expose money to an agent

  1. Read tools annotated readOnlyHint: true; writes annotated destructiveHint: true.
  2. Two-phase write flow with human approval between intent and execution.
  3. Idempotency keys threaded to the gateway on every irreversible call.
  4. Server-side policy limits keyed to the caller’s identity.
  5. Full audit logging of every tools/call.
  6. A kill switch that revokes a session’s write scope without redeploying.
  7. Sandbox-first: run the whole agent against gateway test credentials for a week and diff its proposed actions against what a human would have done.

Further reading

Exposing payments through MCP is not about making agents richer — it is about making their financial actions inspectable. A well-designed tool server makes the safe path the easiest path, and turns “the agent moved money” from a horror story into an audited, approved, idempotent transaction.