d0e43025 by Ean Schuessler

Fix method signature mismatch in screen discovery to use getScreenInfoList instead of getScreenInfo

This resolves the error: 'No signature of method: org.moqui.impl.screen.ScreenFacadeImpl.getScreenInfo() is applicable for argument types: (String)' that occurred when trying to discover subscreens for screens like component://PopCommerce/screen/PopCommerceAdmin/Shipment.xml. The fix changes calls from getScreenInfo() to getScreenInfoList() which is the correct method available in ScreenFacadeImpl.
1 parent ea17693e
...@@ -420,17 +420,23 @@ ...@@ -420,17 +420,23 @@
420 UserInfo restoredUserInfo = null 420 UserInfo restoredUserInfo = null
421 try { 421 try {
422 // Get Visit to find the actual user who created this session 422 // Get Visit to find the actual user who created this session
423 visit = ec.entity.find("moqui.server.Visit") 423 if (sessionId) {
424 .condition("visitId", sessionId) 424 visit = ec.entity.find("moqui.server.Visit")
425 .disableAuthz() 425 .condition("visitId", sessionId)
426 .one() 426 .disableAuthz()
427 427 .one()
428 if (!visit) { 428
429 throw new Exception("Invalid session for screen tool execution: ${sessionId}") 429 if (!visit) {
430 throw new Exception("Invalid session for screen tool execution: ${sessionId}")
431 }
432 } else {
433 // If no sessionId, we're likely in a test/debug scenario, use current user context
434 ec.logger.warn("No sessionId provided for screen tool execution, using current user context")
435 visit = null // Explicitly set to null to indicate no session context
430 } 436 }
431 437
432 // Restore user context - handle special MCP case where Visit was created with ADMIN 438 // Restore user context - handle special MCP case where Visit was created with ADMIN
433 if (visit.userId && visit.userId != ec.user.userId) { 439 if (visit && visit.userId && visit.userId != ec.user.userId) {
434 // Restore the actual user who created the session 440 // Restore the actual user who created the session
435 def userAccount = ec.entity.find("moqui.security.UserAccount") 441 def userAccount = ec.entity.find("moqui.security.UserAccount")
436 .condition("userId", visit.userId) 442 .condition("userId", visit.userId)
...@@ -1048,8 +1054,65 @@ try { ...@@ -1048,8 +1054,65 @@ try {
1048 ] 1054 ]
1049 } 1055 }
1050 1056
1051 // Use discovered screens instead of hardcoded list 1057 // Helper function to recursively discover subscreens
1058 def discoverAllScreens = { baseScreenPath ->
1059 def allScreens = [] as Set<String>
1060 def screensToProcess = [baseScreenPath]
1061
1062 ec.logger.info("MCP Screen Discovery: Starting discovery for base ${baseScreenPath}")
1063
1064 while (screensToProcess) {
1065 def currentScreenPath = screensToProcess.remove(0)
1066
1067 ec.logger.info("MCP Screen Discovery: Processing screen ${currentScreenPath}")
1068
1069 if (allScreens.contains(currentScreenPath)) {
1070 ec.logger.info("MCP Screen Discovery: Already processed ${currentScreenPath}, skipping")
1071 continue
1072 }
1073
1074 allScreens.add(currentScreenPath)
1075
1076 try {
1077 ec.logger.info("MCP Screen Discovery: Getting screen info for ${currentScreenPath}")
1078 // Fix: Use getScreenInfoList instead of getScreenInfo to avoid method signature mismatch
1079 def screenInfoList = ec.screen.getScreenInfoList(currentScreenPath, 1)
1080 def screenInfo = screenInfoList?.first()
1081 ec.logger.info("MCP Screen Discovery: Screen info for ${currentScreenPath}: subscreens=${screenInfo?.subScreenInfoByName?.size() ?: 0}")
1082 if (screenInfo?.subScreenInfoByName) {
1083 ec.logger.info("MCP Screen Discovery: Found subscreens map: ${screenInfo.subScreenInfoByName.keySet()}")
1084 for (subScreenEntry in screenInfo.subScreenInfoByName) {
1085 def subScreenPath = subScreenEntry.value.location
1086 ec.logger.info("MCP Screen Discovery: Found subscreen ${subScreenPath} for ${currentScreenPath}")
1087 if (subScreenPath && !allScreens.contains(subScreenPath)) {
1088 screensToProcess.add(subScreenPath)
1089 ec.logger.info("MCP Screen Discovery: Added ${subScreenPath} to processing queue")
1090 }
1091 }
1092 } else {
1093 ec.logger.info("MCP Screen Discovery: No subscreens found for ${currentScreenPath}")
1094 }
1095 } catch (Exception e) {
1096 ec.logger.info("MCP Screen Discovery: Could not get subscreens for ${currentScreenPath}: ${e.message}")
1097 ec.logger.error("MCP Screen Discovery: Error details:", e)
1098 }
1099 }
1100
1101 return allScreens
1102 }
1103
1104 // Discover all screens recursively starting from accessible screens
1105 def allAccessibleScreens = [] as Set<String>
1106 ec.logger.info("MCP Screen Discovery: Starting recursive discovery from ${accessibleScreens.size()} base screens")
1052 for (screenPath in accessibleScreens) { 1107 for (screenPath in accessibleScreens) {
1108 def discoveredScreens = discoverAllScreens(screenPath)
1109 ec.logger.info("MCP Screen Discovery: Found ${discoveredScreens.size()} screens from base ${screenPath}")
1110 allAccessibleScreens.addAll(discoveredScreens)
1111 }
1112 ec.logger.info("MCP Screen Discovery: Recursive discovery found ${allAccessibleScreens.size()} total screens")
1113
1114 // Use recursively discovered screens instead of hardcoded list
1115 for (screenPath in allAccessibleScreens) {
1053 try { 1116 try {
1054 //ec.logger.info("MCP Screen Discovery: Processing screen ${screenPath}") 1117 //ec.logger.info("MCP Screen Discovery: Processing screen ${screenPath}")
1055 1118
...@@ -1113,7 +1176,7 @@ try { ...@@ -1113,7 +1176,7 @@ try {
1113 } 1176 }
1114 } 1177 }
1115 1178
1116 ec.logger.info("MCP Screen Discovery: Created ${tools.size()} hardcoded screen tools for user ${originalUsername}") 1179 ec.logger.info("MCP Screen Discovery: Created ${tools.size()} screen tools for user ${originalUsername}")
1117 1180
1118 result.tools = tools 1181 result.tools = tools
1119 1182
...@@ -1567,12 +1630,82 @@ ${truncatedOutput} ...@@ -1567,12 +1630,82 @@ ${truncatedOutput}
1567 output = errorDetails.join("\n") 1630 output = errorDetails.join("\n")
1568 } 1631 }
1569 1632
1633 // Helper function to convert web paths to MCP tool names
1634 def convertWebPathToMcpTool = { path ->
1635 try {
1636 // Handle simple catalog paths (dropdown menu items)
1637 if (path == "Category" || path.startsWith("Category/")) {
1638 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Category"
1639 } else if (path == "Feature" || path.startsWith("Feature/")) {
1640 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Feature"
1641 } else if (path == "FeatureGroup" || path.startsWith("FeatureGroup/")) {
1642 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_FeatureGroup"
1643 } else if (path == "Product" || path.startsWith("Product/")) {
1644 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Product"
1645 } else if (path.startsWith("Search")) {
1646 return "screen_SimpleScreens_screen_SimpleScreens_Search"
1647 }
1648
1649 // Handle full catalog paths
1650 if (path.startsWith("Product/FindProduct")) {
1651 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Product"
1652 } else if (path.startsWith("Category/FindCategory")) {
1653 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Category"
1654 } else if (path.startsWith("Feature/FindFeature")) {
1655 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_Feature"
1656 } else if (path.startsWith("FeatureGroup/FindFeatureGroup")) {
1657 return "screen_SimpleScreens_screen_SimpleScreens_Catalog_FeatureGroup"
1658 }
1659
1660 // Handle PopCommerce Admin paths
1661 if (path.startsWith("PopcAdmin/")) {
1662 def cleanPath = path.replace("PopcAdmin/", "PopCommerceAdmin/")
1663 def toolName = "screen_PopCommerce_screen_" + cleanPath.replace("/", "_")
1664 return toolName
1665 }
1666
1667 // Handle SimpleScreens paths
1668 if (path.startsWith("apps/")) {
1669 def cleanPath = path.replace("apps/", "")
1670 def toolName = "screen_SimpleScreens_screen_SimpleScreens_" + cleanPath.replace("/", "_")
1671 return toolName
1672 }
1673
1674 return null
1675 } catch (Exception e) {
1676 ec.logger.debug("Error converting web path ${path} to MCP tool: ${e.message}")
1677 return null
1678 }
1679 }
1680
1570 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0 1681 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0
1571 1682
1683 // Convert web URLs to MCP tool suggestions to keep users in MCP ecosystem
1684 def processedOutput = output
1685 if (output && !isError) {
1686 try {
1687 // Convert common web URLs to MCP tool suggestions
1688 processedOutput = output.replaceAll(/http:\/\/localhost:8080\/([^\s"'>]+)/) { match ->
1689 def path = match[1]
1690 def toolName = convertWebPathToMcpTool(path)
1691 if (toolName) {
1692 return "MCP_TOOL:${toolName}"
1693 } else {
1694 return match[0] // Keep original if no MCP tool found
1695 }
1696 }
1697
1698 ec.logger.info("MCP Screen Execution: Converted web URLs to MCP tool suggestions for ${screenPath}")
1699 } catch (Exception e) {
1700 ec.logger.warn("MCP Screen Execution: Error converting URLs to MCP tools: ${e.message}")
1701 // Keep original output if conversion fails
1702 }
1703 }
1704
1572 // Return just the rendered screen content for MCP wrapper to handle 1705 // Return just the rendered screen content for MCP wrapper to handle
1573 result = [ 1706 result = [
1574 type: "text", 1707 type: "text",
1575 text: output, 1708 text: processedOutput,
1576 screenPath: screenPath, 1709 screenPath: screenPath,
1577 screenUrl: screenUrl, 1710 screenUrl: screenUrl,
1578 executionTime: executionTime, 1711 executionTime: executionTime,
......