On this page
Stripe has a well-documented REST API. This tutorial connects it to Claude Desktop so you can ask Claude about charges, balances, and customers.
What you need
- Node.js 18+ (or Python 3.10+)
- A Stripe account with an API key
- Claude Desktop installed
1. Install paso
npm install -g usepaso
2. Create the declaration
Create usepaso.yaml:
version: "1.0"
service:
name: Stripe
description: Payment processing and billing management
base_url: https://api.stripe.com/v1
auth:
type: bearer
capabilities:
- name: get_balance
description: Get the current account balance
method: GET
path: /balance
permission: read
- name: list_charges
description: List recent charges with optional filters
method: GET
path: /charges
permission: read
inputs:
limit:
type: integer
default: 10
description: Number of charges to return (1-100)
in: query
constraints:
max_value: 100
created_gte:
type: string
description: Filter charges created after this Unix timestamp
in: query
- name: get_charge
description: Get details for a specific charge
method: GET
path: /charges/{charge_id}
permission: read
inputs:
charge_id:
type: string
required: true
description: The charge ID (e.g. ch_1234)
in: path
- name: list_customers
description: List customers with optional email filter
method: GET
path: /customers
permission: read
inputs:
limit:
type: integer
default: 10
description: Number of customers to return (1-100)
in: query
constraints:
max_value: 100
email:
type: string
description: Filter by customer email
in: query
- name: create_refund
description: Refund a charge
method: POST
path: /refunds
permission: write
consent_required: true
inputs:
charge:
type: string
required: true
description: The charge ID to refund
amount:
type: integer
description: Amount to refund in cents (partial refund). Omit for full refund.
permissions:
read:
- get_balance
- list_charges
- get_charge
- list_customers
write:
- create_refund
forbidden:
- delete_customer
- update_account
Five capabilities. Four reads, one write with consent required. Destructive operations are in forbidden.
3. Validate
usepaso validate --strict
valid (Stripe, 5 capabilities, 0 regrets)
4. Test
usepaso test --all --dry-run
ok get_balance GET https://api.stripe.com/v1/balance
ok list_charges GET https://api.stripe.com/v1/charges?limit=10
ok get_charge GET https://api.stripe.com/v1/charges/{charge_id}
ok list_customers GET https://api.stripe.com/v1/customers?limit=10
ok create_refund POST https://api.stripe.com/v1/refunds
5 passed. 5 capabilities total.
All requests build correctly. No API calls were made.
5. Connect to Claude Desktop
One command. paso writes the config for you.
usepaso connect claude-desktop
Added "Stripe" in Claude Desktop config.
Config: ~/Library/Application Support/Claude/claude_desktop_config.json
Restart Claude Desktop to connect.
Restart Claude Desktop.
6. Try it
Open Claude Desktop and ask:
- “What’s my current Stripe balance?” Claude calls
get_balanceand returns your available and pending amounts. - “Show me the last 5 charges.” Claude calls
list_chargeswithlimit=5. - “Find charges from customer alice@example.com.” Claude calls
list_customersto find the customer, thenlist_chargesfiltered by customer. - “Refund charge ch_3ABC123.” Claude shows a confirmation dialog (because
consent_required: true), then callscreate_refund.
A note on API key scope
Use a restricted API key. Stripe lets you create keys with specific permissions:
- Go to Stripe Dashboard > Developers > API keys
- Create a restricted key
- Enable only the permissions your MCP server needs (Read for charges, customers, balance. Write for refunds.)
- Use this restricted key as
USEPASO_AUTH_TOKEN
A restricted key combined with paso’s permission model gives you two layers of access control. The key limits what the API allows. paso limits what the agent can call.
Extend it
Add more capabilities as you need them. Each one is a few lines of YAML:
- name: list_invoices
description: List invoices with optional status filter
method: GET
path: /invoices
permission: read
inputs:
limit:
type: integer
default: 10
in: query
status:
type: enum
values: [draft, open, paid, void, uncollectible]
description: Filter by invoice status
in: query
Add it to the capabilities list, run usepaso validate, restart Claude Desktop. No TypeScript. No new handler functions.
Questions
Can I use a test mode key?
Yes. Use sk_test_... instead of sk_live_.... All requests go to Stripe’s test environment. Good for trying this out without touching real data.
What about webhook events? paso exposes REST endpoints as MCP tools. Webhooks are push-based and don’t map to the request-response model. For webhook handling, use Stripe’s SDK or a separate service.
Can I do this with Stripe’s OpenAPI spec instead?
Yes. usepaso init --from-openapi can generate the declaration from Stripe’s public OpenAPI spec. The spec has hundreds of endpoints, so you’ll want to curate the output. See OpenAPI to MCP in 60 Seconds.
Related:
- The Complete Guide to MCP Servers. the full reference
- OpenAPI to MCP in 60 Seconds to generate from Stripe’s OpenAPI spec
- What Happens When an Agent Calls DELETE on permission boundaries
- Five Ways to Test Before You Ship for the full testing workflow