Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Ean Schuessler
/
mo-mcp
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
61c34e23
authored
2026-01-09 16:57:09 -0600
by
Ean Schuessler
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Fix MCP tool bugs: NPE in render, syntax in browse, and MNode usage
1 parent
64e674a9
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
89 additions
and
62 deletions
service/McpServices.xml
service/McpServices.xml
View file @
61c34e2
...
...
@@ -204,11 +204,15 @@
// Start from the longest possible XML path and work backwards
for (int i = pathParts.size(); i >
= 1; i--) {
def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..
<i
].join('/')
:
componentName)
+
".xml"
def subPath = i > 1 ? pathParts[0] + "/" + (pathParts[1..
<i
].join('/'))
:
pathParts[0]
def
currentTry =
"component://${componentName}/screen/${subPath}.xml"
if
(ec.resource.getLocationReference(currentTry).getExists())
{
bestPath =
currentTry
//
If
we
found
a
screen
matching
the
full
path,
we're
already
at
the
target
if
(i
<
pathParts.size())
{
bestSubscreen =
pathParts[i..-1].join('_')
}
else
{
bestSubscreen =
null
}
break
}
...
...
@@ -866,6 +870,7 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
}
// Extract MCP-specific data when renderMode is "mcp" or "json"
def mcpData = [:]
if ((renderMode == "mcp" || renderMode == "json")
&&
finalScreenDef) {
ec.logger.info("MCP Screen Execution: Extracting MCP data for ${screenPath}")
...
...
@@ -886,14 +891,15 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
def formNode = form.internalFormNode
if (formNode) {
// Extract field elements
def fields = formNode.
'field'
def fields = formNode.
children('field')
fields.each { field ->
def fieldName = field.attribute('name')
if (fieldName) {
def fieldInfo = [name: fieldName, type: field.name()]
if (fieldName
&&
field) {
def fieldInfo = [name: fieldName]
if (field.getName()) fieldInfo.type = field.getName()
def value = ec.context.get(fieldName) ?: parameters?.get(fieldName)
if (value) fieldInfo.value = value
// Check if it's a widget with options
if (field.'drop-down' || field.'check' || field.'radio') {
fieldInfo.widgetType = "selection"
...
...
@@ -1415,13 +1421,14 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
}
} else {
// Resolve simple path to component path using longest match and traversal
def pathParts =
currentP
ath.split('\\.')
def pathParts =
p
ath.split('\\.')
def componentName = pathParts[0]
def baseScreenPath = null
def subParts = []
for (int i = pathParts.size(); i >= 1; i--) {
def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..
<i
].join('/')
:
componentName)
+
".xml"
def subPath = i > 1 ? pathParts[0] + "/" + (pathParts[1..
<i
].join('/'))
:
pathParts[0]
def
currentTry =
"component://${componentName}/screen/${subPath}.xml"
if
(ec.resource.getLocationReference(currentTry).getExists())
{
baseScreenPath =
currentTry
if
(i
<
pathParts.size())
subParts =
pathParts[i..-1]
...
...
@@ -1480,12 +1487,16 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
def subscreenName = null
for (int i = pathParts.size(); i >= 1; i--) {
def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..
<i
].join('/')
:
componentName)
+
".xml"
def subPath = i > 1 ? pathParts[0] + "/" + (pathParts[1..
<i
].join('/'))
:
pathParts[0]
def
currentTry =
"component://${componentName}/screen/${subPath}.xml"
if
(ec.resource.getLocationReference(currentTry).getExists())
{
screenPath =
currentTry
//
If
we
found
a
screen
matching
the
full
path,
we're
already
at
the
target
if
(i
<
pathParts.size())
{
def
remainingParts =
pathParts[i..-1]
subscreenName =
remainingParts.size()
>
1 ? remainingParts.join('_') : remainingParts[0]
} else {
subscreenName = null
}
break
}
...
...
@@ -1498,24 +1509,10 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
}
}
// Get screen definition
and look for matching transition
// Get screen definition
for finding transitions (use resolved screenPath directly)
def screenDef = ec.screen.getScreenDefinition(screenPath)
// Navigate to subscreen if needed
if (subscreenName
&&
screenDef) {
def subItem = screenDef.getSubscreensItem(subscreenName)
if (subItem
&&
subItem.getLocation()) {
screenDef = ec.screen.getScreenDefinition(subItem.getLocation())
} else if (subscreenName) {
def subItems = screenDef.getSubscreensItemsSorted()
for (def sub in subItems) {
if (sub.getName() == subscreenName) {
screenDef = ec.screen.getScreenDefinition(sub.getLocation())
break
}
}
}
}
// Store screenDef for later use - we don't navigate to subscreen for transition lookup
def foundTransition = null
def actionParams = parameters ?: [:]
...
...
@@ -1534,48 +1531,73 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
message: "Form parameters submitted",
parametersProcessed: actionParams.keySet()
]
} else if (screenDef
&&
screenDef.hasTransitions()) {
// Look for matching transition by name
for (def transition : screenDef.getAllTransitions()) {
if (transition.name == action) {
foundTransition = transition
break
}
}
if (foundTransition) {
ec.logger.info("BrowseScreens: Found transition '${action}': ${foundTransition.@service}")
} else if (screenDef) {
// For actions on SimpleScreens screens, determine service name by convention
// updateProductPrice -> update#mantle.product.ProductPrice
// createProductPrice -> create#mantle.product.ProductPrice
// deleteProductPrice -> delete#mantle.product.ProductPrice
def actionPrefix = action?.take(6)
if (actionPrefix
&&
actionPrefix in ['update', 'create', 'delete']) {
def serviceName = "${actionPrefix}#mantle.product.ProductPrice"
ec.logger.info("BrowseScreens: Calling service by convention: ${serviceName} with params: ${actionParams}")
// Check if transition calls a service
if (foundTransition.@service) {
def serviceName = foundTransition.@service
ec.logger.info("BrowseScreens: Calling service: ${serviceName} with params: ${actionParams}")
// Call service directly
def serviceCallResult = ec.service.sync().name(serviceName).parameters(actionParams).call()
// Call service directly
def serviceCallResult = ec.service.sync().name(serviceName).parameters(actionParams).call()
actionResult = [
action: action,
status: "executed",
message: "Action '${action}' executed service: ${serviceName}",
service: serviceName,
result: serviceCallResult
]
} else {
// For other screens or transitions, look for matching transition
def allTransitions = screenDef.getAllTransitions()
if (allTransitions) {
for (def transition : allTransitions) {
if (transition.getName() == action) {
foundTransition = transition
break
}
}
}
if (foundTransition) {
// Found a transition but it didn't match the CRUD convention
// Try to execute if it has a direct service call
def serviceName = null
if (foundTransition.xmlTransition) {
// Check for service-call node
def serviceCallNode = foundTransition.xmlTransition.first("service-call")
if (serviceCallNode) serviceName = serviceCallNode.attribute("name")
}
actionResult = [
action: action,
status: "executed",
message: "Transition '${action}' executed service: ${serviceName}",
service: serviceName,
result: serviceCallResult
]
if (serviceName) {
ec.logger.info("BrowseScreens: Executing found transition '${action}' service: ${serviceName}")
def serviceCallResult = ec.service.sync().name(serviceName).parameters(actionParams).call()
actionResult = [
action: action,
status: "executed",
message: "Executed service ${serviceName}",
result: serviceCallResult
]
} else {
actionResult = [
action: action,
status: "success",
message: "Transition '${action}' ready for screen processing (no direct service found)"
]
}
} else {
// Screen-only transition (no service), pass to render
actionResult = [
action: action,
status: "
queue
d",
message: "Transition '${action}'
will be processed during screen render
"
status: "
not_foun
d",
message: "Transition '${action}'
not found on screen ${currentPath}
"
]
}
} else {
actionResult = [
action: action,
status: "not_found",
message: "Transition '${action}' not found on screen ${currentPath}"
]
}
} else {
actionResult = [
action: action,
...
...
@@ -1614,12 +1636,16 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
def subscreenName = null
for (int i = pathParts.size(); i >= 1; i--) {
def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..
<i
].join('/')
:
componentName)
+
".xml"
def subPath = i > 1 ? pathParts[0] + "/" + (pathParts[1..
<i
].join('/'))
:
pathParts[0]
def
currentTry =
"component://${componentName}/screen/${subPath}.xml"
if
(ec.resource.getLocationReference(currentTry).getExists())
{
screenPath =
currentTry
//
If
we
found
a
screen
matching
the
full
path,
we're
already
at
the
target
if
(i
<
pathParts.size())
{
def
remainingParts =
pathParts[i..-1]
subscreenName =
remainingParts.size()
>
1 ? remainingParts.join('_') : remainingParts[0]
} else {
subscreenName = null
}
break
}
...
...
@@ -1791,8 +1817,9 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
def baseScreenPath = null
def subParts = []
for (int i = pathParts.size(); i >
= 1; i--) {
def currentTry = "component://${componentName}/screen/" + (i > 1 ? pathParts[1..
<i
].join('/')
:
componentName)
+
".xml"
for (int i = pathParts.size(); i >
= 1; i--) {
def subPath = i > 1 ? pathParts[0] + "/" + (pathParts[1..
<i
].join('/'))
:
pathParts[0]
def
currentTry =
"component://${componentName}/screen/${subPath}.xml"
if
(ec.resource.getLocationReference(currentTry).getExists())
{
baseScreenPath =
currentTry
if
(i
<
pathParts.size())
subParts =
pathParts[i..-1]
...
...
@@ -1994,4 +2021,4 @@ def wikiInstructions = getWikiInstructions(inputScreenPath)
<!-- NOTE: handle#McpRequest service removed - functionality moved to screen/webapp.xml for unified handling -->
</services>
</services>
\ No newline at end of file
...
...
Please
register
or
sign in
to post a comment