I Built a Production-Grade Stripe MCP Server in Python — Here's What I Learned

Published: (February 12, 2026 at 09:32 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

The Gap I Found

Stripe has an official MCP server, but it’s TypeScript‑only for local use. The community Python alternatives are basic—typically 5–8 tools, API keys hard‑coded in environment variables, no tests, and outdated MCP spec versions.

Meanwhile, the MCP spec had evolved significantly:

  • November 2025 spec introduced async Tasks and structured outputs.
  • OAuth 2.1 became the standard (replacing API keys), but only ~8.5 % of servers implement it.
  • The Python SDK added full resource‑server support with RFC 9728.

I saw an opportunity to build something that could actually be used in production.

What I Built

stripe-mcp-python – a Python MCP server that connects any AI client (Claude, ChatGPT, Cursor) to the full Stripe API.

Key decisions

  • 41 tools across 10 domains – Customers, Products, Payments, Subscriptions, Invoices, Refunds, Balance, Payment Links, Disputes, and Coupons. Each tool includes proper MCP annotations (readOnlyHint, destructiveHint, etc.) so AI clients know what’s safe to call.
  • Pydantic v2 for everything – Input validation with regex patterns, min/max constraints, and type safety. Invalid data (e.g., "sub_abc" passed to a customer tool) is rejected before hitting Stripe, preventing wasted API calls and providing clear error messages.
  • _helpers.py pattern – Extracted do_list(), do_get(), do_create(), do_modify(), do_delete(), and do_search() into shared helpers. This reduced each tool module from 100+ lines of boilerplate to clean, focused 5‑line functions.
  • OAuth 2.1 as a Resource Server – Publishes RFC 9728 Protected Resource Metadata and validates tokens from any provider (Auth0, Okta, Cognito). Granular scopes (stripe:read, stripe:write, stripe:delete, stripe:admin) map to every tool.
  • Dual transportstdio for local use with Claude Desktop/Cursor, and streamable HTTP for remote deployment. One codebase, two modes.

Architecture

The project follows a clean, modular structure:

src/stripe_mcp/
├── server.py          # FastMCP init + lifespan
├── cli.py             # Click CLI (stdio + HTTP)
├── auth/              # OAuth 2.1 + scope enforcement
├── tools/             # 10 tool modules + shared helpers
├── models/            # Pydantic input/output models
└── utils/             # Stripe client, errors, pagination, formatting

Every Stripe API call goes through a centralized stripe_api_call() wrapper that handles logging and error formatting consistently. Errors return actionable JSON messages—so when an AI agent receives a 404, it knows to “check the ID is correct” instead of just failing.

What I’d Do Differently

  • Start with tests first. I wrote them after the implementation, which required later refactoring. Next time I’d use TDD for the tool modules.
  • OAuth complexity. The MCP auth spec is still evolving (Client Metadata Documents are in draft). I’d recommend beginning with API‑key auth and adding OAuth as a second phase.

Results

  • 38 unit tests, all passing.
  • 41 MCP tools registered and discoverable.
  • Works with Claude Desktop, Cursor, VS Code, and any MCP client.
  • CI/CD with GitHub Actions (lint + test on Python 3.11/3.12/3.13).
  • Published to PyPI as stripe-mcp-python.

Try It

pip install stripe-mcp-python
export STRIPE_API_KEY=sk_test_...
stripe-mcp

GitHub:

If you’re building MCP servers, I’d love to hear what gaps you’re seeing in the ecosystem. What services need a good MCP integration?

0 views
Back to Blog

Related posts

Read more »

Python OOP for Java Developers

Converting a Simple Java Square Class to Python Below is a step‑by‑step conversion of a basic Square class written in Java into an equivalent Python implementa...