Fix MCP session initialization - ensure Visit created in servlet before Initialize service
- Add Visit creation to servlet service method for JSON-RPC requests - Fix variable scope issue where visit was undefined in service method - Pass visitId to Initialize service instead of null sessionId - Clean up duplicate session validation code in services - Update version numbers to reflect fixes MCP interface now fully functional with proper session management
Showing
2 changed files
with
96 additions
and
166 deletions
| ... | @@ -109,7 +109,7 @@ | ... | @@ -109,7 +109,7 @@ |
| 109 | // Build server info | 109 | // Build server info |
| 110 | def serverInfo = [ | 110 | def serverInfo = [ |
| 111 | name: "Moqui MCP Server", | 111 | name: "Moqui MCP Server", |
| 112 | version: "2.0.0" | 112 | version: "2.0.1" |
| 113 | ] | 113 | ] |
| 114 | 114 | ||
| 115 | result = [ | 115 | result = [ |
| ... | @@ -380,6 +380,7 @@ | ... | @@ -380,6 +380,7 @@ |
| 380 | <actions> | 380 | <actions> |
| 381 | <script><![CDATA[ | 381 | <script><![CDATA[ |
| 382 | import org.moqui.context.ExecutionContext | 382 | import org.moqui.context.ExecutionContext |
| 383 | import org.moqui.impl.context.UserFacadeImpl.UserInfo | ||
| 383 | import groovy.json.JsonBuilder | 384 | import groovy.json.JsonBuilder |
| 384 | 385 | ||
| 385 | ExecutionContext ec = context.ec | 386 | ExecutionContext ec = context.ec |
| ... | @@ -391,11 +392,13 @@ | ... | @@ -391,11 +392,13 @@ |
| 391 | 392 | ||
| 392 | // Capture original user for permission context | 393 | // Capture original user for permission context |
| 393 | def originalUsername = ec.user.username | 394 | def originalUsername = ec.user.username |
| 395 | UserInfo adminUserInfo = null | ||
| 394 | 396 | ||
| 395 | // Validate session if provided | 397 | // Validate session if provided |
| 398 | /* | ||
| 396 | if (sessionId) { | 399 | if (sessionId) { |
| 397 | def visit = null | 400 | def visit = null |
| 398 | UserInfo adminUserInfo = null | 401 | adminUserInfo = null |
| 399 | try { | 402 | try { |
| 400 | adminUserInfo = ec.user.pushUser("ADMIN") | 403 | adminUserInfo = ec.user.pushUser("ADMIN") |
| 401 | visit = ec.entity.find("moqui.server.Visit") | 404 | visit = ec.entity.find("moqui.server.Visit") |
| ... | @@ -422,13 +425,14 @@ | ... | @@ -422,13 +425,14 @@ |
| 422 | //throw new Exception("Invalid session: ${sessionId}") | 425 | //throw new Exception("Invalid session: ${sessionId}") |
| 423 | } | 426 | } |
| 424 | } | 427 | } |
| 428 | */ | ||
| 425 | 429 | ||
| 426 | def startTime = System.currentTimeMillis() | 430 | def startTime = System.currentTimeMillis() |
| 427 | try { | 431 | try { |
| 428 | // Execute service with elevated privileges for system access | 432 | // Execute service with elevated privileges for system access |
| 429 | // but maintain audit context with actual user | 433 | // but maintain audit context with actual user |
| 430 | def serviceResult | 434 | def serviceResult |
| 431 | UserInfo adminUserInfo = null | 435 | adminUserInfo = null |
| 432 | try { | 436 | try { |
| 433 | serviceResult = ec.service.sync().name(name).parameters(arguments ?: [:]).call() | 437 | serviceResult = ec.service.sync().name(name).parameters(arguments ?: [:]).call() |
| 434 | } finally { | 438 | } finally { |
| ... | @@ -491,40 +495,18 @@ | ... | @@ -491,40 +495,18 @@ |
| 491 | 495 | ||
| 492 | ExecutionContext ec = context.ec | 496 | ExecutionContext ec = context.ec |
| 493 | 497 | ||
| 494 | // Permissions are handled by Moqui's artifact authorization system | ||
| 495 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group | ||
| 496 | |||
| 497 | def visit | ||
| 498 | |||
| 499 | // Validate session if provided | ||
| 500 | if (sessionId) { | ||
| 501 | visit = ec.entity.find("moqui.server.Visit") | ||
| 502 | .condition("visitId", sessionId) | ||
| 503 | .disableAuthz() | ||
| 504 | .one() | ||
| 505 | |||
| 506 | ec.logger.info("VISIT 530 ${visit}") | ||
| 507 | |||
| 508 | /* | ||
| 509 | if (!visit || visit.userId != ec.user.userId) { | ||
| 510 | throw new Exception("Invalid session: ${sessionId}") | ||
| 511 | } | ||
| 512 | */ | ||
| 513 | } | ||
| 514 | |||
| 515 | // Build list of available entities as resources | 498 | // Build list of available entities as resources |
| 516 | def resources = [] | 499 | def resources = [] |
| 517 | 500 | ||
| 518 | UserInfo adminUserInfo = null | 501 | UserInfo adminUserInfo = null |
| 519 | 502 | ||
| 520 | // Update session activity | 503 | // Update session activity |
| 521 | /* | 504 | def metadata = [:] |
| 522 | def metadata = [:] | 505 | try { |
| 523 | try { | 506 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map |
| 524 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map | 507 | } catch (Exception e) { |
| 525 | } catch (Exception e) { | 508 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") |
| 526 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | 509 | } |
| 527 | } | ||
| 528 | 510 | ||
| 529 | // Store original user context before switching to ADMIN | 511 | // Store original user context before switching to ADMIN |
| 530 | def originalUsername = ec.user.username | 512 | def originalUsername = ec.user.username |
| ... | @@ -594,52 +576,6 @@ | ... | @@ -594,52 +576,6 @@ |
| 594 | 576 | ||
| 595 | ExecutionContext ec = context.ec | 577 | ExecutionContext ec = context.ec |
| 596 | 578 | ||
| 597 | // Validate session if provided | ||
| 598 | if (sessionId) { | ||
| 599 | def visit = null | ||
| 600 | UserInfo adminUserInfo = null | ||
| 601 | try { | ||
| 602 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 603 | visit = ec.entity.find("moqui.server.Visit") | ||
| 604 | .condition("visitId", sessionId) | ||
| 605 | .one() | ||
| 606 | } finally { | ||
| 607 | if (adminUserInfo != null) { | ||
| 608 | ec.user.popUser() | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | if (!visit || visit.userId != ec.user.userId) { | ||
| 613 | //throw new Exception("Invalid session: ${sessionId}") | ||
| 614 | } | ||
| 615 | |||
| 616 | // Update session activity | ||
| 617 | def metadata = [:] | ||
| 618 | try { | ||
| 619 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map | ||
| 620 | } catch (Exception e) { | ||
| 621 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | ||
| 622 | } | ||
| 623 | |||
| 624 | metadata.mcpLastActivity = System.currentTimeMillis() | ||
| 625 | metadata.mcpLastOperation = "resources/read" | ||
| 626 | metadata.mcpLastResource = uri | ||
| 627 | |||
| 628 | UserInfo adminUserInfo = null | ||
| 629 | try { | ||
| 630 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 631 | ec.logger.info("MCP session update visit 671 ${visit}") | ||
| 632 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | ||
| 633 | ec.artifactExecution.disableAuthz() | ||
| 634 | visit.update() | ||
| 635 | ec.artifactExecution.enableAuthz() | ||
| 636 | } finally { | ||
| 637 | if (adminUserInfo != null) { | ||
| 638 | ec.user.popUser() | ||
| 639 | } | ||
| 640 | } | ||
| 641 | } | ||
| 642 | |||
| 643 | // Parse entity URI (format: entity://EntityName) | 579 | // Parse entity URI (format: entity://EntityName) |
| 644 | if (!uri.startsWith("entity://")) { | 580 | if (!uri.startsWith("entity://")) { |
| 645 | throw new Exception("Invalid resource URI: ${uri}") | 581 | throw new Exception("Invalid resource URI: ${uri}") |
| ... | @@ -719,80 +655,10 @@ | ... | @@ -719,80 +655,10 @@ |
| 719 | </out-parameters> | 655 | </out-parameters> |
| 720 | <actions> | 656 | <actions> |
| 721 | <script><![CDATA[ | 657 | <script><![CDATA[ |
| 722 | // Permissions are handled by Moqui's artifact authorization system | ||
| 723 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group | ||
| 724 | |||
| 725 | // Validate session if provided | ||
| 726 | if (sessionId) { | ||
| 727 | def visit = ec.entity.find("moqui.server.Visit") | ||
| 728 | .condition("visitId", sessionId) | ||
| 729 | .one() | ||
| 730 | |||
| 731 | if (!visit || visit.userId != ec.user.userId) { | ||
| 732 | //throw new Exception("Invalid session: ${sessionId}") | ||
| 733 | } | ||
| 734 | |||
| 735 | // Update session activity | ||
| 736 | def metadata = [:] | ||
| 737 | try { | ||
| 738 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map | ||
| 739 | } catch (Exception e) { | ||
| 740 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | ||
| 741 | } | ||
| 742 | |||
| 743 | metadata.mcpLastActivity = System.currentTimeMillis() | ||
| 744 | metadata.mcpLastOperation = "ping" | ||
| 745 | |||
| 746 | // Update Visit - need admin context for Visit updates | ||
| 747 | UserInfo adminUserInfo = null | ||
| 748 | try { | ||
| 749 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 750 | ec.logger.info("MCP session update visit 789 ${visit}") | ||
| 751 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | ||
| 752 | ec.artifactExecution.disableAuthz() | ||
| 753 | visit.update() | ||
| 754 | ec.artifactExecution.enableAuthz() | ||
| 755 | } finally { | ||
| 756 | if (adminUserInfo != null) { | ||
| 757 | ec.user.popUser() | ||
| 758 | } | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 762 | if (!visit || visit.userId != ec.user.userId) { | ||
| 763 | //throw new Exception("Invalid session: ${sessionId}") | ||
| 764 | } | ||
| 765 | |||
| 766 | // Update session activity | ||
| 767 | def metadata = [:] | ||
| 768 | try { | ||
| 769 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map | ||
| 770 | } catch (Exception e) { | ||
| 771 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | ||
| 772 | } | ||
| 773 | |||
| 774 | metadata.mcpLastActivity = System.currentTimeMillis() | ||
| 775 | metadata.mcpLastOperation = "ping" | ||
| 776 | |||
| 777 | UserInfo adminUserInfo = null | ||
| 778 | try { | ||
| 779 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 780 | ec.logger.info("MCP session update visit 819 ${visit}") | ||
| 781 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | ||
| 782 | ec.artifactExecution.disableAuthz() | ||
| 783 | visit.update() | ||
| 784 | ec.artifactExecution.enableAuthz() | ||
| 785 | } finally { | ||
| 786 | if (adminUserInfo != null) { | ||
| 787 | ec.user.popUser() | ||
| 788 | } | ||
| 789 | } | ||
| 790 | } | ||
| 791 | |||
| 792 | result = [ | 658 | result = [ |
| 793 | timestamp: ec.user.getNowTimestamp(), | 659 | timestamp: ec.user.getNowTimestamp(), |
| 794 | status: "healthy", | 660 | status: "healthy", |
| 795 | version: "2.0.0", | 661 | version: "2.0.2", |
| 796 | sessionId: sessionId, | 662 | sessionId: sessionId, |
| 797 | architecture: "Visit-based sessions" | 663 | architecture: "Visit-based sessions" |
| 798 | ] | 664 | ] | ... | ... |
| ... | @@ -163,6 +163,71 @@ try { | ... | @@ -163,6 +163,71 @@ try { |
| 163 | return | 163 | return |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | // Create Visit for JSON-RPC requests too | ||
| 167 | def visit = null | ||
| 168 | try { | ||
| 169 | // Initialize web facade for Visit creation | ||
| 170 | ec.initWebFacade(webappName, request, response) | ||
| 171 | // Web facade was successful, get Visit it created | ||
| 172 | visit = ec.user.getVisit() | ||
| 173 | if (!visit) { | ||
| 174 | throw new Exception("Web facade succeeded but no Visit created") | ||
| 175 | } | ||
| 176 | } catch (Exception e) { | ||
| 177 | logger.warn("Web facade initialization failed: ${e.message}, trying manual Visit creation") | ||
| 178 | // Try to create Visit manually using the same pattern as handleSseConnection | ||
| 179 | try { | ||
| 180 | def visitParams = [ | ||
| 181 | sessionId: request.session.id, | ||
| 182 | webappName: webappName, | ||
| 183 | fromDate: new Timestamp(System.currentTimeMillis()), | ||
| 184 | initialLocale: request.locale.toString(), | ||
| 185 | initialRequest: (request.requestURL.toString() + (request.queryString ? "?" + request.queryString : "")).take(255), | ||
| 186 | initialReferrer: request.getHeader("Referer")?.take(255), | ||
| 187 | initialUserAgent: request.getHeader("User-Agent")?.take(255), | ||
| 188 | clientHostName: request.remoteHost, | ||
| 189 | clientUser: request.remoteUser, | ||
| 190 | serverIpAddress: ec.ecfi.getLocalhostAddress().getHostAddress(), | ||
| 191 | serverHostName: ec.ecfi.getLocalhostAddress().getHostName(), | ||
| 192 | clientIpAddress: request.remoteAddr, | ||
| 193 | userId: ec.user.userId, | ||
| 194 | userCreated: "Y" | ||
| 195 | ] | ||
| 196 | |||
| 197 | logger.info("Creating Visit with params: ${visitParams}") | ||
| 198 | def visitResult = ec.service.sync().name("create", "moqui.server.Visit") | ||
| 199 | .parameters(visitParams) | ||
| 200 | .disableAuthz() | ||
| 201 | .call() | ||
| 202 | logger.info("Visit creation result: ${visitResult}") | ||
| 203 | |||
| 204 | if (!visitResult || !visitResult.visitId) { | ||
| 205 | throw new Exception("Visit creation service returned null or no visitId") | ||
| 206 | } | ||
| 207 | |||
| 208 | // Look up the actual Visit EntityValue | ||
| 209 | visit = ec.entity.find("moqui.server.Visit") | ||
| 210 | .condition("visitId", visitResult.visitId) | ||
| 211 | .one() | ||
| 212 | if (!visit) { | ||
| 213 | throw new Exception("Failed to look up newly created Visit") | ||
| 214 | } | ||
| 215 | ec.web.session.setAttribute("moqui.visitId", visit.visitId) | ||
| 216 | logger.info("Manually created Visit ${visit.visitId} for user ${ec.user.username}") | ||
| 217 | |||
| 218 | } catch (Exception visitEx) { | ||
| 219 | logger.error("Manual Visit creation failed: ${visitEx.message}", visitEx) | ||
| 220 | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create Visit") | ||
| 221 | return | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | // Final check that we have a Visit | ||
| 226 | if (!visit) { | ||
| 227 | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create Visit") | ||
| 228 | return | ||
| 229 | } | ||
| 230 | |||
| 166 | // Route based on request method and path | 231 | // Route based on request method and path |
| 167 | String requestURI = request.getRequestURI() | 232 | String requestURI = request.getRequestURI() |
| 168 | String method = request.getMethod() | 233 | String method = request.getMethod() |
| ... | @@ -174,13 +239,13 @@ try { | ... | @@ -174,13 +239,13 @@ try { |
| 174 | handleMessage(request, response, ec) | 239 | handleMessage(request, response, ec) |
| 175 | } else if ("POST".equals(method) && (requestURI.equals("/mcp") || requestURI.endsWith("/mcp"))) { | 240 | } else if ("POST".equals(method) && (requestURI.equals("/mcp") || requestURI.endsWith("/mcp"))) { |
| 176 | // Handle POST requests to /mcp for JSON-RPC | 241 | // Handle POST requests to /mcp for JSON-RPC |
| 177 | handleJsonRpc(request, response, ec, webappName, requestBody) | 242 | handleJsonRpc(request, response, ec, webappName, requestBody, visit) |
| 178 | } else if ("GET".equals(method) && (requestURI.equals("/mcp") || requestURI.endsWith("/mcp"))) { | 243 | } else if ("GET".equals(method) && (requestURI.equals("/mcp") || requestURI.endsWith("/mcp"))) { |
| 179 | // Handle GET requests to /mcp - maybe for server info or SSE fallback | 244 | // Handle GET requests to /mcp - maybe for server info or SSE fallback |
| 180 | handleSseConnection(request, response, ec, webappName) | 245 | handleSseConnection(request, response, ec, webappName) |
| 181 | } else { | 246 | } else { |
| 182 | // Fallback to JSON-RPC handling | 247 | // Fallback to JSON-RPC handling |
| 183 | handleJsonRpc(request, response, ec, webappName, requestBody) | 248 | handleJsonRpc(request, response, ec, webappName, requestBody, visit) |
| 184 | } | 249 | } |
| 185 | 250 | ||
| 186 | } catch (ArtifactAuthorizationException e) { | 251 | } catch (ArtifactAuthorizationException e) { |
| ... | @@ -527,7 +592,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -527,7 +592,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 527 | } | 592 | } |
| 528 | } | 593 | } |
| 529 | 594 | ||
| 530 | private void handleJsonRpc(HttpServletRequest request, HttpServletResponse response, ExecutionContextImpl ec, String webappName, String requestBody) | 595 | private void handleJsonRpc(HttpServletRequest request, HttpServletResponse response, ExecutionContextImpl ec, String webappName, String requestBody, def visit) |
| 531 | throws IOException { | 596 | throws IOException { |
| 532 | 597 | ||
| 533 | // Initialize web facade for proper session management (like SSE connections) | 598 | // Initialize web facade for proper session management (like SSE connections) |
| ... | @@ -657,11 +722,11 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -657,11 +722,11 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 657 | // This ensures Moqui picks up the existing Visit when initWebFacade() is called | 722 | // This ensures Moqui picks up the existing Visit when initWebFacade() is called |
| 658 | if (sessionId && rpcRequest.method != "initialize") { | 723 | if (sessionId && rpcRequest.method != "initialize") { |
| 659 | try { | 724 | try { |
| 660 | def visit = ec.entity.find("moqui.server.Visit") | 725 | def existingVisit = ec.entity.find("moqui.server.Visit") |
| 661 | .condition("visitId", sessionId) | 726 | .condition("visitId", sessionId) |
| 662 | .one() | 727 | .one() |
| 663 | 728 | ||
| 664 | if (!visit) { | 729 | if (!existingVisit) { |
| 665 | response.setStatus(HttpServletResponse.SC_NOT_FOUND) | 730 | response.setStatus(HttpServletResponse.SC_NOT_FOUND) |
| 666 | response.setContentType("application/json") | 731 | response.setContentType("application/json") |
| 667 | response.writer.write(groovy.json.JsonOutput.toJson([ | 732 | response.writer.write(groovy.json.JsonOutput.toJson([ |
| ... | @@ -672,14 +737,8 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -672,14 +737,8 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 672 | return | 737 | return |
| 673 | } | 738 | } |
| 674 | 739 | ||
| 675 | // Verify user has access to this Visit | ||
| 676 | logger.info("Session access check - visit.userId: ${visit.userId}, ec.user.userId: ${ec.user.userId}") | ||
| 677 | |||
| 678 | // Allow access if: | ||
| 679 | // 1. Visit userId matches current user, OR | ||
| 680 | // 2. Visit was created with ADMIN (for privileged access) but current user is MCP_USER (actual authenticated user) | ||
| 681 | // Rely on Moqui security - only allow access if visit and current user match | 740 | // Rely on Moqui security - only allow access if visit and current user match |
| 682 | if (!visit.userId || !ec.user.userId || visit.userId.toString() != ec.user.userId.toString()) { | 741 | if (!existingVisit.userId || !ec.user.userId || existingVisit.userId.toString() != ec.user.userId.toString()) { |
| 683 | response.setStatus(HttpServletResponse.SC_FORBIDDEN) | 742 | response.setStatus(HttpServletResponse.SC_FORBIDDEN) |
| 684 | response.setContentType("application/json") | 743 | response.setContentType("application/json") |
| 685 | response.writer.write(groovy.json.JsonOutput.toJson([ | 744 | response.writer.write(groovy.json.JsonOutput.toJson([ |
| ... | @@ -708,7 +767,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -708,7 +767,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 708 | } | 767 | } |
| 709 | 768 | ||
| 710 | // Process MCP method using Moqui services with session ID if available | 769 | // Process MCP method using Moqui services with session ID if available |
| 711 | def result = processMcpMethod(rpcRequest.method, rpcRequest.params, ec, sessionId) | 770 | def result = processMcpMethod(rpcRequest.method, rpcRequest.params, ec, sessionId, visit) |
| 712 | 771 | ||
| 713 | // Set Mcp-Session-Id header BEFORE any response data (per MCP 2025-06-18 spec) | 772 | // Set Mcp-Session-Id header BEFORE any response data (per MCP 2025-06-18 spec) |
| 714 | if (result?.sessionId) { | 773 | if (result?.sessionId) { |
| ... | @@ -728,7 +787,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -728,7 +787,7 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 728 | response.writer.write(groovy.json.JsonOutput.toJson(rpcResponse)) | 787 | response.writer.write(groovy.json.JsonOutput.toJson(rpcResponse)) |
| 729 | } | 788 | } |
| 730 | 789 | ||
| 731 | private Map<String, Object> processMcpMethod(String method, Map params, ExecutionContextImpl ec, String sessionId) { | 790 | private Map<String, Object> processMcpMethod(String method, Map params, ExecutionContextImpl ec, String sessionId, def visit) { |
| 732 | logger.info("Enhanced METHOD: ${method} with sessionId: ${sessionId}") | 791 | logger.info("Enhanced METHOD: ${method} with sessionId: ${sessionId}") |
| 733 | 792 | ||
| 734 | try { | 793 | try { |
| ... | @@ -738,18 +797,23 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") | ... | @@ -738,18 +797,23 @@ logger.info("Handling Enhanced SSE connection from ${request.remoteAddr}") |
| 738 | } | 797 | } |
| 739 | 798 | ||
| 740 | // Add session context to parameters for services | 799 | // Add session context to parameters for services |
| 741 | params.sessionId = sessionId | 800 | params.sessionId = visit.visitId |
| 742 | 801 | ||
| 743 | switch (method) { | 802 | switch (method) { |
| 744 | case "initialize": | 803 | case "initialize": |
| 745 | // For initialize, use the visitId we just created instead of null sessionId from request | 804 | // For initialize, use the visitId we just created instead of null sessionId from request |
| 746 | params.sessionId = visit.visitId | 805 | if (visit && visit.visitId) { |
| 806 | params.sessionId = visit.visitId | ||
| 807 | logger.info("Initialize - using visitId: ${visit.visitId}") | ||
| 808 | } else { | ||
| 809 | logger.warn("Initialize - no visit available, using null sessionId") | ||
| 810 | } | ||
| 747 | params.actualUserId = ec.user.userId | 811 | params.actualUserId = ec.user.userId |
| 748 | logger.info("Initialize - actualUserId: ${params.actualUserId}, sessionId: ${params.sessionId}") | 812 | logger.info("Initialize - actualUserId: ${params.actualUserId}, sessionId: ${params.sessionId}") |
| 749 | return callMcpService("mcp#Initialize", params, ec) | 813 | return callMcpService("mcp#Initialize", params, ec) |
| 750 | case "ping": | 814 | case "ping": |
| 751 | // Simple ping for testing - bypass service for now | 815 | // Simple ping for testing - bypass service for now |
| 752 | return [pong: System.currentTimeMillis(), sessionId: sessionId, user: ec.user.username] | 816 | return [pong: System.currentTimeMillis(), sessionId: visit.visitId, user: ec.user.username] |
| 753 | case "tools/list": | 817 | case "tools/list": |
| 754 | return callMcpService("mcp#ToolsList", params, ec) | 818 | return callMcpService("mcp#ToolsList", params, ec) |
| 755 | case "tools/call": | 819 | case "tools/call": | ... | ... |
-
Please register or sign in to post a comment