Skip to main content

Stripe MCP server for Stallari — billing-v1 (subscriptions, products, prices, invoices) + payments-v1 (PaymentIntents, refunds, disputes, webhooks). Token-efficient pipe-delimited output, mandatory env isolation, Restricted-Key-only, per-resource write-gating.

Project description

stripe-blade-mcp

⚠️ Phase 0 scaffold — pre-alpha (0.1.0a1). All 45 tools currently raise NotImplementedError. The scaffold exists to validate the /build-blade-mcp skill conventions (security, privacy, token-efficiency, devops baseline) end-to-end. Production implementation of Phases A–E is gated on a real Stallari build trigger per BUILD_PLAN.md. Do not install for production use. Use @stripe/mcp for direct Claude Desktop / Cursor Stripe access in the meantime.

Stripe MCP server for Stallari workloads. Token-efficient, Restricted-Key-only, per-resource write-gated. Closes the gaps in Stripe's own @stripe/mcp for Stallari pack-workload integration.

PyPI Tests License Python 3.12+

Dual-contract blade implementing both billing-v1 (subscriptions, products, prices, invoices) and payments-v1 (PaymentIntents, refunds, disputes, webhooks). First blade where one repo cleanly implements both Stallari payment contracts end-to-end.

Why another Stripe MCP?

Stripe ships @stripe/mcp. It covers 23 tools across 11 resource categories and works well for direct Claude Desktop / Cursor use. This blade exists because:

  • Missing payments-v1 Required ops. @stripe/mcp ships list_payment_intents + create_refund only — missing payment_intent_create/capture/cancel/get, refund_get/list, and the full webhook_verify + webhook_subscription_* block that Stallari's payments-v1 contract requires.
  • HTTP-only transport@stripe/mcp is HTTP only; DD-242 requires stdio when launched by Stallari.
  • Raw JSON responses@stripe/mcp returns standard MCP JSON-RPC payloads. This blade emits pipe-delimited summaries on list ops (~16× token reduction measured on equivalent paddle-blade ops), with field selection and null-omit on detail views.
  • Advisory-only write-gating@stripe/mcp recommends human confirmation but doesn't enforce. This blade enforces per-resource STRIPE_WRITE_* env gates AND a confirm=true parameter on destructive ops.

If you only need basic Stripe access in Claude Desktop, use @stripe/mcp. If you're running Stallari pack workloads, use this blade.

Comparison

Capability stripe-blade-mcp @stripe/mcp
Tool count ~45 (full billing-v1 + payments-v1) 23 (partial coverage)
payments-v1 Required ops 8/8 2/8
billing-v1 Required ops 6/6 3/6
Webhook HMAC verification Built-in stripe_webhook_verify Not present
Webhook subscription management 4-op block (list/create/delete/replay) Not present
Token-efficient responses Pipe-delimited, field selection, null-omit, money-formatted Raw JSON
Write gating Per-op env var, fail-closed Advisory only
Destructive op confirmation confirm=true enforced None enforced
Sandbox/live isolation Mandatory STRIPE_ENV, fail-closed Yes (per-env access)
API key security Env var only, credential scrubbing Env var OR --api-key CLI arg (ps leak)
Restricted-Key enforcement Startup check + scope coherence warn None
Stdio when harness-launched Yes (DD-242) No — HTTP only
Money formatting Human-readable ($29.00 USD) Raw cents
Field selection fields= parameter Not available
Pagination hints Cursor + "N more" Standard has_more only
Idempotency-key auto-attach Yes (stallari-... prefix) Unclear
Connect (multi-tenant) Out of scope v1 — explicit refuse Possibly available
Runtime Python (uv) TypeScript (npm)

Token efficiency: before and after

Raw Stripe API (≈ @stripe/mcp shape) — 1 page of 25 subscriptions:

{
  "object": "list",
  "url": "/v1/subscriptions",
  "has_more": true,
  "data": [
    {
      "id": "sub_1NkVJ8...",
      "object": "subscription",
      "application": null,
      "application_fee_percent": null,
      "automatic_tax": {"enabled": false, "liability": null},
      "billing_cycle_anchor": 1715000000,
      "billing_thresholds": null,
      "cancel_at": null,
      "cancel_at_period_end": false,
      "canceled_at": null,
      "cancellation_details": {"comment": null, "feedback": null, "reason": null},
      "collection_method": "charge_automatically",
      "created": 1715000000,
      ... ~50 more fields per subscription
    },
    ... 24 more
  ]
}

