Implement MCP 2025-06-18 specification compliance
- Replace cookie-based session with Mcp-Session-Id header per MCP spec - Add MCP-Protocol-Version header validation (supports 2025-06-18 only) - Require Mcp-Session-Id header for non-initialize requests per spec - Set Mcp-Session-Id response header during initialization - Update CORS headers to include MCP-specific headers This ensures full compliance with MCP Streamable HTTP transport specification: - Proper session management via headers instead of cookies - Protocol version negotiation and validation - Session ID validation for security - Standards-compliant header handling
Showing
1 changed file
with
27 additions
and
2 deletions
| ... | @@ -597,9 +597,34 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -597,9 +597,34 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 597 | return | 597 | return |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | // Validate MCP protocol version per specification | ||
| 601 | String protocolVersion = request.getHeader("MCP-Protocol-Version") | ||
| 602 | if (protocolVersion && protocolVersion != "2025-06-18") { | ||
| 603 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST) | ||
| 604 | response.setContentType("application/json") | ||
| 605 | response.writer.write(groovy.json.JsonOutput.toJson([ | ||
| 606 | jsonrpc: "2.0", | ||
| 607 | error: [code: -32600, message: "Unsupported MCP protocol version: ${protocolVersion}. Supported: 2025-06-18"], | ||
| 608 | id: null | ||
| 609 | ])) | ||
| 610 | return | ||
| 611 | } | ||
| 612 | |||
| 600 | // Get session ID from Mcp-Session-Id header per MCP specification | 613 | // Get session ID from Mcp-Session-Id header per MCP specification |
| 601 | String sessionId = request.getHeader("Mcp-Session-Id") | 614 | String sessionId = request.getHeader("Mcp-Session-Id") |
| 602 | 615 | ||
| 616 | // Validate session ID for non-initialize requests per MCP spec | ||
| 617 | if (!sessionId && rpcRequest.method != "initialize") { | ||
| 618 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST) | ||
| 619 | response.setContentType("application/json") | ||
| 620 | response.writer.write(groovy.json.JsonOutput.toJson([ | ||
| 621 | jsonrpc: "2.0", | ||
| 622 | error: [code: -32600, message: "Mcp-Session-Id header required for non-initialize requests"], | ||
| 623 | id: rpcRequest.id | ||
| 624 | ])) | ||
| 625 | return | ||
| 626 | } | ||
| 627 | |||
| 603 | // Process MCP method using Moqui services with session ID if available | 628 | // Process MCP method using Moqui services with session ID if available |
| 604 | def result = processMcpMethod(rpcRequest.method, rpcRequest.params, ec, sessionId) | 629 | def result = processMcpMethod(rpcRequest.method, rpcRequest.params, ec, sessionId) |
| 605 | 630 | ||
| ... | @@ -613,9 +638,9 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -613,9 +638,9 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 613 | response.setContentType("application/json") | 638 | response.setContentType("application/json") |
| 614 | response.setCharacterEncoding("UTF-8") | 639 | response.setCharacterEncoding("UTF-8") |
| 615 | 640 | ||
| 616 | // Set session cookie if result contains sessionId | 641 | // Set Mcp-Session-Id header if result contains sessionId (per MCP 2025-06-18 spec) |
| 617 | if (rpcResponse.result?.sessionId) { | 642 | if (rpcResponse.result?.sessionId) { |
| 618 | response.setHeader("Set-Cookie", "MCP-SESSION=${rpcResponse.result.sessionId}; Path=/; HttpOnly; SameSite=Lax") | 643 | response.setHeader("Mcp-Session-Id", rpcResponse.result.sessionId) |
| 619 | } | 644 | } |
| 620 | 645 | ||
| 621 | response.writer.write(groovy.json.JsonOutput.toJson(rpcResponse)) | 646 | response.writer.write(groovy.json.JsonOutput.toJson(rpcResponse)) | ... | ... |
-
Please register or sign in to post a comment