From 624c8e263bb1af40254731267c79a0b82e07f797 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Tue, 2 Sep 2025 14:21:23 -0300 Subject: [PATCH] The ability to publish APIObjects methods as tools on an MCP server of the model is implemented. Issue: 206085 --- gxspringboot/pom.xml | 10 +++ .../java/com/genexus/springboot/GXUtils.java | 61 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 gxspringboot/src/main/java/com/genexus/springboot/GXUtils.java diff --git a/gxspringboot/pom.xml b/gxspringboot/pom.xml index 13420c1e4..869e1a2fb 100644 --- a/gxspringboot/pom.xml +++ b/gxspringboot/pom.xml @@ -47,6 +47,16 @@ urlrewritefilter 5.1.3 + + org.springframework.ai + spring-ai-model + 1.0.1 + + + org.reflections + reflections + 0.10.2 + diff --git a/gxspringboot/src/main/java/com/genexus/springboot/GXUtils.java b/gxspringboot/src/main/java/com/genexus/springboot/GXUtils.java new file mode 100644 index 000000000..5f337a0dd --- /dev/null +++ b/gxspringboot/src/main/java/com/genexus/springboot/GXUtils.java @@ -0,0 +1,61 @@ +package com.genexus.springboot; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.specific.java.Connect; +import com.genexus.specific.java.LogManager; +import org.springframework.ai.tool.ToolCallbackProvider; +import org.springframework.ai.tool.method.MethodToolCallbackProvider; +import org.springframework.ai.tool.annotation.Tool; +import org.reflections.Reflections; + +import java.lang.reflect.Method; +import java.util.Set; + +public class GXUtils { + public static final ILogger logger = com.genexus.diagnostics.core.LogManager.getLogger(GXUtils.class); + + public static ToolCallbackProvider operationsTools(String packageName) { + Connect.init(); + LogManager.initialize("."); + + Reflections reflections = new Reflections( + new org.reflections.util.ConfigurationBuilder() + .forPackages(packageName) + .addScanners(org.reflections.scanners.Scanners.MethodsAnnotated) + ); + + Set toolMethods = reflections.getMethodsAnnotatedWith(Tool.class); + + MethodToolCallbackProvider.Builder builder = MethodToolCallbackProvider.builder(); + + // Keep track of classes that have already been added + Set> processedClasses = new java.util.HashSet<>(); + + for (Method method : toolMethods) { + Class clazz = method.getDeclaringClass(); + + // Skip if we've already processed this class + if (processedClasses.contains(clazz)) { + continue; + } + + try { + Object instance = clazz.getConstructor(int.class).newInstance(-1); + builder.toolObjects(instance); + processedClasses.add(clazz); + + Tool toolAnnotation = method.getAnnotation(Tool.class); + logger.debug(String.format("Registered tool: %s - %s", + toolAnnotation.name().isEmpty() ? method.getName() : toolAnnotation.name(), + toolAnnotation.description())); + } catch (Exception e) { + logger.error("Error instantiating tool class: " + clazz.getName(), e); + } + } + + if (!toolMethods.isEmpty()) + return builder.build(); + + return null; + } +}