~12,000 tokens for the page.

stripe-blade-mcp pipe-delimited:

[env=test]
sub_1NkVJ8 | acme inc. | active | $29.00 USD / month | 3 days ago
sub_1NkVK2 | beta corp  | active | $99.00 USD / month | 7 days ago
sub_1NkVL5 | trial co.  | trialing | $0.00 USD / month | 1 day ago
... 22 more (pass starting_after=sub_1NkVL5 to continue)

~280 tokens.40× reduction.

Need a single field? Call stripe_subscription_get with fields=["id", "status", "current_period_end"] to project exactly what you need.

Installation

As a Stallari blade

stripe-blade-mcp installs as a Stallari pack. The blade resolves credentials through the Stallari CredentialStore (DD-186) at launch — never commit secrets.

stallari pack install groupthink-dev/stripe-blade-mcp

Standalone (Claude Desktop, Cursor, etc.)

uv tool install stripe-blade-mcp

Claude Desktop MCP config:

{
  "mcpServers": {
    "stripe": {
      "command": "stripe-blade-mcp",
      "env": {
        "STRIPE_ENV": "test",
        "STRIPE_API_KEY": "rk_test_..."
      }
    }
  }
}

Quickstart

  1. Create a Restricted Key at https://dashboard.stripe.com/apikeys/create — Standard Keys are rejected
  2. Enable the resources your workload needs (Payments / Subscriptions / Refunds)
  3. Configure the env:
export STRIPE_ENV=test                    # or 'live' for production
export STRIPE_API_KEY=rk_test_...         # restricted key only
export STRIPE_WRITE_PAYMENTS=1            # only enable writes you need
  1. Validate: stripe-blade-mcp then invoke stripe_account_info

Usage examples

# List recent subscriptions (pipe-delimited)
await stripe_subscription_list(after=None, limit=10)

# Get one with field selection
await stripe_subscription_get(id="sub_1NkVJ8", fields=["id", "status", "current_period_end"])

# Create a PaymentIntent (gated — requires STRIPE_WRITE_PAYMENTS=1)
await stripe_payment_intent_create(
    payload={"amount": 2900, "currency": "usd", "customer": "cus_QABCDEF", "confirm": True}
)

# Verify a Stripe webhook
await stripe_webhook_verify(
    body=raw_request_body,
    signature_header=req.headers["Stripe-Signature"],
    secret=os.environ["STRIPE_WEBHOOK_SECRET"]
)
# → {"verified": True, "event_type": "payment_intent.succeeded", "event_id": "evt_...", "age_seconds": 2}

