Continuing to flesh out MCP connectivity
Showing
3 changed files
with
135 additions
and
46 deletions
| ... | @@ -30,6 +30,21 @@ | ... | @@ -30,6 +30,21 @@ |
| 30 | <set field="locale" from="ec.user?.locale ?: 'en_US'"/> | 30 | <set field="locale" from="ec.user?.locale ?: 'en_US'"/> |
| 31 | </actions> | 31 | </actions> |
| 32 | 32 | ||
| 33 | <transition name="fixConfig"> | ||
| 34 | <actions> | ||
| 35 | <script><![CDATA[ | ||
| 36 | ec.entity.find("moqui.mcp.agent.ProductStoreAiConfig") | ||
| 37 | .condition("productStoreId", "POPC_DEFAULT") | ||
| 38 | .condition("aiConfigId", "DEFAULT") | ||
| 39 | .one() | ||
| 40 | .set("modelName", "devstral") | ||
| 41 | .update() | ||
| 42 | ]]></script> | ||
| 43 | <set field="message" value="Config updated successfully to devstral"/> | ||
| 44 | </actions> | ||
| 45 | <default-response type="screen-last"/> | ||
| 46 | </transition> | ||
| 47 | |||
| 33 | <widgets> | 48 | <widgets> |
| 34 | <container style="mcp-test-screen"> | 49 | <container style="mcp-test-screen"> |
| 35 | <container style="text-center"> | 50 | <container style="text-center"> | ... | ... |
| ... | @@ -193,7 +193,9 @@ | ... | @@ -193,7 +193,9 @@ |
| 193 | def internalToolMappings = [ | 193 | def internalToolMappings = [ |
| 194 | "moqui_search_screens": "McpServices.mcp#SearchScreens", | 194 | "moqui_search_screens": "McpServices.mcp#SearchScreens", |
| 195 | "moqui_get_screen_details": "McpServices.mcp#GetScreenDetails", | 195 | "moqui_get_screen_details": "McpServices.mcp#GetScreenDetails", |
| 196 | "moqui_get_help": "McpServices.mcp#GetHelp" | 196 | "moqui_get_help": "McpServices.mcp#GetHelp", |
| 197 | "moqui_prompts_list": "McpServices.mcp#PromptsList", | ||
| 198 | "moqui_prompts_get": "McpServices.mcp#PromptsGet" | ||
| 197 | // "moqui_batch_operations": "McpServices.mcp#BatchOperations" - hidden until fixed | 199 | // "moqui_batch_operations": "McpServices.mcp#BatchOperations" - hidden until fixed |
| 198 | ] | 200 | ] |
| 199 | 201 | ||
| ... | @@ -654,16 +656,16 @@ def getWikiInstructions = { lookupPath -> | ... | @@ -654,16 +656,16 @@ def getWikiInstructions = { lookupPath -> |
| 654 | 656 | ||
| 655 | if (!wikiSpace) continue | 657 | if (!wikiSpace) continue |
| 656 | 658 | ||
| 657 | // Build the resource location for the page | 659 | // Build the resource location for the page |
| 658 | def pageLocation = wikiSpace.rootPageLocation | 660 | // rootPageLocation is dbresource://WikiSpace/MCP_PROMPTS.md |
| 659 | if (!pageLocation.endsWith('/')) { | 661 | // Need to construct: dbresource://WikiSpace/MCP_PROMPTS/get-started.md |
| 660 | pageLocation += '/' | 662 | // TEST - adding marker |
| 661 | } | 663 | def pageLocation = wikiSpace.rootPageLocation |
| 662 | pageLocation += wikiPage.pagePath + '.md' | 664 | // Replace .md with /pagePath.md |
| 663 | 665 | if (pageLocation.endsWith('.md')) { | |
| 664 | // Get the resource reference and text content | 666 | pageLocation = pageLocation.substring(0, pageLocation.length() - 3) + '/' + wikiPage.pagePath + '.md' |
| 665 | def pageRef = ec.resource.getLocationReference(pageLocation) | 667 | } |
| 666 | def wikiText = pageRef?.getText() | 668 | ec.logger.error("MCP PromptsGet: TEST MARKER - Using location: ${pageLocation}") |
| 667 | 669 | ||
| 668 | if (wikiText) { | 670 | if (wikiText) { |
| 669 | if (tryPath != normalizedPath) { | 671 | if (tryPath != normalizedPath) { |
| ... | @@ -2107,24 +2109,29 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) | ... | @@ -2107,24 +2109,29 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) |
| 2107 | .list() | 2109 | .list() |
| 2108 | 2110 | ||
| 2109 | for (def wp in wikiPageList) { | 2111 | for (def wp in wikiPageList) { |
| 2110 | // Try to load argument schema from attachment | 2112 | // Try to load argument schema from DbResource |
| 2111 | def arguments = [] | 2113 | def arguments = [] |
| 2112 | try { | 2114 | try { |
| 2113 | def attachment = ec.entity.find("moqui.resource.wiki.WikiPageAttachment") | 2115 | // Build resourceId for arguments file (e.g., WIKI_MCP_GET_STARTED_ARGS) |
| 2114 | .condition("wikiPageId", wp.wikiPageId) | 2116 | def argsResourceId = "WIKI_MCP_${wp.pagePath.toUpperCase().replace('-', '_')}_ARGS" |
| 2115 | .condition("filename", "arguments.json") | 2117 | def dbResource = ec.entity.find("moqui.resource.DbResource") |
| 2118 | .condition("resourceId", argsResourceId) | ||
| 2116 | .one() | 2119 | .one() |
| 2117 | if (attachment) { | 2120 | if (dbResource) { |
| 2118 | def attachmentRef = ec.resource.getLocationReference(attachment.getLocation()) | 2121 | def dbResourceFile = ec.entity.find("moqui.resource.DbResourceFile") |
| 2119 | def jsonText = attachmentRef?.getText() | 2122 | .condition("resourceId", argsResourceId) |
| 2120 | if (jsonText) { | 2123 | .one() |
| 2121 | arguments = new JsonSlurper().parseText(jsonText) ?: [] | 2124 | if (dbResourceFile) { |
| 2125 | def jsonText = dbResourceFile.fileData?.getText() | ||
| 2126 | if (jsonText) { | ||
| 2127 | arguments = new JsonSlurper().parseText(jsonText) ?: [] | ||
| 2128 | } | ||
| 2122 | } | 2129 | } |
| 2123 | } | 2130 | } |
| 2124 | } catch (Exception e) { | 2131 | } catch (Exception e) { |
| 2125 | ec.logger.debug("Could not parse arguments for ${wp.pagePath}: ${e.message}") | 2132 | ec.logger.debug("Could not parse arguments for ${wp.pagePath}: ${e.message}") |
| 2126 | } | 2133 | } |
| 2127 | 2134 | ||
| 2128 | prompts << [ | 2135 | prompts << [ |
| 2129 | name: wp.pagePath, | 2136 | name: wp.pagePath, |
| 2130 | title: wp.pagePath.split('-').collect { it.capitalize() }.join(' '), | 2137 | title: wp.pagePath.split('-').collect { it.capitalize() }.join(' '), |
| ... | @@ -2153,16 +2160,25 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) | ... | @@ -2153,16 +2160,25 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) |
| 2153 | import groovy.text.GStringTemplateEngine | 2160 | import groovy.text.GStringTemplateEngine |
| 2154 | import groovy.json.JsonSlurper | 2161 | import groovy.json.JsonSlurper |
| 2155 | import groovy.json.JsonBuilder | 2162 | import groovy.json.JsonBuilder |
| 2156 | 2163 | ||
| 2157 | ExecutionContext ec = context.ec | 2164 | ExecutionContext ec = context.ec |
| 2158 | 2165 | ||
| 2159 | ec.logger.info("MCP PromptsGet: Retrieving prompt '${name}' from wiki space MCP_PROMPTS") | 2166 | ec.logger.info("MCP PromptsGet: START v2.0 - Retrieving prompt '${name}' from wiki space MCP_PROMPTS") |
| 2160 | 2167 | ||
| 2168 | // Debug: Check what wiki pages exist in MCP_PROMPTS space | ||
| 2169 | def allPages = ec.entity.find("moqui.resource.wiki.WikiPage") | ||
| 2170 | .condition("wikiSpaceId", "MCP_PROMPTS") | ||
| 2171 | .useCache(true) | ||
| 2172 | .list() | ||
| 2173 | ec.logger.info("MCP PromptsGet: All pages in MCP_PROMPTS space: ${allPages.collect { [pageId: it.wikiPageId, pagePath: it.pagePath] }}") | ||
| 2174 | |||
| 2161 | // Get the wiki page for this prompt | 2175 | // Get the wiki page for this prompt |
| 2162 | def wikiPage = ec.entity.find("moqui.resource.wiki.WikiPage") | 2176 | def wikiPage = ec.entity.find("moqui.resource.wiki.WikiPage") |
| 2163 | .condition("wikiSpaceId", "MCP_PROMPTS") | 2177 | .condition("wikiSpaceId", "MCP_PROMPTS") |
| 2164 | .condition("pagePath", name) | 2178 | .condition("pagePath", name) |
| 2179 | .useCache(true) | ||
| 2165 | .one() | 2180 | .one() |
| 2181 | ec.logger.info("MCP PromptsGet: Looking for pagePath='${name}', found: ${wikiPage?.wikiPageId}") | ||
| 2166 | 2182 | ||
| 2167 | if (!wikiPage) { | 2183 | if (!wikiPage) { |
| 2168 | throw new Exception("Prompt not found: ${name}") | 2184 | throw new Exception("Prompt not found: ${name}") |
| ... | @@ -2171,37 +2187,68 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) | ... | @@ -2171,37 +2187,68 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) |
| 2171 | // Get the wiki space to build the page location | 2187 | // Get the wiki space to build the page location |
| 2172 | def wikiSpace = ec.entity.find("moqui.resource.wiki.WikiSpace") | 2188 | def wikiSpace = ec.entity.find("moqui.resource.wiki.WikiSpace") |
| 2173 | .condition("wikiSpaceId", "MCP_PROMPTS") | 2189 | .condition("wikiSpaceId", "MCP_PROMPTS") |
| 2190 | .useCache(true) | ||
| 2174 | .one() | 2191 | .one() |
| 2175 | 2192 | ||
| 2176 | if (!wikiSpace) { | 2193 | if (!wikiSpace) { |
| 2177 | throw new Exception("MCP Prompts wiki space not found") | 2194 | throw new Exception("MCP Prompts wiki space not found") |
| 2178 | } | 2195 | } |
| 2179 | 2196 | ||
| 2180 | // Build the resource location for the page (root + page path + .md) | 2197 | // Build resource location using framework's findChildFile pattern |
| 2181 | def pageLocation = wikiSpace.rootPageLocation | 2198 | // Note: pagePath is "get-started" but file is "get-started.md" |
| 2182 | if (!pageLocation.endsWith('/')) { | 2199 | ec.logger.info("MCP PromptsGet: rootPageLocation=${wikiSpace.rootPageLocation}, pagePath=${wikiPage.pagePath}") |
| 2183 | pageLocation += '/' | 2200 | def rootPageRef = ec.resource.getLocationReference(wikiSpace.rootPageLocation) |
| 2201 | ec.logger.info("MCP PromptsGet: rootPageRef.location=${rootPageRef?.location}") | ||
| 2202 | |||
| 2203 | // Try with .md extension first, then without | ||
| 2204 | def pageRef = rootPageRef.findChildFile(wikiPage.pagePath + '.md') | ||
| 2205 | if (!pageRef) { | ||
| 2206 | pageRef = rootPageRef.findChildFile(wikiPage.pagePath) | ||
| 2184 | } | 2207 | } |
| 2185 | pageLocation += name + '.md' | 2208 | ec.logger.info("MCP PromptsGet: pageRef.location=${pageRef?.location}") |
| 2186 | 2209 | ||
| 2187 | // Get the resource reference and text content | ||
| 2188 | def pageRef = ec.resource.getLocationReference(pageLocation) | ||
| 2189 | def templateText = pageRef?.getText() | 2210 | def templateText = pageRef?.getText() |
| 2190 | 2211 | ec.logger.info("MCP PromptsGet: templateText.length=${templateText?.length() ?: 'null'}") | |
| 2212 | |||
| 2191 | if (!templateText) { | 2213 | if (!templateText) { |
| 2192 | throw new Exception("Prompt template not found: ${name}") | 2214 | throw new Exception("Prompt template not found: ${name}") |
| 2193 | } | 2215 | } |
| 2194 | 2216 | ||
| 2217 | // Load arguments schema from DbResource for prompt metadata | ||
| 2218 | def promptArguments = [] | ||
| 2219 | try { | ||
| 2220 | def argsResourceId = "WIKI_MCP_${name.toUpperCase().replace('-', '_')}_ARGS" | ||
| 2221 | def dbResource = ec.entity.find("moqui.resource.DbResource") | ||
| 2222 | .condition("resourceId", argsResourceId) | ||
| 2223 | .useCache(true) | ||
| 2224 | .one() | ||
| 2225 | if (dbResource) { | ||
| 2226 | def dbResourceFile = ec.entity.find("moqui.resource.DbResourceFile") | ||
| 2227 | .condition("resourceId", argsResourceId) | ||
| 2228 | .useCache(true) | ||
| 2229 | .one() | ||
| 2230 | if (dbResourceFile) { | ||
| 2231 | def jsonText = dbResourceFile.fileData?.getText() | ||
| 2232 | if (jsonText) { | ||
| 2233 | promptArguments = new JsonSlurper().parseText(jsonText) ?: [] | ||
| 2234 | } | ||
| 2235 | } | ||
| 2236 | } | ||
| 2237 | } catch (Exception e) { | ||
| 2238 | ec.logger.debug("Could not parse arguments for ${name}: ${e.message}") | ||
| 2239 | } | ||
| 2240 | |||
| 2195 | // Render template using Groovy GString engine | 2241 | // Render template using Groovy GString engine |
| 2196 | def templateEngine = new GStringTemplateEngine() | 2242 | def templateEngine = new GStringTemplateEngine() |
| 2197 | def template = templateEngine.createTemplate(templateText) | 2243 | def template = templateEngine.createTemplate(templateText) |
| 2198 | def binding = arguments ?: [:] | 2244 | def binding = arguments ?: [:] |
| 2199 | def rendered = template.make(binding).toString() | 2245 | def rendered = template.make(binding).toString() |
| 2200 | 2246 | ||
| 2201 | ec.logger.info("MCP PromptsGet: Rendered prompt '${name}' with ${binding.size()} arguments") | 2247 | ec.logger.info("MCP PromptsGet: Rendered prompt '${name}' with ${binding.size()} arguments") |
| 2202 | 2248 | ||
| 2203 | result = [ | 2249 | result = [ |
| 2204 | description: "MCP prompt template", | 2250 | description: "MCP prompt template", |
| 2251 | arguments: promptArguments, | ||
| 2205 | messages: [[ | 2252 | messages: [[ |
| 2206 | role: "user", | 2253 | role: "user", |
| 2207 | content: [type: "text", text: rendered] | 2254 | content: [type: "text", text: rendered] |
| ... | @@ -3008,19 +3055,19 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) | ... | @@ -3008,19 +3055,19 @@ def wikiInstructions = getWikiInstructions(inputScreenPath) |
| 3008 | required: ["uri"] | 3055 | required: ["uri"] |
| 3009 | ] | 3056 | ] |
| 3010 | ], | 3057 | ], |
| 3011 | // moqui_batch_operations - hidden until fixed | 3058 | // moqui_batch_operations - hidden until fixed |
| 3012 | // | 3059 | // |
| 3013 | [ | 3060 | [ |
| 3014 | name: "prompts_list", | 3061 | name: "moqui_prompts_list", |
| 3015 | title: "List Prompts", | 3062 | title: "List Prompts", |
| 3016 | description: "List available MCP prompt templates.", | 3063 | description: "List available MCP prompt templates.", |
| 3017 | inputSchema: [ | 3064 | inputSchema: [ |
| 3018 | type: "object", | 3065 | type: "object", |
| 3019 | properties: [:] | 3066 | properties: [:] |
| 3020 | ] | 3067 | ] |
| 3021 | ], | 3068 | ], |
| 3022 | [ | 3069 | [ |
| 3023 | name: "prompts_get", | 3070 | name: "moqui_prompts_get", |
| 3024 | title: "Get Prompt", | 3071 | title: "Get Prompt", |
| 3025 | description: "Retrieve and render a specific MCP prompt template.", | 3072 | description: "Retrieve and render a specific MCP prompt template.", |
| 3026 | inputSchema: [ | 3073 | inputSchema: [ | ... | ... |
service/UpdateAgentConfig.xml
0 → 100644
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 3 | xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd"> | ||
| 4 | |||
| 5 | <service verb="update" noun="ModelName" authenticate="false"> | ||
| 6 | <description>Update modelName in ProductStoreAiConfig</description> | ||
| 7 | <actions> | ||
| 8 | <script><![CDATA[ | ||
| 9 | def config = ec.entity.find("moqui.mcp.agent.ProductStoreAiConfig") | ||
| 10 | .condition("productStoreId", "POPC_DEFAULT") | ||
| 11 | .condition("aiConfigId", "DEFAULT") | ||
| 12 | .one() | ||
| 13 | |||
| 14 | if (config) { | ||
| 15 | ec.logger.info("UPDATE MODEL NAME: Current=${config.modelName}") | ||
| 16 | config.modelName = "devstral" | ||
| 17 | config.update() | ||
| 18 | ec.logger.info("UPDATE MODEL NAME: Updated to=${config.modelName}") | ||
| 19 | return "Updated modelName to devstral" | ||
| 20 | } else { | ||
| 21 | ec.logger.warn("UPDATE MODEL NAME: Config not found") | ||
| 22 | return "Config not found" | ||
| 23 | } | ||
| 24 | ]]></script> | ||
| 25 | </actions> | ||
| 26 | </service> | ||
| 27 | </services> |
-
Please register or sign in to post a comment