From a15be695e0f5342a46680d0bdd35aa9dade4becb Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Sun, 18 Jan 2026 23:19:04 +0500 Subject: [PATCH] Add GET/OPTIONS handlers for MCP HTTP transport - Add render_GET() returning 405 Method Not Allowed - Add render_OPTIONS() --- include/MCP_Endpoint.h | 37 +++++++++++++++++++++++++++---- lib/MCP_Endpoint.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/include/MCP_Endpoint.h b/include/MCP_Endpoint.h index 7e7bd5f05..2793b5a79 100644 --- a/include/MCP_Endpoint.h +++ b/include/MCP_Endpoint.h @@ -61,12 +61,12 @@ private: * @brief Create a JSON-RPC 2.0 success response * * @param result The result data to include - * @param id The request ID + * @param id The request ID (can be string, number, or null) * @return JSON string representing the response */ std::string create_jsonrpc_response( const std::string& result, - const std::string& id = "1" + const json& id = nullptr ); /** @@ -74,13 +74,13 @@ private: * * @param code The error code (JSON-RPC standard or custom) * @param message The error message - * @param id The request ID + * @param id The request ID (can be string, number, or null) * @return JSON string representing the error response */ std::string create_jsonrpc_error( int code, const std::string& message, - const std::string& id = "" + const json& id = nullptr ); /** @@ -127,6 +127,35 @@ public: */ ~MCP_JSONRPC_Resource(); + /** + * @brief Handle GET requests + * + * Returns HTTP 405 Method Not Allowed for GET requests. + * + * According to the MCP specification (Streamable HTTP transport): + * "The server MUST either return Content-Type: text/event-stream in response to + * this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that + * the server does not offer an SSE stream at this endpoint." + * + * @param req The HTTP request + * @return HTTP 405 response with Allow: POST header + */ + const std::shared_ptr render_GET( + const httpserver::http_request& req + ) override; + + /** + * @brief Handle OPTIONS requests (CORS preflight) + * + * Returns CORS headers for OPTIONS preflight requests. + * + * @param req The HTTP request + * @return HTTP response with CORS headers + */ + const std::shared_ptr render_OPTIONS( + const httpserver::http_request& req + ) override; + /** * @brief Handle POST requests * diff --git a/lib/MCP_Endpoint.cpp b/lib/MCP_Endpoint.cpp index f5484a94a..7b39c31cf 100644 --- a/lib/MCP_Endpoint.cpp +++ b/lib/MCP_Endpoint.cpp @@ -98,6 +98,55 @@ bool MCP_JSONRPC_Resource::authenticate_request(const httpserver::http_request& return authenticated; } +const std::shared_ptr MCP_JSONRPC_Resource::render_GET( + const httpserver::http_request& req +) { + std::string req_path = req.get_path(); + proxy_debug(PROXY_DEBUG_GENERIC, 2, "Received MCP GET request on %s - returning 405 Method Not Allowed\n", req_path.c_str()); + + // According to the MCP specification (Streamable HTTP transport): + // "The server MUST either return Content-Type: text/event-stream in response to + // this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that + // the server does not offer an SSE stream at this endpoint." + // + // This server does not currently support SSE streaming, so we return 405. + auto response = std::shared_ptr(new string_response( + "", + http::http_utils::http_method_not_allowed // 405 + )); + response->with_header("Allow", "POST"); // Tell client what IS allowed + + if (handler) { + handler->status_variables.total_requests++; + } + + return response; +} + +const std::shared_ptr MCP_JSONRPC_Resource::render_OPTIONS( + const httpserver::http_request& req +) { + std::string req_path = req.get_path(); + proxy_debug(PROXY_DEBUG_GENERIC, 2, "Received MCP OPTIONS request on %s\n", req_path.c_str()); + + // Handle CORS preflight requests for MCP HTTP transport + // Return 200 OK with appropriate CORS headers + auto response = std::shared_ptr(new string_response( + "", + http::http_utils::http_ok + )); + response->with_header("Content-Type", "application/json"); + response->with_header("Access-Control-Allow-Origin", "*"); + response->with_header("Access-Control-Allow-Methods", "POST, OPTIONS"); + response->with_header("Access-Control-Allow-Headers", "Content-Type, Authorization"); + + if (handler) { + handler->status_variables.total_requests++; + } + + return response; +} + std::string MCP_JSONRPC_Resource::create_jsonrpc_response( const std::string& result, const std::string& id