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
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
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...")
Result:
-
spec:
stripe -
workflow:
accept_payment(Tier-1 default) - confidence: 0.85
-
reasoning: no
slackspec; 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_declined → payment_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:
- No new endpoint — side effects only at existing handler lines.
- Third target surfaced — receipt-send swallow, not only the two webhooks the user named.
- Routing limitation named — upstream Stripe proof, Slack downstream on you.
-
Idempotency applied to Slack — Stripe retries on 5xx; use
pi.idas dedupe key for duplicate alerts. - 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:
- Propose
payment_intent.payment_failed→ Slack at L95–98 (SLACK_WEBHOOK_URLenv). -
stripe trigger payment_intent.payment_failedbefore editing message text. - Separate Resend proof for bounce/complaint templates.
- 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"]
}
}
}
Cursor: ~/.cursor/mcp.json, restart IDE, enable server in Settings → MCP.
Optional skills:
curl -sL https://fetchsandbox.com/skills/install.sh | bash
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)