# Secure Your Stripe MCP Server: Rate Limits and Spending Controls

> The Stripe MCP server exposes 27 tools to AI agents — refunds, charges, payment links. Add rate limits and spending caps before something goes wrong.

Published: Mon Mar 16

Canonical: https://policylayer.com/blog/secure-stripe-mcp-server

Your AI support agent just issued 200 refunds in three minutes. It misread a batch of customer complaints, decided every order from the past week deserved a full refund, and processed them all before anyone noticed. Your Stripe balance is negative, and the charges are real.

This is not hypothetical. The [Stripe MCP server](https://docs.stripe.com/mcp) exposes 27 tools to any AI agent that connects to it — and several of those tools move money.

<!--truncate-->

## What the Stripe MCP server exposes

Stripe's official `stripe/agent-toolkit` MCP server gives agents access to everything from harmless read operations to financially destructive actions. The dangerous ones:

- **`create_refund`** — issues refunds against existing charges
- **`create_invoice`** and **`finalize_invoice`** — creates and locks invoices that get sent to customers (finalised invoices cannot be edited)
- **`create_payment_link`** — generates live payment URLs
- **`cancel_subscription`** — cancels recurring revenue
- **`create_customer`**, **`create_product`**, **`create_price`**, **`create_coupon`** — bulk creation tools that can pollute your account with junk data

Read tools like `list_charges`, `retrieve_balance`, and `search_stripe_resources` are relatively safe. But the write and financial tools need constraints — and MCP does not provide any.

## Why prompt guardrails don't work

You could add "never issue more than 5 refunds per hour" to your system prompt. The agent will follow that instruction right up until it doesn't. Prompts are suggestions, not enforcement. A sufficiently long context window, an unexpected edge case, or a prompt injection can override any instruction. As we covered in [MCP Security: Beyond Guardrails](/blog/mcp-security-beyond-guardrails), the only reliable control is one that operates outside the model's decision loop — at the transport layer, [deterministically](/blog/deterministic-ai-agent-policies).

## The fix: rate limits on financial operations

[Intercept](https://github.com/policylayer/intercept) sits between your agent and the Stripe MCP server. Every `tools/call` is evaluated against a YAML policy before it reaches Stripe. Violating calls are blocked and the agent receives a clear denial message.

Here is the financial tools section from the Stripe policy:

```yaml
version: "1"
description: "Policy for stripe/agent-toolkit"
default: "allow"
tools:
    create_refund:
        rules:
          - name: "refund-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 refunds per hour — review refund activity before retrying"

    create_invoice:
        rules:
          - name: "invoice-creation-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 invoice creations per hour"

    finalize_invoice:
        rules:
          - name: "invoice-finalise-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 invoice finalisations per hour — finalised invoices cannot be edited"

    create_payment_link:
        rules:
          - name: "payment-link-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 payment links per hour"

    cancel_subscription:
        rules:
          - name: "subscription-cancel-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 subscription cancellations per hour — review before retrying"
```

Financial tools are capped at 10 per hour. Write tools like `create_customer` and `create_product` get a higher limit of 30 per hour — enough for legitimate bulk operations, tight enough to stop a runaway loop.

A global rate limit catches anything else:

```yaml
    "*":
        rules:
          - name: "global-rate-limit"
            rate_limit: "60/minute"
            on_deny: "Global rate limit: max 60 tool calls per minute across all Stripe tools"
```

The `rate_limit` shorthand expands internally to a stateful counter that tracks calls and resets at the start of each window. When the agent hits the limit, it receives the `on_deny` message as the tool response — no silent failures, no retries slipping through. For more on how this mechanism works, see [Rate Limiting MCP Tool Calls](/blog/rate-limiting-mcp-tool-calls).

The `default: "allow"` posture means read tools like `list_customers` and `retrieve_balance` pass through without restriction. If you want a stricter setup, switch to `default: "deny"` and explicitly allowlist every tool — an approach we walk through in [Spending Controls for MCP Agents](/blog/spending-controls-mcp-agent).

## Getting started

Install Intercept and point it at the Stripe MCP server:

```bash
npm install -g @policylayer/intercept
```

Then run it with the Stripe policy:

```bash
intercept -c stripe.yaml -- npx -y @stripe/mcp --tools=all
```

Every tool call from your agent now passes through the policy engine. Refund number 11 in an hour gets blocked. The 61st tool call in a minute gets blocked. Your Stripe balance stays intact.

Adjust the limits to match your operations. A high-volume support team might raise `create_refund` to 50/hour. A solo founder might drop it to 3. The point is that the limit is deterministic, transport-level, and impossible for the model to override.

[Full Stripe policy →](/policies/stripe)
