# Monetize your Model Context Protocol (MCP) server

Charge AI agents for one-time payments using MPP.

This guide shows how to charge AI agents for one-time purchases, such as service bookings, donations, or digital goods, by using a Model Context Protocol (MCP) server, Stripe, and the [Machine Payments Protocol (MPP)](https://docs.stripe.com/payments/machine/mpp.md).

Listing your MCP server in the [Stripe Directory](https://docs.stripe.com/directory.md) makes it discoverable to AI agents, so they can find and pay you without requiring a human to search first. This approach keeps you at the center of the transaction. Payments settle through your existing Stripe or Connect setup, so you keep your receipts, fees, and customer relationship. The same link also falls back to your existing checkout or donation form for human users, so you don’t need to change how you currently accept payments to support agents.

The approach in this guide is experimental and works with AI agents that support MCP and can make HTTP requests that handle MPP. The payment flow runs over standard HTTP, so it isn’t limited to MCP. Any agent that can make HTTP requests and handle MPP can use it. Many agents use MCP to discover tools, which is why we use it in this integration.

This flow uses [Shared Payment Tokens](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md), which are credentials provisioned by a user’s Link agent wallet or through an API. Shared payment tokens are one way for a customer to pay. The same MPP-based approach also works with other payment methods, such as stablecoins, as long as the customer has a compatible wallet. Learn more about the [MPP payment lifecycle](https://docs.stripe.com/payments/machine/mpp.md).

> Nonprofits and fundraising platforms can use this flow to accept agent-initiated donations. The MPP receipt confirms the payment, but it doesn’t replace any donation acknowledgment or tax receipt that the nonprofit or platform must provide.

## Before you begin

Make sure you have the following set up before you start:

- Access to [Shared Payment Tokens](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md) and a valid Stripe network ID.
- A fulfillment flow that can validate requests and complete purchases, such as checking availability, confirming inventory, or recording a donation.
- These environment variables:
  - `BASE_URL`: The base URL for your application
  - `MPP_SECRET_KEY`: Your MPP secret key
  - `STRIPE_NETWORK_ID`: The ID representing your [Stripe profile](https://dashboard.stripe.com/profiles)

If you use [Connect](https://stripe.com/connect) to route funds to connected accounts, make sure you have the connected account ID available.

## Understand how payment works

When an AI agent calls one of your MCP tools, you can collect payment before you return a result.

When MPP defines the HTTP payment handshake:

1. The client requests a resource without payment.
2. Your server returns an HTTP `402` response with a payment challenge.
3. The client obtains an SPT credential and retries the request.
4. Your server verifies payment and returns the resource with a receipt.

In this pattern, your MCP tool validates the request, then returns a payment link. That link points to a separate HTTP endpoint that handles MPP. The agent posts to the URL, and MPP handles the challenge and credential flow at the HTTP layer.

The same URL can also work for human users. If a browser opens it, the endpoint recognizes the `Accept: text/html` header and redirects to a checkout page that you control and prefills the relevant parameters.

## Review the flow

The following sequence diagrams show how the same integration supports both the agent flow and browser fallback.

#### Agent flow

An agent calls an MCP tool, receives a payment link, and uses an SPT to pay for and complete the purchase. (See full diagram at https://docs.stripe.com/agentic-commerce/monetize-mcp)

```text
[Agent] -- Call the MCP tool --> [MCP tool]
[MCP tool] -- Validate the request --> [MCP tool]
[MCP tool] -- Return paymentLink --> [Agent]
[Agent] -- POST without a credential --> [Endpoint]
[Endpoint] -- Return a 402 payment challenge --> [Agent]
[Agent] -- Request an SPT --> [Agent wallet]
[Agent wallet] -- Return the SPT --> [Agent]
[Agent] -- Retry with the SPT --> [Endpoint]
[Endpoint] -- Verify payment and complete the purchase --> [Endpoint]
[Endpoint] -- Return confirmation and an MPP receipt --> [Agent]
```

#### Browser fallback

A customer opens the payment link in a browser and is redirected to a prefilled checkout page that the seller controls. (See full diagram at https://docs.stripe.com/agentic-commerce/monetize-mcp)

```text
[Customer] -- Open the payment link --> [Browser]
[Browser] -- Request with Accept: text/html --> [Endpoint]
[Endpoint] -- Redirect to a prefilled checkout page that you control --> [Browser]
```

## Define the MCP tool

The following example shows the MCP tool definition. It validates the purchase request and returns a payment link without handling payment directly.

```typescript
server.registerTool(
  'create_purchase_link',
  {
    description:
      'Returns a payment link for a one-time purchase. ' +
      'POST to the link with an MPP credential to pay automatically, ' +
      'or open it in a browser to pay with a card.',
      inputSchema: {
      itemId: z.string(),
      quantity: z.number().int().positive(),
      customerName: z.string().optional(),
      customerEmail: z.string().optional(),
      notes: z.string().optional(),
    },
  },
  async ({ itemId, quantity, customerName, customerEmail, notes }) => {
    const params = new URLSearchParams({ ... })
    const paymentLink = `${process.env.BASE_URL}/api/purchase?${params}`

    // Do your normal business logic
    const item = await getItem(itemId)
    if (!item) throw new Error('Item not found')
    await validatePurchase({ ... })

    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          // This link must be MPP enabled
          paymentLink,
          instructions: {
            agent: `POST to paymentLink. Server returns 402 on first call — obtain an SPT for networkId "${process.env.STRIPE_NETWORK_ID}" and retry.`,
            browser: 'Open paymentLink in a browser to pay with a card.',
          },
          item: { title: item.title, quantity, price: formatCents(item.priceCents) },
        }, null, 2),
      }],
    }
  },
)
```

## Create the payment endpoint

The following example shows the HTTP endpoint that handles MPP payments for agents and redirects browsers to a checkout flow that you control.

```typescript
import { Mppx, stripe as mppStripe } from 'mppx/server'

// GET or POST /api/purchase?itemId=...&quantity=...
async function handler(request: Request): Promise<Response> {
  // Secret used to secure payment challenges
  // https://mpp.dev/protocol/challenges#challenge-binding
  const mppSecretKey = crypto.createHmac("sha256", process.env.STRIPE_SECRET_KEY!).update("mpp-challenge-signing").digest("base64");
  const payment = Mppx.create({
    methods: [
      mppStripe.charge({
        client: stripe,
        // Use your Stripe network ID here.
        //
        // For platforms using connect: for direct charges, use the connected
        // account's network ID; for destination charges, use your
        // platform's network ID.
        networkId: networkId,
        paymentMethodTypes: ['card', 'link'],
      }),
    ],
    secretKey: mppSecretKey,
  })
  const url = new URL(request.url)
  const params = url.searchParams

  // Browser redirect — send humans to a checkout page you control
  const accept = request.headers.get('Accept') ?? ''
  if (accept.includes('text/html')) {
    return Response.redirect(`/checkout/${params.get('itemId')}?${params}`)
  }

  // Agent/programmatic path — MPP 402-challenge flow
  const item = await getItem(Number(params.get('itemId')))
  if (!item) return Response.json({ error: 'Not found' }, { status: 404 })

  const result = await payment.stripe.charge({
    amount: centsToAmount(item.priceCents),
    currency: 'usd',
    decimals: 2,
    description: item.title,
    // Connect parameters — pass-through to the underlying PaymentIntent.
    // Use whichever charge type matches your existing Connect integration;
    // don't mix the two.
    application_fee_amount: 250,

     // Direct charge — the PaymentIntent is created directly on the
    // connected account. Pass the connected account ID as `stripeAccount`
    // instead of `transfer_data`/`on_behalf_of`.
    stripeAccount: connectedAccountId,

    // Destination charge — the PaymentIntent is created on your platform
    // account and funds move to the connected account after the charge.
    // `on_behalf_of` is optional; set it if you want the connected
    // account's statement descriptor, MCC, etc. to apply to the charge.
    // transfer_data: { destination: connectedAccountId },
    // on_behalf_of: connectedAccountId,

  })(request)

  if (result.status === 402) return result.challenge

  // Payment confirmed — run your business logic
  const order = await completeOrder(params)
  return result.withReceipt(Response.json({ success: true, orderId: order.id }))
}
```

## List your MCP server on the Stripe Directory

When your MCP server is ready to share externally, contact your Stripe representative or [Stripe Support](https://support.stripe.com/) with the server URL and the relevant integration details to ask about listing it in the Stripe Directory.

## Test your integration

You can test the full agent payment flow end to end by connecting your MCP server and the Link agent wallet to an agent harness that you control, such as [Claude Code](https://docs.claude.com/en/docs/claude-code), then asking the agent to complete a payment. When everything is configured correctly, the agent can use your MCP server and the Link agent wallet independently to discover your tool, call the payment endpoint, obtain a credential, and complete the purchase.

### Add your MCP server

Add your MCP server to an agent harness that you control. For Claude Code, add it to your `.mcp.json` file:

```json
{
  "mcpServers": {
    "your-mcp-server": {
      "command": "npx",
      "args": ["your-mcp-server"]
    }
  }
}
```

### Add the Link agent wallet skill

Add the [Link agent wallet skill](https://github.com/stripe/link-cli) so the agent can provision a shared payment token to pay:

```bash
npx skills add stripe/link-cli
```

### Configure test mode

Add an instruction to your agent’s context, such as in `CLAUDE.md` or the system prompt, that identifies the flow as a test. This signals the Link agent wallet to create shared payment tokens in a [sandbox](https://docs.stripe.com/sandboxes.md), which return test credentials and don’t charge the underlying payment method.

With that configuration in place, make sure that your agent passes the `--test` flag when it creates a spend request so the entire flow runs against test credentials end to end.

### Ask the agent to complete a payment

Prompt the agent to use your MCP server to make a purchase.

When your integration is configured correctly, the agent calls your MCP tool, obtains a sandbox credential from the Link agent wallet, and completes the payment.

### Verify expected behavior

Verify these behaviors during testing:

- The order is completed in your system.
- The payment succeeds.
- The link shows a payment interface when you open it in a browser.
- If you use [Connect](https://docs.stripe.com/connect.md), your integration routes funds to the expected connected account.

You can also test the payment endpoint directly, open it in a browser, or use the [Link CLI](https://github.com/stripe/link-cli) to make an MPP payment request manually.

## See also

- [Link agent wallet](https://github.com/stripe/link-cli)
- [Machine Payments Protocol (MPP)](https://docs.stripe.com/payments/machine/mpp.md)
- [Shared Payment Tokens (SPT)](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md)
