Webhooks for Operations in MCP #523
Replies: 4 comments 6 replies
-
Why transmit the results to the webhook? Why not store the results server side, and then call the webhook with a just reference (e.g. a task ID) that can be used to fetch the results? |
Beta Was this translation helpful? Give feedback.
-
The MCP protocol is fundamentally session-based. When a task spans several hours or even days, it’s no longer just a "task"—it’s effectively a long-running job. Introducing webhooks on the client side implies that the client must expose the IP of the server receiving the callback. This isn’t always feasible, especially when servers are behind load balancers or services like Cloudflare. A more robust approach is to have the server return a token representing the long-running task. That token can be used in any future session to query status, retrieve results, or check progress. Tooling can easily be built around this mechanism. Additionally, the updated MCP specification makes it clear that SSE is no longer a requirement. Streamable HTTP with resumability is now the preferred method, offering both flexibility and better alignment with modern HTTP patterns. Webhooks, much like batching, are appealing in theory but rarely practical. This is precisely why batching was deprecated in the 2025-03 specification and is planned for removal in the next release. Moreover, requiring clients to host webhook endpoints assumes they have a stable IP or DNS and are always online. But what happens if the MCP client is installed on a mobile device? What if the server completes the task while the device is offline? These are critical edge cases that webhooks fail to handle gracefully. |
Beta Was this translation helpful? Give feedback.
-
I have given more thought to the idea of supporting webhooks in MCP servers. Rather than having webhook transmission work at the messaging layer like I had mentioned at the start of the discussion, I think it makes more sense to integrate it at the transport layer. Streamable HTTP would ideally be the first transport that is fitted for webhook support. Revised spec changes:
Servers will still treat webhooks as a capability and will have the ability to support or not support webhooks. This decision could be based on whether the server comprises of asynchronous tools, whether the server wants to establish connections to the webhooks uris provided by the client (security concerns), if the server wants to risk additional latency of transmitting results to webhook (reliability) etc-. If a server supports webhook capability, webhooks will be supported for all tools rather than just being restricted to asynchronous tools. The client will have the option to pass webhooks as part of the CallToolsRequest. Any request with webhooks will have the final results transmitted to webhooks instead of back to the client. The client will receive an acknowledgement response once the tool call with webhooks has been received by the server. The response will be 200 instead of 202 (202 is only returned by the server when the client sends a notification/response). The tool call implementations should be modifiable depending on whether the tool call consists of a webhook or not.
In order to do this, the tool should be able to access whether a webhook has been passed by the client or not in its implementation. This can be achieved by using the request context.
|
Beta Was this translation helpful? Give feedback.
-
Authenticating webhooks is at tricky proposition and additionally it looks like Authentication itself is moving towards some centralized interfacing mechanism in the spec. Can I suggest that an initial impl for a WH callback would be to a publicly callable webhook endpoint without guarantees of authorization handling on the part of the client/mcp server? Another way to simplify this is to have the webhook URL provider (ex. some service outside the client), provide its own authentication criteria on the URL such as a token. The responsibility then lies on that provider to validate that token / reference. Example flow: Client calls Webhook Server to generate an endpoint to receive calls ex |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Pre-submission Checklist
Your Idea
Motivation and Context
As MCP expands to support asynchronous communication (#491), there will arise scenarios wherein the async execution will take anywhere from a few hours to a few days (or even more in some cases). The current discussion revolves around modeling async tool executions as an asynchronous resource that can be tracked for progress updates and can be read from the server, once the async execution has been completed. The server will initially respond with an Accepted (HTTP Status 202) response and can then disconnect from the server (instead of maintaining open SSE connection with the client for an extended period of time). The onus then lies with the client to query the server and fetch the response.
In order to free up the client and reduce load when handling multiple async operations, the recommended approach for such async scenarios is often to offer support for webhooks (similar discussion: #266). Webhooks offer a lightweight approach that allow the server to send results to the client when the async execution for a tool has been completed. Webhooks can be hosted by the client or can point to a server that notifies the client and/or stores the response.
Example, user interacts with a client and tasks it with performing time series forecasting on stock market prices for select securities. The client would interact with a server to fetch the stock price history and another server to perform time series forecasting using ML algorithms. The time series forecasting tool on the server would be modeled as asynchronous. The final response could be a large dataset since the forecasting granularity might be in minutes and over the period of a few months. In such a scenario, it would make sense to provide the server with a webhook to another datastore to store the response before the user asks the client to further interact with the results.
Proposed Solution
Supporting webhooks should be a server-level capability even though this capability would only be supported for the asynchronous tools within the server. The server’s capability to support webhooks should be communicated to the client during initialization when capability negotiation takes place.
If the client wishes to make use of webhook(s) when interacting with a tool, it needs to add the webhooks to the call tool request. The client can base this decision on the tool annotations that can provide details about whether the tool is async, supports streaming etc- (#489).
Call tools request should be able to accept multiple webhooks from the client. Each webhook should provide details about its authentication mechanism (if any) and the credentials needed for them. The mentioned auth mechanisms mostly involve passing credential values in some form of header.
If the server detects webhooks provided as part of a CallTools request and the tool is asynchronous, it will return an HTTP status of 202 to indicate that the request has been accepted and is being executed asynchronously. It will also communicate a unique identifier to identify the async execution/resource since there might be multiple async executions that the server is performing for the client in the background. The client should be able to recognize which response corresponds to which query when the result is transmitted to the webhook.
The result transmitted to the webhook will be of type CallToolResult and will contain the resource uri to identify which async execution it pertains to.
The above solution is written with the idea that an async tool execution can be modeled as an async resource. There is some conversation on the discussion that indicates that async tool executions can instead be modeled as async+streaming. In that case, the server should stream the response to the webhooks. However, there would need to be some stream handling logic that is built-in at the webhook to be able to deal with the mergeable results.
Scope
Beta Was this translation helpful? Give feedback.
All reactions