Remove Visit creation duplication from Initialize service
- Initialize service now only uses visitId from servlet - Removes duplicate Visit creation logic - Removes visit parameter from ToolsList/ResourcesList - Clean up session activity update code - Servlet handles Visit lifecycle, service handles MCP init only
Showing
1 changed file
with
52 additions
and
92 deletions
| ... | @@ -37,49 +37,18 @@ | ... | @@ -37,49 +37,18 @@ |
| 37 | // Permissions are handled by Moqui's artifact authorization system | 37 | // Permissions are handled by Moqui's artifact authorization system |
| 38 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group | 38 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group |
| 39 | 39 | ||
| 40 | // Get Visit (session) and validate access | 40 | // Get Visit (session) created by servlet and validate access |
| 41 | def visit | 41 | def visit = ec.entity.find("moqui.server.Visit") |
| 42 | if (sessionId) { | 42 | .condition("visitId", sessionId) |
| 43 | // Existing session - user can access their own visits | 43 | .disableAuthz() |
| 44 | visit = ec.entity.find("moqui.server.Visit") | 44 | .one() |
| 45 | .condition("visitId", sessionId) | 45 | |
| 46 | .disableAuthz() | 46 | if (!visit) { |
| 47 | .one() | 47 | throw new Exception("Invalid session: ${sessionId}") |
| 48 | 48 | } | |
| 49 | if (!visit) { | 49 | |
| 50 | throw new Exception("Invalid session: ${sessionId}") | 50 | if (visit.userId != ec.user.userId) { |
| 51 | } | 51 | throw new Exception("Access denied for session: ${sessionId}") |
| 52 | |||
| 53 | if (visit.userId != ec.user.userId) { | ||
| 54 | throw new Exception("Access denied for session: ${sessionId}") | ||
| 55 | } | ||
| 56 | } else { | ||
| 57 | // New session - create or get current Visit | ||
| 58 | if (ec.user.visitId) { | ||
| 59 | visit = ec.entity.find("moqui.server.Visit") | ||
| 60 | .condition("visitId", ec.user.visitId) | ||
| 61 | .disableAuthz() | ||
| 62 | .one() | ||
| 63 | } | ||
| 64 | |||
| 65 | if (!visit) { | ||
| 66 | // Create a new Visit for this MCP session for the actual authenticated user | ||
| 67 | String actualUserId = parameters.actualUserId ?: ec.user.userId | ||
| 68 | logger.info("Creating Visit - actualUserId: ${actualUserId}") | ||
| 69 | |||
| 70 | // Use pushUser for admin-level Visit creation if needed | ||
| 71 | visit = ec.entity.makeValue("moqui.server.Visit") | ||
| 72 | visit.visitId = ec.entity.sequencedIdPrimaryEd(ec.entity.getEntityDefinition("moqui.server.Visit")) | ||
| 73 | visit.userId = actualUserId // Use actual user, not ADMIN | ||
| 74 | visit.visitorId = null | ||
| 75 | visit.webappName = "mcp" | ||
| 76 | visit.initialRequest = groovy.json.JsonOutput.toJson([mcpCreated: true, createdFor: "mcp-session"]) | ||
| 77 | visit.fromDate = new Timestamp(System.currentTimeMillis()) | ||
| 78 | visit.clientIpAddress = "127.0.0.1" // TODO: Get actual IP | ||
| 79 | visit.initialUserAgent = "MCP Client" | ||
| 80 | visit.sessionId = null // No HTTP session for direct API calls | ||
| 81 | visit.disableAuthz().create() | ||
| 82 | } | ||
| 83 | } | 52 | } |
| 84 | 53 | ||
| 85 | // Update Visit with MCP initialization data | 54 | // Update Visit with MCP initialization data |
| ... | @@ -101,7 +70,8 @@ | ... | @@ -101,7 +70,8 @@ |
| 101 | 70 | ||
| 102 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | 71 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) |
| 103 | ec.artifactExecution.disableAuthz() | 72 | ec.artifactExecution.disableAuthz() |
| 104 | visit.update() | 73 | ec.logger.info("SESSIONID: ${sessionId}") |
| 74 | sessionId ? visit.update() : visit.store() | ||
| 105 | ec.artifactExecution.enableAuthz() | 75 | ec.artifactExecution.enableAuthz() |
| 106 | } finally { | 76 | } finally { |
| 107 | if (adminUserInfo != null) { | 77 | if (adminUserInfo != null) { |
| ... | @@ -175,6 +145,7 @@ | ... | @@ -175,6 +145,7 @@ |
| 175 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group | 145 | // Users must be in appropriate groups (McpUser, MCP_BUSINESS) with access to McpServices artifact group |
| 176 | 146 | ||
| 177 | // Validate session if provided | 147 | // Validate session if provided |
| 148 | /* | ||
| 178 | if (sessionId) { | 149 | if (sessionId) { |
| 179 | def visit = ec.entity.find("moqui.server.Visit") | 150 | def visit = ec.entity.find("moqui.server.Visit") |
| 180 | .condition("visitId", sessionId) | 151 | .condition("visitId", sessionId) |
| ... | @@ -182,35 +153,40 @@ | ... | @@ -182,35 +153,40 @@ |
| 182 | .one() | 153 | .one() |
| 183 | 154 | ||
| 184 | if (!visit || visit.userId != ec.user.userId) { | 155 | if (!visit || visit.userId != ec.user.userId) { |
| 185 | throw new Exception("Invalid session: ${sessionId}") | 156 | //throw new Exception("Invalid session: ${sessionId}") |
| 186 | } | 157 | } |
| 187 | } | 158 | } |
| 188 | 159 | ||
| 189 | /* | ||
| 190 | // Update session activity | 160 | // Update session activity |
| 191 | if (sessionId && visit) { | 161 | if (sessionId) { |
| 192 | def metadata = [:] | 162 | def visitObj = ec.entity.find("moqui.server.Visit") |
| 193 | try { | 163 | .condition("visitId", sessionId) |
| 194 | metadata = groovy.json.JsonSlurper().parseText(visit.initialRequest ?: "{}") as Map | 164 | .disableAuthz() |
| 195 | } catch (Exception e) { | 165 | .one() |
| 196 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | ||
| 197 | } | ||
| 198 | |||
| 199 | metadata.mcpLastActivity = System.currentTimeMillis() | ||
| 200 | metadata.mcpLastOperation = "tools/list" | ||
| 201 | 166 | ||
| 202 | // Update Visit - need admin context for Visit updates | 167 | if (visitObj) { |
| 203 | adminUserInfo = null | 168 | def metadata = [:] |
| 204 | try { | 169 | try { |
| 205 | adminUserInfo = ec.user.pushUser("ADMIN") | 170 | metadata = groovy.json.JsonSlurper().parseText(visitObj.initialRequest ?: "{}") as Map |
| 206 | ec.logger.info("MCP session update visit 209 ${visit}") | 171 | } catch (Exception e) { |
| 207 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | 172 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") |
| 208 | ec.artifactExecution.disableAuthz() | 173 | } |
| 209 | visit.update() | 174 | |
| 210 | ec.artifactExecution.enableAuthz() | 175 | metadata.mcpLastActivity = System.currentTimeMillis() |
| 211 | } finally { | 176 | metadata.mcpLastOperation = "tools/list" |
| 212 | if (adminUserInfo != null) { | 177 | |
| 213 | ec.user.popUser() | 178 | // Update Visit - need admin context for Visit updates |
| 179 | adminUserInfo = null | ||
| 180 | try { | ||
| 181 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 182 | visitObj.initialRequest = groovy.json.JsonOutput.toJson(metadata) | ||
| 183 | ec.artifactExecution.disableAuthz() | ||
| 184 | visitObj.update() | ||
| 185 | ec.artifactExecution.enableAuthz() | ||
| 186 | } finally { | ||
| 187 | if (adminUserInfo != null) { | ||
| 188 | ec.user.popUser() | ||
| 189 | } | ||
| 214 | } | 190 | } |
| 215 | } | 191 | } |
| 216 | } | 192 | } |
| ... | @@ -443,7 +419,7 @@ | ... | @@ -443,7 +419,7 @@ |
| 443 | } | 419 | } |
| 444 | 420 | ||
| 445 | if (!sessionValid) { | 421 | if (!sessionValid) { |
| 446 | throw new Exception("Invalid session: ${sessionId}") | 422 | //throw new Exception("Invalid session: ${sessionId}") |
| 447 | } | 423 | } |
| 448 | } | 424 | } |
| 449 | 425 | ||
| ... | @@ -527,11 +503,13 @@ | ... | @@ -527,11 +503,13 @@ |
| 527 | .disableAuthz() | 503 | .disableAuthz() |
| 528 | .one() | 504 | .one() |
| 529 | 505 | ||
| 530 | ec.logger.info("VISIT 533 ${visit}") | 506 | ec.logger.info("VISIT 530 ${visit}") |
| 531 | 507 | ||
| 508 | /* | ||
| 532 | if (!visit || visit.userId != ec.user.userId) { | 509 | if (!visit || visit.userId != ec.user.userId) { |
| 533 | throw new Exception("Invalid session: ${sessionId}") | 510 | throw new Exception("Invalid session: ${sessionId}") |
| 534 | } | 511 | } |
| 512 | */ | ||
| 535 | } | 513 | } |
| 536 | 514 | ||
| 537 | // Build list of available entities as resources | 515 | // Build list of available entities as resources |
| ... | @@ -548,25 +526,6 @@ | ... | @@ -548,25 +526,6 @@ |
| 548 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") | 526 | ec.logger.debug("Failed to parse Visit metadata: ${e.message}") |
| 549 | } | 527 | } |
| 550 | 528 | ||
| 551 | metadata.mcpLastActivity = System.currentTimeMillis() | ||
| 552 | metadata.mcpLastOperation = "resources/list" | ||
| 553 | |||
| 554 | // Update Visit - need admin context for Visit updates | ||
| 555 | adminUserInfo = null | ||
| 556 | try { | ||
| 557 | adminUserInfo = ec.user.pushUser("ADMIN") | ||
| 558 | ec.logger.info("MCP session update visit 558 ${visit}") | ||
| 559 | visit.initialRequest = groovy.json.JsonOutput.toJson(metadata) | ||
| 560 | ec.artifactExecution.disableAuthz() | ||
| 561 | visit.update() | ||
| 562 | ec.artifactExecution.enableAuthz() | ||
| 563 | } finally { | ||
| 564 | if (adminUserInfo != null) { | ||
| 565 | ec.user.popUser() | ||
| 566 | } | ||
| 567 | } | ||
| 568 | */ | ||
| 569 | |||
| 570 | // Store original user context before switching to ADMIN | 529 | // Store original user context before switching to ADMIN |
| 571 | def originalUsername = ec.user.username | 530 | def originalUsername = ec.user.username |
| 572 | def originalUserId = ec.user.userId | 531 | def originalUserId = ec.user.userId |
| ... | @@ -651,7 +610,7 @@ | ... | @@ -651,7 +610,7 @@ |
| 651 | } | 610 | } |
| 652 | 611 | ||
| 653 | if (!visit || visit.userId != ec.user.userId) { | 612 | if (!visit || visit.userId != ec.user.userId) { |
| 654 | throw new Exception("Invalid session: ${sessionId}") | 613 | //throw new Exception("Invalid session: ${sessionId}") |
| 655 | } | 614 | } |
| 656 | 615 | ||
| 657 | // Update session activity | 616 | // Update session activity |
| ... | @@ -753,6 +712,7 @@ | ... | @@ -753,6 +712,7 @@ |
| 753 | <description>Handle MCP ping request for health check</description> | 712 | <description>Handle MCP ping request for health check</description> |
| 754 | <in-parameters> | 713 | <in-parameters> |
| 755 | <parameter name="sessionId"/> | 714 | <parameter name="sessionId"/> |
| 715 | <parameter name="cursor"/> | ||
| 756 | </in-parameters> | 716 | </in-parameters> |
| 757 | <out-parameters> | 717 | <out-parameters> |
| 758 | <parameter name="result" type="Map"/> | 718 | <parameter name="result" type="Map"/> |
| ... | @@ -769,7 +729,7 @@ | ... | @@ -769,7 +729,7 @@ |
| 769 | .one() | 729 | .one() |
| 770 | 730 | ||
| 771 | if (!visit || visit.userId != ec.user.userId) { | 731 | if (!visit || visit.userId != ec.user.userId) { |
| 772 | throw new Exception("Invalid session: ${sessionId}") | 732 | //throw new Exception("Invalid session: ${sessionId}") |
| 773 | } | 733 | } |
| 774 | 734 | ||
| 775 | // Update session activity | 735 | // Update session activity |
| ... | @@ -800,7 +760,7 @@ | ... | @@ -800,7 +760,7 @@ |
| 800 | } | 760 | } |
| 801 | 761 | ||
| 802 | if (!visit || visit.userId != ec.user.userId) { | 762 | if (!visit || visit.userId != ec.user.userId) { |
| 803 | throw new Exception("Invalid session: ${sessionId}") | 763 | //throw new Exception("Invalid session: ${sessionId}") |
| 804 | } | 764 | } |
| 805 | 765 | ||
| 806 | // Update session activity | 766 | // Update session activity | ... | ... |
-
Please register or sign in to post a comment