c5aae9fc by Ean Schuessler

Merge screen rendering into browse functionality

- Add renderMode parameter (default: 'mcp') to browse_screens
- Add parameters parameter for screen rendering
- Add screen rendering logic for non-root paths
- Return rendered content along with subscreens list
- Update list#Tools schema to expose new parameters

Default renderMode is 'mcp' unless explicitly specified.
1 parent 185763c0
...@@ -942,10 +942,12 @@ def startTime = System.currentTimeMillis() ...@@ -942,10 +942,12 @@ def startTime = System.currentTimeMillis()
942 </actions> 942 </actions>
943 </service> 943 </service>
944 944
945 <service verb="mcp" noun="BrowseScreens" authenticate="false" allow-remote="true" transaction-timeout="30"> 945 <service verb="mcp" noun="BrowseScreens" authenticate="false" allow-remote="true" transaction-timeout="60">
946 <description>Browse Moqui screens hierarchically to discover functionality.</description> 946 <description>Browse Moqui screens hierarchically to discover functionality. Renders screen content with renderMode='mcp' by default.</description>
947 <in-parameters> 947 <in-parameters>
948 <parameter name="path" required="false"><description>Screen path to browse (e.g. 'PopCommerce'). Leave empty for root apps.</description></parameter> 948 <parameter name="path" required="false"><description>Screen path to browse (e.g. 'PopCommerce'). Leave empty for root apps.</description></parameter>
949 <parameter name="renderMode" default="mcp"><description>Render mode: mcp (default), text, html, xml, vuet, qvt</description></parameter>
950 <parameter name="parameters" type="Map"><description>Parameters to pass to screen during rendering</description></parameter>
949 <parameter name="sessionId"/> 951 <parameter name="sessionId"/>
950 </in-parameters> 952 </in-parameters>
951 <out-parameters> 953 <out-parameters>
...@@ -1054,10 +1056,99 @@ def startTime = System.currentTimeMillis() ...@@ -1054,10 +1056,99 @@ def startTime = System.currentTimeMillis()
1054 } 1056 }
1055 } 1057 }
1056 1058
1057 result = [ 1059 // Render current screen if not root browsing
1060 def renderedContent = null
1061 def renderError = null
1062 def actualRenderMode = renderMode ?: "mcp"
1063
1064 if (currentPath != "root") {
1065 try {
1066 ec.logger.info("BrowseScreens: Rendering screen ${currentPath} with mode=${actualRenderMode}")
1067
1068 // Use same resolution logic as browse_screens
1069 def pathParts = currentPath.split('\\.')
1070 def componentName = pathParts[0]
1071 def screenPath = null
1072 def subscreenName = null
1073
1074 for (int i = pathParts.size(); i >= 1; i--) {
1075 def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..<i].join('/') : componentName) + ".xml"
1076 if (ec.resource.getLocationReference(currentTry).getExists()) {
1077 screenPath = currentTry
1078 if (i < pathParts.size()) {
1079 def remainingParts = pathParts[i..-1]
1080 subscreenName = remainingParts.size() > 1 ? remainingParts.join('_') : remainingParts[0]
1081 }
1082 break
1083 }
1084 }
1085
1086 if (!screenPath) {
1087 screenPath = "component://${componentName}/screen/${componentName}.xml"
1088 if (pathParts.size() > 1) {
1089 subscreenName = pathParts[1..-1].join('_')
1090 }
1091 }
1092
1093 // Build render parameters
1094 def renderParams = parameters ?: [:]
1095 renderParams.userId = ec.user.userId
1096 renderParams.username = ec.user.username
1097
1098 def screenCallParams = [
1099 screenPath: screenPath,
1100 parameters: renderParams,
1101 renderMode: actualRenderMode,
1102 sessionId: sessionId
1103 ]
1104 if (subscreenName) screenCallParams.subscreenName = subscreenName
1105
1106 // Call ScreenAsMcpTool to render
1107 def serviceResult = ec.service.sync().name("McpServices.execute#ScreenAsMcpTool")
1108 .parameters(screenCallParams)
1109 .call()
1110
1111 // Extract rendered content from result
1112 // ScreenAsMcpTool returns {content: [{type: "text", text: "...", ...}]}
1113 ec.logger.info("BrowseScreens: serviceResult keys: ${serviceResult?.keySet()}, has content: ${serviceResult?.containsKey('content')}, has result: ${serviceResult?.containsKey('result')}")
1114 if (serviceResult) {
1115 if (serviceResult.containsKey('content') && serviceResult.content && serviceResult.content.size() > 0) {
1116 renderedContent = serviceResult.content[0].text
1117 ec.logger.info("BrowseScreens: Extracted content from serviceResult.content[0].text")
1118 } else if (serviceResult.containsKey('result') && serviceResult.result && serviceResult.result.content && serviceResult.result.content.size() > 0) {
1119 renderedContent = serviceResult.result.content[0].text
1120 ec.logger.info("BrowseScreens: Extracted content from serviceResult.result.content[0].text")
1121 } else {
1122 ec.logger.info("BrowseScreens: serviceResult structure: ${serviceResult}, result content size: ${serviceResult?.result?.content?.size()}")
1123 }
1124 }
1125
1126 ec.logger.info("BrowseScreens: Successfully rendered screen ${currentPath}, content length: ${renderedContent?.length() ?: 0}")
1127 } catch (Exception e) {
1128 renderError = "Screen rendering failed: ${e.message}"
1129 ec.logger.warn("BrowseScreens render error for ${currentPath}: ${e.message}")
1130 }
1131 }
1132
1133 // Build result - return in MCP format with content array
1134 def resultMap = [
1058 currentPath: currentPath, 1135 currentPath: currentPath,
1059 subscreens: subscreens, 1136 subscreens: subscreens,
1060 message: "Found ${subscreens.size()} subscreens. Use moqui_render_screen(path='...') to execute." 1137 renderMode: actualRenderMode
1138 ]
1139
1140 if (renderedContent) {
1141 resultMap.renderedContent = renderedContent
1142 }
1143
1144 if (renderError) {
1145 resultMap.renderError = renderError
1146 }
1147
1148 // Return in MCP format - content array as direct child of result
1149 result = [
1150 content: [[type: "text", text: new groovy.json.JsonBuilder(resultMap).toString()]],
1151 isError: false
1061 ] 1152 ]
1062 ]]></script> 1153 ]]></script>
1063 </actions> 1154 </actions>
...@@ -1273,11 +1364,13 @@ def startTime = System.currentTimeMillis() ...@@ -1273,11 +1364,13 @@ def startTime = System.currentTimeMillis()
1273 [ 1364 [
1274 name: "moqui_browse_screens", 1365 name: "moqui_browse_screens",
1275 title: "Browse Screens", 1366 title: "Browse Screens",
1276 description: "Browse the Moqui screen hierarchy to discover paths. Input 'path' (empty for root).", 1367 description: "Browse the Moqui screen hierarchy and render screen content. Input 'path' (empty for root). Default renderMode is 'mcp'.",
1277 inputSchema: [ 1368 inputSchema: [
1278 type: "object", 1369 type: "object",
1279 properties: [ 1370 properties: [
1280 path: [type: "string", description: "Path to browse (e.g. 'PopCommerce')"] 1371 path: [type: "string", description: "Path to browse (e.g. 'PopCommerce')"],
1372 renderMode: [type: "string", description: "Render mode: mcp (default), text, html, xml, vuet, qvt"],
1373 parameters: [type: "object", description: "Parameters to pass to screen during rendering"]
1281 ] 1374 ]
1282 ] 1375 ]
1283 ], 1376 ],
......