66
77package modelengine .fel .tool .mcp .server .support ;
88
9+ import static modelengine .fel .tool .info .schema .PluginSchema .TYPE ;
10+ import static modelengine .fel .tool .info .schema .ToolsSchema .PROPERTIES ;
11+ import static modelengine .fel .tool .info .schema .ToolsSchema .REQUIRED ;
12+ import static modelengine .fitframework .inspection .Validation .notNull ;
13+
914import io .modelcontextprotocol .server .McpServerFeatures ;
1015import io .modelcontextprotocol .server .McpSyncServer ;
1116import io .modelcontextprotocol .spec .McpSchema ;
2429import java .util .Map ;
2530import java .util .stream .Collectors ;
2631
27- import static modelengine .fel .tool .info .schema .PluginSchema .TYPE ;
28- import static modelengine .fel .tool .info .schema .ToolsSchema .PROPERTIES ;
29- import static modelengine .fel .tool .info .schema .ToolsSchema .REQUIRED ;
30- import static modelengine .fitframework .inspection .Validation .notNull ;
31-
3232/**
3333 * Mcp Server implementing interface {@link McpServer}, {@link ToolChangedObserver}
3434 * with MCP Server Bean {@link McpSyncServer}.
@@ -57,9 +57,7 @@ public DefaultMcpStreamableServer(ToolExecuteService toolExecuteService, McpSync
5757
5858 @ Override
5959 public List <Tool > getTools () {
60- return this .mcpSyncServer .listTools ().stream ()
61- .map (this ::convertToFelTool )
62- .collect (Collectors .toList ());
60+ return this .mcpSyncServer .listTools ().stream ().map (this ::convertToFelTool ).collect (Collectors .toList ());
6361 }
6462
6563 @ Override
@@ -87,30 +85,9 @@ public void onToolAdded(String name, String description, Map<String, Object> par
8785 log .warn ("Invalid parameter schema. [toolName={}]" , name );
8886 return ;
8987 }
90- @ SuppressWarnings ("unchecked" )
91- McpSchema .JsonSchema inputSchema = new McpSchema .JsonSchema ((String ) parameters .get (TYPE ),
92- (Map <String , Object >) parameters .get (PROPERTIES ), (List <String >) parameters .get (REQUIRED ),
93- null , null ,null );
94- McpServerFeatures .SyncToolSpecification toolSpecification = McpServerFeatures .SyncToolSpecification .builder ()
95- .tool (McpSchema .Tool .builder ()
96- .name (name )
97- .description (description )
98- .inputSchema (inputSchema )
99- .build ())
100- .callHandler ((exchange , request ) -> {
101- try {
102- Map <String , Object > args = request .arguments ();
103- String result = this .toolExecuteService .execute (name , args );
104- return new McpSchema .CallToolResult (result , false );
105- } catch (IllegalArgumentException e ) {
106- log .warn ("Invalid arguments for tool execution. [toolName={}, error={}]" , name , e .getMessage ());
107- return new McpSchema .CallToolResult ("Error: Invalid arguments - " + e .getMessage (), true );
108- } catch (Exception e ) {
109- log .error ("Failed to execute tool. [toolName={}]" , name , e );
110- return new McpSchema .CallToolResult ("Error: Tool execution failed - " + e .getMessage (), true );
111- }
112- })
113- .build ();
88+
89+ McpServerFeatures .SyncToolSpecification toolSpecification =
90+ createToolSpecification (name , description , parameters );
11491
11592 this .mcpSyncServer .addTool (toolSpecification );
11693 log .info ("Tool added to MCP server. [toolName={}, description={}, schema={}]" , name , description , parameters );
@@ -128,6 +105,63 @@ public void onToolRemoved(String name) {
128105 this .toolsChangedObservers .forEach (ToolsChangedObserver ::onToolsChanged );
129106 }
130107
108+ /**
109+ * Creates a tool specification for the MCP server.
110+ * <p>
111+ * This method constructs a {@link McpServerFeatures.SyncToolSpecification} that includes:
112+ * <ul>
113+ * <li>Tool metadata (name, description, input schema)</li>
114+ * <li>Call handler that executes the tool and handles exceptions</li>
115+ * </ul>
116+ *
117+ * @param name The name of the tool.
118+ * @param description The description of the tool.
119+ * @param parameters The parameter schema containing type, properties, and required fields.
120+ * @return A fully configured {@link McpServerFeatures.SyncToolSpecification}.
121+ */
122+ private McpServerFeatures .SyncToolSpecification createToolSpecification (String name , String description ,
123+ Map <String , Object > parameters ) {
124+ @ SuppressWarnings ("unchecked" ) McpSchema .JsonSchema inputSchema =
125+ new McpSchema .JsonSchema ((String ) parameters .get (TYPE ),
126+ (Map <String , Object >) parameters .get (PROPERTIES ),
127+ (List <String >) parameters .get (REQUIRED ),
128+ null ,
129+ null ,
130+ null );
131+
132+ return McpServerFeatures .SyncToolSpecification .builder ()
133+ .tool (McpSchema .Tool .builder ().name (name ).description (description ).inputSchema (inputSchema ).build ())
134+ .callHandler ((exchange , request ) -> executeToolWithErrorHandling (name , request ))
135+ .build ();
136+ }
137+
138+ /**
139+ * Executes a tool and handles any exceptions that may occur.
140+ * <p>
141+ * This method handles two types of exceptions:
142+ * <ul>
143+ * <li>{@link IllegalArgumentException}: Invalid tool arguments (logged as warning)</li>
144+ * <li>{@link Exception}: Any other execution failure (logged as error)</li>
145+ * </ul>
146+ *
147+ * @param toolName The name of the tool to execute.
148+ * @param request The tool call request containing arguments.
149+ * @return A {@link McpSchema.CallToolResult} with the execution result or error message.
150+ */
151+ private McpSchema .CallToolResult executeToolWithErrorHandling (String toolName , McpSchema .CallToolRequest request ) {
152+ try {
153+ Map <String , Object > args = request .arguments ();
154+ String result = this .toolExecuteService .execute (toolName , args );
155+ return new McpSchema .CallToolResult (result , false );
156+ } catch (IllegalArgumentException e ) {
157+ log .warn ("Invalid arguments for tool execution. [toolName={}, error={}]" , toolName , e .getMessage ());
158+ return new McpSchema .CallToolResult ("Error: Invalid arguments - " + e .getMessage (), true );
159+ } catch (Exception e ) {
160+ log .error ("Failed to execute tool. [toolName={}]" , toolName , e );
161+ return new McpSchema .CallToolResult ("Error: Tool execution failed - " + e .getMessage (), true );
162+ }
163+ }
164+
131165 /**
132166 * Converts an MCP SDK Tool to a FEL Tool entity.
133167 *
@@ -138,7 +172,7 @@ private Tool convertToFelTool(McpSchema.Tool mcpTool) {
138172 Tool tool = new Tool ();
139173 tool .setName (mcpTool .name ());
140174 tool .setDescription (mcpTool .description ());
141-
175+
142176 // Convert JsonSchema to Map<String, Object>
143177 McpSchema .JsonSchema inputSchema = mcpTool .inputSchema ();
144178 Map <String , Object > schemaMap = new HashMap <>();
@@ -150,7 +184,7 @@ private Tool convertToFelTool(McpSchema.Tool mcpTool) {
150184 schemaMap .put (REQUIRED , inputSchema .required ());
151185 }
152186 tool .setInputSchema (schemaMap );
153-
187+
154188 return tool ;
155189 }
156190
@@ -178,10 +212,6 @@ private boolean isValidParameterSchema(Map<String, Object> parameters) {
178212 if (!(reqs instanceof List <?> reqsList )) {
179213 return false ;
180214 }
181- if (reqsList .stream ().anyMatch (v -> !(v instanceof String ))) {
182- return false ;
183- }
184-
185- return true ;
215+ return reqsList .stream ().allMatch (v -> v instanceof String );
186216 }
187217}
0 commit comments