Skip to content

Commit 7b380f1

Browse files
Merge pull request #502 from chathuranga-jayanath-99/mcp-bug-fixes
Update MCP Tools Handling and Fix Data Loss Bugs
2 parents c0c41de + 3ef75a2 commit 7b380f1

File tree

11 files changed

+280
-74
lines changed

11 files changed

+280
-74
lines changed

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/SynapseLanguageService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,9 +802,13 @@ public CompletableFuture<List<List<Object>>> getInputOutputMappings(MappingsGenR
802802
@Override
803803
public CompletableFuture<MCPToolResponse> getMCPTools(MCPToolRequest param) {
804804

805+
log.log(Level.INFO, "Fetching MCP tools for connection: {}", param.connectionName);
805806
Connections connections = ConnectionFinder.findConnections(projectUri, Constant.LOWERCASE_AI, connectorHolder, isLegacyProject).getLeft();
806807
AIConnectorHandler aiConnectorHandler = new AIConnectorHandler(mediatorHandler, projectUri);
807-
return CompletableFuture.supplyAsync(() -> aiConnectorHandler.fetchMcpTools(connections.getConnections(), param.connectionName));
808+
log.log(Level.INFO, "Initialized AI connector handler for MCP tools fetch");
809+
return CompletableFuture.supplyAsync(
810+
() -> aiConnectorHandler.fetchMcpTools(param.documentUri, param.range, connections.getConnections(),
811+
param.connectionName));
808812
}
809813

810814
public String getProjectUri() {

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediatorService/AIConnectorHandler.java

Lines changed: 135 additions & 68 deletions
Large diffs are not rendered by default.

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediatorService/pojo/MCPToolRequest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
package org.eclipse.lemminx.customservice.synapse.mediatorService.pojo;
1616

17-
import java.util.Map;
17+
import org.eclipse.lsp4j.Range;
1818

1919
public class MCPToolRequest {
2020

21+
public String documentUri;
22+
public Range range;
2123
public String connectionName;
2224
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediatorService/pojo/MCPToolResponse.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414

1515
package org.eclipse.lemminx.customservice.synapse.mediatorService.pojo;
1616

17-
import org.eclipse.lsp4j.Range;
18-
1917
import java.util.Map;
18+
import java.util.List;
2019

2120
public class MCPToolResponse {
2221

2322
public Map<String, String> tools;
2423
public String error;
24+
// Names of tools already present in the document for the requested connection
25+
public List<String> selectedTools;
2526
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/syntaxTree/factory/mediators/ai/AIAgentConnectorFactory.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.connector.ai.AIConnector;
2121
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.connector.ai.AgentTool;
2222
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.connector.ai.AgentTools;
23+
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.connector.ai.MCPConnections;
2324
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.mediator.Mediator;
2425
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.template.Template;
2526
import org.eclipse.lemminx.customservice.synapse.utils.ConfigFinder;
@@ -52,10 +53,49 @@ protected Mediator createSpecificMediator(DOMElement element) {
5253
((AIAgent) aiAgent).setAgentID(Utils.getInlineString(agentIDNode.getFirstChild()));
5354
}
5455

56+
populateMCPConnections((AIAgent) aiAgent, element);
5557
populateTools((AIAgent) aiAgent, element);
5658
return aiAgent;
5759
}
5860

61+
/**
62+
* Extracts MCP connection configuration details from the given DOM element
63+
* and populates the provided {@link AIAgent} instance.
64+
*
65+
* <p>This method searches for a child element named {@code <mcpConnections>}
66+
* inside the provided element. If found, it iterates through its
67+
* child nodes and collects the values of all {@code <mcpConfigKey>} elements.
68+
* Non-null and non-blank values are added to a list of MCP connection keys.</p>
69+
*
70+
* <p>The collected connection keys are then set into a {@link MCPConnections}
71+
* object, which is attached to the given {@link AIAgent}.</p>
72+
*
73+
* @param aiAgent the {@link AIAgent} instance to populate with MCP connection data
74+
* @param element the DOM element that potentially contains the
75+
* {@code <mcpConnections>} configuration
76+
*/
77+
private void populateMCPConnections(AIAgent aiAgent, DOMElement element) {
78+
79+
DOMNode mcpConnectionsElement = Utils.getChildNodeByName(element, Constant.MCP_CONNECTIONS);
80+
if (mcpConnectionsElement != null) {
81+
LOGGER.log(Level.INFO, "Processing MCP connections for AI agent");
82+
MCPConnections mcpConnectionsObj = new MCPConnections();
83+
List<DOMNode> mcpChildren = mcpConnectionsElement.getChildren();
84+
List<String> mcpConnectionList = new java.util.ArrayList<>();
85+
for (DOMNode child : mcpChildren) {
86+
if (child instanceof DOMElement && Constant.MCP_CONFIG_KEY.equals(child.getNodeName())) {
87+
String value = Utils.getInlineString(child.getFirstChild());
88+
if (value != null && !value.isBlank()) {
89+
mcpConnectionList.add(value);
90+
}
91+
}
92+
}
93+
mcpConnectionsObj.setMcpConnections(mcpConnectionList);
94+
aiAgent.setMcpConnections(mcpConnectionsObj);
95+
LOGGER.log(Level.INFO, "MCP connections configured for AI agent with {} connections", mcpConnectionList.size());
96+
}
97+
}
98+
5999
private void populateTools(AIAgent aiAgent, DOMElement element) {
60100

61101
DOMNode toolsElement = Utils.getChildNodeByName(element, Constant.TOOLS);

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/syntaxTree/pojo/connector/ai/AIAgent.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
public class AIAgent extends AIConnector {
1818

1919
private String agentID;
20+
private MCPConnections mcpConnections;
2021
private AgentTools tools;
2122

2223
public String getAgentID() {
@@ -38,4 +39,14 @@ public void setTools(AgentTools tools) {
3839

3940
this.tools = tools;
4041
}
42+
43+
public MCPConnections getMcpConnections() {
44+
45+
return mcpConnections;
46+
}
47+
48+
public void setMcpConnections(MCPConnections mcpConnections) {
49+
50+
this.mcpConnections = mcpConnections;
51+
}
4152
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com).
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License v2.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/legal/epl-v20.html
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* WSO2 LLC - support for WSO2 Micro Integrator Configuration
13+
*/
14+
15+
package org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.connector.ai;
16+
17+
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.STNode;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
public class MCPConnections extends STNode {
23+
24+
private List<String> mcpConnections;
25+
26+
public MCPConnections() {
27+
28+
this.mcpConnections = new ArrayList<>();
29+
}
30+
31+
public List<String> getMcpConnections() {
32+
33+
return mcpConnections;
34+
}
35+
36+
public void setMcpConnections(List<String> mcpConnections) {
37+
38+
this.mcpConnections = mcpConnections;
39+
}
40+
41+
public void addMcpConnection(String mcpConnection) {
42+
43+
this.mcpConnections.add(mcpConnection);
44+
}
45+
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/utils/Constant.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,8 @@ public class Constant {
605605
public static final String TOOLS = "tools";
606606
public static final String TOOL = "tool";
607607
public static final String MCP_TOOLS = "mcpTools";
608+
public static final String MCP_CONFIG_KEY = "mcpConfigKey";
609+
public static final String MCP_CONNECTIONS = "mcpConnections";
608610
public static final String AI_AGENT_TAG = "ai.agent";
609611
public static final String ATTRIBUTE_GROUP = "attributeGroup";
610612
public static final String CURRENT_VALUE = "currentValue";

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/utils/Utils.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.maven.shared.invoker.Invoker;
3232
import org.apache.maven.shared.invoker.InvocationResult;
3333
import org.apache.maven.shared.invoker.InvocationRequest;
34+
import org.eclipse.lemminx.commons.BadLocationException;
3435
import org.eclipse.lemminx.commons.TextDocument;
3536
import org.eclipse.lemminx.customservice.synapse.connectors.ConnectorHolder;
3637
import org.eclipse.lemminx.customservice.synapse.connectors.entity.Connector;
@@ -47,6 +48,7 @@
4748
import org.eclipse.lemminx.dom.DOMParser;
4849
import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager;
4950
import org.eclipse.lsp4j.InitializeParams;
51+
import org.eclipse.lsp4j.Position;
5052
import org.w3c.dom.Node;
5153

5254
import java.io.BufferedInputStream;
@@ -221,6 +223,33 @@ public static DOMDocument getDOMDocument(File file) throws IOException {
221223
return domDocument;
222224
}
223225

226+
/**
227+
* Returns the {@link DOMNode} located at the given LSP {@link Position} in the document identified
228+
* by {@code documentUri}.
229+
*
230+
* @param documentUri the document URI as a string
231+
* @param position the position inside the document
232+
* @return the {@link DOMNode} at the given position, or {@code null} if not found
233+
* @throws IOException if an I/O error occurs while reading or parsing the document
234+
* @throws BadLocationException if the provided {@code position} is invalid for the document
235+
*/
236+
public static DOMNode getDOMNode(String documentUri, Position position)
237+
throws IOException, BadLocationException {
238+
239+
if (StringUtils.isEmpty(documentUri) || position == null) {
240+
logger.log(Level.INFO, "Invalid input: documentUri is empty or position is null");
241+
return null;
242+
}
243+
logger.log(Level.INFO,
244+
String.format("Retrieving DOM node at position [%d:%d] in document: %s", position.getLine(),
245+
position.getCharacter(), documentUri));
246+
DOMDocument document = Utils.getDOMDocumentFromPath(getAbsolutePath(documentUri));
247+
int offset = document.offsetAt(position);
248+
DOMNode node = document.findNodeAt(offset);
249+
logger.log(Level.INFO, "Found DOM node of type '%s'", node != null ? node.getNodeName() : "null");
250+
return node;
251+
}
252+
224253
/**
225254
* Get the DOM document from the given xml content
226255
*
@@ -778,6 +807,8 @@ public static String getAbsolutePath(String path) {
778807
try {
779808
return Paths.get(new URI(path)).toAbsolutePath().toString();
780809
} catch (URISyntaxException e) {
810+
logger.log(Level.SEVERE,
811+
String.format("Failed to convert URI to absolute path: %s", path), e);
781812
}
782813
}
783814
return path;

org.eclipse.lemminx/src/main/resources/org/eclipse/lemminx/mediators/440/templates/AIConnector.mustache

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
{{/connections}}
66
</connections>
77
{{#supportTools}}<mcpConnections>
8+
{{#mcpConnections}}
9+
<mcpConfigKey>{{.}}</mcpConfigKey>
10+
{{/mcpConnections}}
811
</mcpConnections>{{/supportTools}}
912
{{#parameters}}
1013
<{{{name}}} {{#value}}{{#namespaces}} xmlns:{{{prefix}}}="{{{uri}}}"{{/namespaces}}>{{#isCDATA}}<![CDATA[{{{value}}}]]>{{/isCDATA}}{{^isCDATA}}{{value}}{{/isCDATA}}{{/value}}</{{{name}}}>
1114
{{/parameters}}
1215
{{#supportTools}}<tools>
1316
{{#tools}}
14-
<tool name="{{name}}" template="{{template}}" resultExpression="{{resultExpression}}" description="{{description}}"/>
17+
<tool name="{{name}}" {{#isMCP}}type="mcp" mcpConnection="{{mcpConnection}}"{{/isMCP}}{{^isMCP}}template="{{template}}" resultExpression="{{resultExpression}}"{{/isMCP}} description="{{description}}"/>
1518
{{/tools}}
1619
</tools>{{/supportTools}}
1720
</{{tag}}>

0 commit comments

Comments
 (0)