Payment Ops MCP Server
Allows interaction with Stripe's API for payment operations, including looking up customers, reviewing charges, issuing refunds, and creating payment links, with human approval required for money-moving actions.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Payment Ops MCP ServerRefund the duplicate charge for sarah@example.com."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
An MCP server that lets Claude handle payment support โ look up customers, review charges, and issue refunds โ by orchestrating between Stripe and an internal orders database, with human approval required before any money moves.
๐ก Why This Exists
Stripe ships an official MCP server โ but it only knows Stripe. Real companies wrap the payment provider with internal data and business rules. This server is that orchestration layer:
๐ Joins Stripe payment data with internal order records via
stripe_customer_id๐ Enforces refund policy (no refunds older than 90 days)
๐ Requires human confirmation before moving money
๐ Writes a full audit log of every refund to the orders DB
That's the layer every company has to build itself. The provider can't.
Related MCP server: Agent Billy MCP Server
๐๏ธ Architecture
๐ ๏ธ Tools
Tool | Type | What it does |
| ๐ Read | Merges internal DB record + live Stripe status by email |
| ๐ Read | Lists recent Stripe PaymentIntents for a customer |
| ๐ Read | Returns full order history from internal DB |
| โ๏ธ Write | Two-step: preview โ confirm โ refund Stripe + log DB |
| โ๏ธ Write | Generates a Stripe test payment link |
| ๐ Read | Aggregates paid orders over a date range |
| โ๏ธ Write | Flags a charge in the audit log for manual review |
Plus 2 resources (customer://email, payment://charge_id) and 2 prompts (daily_revenue_report, find_refund_candidates).
๐ Safety Design
Three layers โ never trust the model alone for money-moving actions:
๐ Human-in-the-loop gate โ
issue_refundrequiresconfirmed=True, which the model only sets after explicitly asking the user๐ Server-side business rule โ refunds older than 90 days are rejected regardless of what the model requests
๐๏ธ Least-privilege Stripe key โ restricted key scoped to Charges + Customers + Refunds only, limits blast radius
๐๏ธ Database Schema
customers
id (uuid, pk)
email (unique)
name
stripe_customer_id โ join key to Stripe
orders
id (uuid, pk)
customer_id (fk)
stripe_charge_id โ Stripe PaymentIntent ID (pi_xxx)
amount_cents
currency
status (paid / refunded / partially_refunded)
created_at
refund_log โ audit trail
id (uuid, pk)
order_id (fk)
stripe_refund_id
amount_cents
reason
refunded_by ("ai-assistant")
created_atโ๏ธ Setup
1. Clone and install
git clone https://github.com/srik4442/Payment-Ops-mcp.git
cd Payment-Ops-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt2. Get a Stripe test key
Create a free account at stripe.com (test mode, no card needed)
Go to Developers โ API keys โ Create restricted key
Grant Write access to: Charges and Refunds, Customers, Payment Intents, Payment Links, Products
Copy the
rk_test_...key
3. Configure environment
cp .env.example .env
# Edit .env and add your key:
# STRIPE_API_KEY=rk_test_your_key_here
# DATABASE_URL=sqlite:///./payments.db4. Seed test data
python scripts/seed.pyCreates 5 test customers in both your local DB and Stripe, each with 2โ3 test charges.
5. Connect Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"payment-ops": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["/absolute/path/to/src/mcp_server.py"],
"env": {
"STRIPE_API_KEY": "rk_test_your_key_here",
"DATABASE_URL": "sqlite:////absolute/path/to/payments.db"
}
}
}
}Restart Claude Desktop โ you should see payment-ops connected.
6. Run the demo
Type into Claude Desktop:
"A customer, sarah@example.com, emailed about a double charge. Look into it and refund the most recent payment."
๐งช Tests
python -m pytest tests/ --cov=src -v24 tests ยท 99% coverage on business logic ยท Stripe client fully mocked (no real API calls in tests)
tests/test_payment_service.py::TestLookupCustomer::test_lookup_customer_merges_db_and_stripe PASSED
tests/test_payment_service.py::TestIssueRefund::test_issue_refund_preview_when_not_confirmed PASSED
tests/test_payment_service.py::TestIssueRefund::test_issue_refund_writes_refund_log_when_confirmed PASSED
tests/test_payment_service.py::TestIssueRefund::test_issue_refund_rejected_for_charge_older_than_90_days PASSED
...๐ค Tech Decisions
Why MCP instead of a backend script? A script automates one fixed workflow. MCP exposes capabilities to any AI client so a human can drive novel, multi-step support tasks in natural language โ without pre-coding every path.
Why SQLite? Zero-config for a portfolio project. The ORM (SQLAlchemy) makes swapping to Postgres a one-line config change.
Why test mode only? Test mode uses the identical Stripe API and code path as live โ the only difference is the key prefix. Switching to production is one environment variable.
Why a restricted Stripe key? Least-privilege: the key can only touch Charges, Customers, and Refunds. Even if the key were compromised, the blast radius is contained.
Why store pi_xxx IDs (PaymentIntent) instead of ch_xxx (Charge)?
Modern Stripe workflows are built around PaymentIntents. Refunds via payment_intent work reliably across all payment methods.
๐ฌ Demo
Prompt typed into Claude Desktop: "A customer, sarah@example.com, emailed about a double charge. Look into it and refund the most recent payment."
STEP 1 Claude calls lookup_customer("sarah@example.com")
โ queries Orders DB โ finds Sarah + Stripe customer ID
STEP 2 Claude calls list_payments(customer="cus_xxx")
โ queries Stripe (test mode) โ returns recent charges
STEP 3 Claude PAUSES:
"I found a duplicate $49.99 charge. Refund the most recent one? Please confirm."
โ human-in-the-loop gate before any money moves
STEP 4 You reply "yes"
โ Claude calls issue_refund(confirmed=True)
โ refund issued in Stripe
โ order status updated + audit row written to DB
STEP 5 Claude confirms:
"Refunded $49.99 to Sarah (re_3To18wCLuf9LMqJ11xb4XutS).
Logged in orders DB as duplicate-charge reversal."๐ Resume Bullet
AI Payment Operations Assistant (MCP Server) ยท Python, MCP SDK, Stripe API, SQLAlchemy, pytest
Built a Model Context Protocol server that lets AI assistants perform payment support operations by orchestrating between the Stripe API and an internal order database, exposing 7 tools, resources, and prompt templates
Implemented human-in-the-loop confirmation and server-side business rules to gate money-moving actions, with a full refund audit log written to the database for every transaction
Applied production payment patterns โ least-privilege restricted API keys, idempotency, and prompt-injection mitigation โ and validated orchestration logic with a mocked-Stripe pytest suite at 99% coverage
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/srik4442/Payment-Ops-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server