DEV Community

Cover image for Brownfield Slack alerts: a 6-minute guided MCP run on Stripe + Resend webhooks
FetchSandbox
FetchSandbox

Posted on

Brownfield Slack alerts: a 6-minute guided MCP run on Stripe + Resend webhooks

I recorded a raw ~6.5 minute screen capture of my IDE running a full FetchSandbox MCP guided flow. No polish, no voiceover script — just what happens when you ask an agent to add Slack notifications for failed payments in a repo that already has Stripe checkout, Clerk JWT verification, and Resend receipt webhooks.

The video:

YOUTUBE_URL

This post is the written version of that session, with the parts that are easier to scan in prose than in a screencast.

The ask (and why it is not a greenfield task)

Prompt:

add slack notifications for failed payments — should plug into the existing stripe + resend webhook handlers
Enter fullscreen mode Exit fullscreen mode

Repo: a small Next.js 15 + FastAPI demo (stripe-checkout-demo) that had seen three prior integration sessions:

Session What landed Where Slack attaches
Stripe seed POST /create-payment-intent, POST /webhook payment_intent.payment_failed branch
Clerk JWT dep, POST /clerk-webhook (Svix) (out of scope for this alert)
Resend send_receipt(), POST /resend-webhook bounce/complaint branches + receipt try/except

Slack is the fourth layer. The agent cannot treat this like a tutorial repo with one file and one webhook. It has to find the exact lines where failures today only print().

That repo reading is why a full guided run is ~6–7 minutes in the recording — not because MCP is slow, but because brownfield integration is mostly comprehension.

What “guided” means in practice

FetchSandbox MCP does not jump straight to POST /chat.completions style codegen. The flow I used (fs-router skill) looks like:

intake → introspect repo → comprehend stack + failure surfaces → guide() routing → discovery questions → prove upstream contract → (then) propose changes
Enter fullscreen mode Exit fullscreen mode

Step 1 — Introspect

The introspect script scanned the repo and returned framework hints (Next.js ^15, FastAPI backend) and SDK signals for Stripe in server/main.py. The intent string mentioned Resend too; Slack is not in the FetchSandbox brain catalog, so it never appears as a routable spec.

Step 2 — Comprehend (the load-bearing step)

The agent catalogued where alerts would attach, not a new /slack-webhook route:

Event Today Location
payment_intent.payment_failed print() only webhook handler ~L95–98
email.bounced / email.complained print() + TODO Resend handler ~L139–145
Receipt send raises (Resend SDK) swallowed with print() inside Stripe success path ~L92–94

The user named Stripe + Resend handlers. The comprehend step also flagged the receipt try/except as a third visibility gap — correct webhook hygiene (do not fail Stripe retries) but operationally invisible without something like Slack.

Step 3 — guide() routing

guide(intent="add slack notifications for failed payments — plug into existing stripe + resend webhook handlers...")
Enter fullscreen mode Exit fullscreen mode

Result:

  • spec: stripe
  • workflow: accept_payment (Tier-1 default)
  • confidence: 0.85
  • reasoning: no slack spec; Stripe is the upstream that emits the event Slack will format

That routing is the right call, but it needs to be said plainly: FetchSandbox proves the upstream event, not the Slack POST.

Step 4 — Discovery (failures tab matters)

Multi-tab confirmation:

Question Answer Implies
Customer geo US only no 3DS scenario
Capture Auto on confirm accept_payment workflow
Failure modes Declined card (~60s) payment_declined scenario

If you skip the failures tab, you get a happy-path proof that does not exercise the webhook your Slack message cares about.

Step 5 — Proof run (and the honest limit)

Delegated to fs-prove-payments: spec=stripe, workflow=accept_payment, scenario=payment_declined.

Sandbox import reused the bundled Stripe spec with hand-curated workflows. Run result on paper: 6/6 steps passed, webhooks verified: payment_intent.created, payment_intent.succeeded.

Asked for Got Why
payment_declinedpayment_intent.payment_failed Terminal succeeded, success webhooks Curated accept_payment uses a deterministic pass card; scenario hook exists in the engine but this Tier-1 workflow does not exercise it

Same class of limit as other Stripe sessions: the catalog workflow is a fast preflight, not a substitute for driving a real decline.

To prove the handler your Slack code will sit in:

Method What it proves
stripe listen --forward-to localhost:8000/webhook + card 4000000000000002 Full PI flow → payment_intent.payment_failed at your handler
stripe trigger payment_intent.payment_failed Fast iteration on Slack message template from a realistic payload

What the agent got right without me asking

Five things worth stealing for your own brownfield prompts:

  1. No new endpoint — side effects only at existing handler lines.
  2. Third target surfaced — receipt-send swallow, not only the two webhooks the user named.
  3. Routing limitation named — upstream Stripe proof, Slack downstream on you.
  4. Idempotency applied to Slack — Stripe retries on 5xx; use pi.id as dedupe key for duplicate alerts.
  5. Resend proof deferred — one workflow per delegation; bounce/complaint shapes need a separate Resend run.

What was not done in this recording

  • No Slack diff applied yet (proof handed back; propose-changes step not shown in the artifact).
  • No Resend proof run for email.bounced / email.complained.
  • No Slack spec proof (none in catalog).

Expected next moves from the session:

  1. Propose payment_intent.payment_failed → Slack at L95–98 (SLACK_WEBHOOK_URL env).
  2. stripe trigger payment_intent.payment_failed before editing message text.
  3. Separate Resend proof for bounce/complaint templates.
  4. Ship payment-failed path first; Resend alerts in a follow-up PR.

MCP setup (unchanged from shorter demos)

{
  "mcpServers": {
    "fetchsandbox": {
      "command": "npx",
      "args": ["-y", "fetchsandbox-mcp"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Cursor: ~/.cursor/mcp.json, restart IDE, enable server in Settings → MCP.

Optional skills:

curl -sL https://fetchsandbox.com/skills/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

The takeaway

Docs tell your agent what should happen. Runnable workflows tell it what did happen in a sandbox — and brownfield comprehend tells it where your code already handles failures.

For Slack-on-Stripe, the valuable proof is not “can we call chat.postMessage” in FetchSandbox. It is: when payment_intent.payment_failed arrives, does your handler have the fields you need for an alert, and have you tested that path with a real or triggered event?

Try FetchSandbox: https://fetchsandbox.com

Stripe workflows: https://fetchsandbox.com/docs/stripe

Watch the raw demo: https://youtu.be/AB36LXwfoTQ

If you have done brownfield API work with agents, I am curious: should the default flow always map existing handlers before any proof run, or do you prefer prove-first on greenfield repos?

Top comments (2)

Collapse
 
harjjotsinghh profile image
Harjot Singh

stripe vs paddle is mostly a billing-ops tax question: chargeback handling + dunning + state filings get expensive fast. for indie/early-stage shipping, we charge $3 flat per shipped saas (no monthly). first run free, no card. moonshift.io

Collapse
 
fetchsandbox profile image
FetchSandbox

Yep, billing ops is definitely where Stripe vs Paddle starts to matter.
The angle I was exploring here is a bit lower-level: before choosing the billing provider or alerting layer, can an agent actually map the existing webhook handlers and prove the failure path it is about to wire into?
That brownfield mapping step is where I keep seeing the most value.