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 (0)