MCP server
Your AI assistant can work your bins through the Model Context Protocol: list and create bins, search requests, read one with its deliveries, replay failures, add destinations (HTTP or Private Relay) and secrets, set a scenario, import and export, subscribe to vendor status feeds, add connections and actions, mail from o.webhooks.xyz, read the inbox, set the digest, ask the AI assistant with your own key, and see your quotas. Same token as the API. For signed-in users on every plan.
Endpoint
POST https://webhooks.xyz/mcp Authorization: Bearer whx_… # token from your account Content-Type: application/json # JSON-RPC 2.0, Streamable HTTP, JSON responses
Claude Desktop, Cursor, Windsurf (stdio clients)
Until the whx mcp bridge ships, use mcp-remote:
{
"mcpServers": {
"webhooks": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://webhooks.xyz/mcp", "--header", "Authorization: Bearer whx_…"]
}
}
}
Clients that speak Streamable HTTP directly
{ "url": "https://webhooks.xyz/mcp", "headers": { "Authorization": "Bearer whx_…" } }
Tools
| Tool | What it does |
|---|---|
| list_bins | List the bins in your account with their URLs and last activity. |
| create_bin | Create a new request bin. Returns its id, capture URL and page URL. |
| search_requests | Search stored requests of a bin. Query syntax: provider:stripe event:payment_intent verify:ok|failed|unchecked status:200 method:POST path:/orders delivered:yes|no|pending since:24h plus free text. |
| get_request | One stored request with headers, body, verification result and deliveries. |
| list_deliveries | Deliveries of a bin to its destinations, optionally filtered by status (queued, delivered, failed). |
| replay_failed | Queue every dead-lettered (failed) delivery of a bin again. |
| add_destination | Forward every request of a bin, with retries: mode http to a public URL, or mode relay to a `whx relay` agent on a private network (url is then the private URL the agent forwards to). |
| list_destinations | The destinations of a bin (url, mode http|relay, paused, delivery counts). |
| add_secret | Add a signing secret so requests from that sender get verified. scheme is a slug from list_schemes, or 'custom' with a custom spec (sig_header, algo sha256|sha1|sha512, encoding hex|base64, sig_prefix, message template with {body} {ts} {id}, ts_header, key raw|base64). |
| list_schemes | Signature schemes the bin can verify (slug, name, which secret to paste). |
| set_scenario | Change what the bin answers: normal, timeout, fail (503 for fail_minutes) or echo (returns echo_field). |
| get_bin | One bin: name, URLs, its inbound mail address (<id>@i.webhooks.xyz) and sender address (<id>@o.webhooks.xyz), scenario, counts, destinations, relay tokens. |
| set_bin_public | Make a bin public (anyone with its link sees the requests) or private (the default for account bins: only you and your team). |
| create_relay_token | Private Relay: mint a token for `whx relay --token …` so an agent inside a private network delivers the bin's relay-mode destinations. The token is shown once. |
| list_relay_tokens | Relay tokens of a bin with last-seen time and whether an agent is connected. |
| revoke_relay_token | Revoke a relay token. |
| export_bin | Full export of a bin (settings without secrets, destinations, every request) in the webhooks.xyz JSON format that import_requests accepts. |
| import_requests | Import requests into a bin (or new bins). source: webhook-site (token = its URL or token, api_key optional), hookdeck (api_key), pipedream (api_key, source_id), svix-play (token = play URL), har (data = parsed HAR), json (data = a webhooks.xyz export or a list of requests). |
| list_imports | Past imports of the account: source, bins created, counts, notes. |
| list_connections | The account's connections (Slack, Teams, Discord, email, mailout = Email from webhooks.xyz, Sentry, HTTP) with ids for actions and status feeds. |
| add_connection | Add a connection. kind slack|discord|teams: config.webhook_url. mailout: config.to (recipient; your account address or one confirmed by mail), config.reply_to. email (your SMTP): host, port, username, password, from_addr, starttls. sentry: dsn. http: url, method, auth_header. |
| list_actions | Actions and alerts of a bin (trigger, filter, connection, template, state). |
| add_action | Add an action to a bin: when `trigger` fires (request, signature_failed, delivery_failed, delivery_dead, silence) and the optional filter matches, send `template` (with {{ field }} placeholders) through a connection. subject/recipient for mail kinds; threshold = N for delivery_failed/silence. |
| list_mail_recipients | Addresses that may receive mail from <bin>@o.webhooks.xyz for this account (verified, pending, blocked), plus today's use of the daily limit. |
| add_mail_recipient | Send a confirmation link to an address so actions can mail it from o.webhooks.xyz. The account's own address needs no confirmation. |
| list_status_feeds | Status Feed Relay: the account's vendor status subscriptions and the curated vendor list (slug, name, feed URL). |
| add_status_feed | Subscribe to a vendor's status page and post incidents to connections. Give vendor (a slug from list_status_feeds) or name + url (any RSS/Atom feed), or kind webhook for a vendor that pushes (returns the inbound URL). |
| delete_status_feed | Delete a status feed subscription. |
| inbox | Notifications Inbox: every mail we sent the account and in-app notices (alerts, bounces, digests). unread_only limits to unread; mark_read marks the returned items read. |
| set_digest | Usage Digest by mail: off, weekly (Monday) or monthly (1st). Returns the current setting; omit period to only read it. |
| ai_ask | AI Assistant (BYOK, the account's own provider key): explain a request, write a handler (lang python|node|go|ruby|php|java|csharp|rust), suggest a filter, or ask a question about it. |
| ai_summary | AI Assistant (BYOK): summarise the last `hours` of a bin's traffic. |
| list_routes | Transformations and Routing: the ordered routes of a bin (conditions, transformation, action, destinations, hits, last error). |
| add_route | Add a route to a bin. conditions: one per line ('body.type starts charge.', 'header:x-github-event is push', 'body.amount > 5000'). action: forward (needs destination_ids), drop, or continue. transform_kind: none, js (a function (req) => req; null drops) or jsonata (expression over the body). A bin with routes forwards only what a route forwards. |
| test_route | Dry run the bin's routes (or one unsaved draft route) against a stored request (default: the latest). Shows which route matched and the exact request a destination would get. Sends nothing. |
| delete_route | Delete a route of a bin. |
| list_schemas | Binary Payloads: the Protobuf schemas of a bin (message types), its path map and the built-in types. MessagePack needs no schema. |
| add_schema | Upload .proto files to a bin so Protobuf bodies decode to JSON. files: {"acme/reading.proto": "syntax = ..."} (imports between the files work). Then set_schema_map chooses the message type per path. |
| set_schema_map | Which Protobuf message type decodes which requests of a bin. One line per rule: '<path prefix or *> <message type>', e.g. '/telemetry acme.Reading\n* transit_realtime.FeedMessage'. A content-type parameter '; proto=pkg.Msg' on a request wins over the map. |
| delete_schema | Remove a Protobuf schema from a bin. |
| sql_schema | SQL Access: the tables and columns of your account's database (bins, requests, deliveries, destinations), row counts and limits. SQLite dialect; JSON functions work on requests.body. |
| sql_query | Run one read-only SELECT on your account's database. Example: SELECT day, provider, count(*) FROM requests GROUP BY 1, 2. Use json_extract(body, '$.field') for body fields and json_extract(headers, '$."x-github-event"') for headers. fresh=true rebuilds the snapshot first (it is at most 60 s old otherwise). |
| list_views | Published Views: the account's public pages (URL, JSON/CSV/RSS URLs, kind, columns, visibility, hits) and the account handle. |
| publish_view | Publish a page at /p/<handle>/<slug> with .json, .csv and .rss. kind search: bin_id + q (search syntax) + fields (public columns: received_at, method, path, provider, event, verify, size, resp_status, ip, id, body.<path>, header:<name>). kind request: bin_id + request_id (fields = body fields to show; show_headers). kind sql: one SELECT on the account database. visibility public or secret (link carries a key). |
| unpublish_view | Remove a published view; its address stops working at once. |
| list_workflows | Workflows: the account's step graphs (trigger, steps, edges, enabled, last run). Workflows must be turned on at https://webhooks.xyz/workflows first. |
| get_workflow | One workflow with its trigger and graph. |
| save_workflow | Create a workflow (or update it with workflow_id). trigger = {type:'request', bin_id, filter}. graph = {start, steps:{id:{type:send|set|if|switch|join|foreach|wait|http|forward|notify|stop, ...}}, edges:[{from, port, to}]}; ports: out; then/else (if); case1..caseN/default (switch); each/done (foreach). Several edges from one port = parallel branches; join waits for them. A step reads earlier outputs as {{ steps.<id>.out.<field> }} and the request as {{ trigger.body.x }}, {{ trigger.headers.x-github-event }}. send: connection_id, template, subject, recipient, retry_if_unsure. set: vars {name: template}. if: conditions (one per line: '<reference> <op> <value>'). notify: subject, text. stop: status done|failed, note. switch: cases [{name, conditions}]. join: mode all|any. foreach: over '{{ trigger.body.items }}', max; the body reads {{ loop.item }} {{ loop.index }}; after the loop read {{ steps.<foreach>.out.items }}. wait: minutes. http: connection_id (an http connection), body, query; output ok/status/json/text. forward: destination_id (queues the trigger request). Saved paused unless enabled=true. |
| set_workflow_enabled | Turn one workflow on or off. |
| delete_workflow | Delete a workflow and its run history. |
| test_workflow | Dry run against the newest request of the trigger bin: shows every step's input-resolved output. Nothing is sent or stored. |
| list_workflow_runs | Runs of a workflow (status, started, finished, note). Pass run_id for one run with every step's stored output. |
| list_team | Teams: the members of the account's team (email, role editor|viewer, accepted) and the teams this account is a member of. |
| invite_member | Invite a person by email to the account's team as editor (can change bins) or viewer (can only look). They get a mail with an accept link. |
| remove_member | Remove a member from the account's team. |
| audit_log | The audit log of the account: every change through the web, API or MCP (time, actor, summary, bin, address, IP). |
| list_short_urls | Short URLs: every bin answers at https://webhooks.in/<bin-id> and https://webhook.in/<bin-id>. Lists the account's short names (webhooks.in/<name>). |
| add_short_url | Give a bin a short name: https://webhooks.in/<alias> then captures for that bin. alias: 3-40 characters a-z, 0-9, '-'. |
| delete_short_url | Remove a short name. |
| list_domains | Your own domains: each with its purposes (web, mail_in, mail_out), the state of each purpose and the DNS records still to add. |
| add_domain | Add your own subdomain. purposes: web (https://<host>/<bin-id> captures; /p/<slug> serves published views), mail_in (<bin-id>@<host> becomes a request), mail_out (actions send from <bin-id>@<host>). Use one subdomain per purpose, or one for all (then web uses A/AAAA records). Returns the DNS records to add; call check_domain after adding them. |
| check_domain | Read DNS for a domain now and return its states and the records still missing. |
| delete_domain | Remove a domain from the account. Its addresses stop working. |
| list_mail_invite_forms | Verify by Email: a visitor solves a captcha, gets an address that takes mail for 5 minutes, and sends one mail to it. DMARC pass = the address is proven. Lists the account's Verify by Email forms with their embed snippet. |
| create_mail_invite_form | Make a Verify by Email form for a bin. domain: an active mail-in domain of the account (the bin's short name is then the local part; Team and Business only), empty = the shared mail domain (all plans). origins: web origins that may embed it (empty = any). Returns the embed snippet. Each mail to an invite address lands on the bin with body.invite.status = verified, failed, expired or used. |
| delete_mail_invite_form | Remove a Verify by Email form. Its open invite addresses stop working. |
| list_outbound_apps | Outbound webhooks (send webhooks to YOUR customers): the account's apps, endpoint and message counts, messages this month. |
| create_outbound_app | Create an outbound app (one per product or environment). Returns its id (app_...) and backing bin. |
| list_outbound_endpoints | Endpoints of an outbound app, optionally for one tenant (your customer's id): URL, event types, signing secret, state. |
| add_outbound_endpoint | Register an https endpoint of a tenant. event_types empty = all events. Returns the signing secret (whsec_...) your customer verifies with. |
| delete_outbound_endpoint | Remove an endpoint of an outbound app. |
| send_outbound_message | Send one message to a tenant: signed (Standard Webhooks), delivered to each of the tenant's endpoints that wants the event type, retried with backoff. event_id makes the call idempotent. |
| list_outbound_deliveries | Deliveries of an outbound app (optionally one tenant): status, attempts, response status, error, message id. |
| outbound_portal_link | A signed link (7 days) where one tenant manages their own endpoints, sees deliveries and replays them. Give it to your customer. |
| billing_status | The account's plan, how it is paid, when it renews, and the plans it can move to with their prices. |
| quotas | Every limit of the service with the account's current use (per bin, mail, connections, AI, API). |
Read-only tokens can call every tool that reads. Replay needs the deliver scope; everything that creates, changes or asks the AI needs write. Every feature of the service has its tool here; a feature ships with its tool.
Try it with curl
curl -s https://webhooks.xyz/mcp -H "Authorization: Bearer $WHX_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_requests","arguments":{"bin_id":"k7f3abc","q":"verify:failed since:7d"}}}'