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.
Showing
1 changed file
with
99 additions
and
6 deletions
| ... | @@ -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 | ], | ... | ... |
-
Please register or sign in to post a comment