diff --git a/src/tools/mcp/http_transport.rs b/src/tools/mcp/http_transport.rs index ec7139c9..59873ce4 100644 --- a/src/tools/mcp/http_transport.rs +++ b/src/tools/mcp/http_transport.rs @@ -130,6 +130,16 @@ impl McpTransport for HttpMcpTransport { ))); } + // MCP notifications commonly acknowledge with 202 Accepted and no body. + if response.status() == reqwest::StatusCode::ACCEPTED { + return Ok(McpResponse { + jsonrpc: "2.0".to_string(), + id: request.id, + result: None, + error: None, + }); + } + // Determine response format from Content-Type. let content_type = response .headers() @@ -506,4 +516,55 @@ mod tests { let echoed = response.result.unwrap(); assert_eq!(echoed["authorization"], "Bearer custom-token"); } + + async fn spawn_accepted_server() -> (String, tokio::task::JoinHandle<()>) { + use axum::{Router, routing::post}; + use tokio::net::TcpListener; + + async fn accepted() -> axum::http::StatusCode { + axum::http::StatusCode::ACCEPTED + } + + let app = Router::new().route("/", post(accepted)); + let listener = TcpListener::bind("127.0.0.1:0") + .await + .expect("Failed to bind to an ephemeral port"); + let addr = listener + .local_addr() + .expect("Failed to get listener's local address"); + let url = format!("http://127.0.0.1:{}", addr.port()); + + let handle = tokio::spawn(async move { + axum::serve(listener, app) + .await + .expect("Test server failed to run"); + }); + + (url, handle) + } + + fn notification_request(method: &str) -> McpRequest { + McpRequest { + jsonrpc: "2.0".to_string(), + id: None, + method: method.to_string(), + params: None, + } + } + + #[tokio::test] + async fn test_accepted_notification_returns_empty_response() { + let (url, _handle) = spawn_accepted_server().await; + let transport = HttpMcpTransport::new(&url, "accepted-test"); + let request = notification_request("notifications/initialized"); + + let response = transport + .send(&request, &HashMap::new()) + .await + .expect("202 notification response"); + assert_eq!(response.jsonrpc, "2.0"); + assert_eq!(response.id, request.id); + assert!(response.result.is_none()); + assert!(response.error.is_none()); + } }