@@ -117,7 +117,8 @@ bool StreamableHttpServerWrapper::start()
117117 svr_->Options (mcp_path_,
118118 [this ](const httplib::Request&, httplib::Response& res)
119119 {
120- res.set_header (" Access-Control-Allow-Methods" , " POST, OPTIONS" );
120+ res.set_header (" Access-Control-Allow-Methods" ,
121+ " GET, POST, DELETE, OPTIONS" );
121122 res.set_header (" Access-Control-Allow-Headers" ,
122123 " Content-Type, Authorization, Mcp-Session-Id" );
123124 apply_additional_response_headers (res);
@@ -129,6 +130,11 @@ bool StreamableHttpServerWrapper::start()
129130 mcp_path_,
130131 [this ](const httplib::Request& req, httplib::Response& res)
131132 {
133+ // Apply CORS / additional headers up-front so they are present on every
134+ // response, including early returns (401, 503, 400, 404) and any exception
135+ // propagated to the catch handlers below.
136+ apply_additional_response_headers (res);
137+
132138 try
133139 {
134140 // Security: Check authentication if configured
@@ -143,8 +149,6 @@ bool StreamableHttpServerWrapper::start()
143149 }
144150 }
145151
146- apply_additional_response_headers (res);
147-
148152 // Parse JSON-RPC message
149153 auto message = fastmcpp::util::json::parse (req.body );
150154
@@ -336,8 +340,13 @@ bool StreamableHttpServerWrapper::start()
336340
337341 // Handle GET request to return 405 Method Not Allowed
338342 svr_->Get (mcp_path_,
339- [](const httplib::Request&, httplib::Response& res)
343+ [this ](const httplib::Request&, httplib::Response& res)
340344 {
345+ // CORS / additional headers must be applied on every response, including
346+ // this 405. Without this, browsers reject the response with a misleading
347+ // "No 'Access-Control-Allow-Origin' header is present" error.
348+ apply_additional_response_headers (res);
349+
341350 res.status = 405 ;
342351 res.set_header (" Allow" , " POST" );
343352 res.set_header (" Content-Type" , " application/json" );
@@ -349,6 +358,27 @@ bool StreamableHttpServerWrapper::start()
349358 res.set_content (error_response.dump (), " application/json" );
350359 });
351360
361+ // Handle DELETE request for session termination (MCP Streamable HTTP spec).
362+ // Without this handler, httplib would fall back to its default 404 response,
363+ // which does not carry the configured CORS headers - causing browsers to report
364+ // a "No 'Access-Control-Allow-Origin' header is present" error.
365+ svr_->Delete (mcp_path_,
366+ [this ](const httplib::Request& req, httplib::Response& res)
367+ {
368+ apply_additional_response_headers (res);
369+
370+ // If an Mcp-Session-Id header is provided, terminate that session.
371+ auto session_it = req.headers .find (" Mcp-Session-Id" );
372+ if (session_it != req.headers .end ())
373+ {
374+ const std::string& session_id = session_it->second ;
375+ std::lock_guard<std::mutex> lock (sessions_mutex_);
376+ sessions_.erase (session_id);
377+ }
378+
379+ res.status = 204 ; // No Content
380+ });
381+
352382 running_ = true ;
353383
354384 thread_ = std::thread ([this ]() { run_server (); });
0 commit comments