How to Give Your AI Coding Assistant Access to Your Webhooks via MCP
You're deep in a debugging session. Your AI coding assistant is helping you trace a payment flow bug. It asks what the last Stripe webhook payload looked like. So you leave your editor, open the Hooklistener dashboard, find the endpoint, locate the request, copy the JSON body, and paste it back into your conversation.
The whole thing takes 30 seconds, but it breaks your focus completely. And you do it dozens of times a day.
There's a better way. The Model Context Protocol (MCP) lets your coding assistant talk directly to Hooklistener's MCP server. No tab-switching. No copy-pasting. Just ask "show me the last webhook on my Stripe endpoint" and get the answer inline. This guide shows you how to set it up in under two minutes.
What we cover:Connecting Hooklistener's MCP server to Claude Code, Cursor, Windsurf, and OpenAI Codex CLI. What you can do with it, and the gotchas we ran into while building it. We won't cover building your own MCP server from scratch—just using ours.
What is MCP, and Why Should You Care?
Think of MCP as a USB-C port for AI assistants. Before USB-C, every device had its own charger. Before MCP, every AI tool needed custom integrations to access external data.
MCP standardizes how AI assistants discover and use external tools. Here's the mental model:
- MCP Server = a service that exposes "tools" (functions the AI can call). Hooklistener runs one at
app.hooklistener.com/api/mcp. - MCP Client = your AI assistant (Claude Code, Cursor, etc.). It connects to the server, discovers the tools, and calls them when relevant.
- Tools = specific actions like "list endpoints", "get a captured request", or "create an uptime monitor". The AI decides when to call them based on your conversation.
The AI doesn't just fetch raw data—it understands the tool schemas, picks the right one, formats the arguments, and presents the result in context. You ask a question in plain English; it handles the plumbing.
Prerequisites
You need exactly one thing: a Hooklistener account. That's it.
The MCP server uses OAuth 2.0for authentication. When you add the server, your client opens a browser, you sign in to Hooklistener, and you're connected. Under the hood it's the full modern OAuth stack—server discovery, dynamic client registration, and PKCE—but you never see any of that. No tokens to copy, no secrets to store in config files.
If your MCP client doesn't support OAuth, there's a legacy fallback: an API key generated from Organization Settings > API Keys (keys start with hklst_). API-key auth is deprecated—tool responses include a deprecation notice nudging you to reconnect with OAuth—but it still works.
If you do use an API key:Never commit it to version control. Each developer should use their own key, stored in an environment variable. Better yet, use OAuth and skip the problem entirely.
Setup: Claude Code
Claude Code has first-class MCP support. One command, and you're connected.
# OAuth 2.0 (recommended) — signs in via browser automatically
claude mcp add --transport http hooklistener https://app.hooklistener.com/api/mcpRun /mcp, pick "hooklistener", and choose authenticate. Your browser opens, you sign in, and the connection is live. This registers the server for the current project. Use --scope user to make it available across all your projects, or --scope project to write it to .mcp.jsonso your whole team gets it—each teammate signs in with their own account, so there's nothing secret in the file.
Verify it's working by typing /mcpin Claude Code. You should see "hooklistener" listed with 46 tools.
Legacy: API key
If you can't use the browser flow, pass an API key as a bearer header instead. This is deprecated—tool responses will include a notice asking you to reconnect with OAuth—but it works:
claude mcp add --transport http hooklistener \
https://app.hooklistener.com/api/mcp \
--header "Authorization: Bearer hklst_your_api_key_here"Manual alternative
If you prefer editing config files directly, add this to .mcp.json (project-level) or ~/.claude/mcp.json(global). No headers needed—Claude Code handles the OAuth sign-in when you first connect:
{
"mcpServers": {
"hooklistener": {
"type": "streamable-http",
"url": "https://app.hooklistener.com/api/mcp"
}
}
}Pitfall:If you add the server while Claude Code is running, you need to restart it. The MCP connection is established at startup. A common frustration is editing the config and wondering why nothing changed.
Setup: Cursor
Cursor supports OAuth for streamable HTTP servers, so the config is just a URL. Add this to .cursor/mcp.json in your project root:
{
"mcpServers": {
"hooklistener": {
"type": "streamable-http",
"url": "https://app.hooklistener.com/api/mcp"
}
}
}Restart Cursor or reload MCP servers from the settings panel, then complete the browser sign-in when prompted. The tools will appear in Cursor's agent mode. If you need the legacy API-key route instead, add a "headers" object with "Authorization": "Bearer hklst_your_api_key_here".
Setup: OpenAI Codex CLI
Codex CLI uses environment variables for bearer tokens. This is the legacy API-key path—if your Codex version supports OAuth for streamable HTTP servers, configure the URL without a token and sign in via browser instead:
export HOOKLISTENER_API_KEY=hklst_your_api_key_here
codex mcp add hooklistener --transport streamable-http \
--url https://app.hooklistener.com/api/mcp \
--bearer-token-env-var HOOKLISTENER_API_KEYOr add it manually to ~/.codex/config.toml:
[mcp_servers.hooklistener]
url = "https://app.hooklistener.com/api/mcp"
bearer_token_env_var = "HOOKLISTENER_API_KEY"At least the key lives in an environment variable rather than the config file—if you have to use API-key auth, this is the right pattern.
Setup: Windsurf
Add this to ~/.codeium/windsurf/mcp_config.json. The headersblock is the legacy API-key route—drop it if your Windsurf version handles OAuth sign-in for HTTP servers:
{
"mcpServers": {
"hooklistener": {
"serverUrl": "https://app.hooklistener.com/api/mcp",
"headers": {
"Authorization": "Bearer hklst_your_api_key_here"
}
}
}
}Note:Windsurf uses serverUrl instead of url. Small difference, but it'll silently fail if you use the wrong key.
What You Can Actually Do With It
Once connected, your AI assistant has access to 46 tools across nine categories. The server launched with 8; the expansion to 46 landed in v1.18.0 (see the changelog). You don't call these tools directly—the assistant picks the right one based on what you ask.
We won't table all 46 here. Instead, here are the tools worth knowing about, then a map of the full surface.
The standouts
wait_for_request — blocks until a webhook actually arriveson an endpoint (up to 60 seconds, or 0 to just check for existing requests). This is the tool that turns your assistant from a viewer into a tester: it can trigger an action in your app, wait for the resulting webhook, and verify the payload—a real end-to-end test, driven by the agent.
wait_for_email — the same blocking pattern for email. Pair it with create_inbox and your assistant can test an entire signup flow: create an inbox, register a user with the generated address, and wait for the confirmation email to land.
diagnose_request— analyzes a captured request's response status, automation runs, forwarding attempts, and body, then returns a health verdict with findings and suggestions. "Why did this webhook fail?" gets a structured answer instead of a guess.
compare_requests— AI-assisted comparison of 2–5 captured requests on the same endpoint. Useful for "this one worked, that one didn't—what changed?" Requires a paid plan.
create_run_script_action— lets the assistant attach custom JavaScript to an endpoint, executed in a sandboxed QuickJS WASM runtime (5-second timeout, 16 MB memory). Your AI writes the transform logic and wires it up in one step.
The full map
| Category | What's in it |
|---|---|
| Debug Endpoints | Full CRUD: list_endpoints, get_endpoint, create_endpoint, update_endpoint, delete_endpoint |
| Captured Requests | List, inspect, replay (forward_request), delete, wait_for_request, plus get_action_runs to debug automation chains |
| Automations | Build and manage action chains: HTTP requests, conditions, response modification, JSON extraction, variables, datastore writes, and sandboxed scripts—plus reorder and delete |
| Schedules | Cron-based HTTP jobs: list_schedules, create_schedule, delete_schedule |
| Secrets | Encrypted secrets for action templates ({{ SECRET_NAME }}); values are never exposed back through the API |
| Datastore | Persistent key-value storage: set, get, list, delete |
| Uptime Monitors | Create and manage monitors, plus get_monitor_status for uptime percentage and response times |
| Email Inboxes | Disposable inboxes for testing email flows: create_inbox, list_emails, get_email, wait_for_email |
| AI Analysis | diagnose_request and compare_requests |
The full reference with every parameter schema lives in the MCP tools documentation.
Real Workflow Examples
Here's where it clicks. These aren't hypothetical—they're the workflows that made us build this in the first place.
"Create a debug endpoint for Stripe and give me the URL"
The assistant calls create_endpointwith the name "Stripe Webhooks" and hands you the public URL. You paste it into Stripe's dashboard. No context switch, no clicking around. Ten seconds.
"Show me the last webhook that came in on my Stripe endpoint"
It calls list_endpoints to find your Stripe endpoint, then list_requests to grab the most recent capture, then get_request to fetch the full payload. You see the headers, body, and metadata right in your conversation. If the body contains a checkout.session.completed event, the assistant can immediately help you write the handler.
"Is my production API healthy? What's the uptime this month?"
The assistant calls get_monitor_statusand reports back: "99.95% uptime over the last 30 days, average response time 125ms. The last check was 2 minutes ago, status 200." If something looks off, you're already in the right context to investigate.
"Set up a health check for our new staging environment"
It calls create_monitorwith the URL, a 5-minute check interval, and a 30-second timeout. Done. You didn't leave your terminal.
"Trigger a test checkout and verify the webhook fires"
The assistant runs your test script, then calls wait_for_requeston the endpoint and blocks until the webhook lands (or times out after 60 seconds). When it arrives, the assistant inspects the payload and confirms the event type and fields match what your handler expects. That's an end-to-end webhook test with zero manual steps.
"Why did the last webhook on this endpoint fail?"
It calls diagnose_request and gets back a health verdict with concrete findings: a 500 response, a halted automation chain, a forward that never got attempted. Instead of you eyeballing logs, the assistant reads the diagnosis and proposes the fix.
How It Works Under the Hood
You don't need to understand the protocol to use it, but knowing the basics helps when things go wrong.
Hooklistener's MCP server uses the Streamable HTTP transport. Your AI assistant communicates with it via JSON-RPC 2.0 over plain HTTP POST requests to a single endpoint: /api/mcp.
The flow looks like this:
- Your assistant sends an
initializerequest with its client info - The server responds with its capabilities (what tools it supports)
- The assistant calls
tools/listto discover available tools and their parameter schemas - When you ask a question, the assistant picks the right tool and calls
tools/callwith the arguments - The server validates your credentials, runs the query, and returns the result
Every request after initialize includes an mcp-session-id header to maintain session context. Authentication works one of two ways. With OAuth (the default), you sign in once via browser and your client attaches a short-lived access token to every request—discovery, dynamic client registration, and PKCE all happen automatically. With a legacy API key, the key rides along as an Authorization: Bearer header on every call instead.
Testing It Manually (For the Curious)
If you want to see what your AI assistant is doing behind the scenes, you can hit the MCP server directly with curl. This is also useful for debugging connection issues. These examples use an API key because curl can't do a browser OAuth dance—it's the one place the legacy auth still earns its keep.
Initialize a session
curl -X POST https://app.hooklistener.com/api/mcp \
-H "Authorization: Bearer hklst_your_key" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "my-test",
"version": "1.0"
}
}
}'Grab the mcp-session-id from the response headers, then list tools:
List available tools
curl -X POST https://app.hooklistener.com/api/mcp \
-H "Authorization: Bearer hklst_your_key" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: SESSION_ID_FROM_ABOVE" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'You'll see all 46 tools with their names, descriptions, and parameter schemas. This is exactly what your AI assistant sees when it connects.
Troubleshooting
"Authentication required" error
On OAuth: your access token has probably expired and the client failed to refresh it. Re-run the sign-in from your client—in Claude Code, type /mcp, select hooklistener, and choose authenticate. The browser flow takes a few seconds.
On a legacy API key: the key is missing or invalid. Double-check that it starts with hklst_ and that the Authorization header is formatted as Bearer hklst_...with a space after "Bearer". Generate a fresh key from Organization Settings if needed—or take the hint and switch to OAuth.
Server not showing up in your assistant
Most MCP clients only load servers at startup. Restart your editor or CLI after editing the config. In Claude Code, run /mcpto check the connection status. Verify your config file is valid JSON—a trailing comma will silently break it.
Tools appear but calls fail
This usually means your plan doesn't include the feature you're trying to use. Debug endpoints and request inspection are available on all plans, but uptime monitors, email inboxes, the datastore, and AI request comparison (compare_requests) are plan-gated. If you're hitting a quota (e.g., max endpoints or schedules), the error message will tell you exactly that.
Windsurf silently fails
Check that you're using serverUrl, not url. Windsurf uses a different key name than Cursor and Claude Code. This is the most common mistake we see.
A Note on Security
Every tool call is authenticated and scoped to your organization. There's no way to access another organization's data through the MCP server—every database query is filtered by your organization ID.
OAuth is the safer default, and it's why we made it the primary flow. Access tokens are short-lived (one hour, with a 30-day refresh token), so a leaked token expires on its own. And because the client handles the token exchange, there are no secrets sitting in your config files—a committed .mcp.json contains nothing but a URL.
If you're still on a legacy API key: it's hashed with SHA-256 before storage—we never store it in plaintext. When you make a request, we match on a prefix, then verify the full hash. But API-key auth for MCP is deprecated, and every tool response includes a deprecation notice asking you to reconnect with OAuth.
For team environments still using keys, avoid putting them directly in .mcp.json if it's committed to version control. Use environment variables or keep the key in a local config file that's gitignored. Codex CLI's bearer-token-env-var pattern is a good example. Or, again: OAuth makes the whole problem disappear.
What This Unlocks
The real value isn't any single tool call. It's the compound effect of your AI assistant having live context about your webhooks while it helps you write code.
When you're writing a Stripe webhook handler and the assistant can see the actual payload that just came in, it writes better code. When you're debugging a failed integration and the assistant can inspect the headers and body—or just call diagnose_request—it finds the bug faster. When it can trigger a flow and block on wait_for_request until the webhook lands, it verifies its own work.
The setup takes two minutes: claude mcp add, sign in, done. If you want the high-level overview of everything the server exposes, the MCP server page has it. The time you save compounds every day.
Related Reading
Hooklistener MCP Server
The full overview: every tool category, setup snippets for each client, and FAQs.
What Is an MCP Server?
The protocol from first principles: servers, clients, tools, and why the standard matters.
Agentic Webhook Testing
How blocking tools like wait_for_request let AI agents run real end-to-end webhook tests.