Security posture

  • Mandatory sandbox/live env isolation. Refuses to start without STRIPE_ENV=test|live.
  • Restricted Keys only. sk_live_* Standard Keys rejected at startup; only rk_* accepted in live mode.
  • Per-resource write gates. Read is always permitted; write requires opt-in per-resource (STRIPE_WRITE_PAYMENTS=1, etc.). Defaults to all off.
  • Confirm gates on destructive ops. cancel, void, delete require confirm=true parameter.
  • Credential scrubbing. Every error path (incl. exception cause chain) is scrubbed of rk_*, sk_*, whsec_*, and generic api_key-named fields.
  • PCI allowlist. Card data projected to last_4 + brand + exp_* + fingerprint only (DD-179). Raw payment_method / card objects never reach the response.
  • Idempotency. Auto-attached stallari-<date>T<run_id>-<uuid> key on every mutation; caller override always wins.
  • Stdio transport when harness-launched (DD-242). HTTP transport opt-in is loopback-only with mandatory bearer token.
  • No telemetry, no phone-home (convention #19).
  • Mesh exposure denied — blade tools never advertised on daemon :9847/mcp (DD-240 invariant #8).

Sandbox vs production

Env STRIPE_ENV Key prefix Notes
Test test rk_test_* or sk_test_* Stripe test mode — no real money. Use freely.
Live live rk_live_* (only) Real-money production. sk_live_* rejected.

The blade echoes _env: test or _env: live on every response so misconfig is visible immediately.

Tool inventory

Required (billing-v1 + payments-v1 conformance)

Tool Wraps Contract op
stripe_product_list / stripe_product_get Products billing-v1 products / product
stripe_price_list Prices billing-v1 prices
stripe_customer_list / stripe_customer_get Customers billing-v1 customers + payments-v1 customer_*
stripe_subscription_list / stripe_subscription_get Subscriptions billing-v1 subscriptions / subscription
stripe_transaction_list Invoices billing-v1 transactions
stripe_payment_intent_create / _capture / _cancel / _get / _list PaymentIntents payments-v1 payment_*
stripe_refund_create / _get / _list Refunds payments-v1 refund_*
stripe_webhook_verify (local HMAC) payments-v1 webhook_verify

Recommended (~14 tools)

stripe_customer_create / _update · stripe_subscription_update / _cancel · stripe_invoice_list / _get · stripe_adjustment_list / _create · stripe_discount_list / _apply · stripe_event_list · stripe_credit_balance_get · stripe_payment_method_list · stripe_dispute_list

Optional / target-specific

stripe_preview_transaction · stripe_notification_list · stripe_simulate · stripe_payout_list / _get · stripe_balance_get · stripe_dispute_get / _evidence_submit · stripe_webhook_endpoint_list / _create / _delete · stripe_replay_notification · stripe_webhook_event_types · stripe_account_info

Out of scope for v1

Stripe Connect · Stripe Issuing · Stripe Treasury · Stripe Climate · Stripe Identity. Each refused upfront at the server boundary with a pointer to a future DD.

Webhook verification

from stripe_blade_mcp.tools import stripe_webhook_verify

result = await stripe_webhook_verify(
    config,
    body=raw_request_body,           # bytes or str
    signature_header=req.headers["Stripe-Signature"],
    secret=webhook_endpoint_secret,
    tolerance_seconds=300,           # default 5min replay window
)
# → {
#     "verified": True,
#     "event_type": "payment_intent.succeeded",
#     "event_id": "evt_1NkVJ8...",
#     "created_at": "2026-05-11T15:32:00+10:00",
#     "age_seconds": 4,
#     "data": {...}                  # parsed event payload
#   }

The HMAC scheme follows Stripe's canonical format: t={timestamp},v1={hmac}. The blade enforces the timestamp tolerance to defeat replay attacks.

Rate limits + retry policy

Mode Global Per endpoint
Live 100 req/s 25 req/s
Test 25 req/s 25 req/s

Plus: PaymentIntent updates ≤ 1000/hour, Search ≤ 20 req/s.

On 429, the blade surfaces RateLimited verbatim with the Stripe-Rate-Limited-Reason header (global-rate / endpoint-rate / global-concurrency / resource-specific). No internal retry beyond 2 attempts — configure token-bucket throttling at the Stallari workload layer if you need it.

Development

git clone https://github.com/groupthink-dev/stripe-blade-mcp
cd stripe-blade-mcp
uv sync --group test --group dev
make test
make lint
make typecheck

The build plan lives in BUILD_PLAN.md. Each phase is a fresh PR.

Contributing

This is a first-party Groupthink blade. Issues + PRs welcome via github.com/groupthink-dev/stripe-blade-mcp/issues.

For Stallari pack development conventions, see the Stallari developer docs.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stripe_blade_mcp-0.1.0a1.tar.gz (132.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stripe_blade_mcp-0.1.0a1-py3-none-any.whl (52.7 kB view details)

Uploaded Python 3

File details

Details for the file stripe_blade_mcp-0.1.0a1.tar.gz.

File metadata

  • Download URL: stripe_blade_mcp-0.1.0a1.tar.gz
  • Upload date:
  • Size: 132.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for stripe_blade_mcp-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 4f2efacacd90d60cc7fc0c52242c280f4928feeb0940157738cb5673a4ac31e3
MD5 23c6c33dfd6813a6e1b7ade716b5f913
BLAKE2b-256 f984a81a66022cce6140f6ed4ad9d70533a1bb25fe08bd49efd3e244daaf3856

See more details on using hashes here.

Provenance

The following attestation bundles were made for stripe_blade_mcp-0.1.0a1.tar.gz:

Publisher: publish.yml on Groupthink-dev/stripe-blade-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stripe_blade_mcp-0.1.0a1-py3-none-any.whl.

File metadata

File hashes

Hashes for stripe_blade_mcp-0.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 e2ac8a5f5fdf5c3505340dd82b813d85d3faff6207efe1fc45f7c167f24f6d40
MD5 512ae550103153d5afdfd81c8903509e
BLAKE2b-256 2124db76673655638c17d61f4e4dea9ae86e6d3f71a65b9bbdeeaee86c257ed7

See more details on using hashes here.

Provenance

The following attestation bundles were made for stripe_blade_mcp-0.1.0a1-py3-none-any.whl:

Publisher: publish.yml on Groupthink-dev/stripe-blade-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page