Refactor: rename ToolHint to GrowToolHint and update annotations
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m2s

This commit is contained in:
jade
2026-08-13 16:20:00 +09:00
parent 206095a7a8
commit 019cbe4199
27 changed files with 95 additions and 67 deletions

View File

@@ -8,7 +8,7 @@ import java.lang.annotation.Target;
/**
* Spring AI @Tool 어노테이션을 보완하여 MCP 시스템 메타데이터를 추가 제공하는 힌트 어노테이션
* @package io.shinhanlife.dap.lib.annotation
* @className ToolHint
* @className GrowToolHint
* @description 비즈니스 로직(Tool) 시스템 제어 메타데이터 분리
* @author 0986406
* @create 2026.09.01
@@ -22,7 +22,7 @@ import java.lang.annotation.Target;
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ToolHint {
public @interface GrowToolHint {
boolean register() default false;
boolean requiresApproval() default false;
String categoryKey() default "com";

View File

@@ -1,6 +1,6 @@
package io.shinhanlife.dap.lib.mcp;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
import io.shinhanlife.dap.lib.config.McpProperties;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
@@ -45,7 +45,7 @@ public class McpToolMethodRegistry {
bean,
findInvocableMethod(bean, declaredMethod),
annotation,
AnnotationUtils.findAnnotation(declaredMethod, ToolHint.class));
AnnotationUtils.findAnnotation(declaredMethod, GrowToolHint.class));
register(discovered, annotation.name(), tool);
registerNamespaceAlias(discovered, annotation.name(), tool);
}
@@ -82,6 +82,6 @@ public class McpToolMethodRegistry {
}
}
public record RegisteredTool(Object bean, Method method, McpTool annotation, ToolHint hint) {
public record RegisteredTool(Object bean, Method method, McpTool annotation, GrowToolHint hint) {
}
}

View File

@@ -17,7 +17,7 @@ package io.shinhanlife.dap.lib.mcp;
*/
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
import io.shinhanlife.dap.lib.config.McpProperties;
import io.shinhanlife.dap.mcc.dto.ToolMetadata;
import io.shinhanlife.dap.lib.util.ToolSchemaResolver;
@@ -102,7 +102,7 @@ public class ToolRegistryHeartbeatSender {
for (Method method : targetClass.getDeclaredMethods()) {
McpTool functionAnnotation = AnnotationUtils.findAnnotation(method, McpTool.class);
ToolHint hintAnnotation = AnnotationUtils.findAnnotation(method, ToolHint.class);
GrowToolHint hintAnnotation = AnnotationUtils.findAnnotation(method, GrowToolHint.class);
if (functionAnnotation != null) {
String baseName = functionAnnotation.name();
@@ -110,7 +110,7 @@ public class ToolRegistryHeartbeatSender {
String subToolName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
? mcpProperties.getNamespace() + "_" + rawSubToolName
: rawSubToolName;
// @ToolHint(register = false)인 Tool은 메타데이터 조회에는 남기되,
// @GrowToolHint(register = false)인 Tool은 메타데이터 조회에는 남기되,
// Gateway 등록 및 heartbeat 전송 대상에서는 제외합니다.
// ToolHint가 없는 기존 Tool은 이전 동작과 동일하게 등록합니다.
boolean isRegister = hintAnnotation == null || hintAnnotation.register();
@@ -184,7 +184,7 @@ public class ToolRegistryHeartbeatSender {
}
}
private void enrichWithDefinition(ToolMetadata meta, String rawToolName, ToolHint hintAnnotation) {
private void enrichWithDefinition(ToolMetadata meta, String rawToolName, GrowToolHint hintAnnotation) {
if (toolDefinitionRepository == null) {
return;
}
@@ -192,7 +192,7 @@ public class ToolRegistryHeartbeatSender {
.ifPresent(definition -> applyDefinition(meta, definition, hintAnnotation));
}
private void applyDefinition(ToolMetadata meta, ToolDefinition definition, ToolHint hintAnnotation) {
private void applyDefinition(ToolMetadata meta, ToolDefinition definition, GrowToolHint hintAnnotation) {
meta.setDisplayName(definition.displayName());
meta.setSemver(definition.version());
meta.setCategoryKey(definition.categoryKey());

View File

@@ -217,7 +217,7 @@ public class ToolScaffolder {
methods.append(" @McpTool(name = \"").append(toToolName(moduleName, tool.group(), baseName))
.append("\", title = \"").append(javaText(option(tool.title(), baseName)))
.append("\", description = \"").append(javaText(option(tool.description(), ""))).append("\")\n")
.append(" @ToolHint(register = ").append(tool.register()).append(", categoryKey = \"")
.append(" @GrowToolHint(register = ").append(tool.register()).append(", categoryKey = \"")
.append(tool.group().toLowerCase(Locale.ROOT)).append("\", mappingId = \"")
.append(javaText(tool.interfaceId())).append("\")\n")
.append(" ").append(baseName).append("Response ").append(tool.methodName()).append("(")
@@ -225,7 +225,7 @@ public class ToolScaffolder {
}
return "package " + bizPackage + ".usecase;\n\n"
+ "import org.springaicommunity.mcp.annotation.McpTool;\n"
+ "import io.shinhanlife.dap.lib.annotation.ToolHint;\n"
+ "import io.shinhanlife.dap.lib.annotation.GrowToolHint;\n"
+ imports + "\npublic interface " + useCaseBaseName + "UseCase {\n\n" + methods + "}\n";
}
@@ -329,7 +329,7 @@ public class ToolScaffolder {
useCase = addImport(useCase, "import " + bizPackage + ".dto." + responseType + ";") ;
String declaration = "\n @McpTool(name = \"" + toolName + "\", title = \"" + javaText(option(tool.title(), baseName))
+ "\", description = \"" + javaText(option(tool.description(), "")) + "\")\n"
+ " @ToolHint(register = " + tool.register() + ", categoryKey = \"" + tool.group().toLowerCase(Locale.ROOT)
+ " @GrowToolHint(register = " + tool.register() + ", categoryKey = \"" + tool.group().toLowerCase(Locale.ROOT)
+ "\", mappingId = \"" + javaText(option(tool.interfaceId(), tool.httpApiName())) + "\")\n"
+ " " + responseType + " " + methodName + "(" + requestType + " req);\n";
useCase = insertBeforeLastBrace(useCase, declaration);
@@ -644,18 +644,18 @@ public class ToolScaffolder {
String toolHintLine;
if (useSchemaResource) {
toolHintLine = (" @ToolHint(register = %s, categoryKey = \"%s\", mappingId = \"%s\",\n" +
toolHintLine = (" @GrowToolHint(register = %s, categoryKey = \"%s\", mappingId = \"%s\",\n" +
" inputSchemaResource = \"%s\",\n" +
" outputSchemaResource = \"%s\")").formatted(register, group.toLowerCase(Locale.ROOT), interfaceId, inputSchemaClasspath, outputSchemaClasspath);
} else {
toolHintLine = " @ToolHint(register = %s, categoryKey = \"%s\", mappingId = \"%s\")".formatted(register, group.toLowerCase(Locale.ROOT), interfaceId);
toolHintLine = " @GrowToolHint(register = %s, categoryKey = \"%s\", mappingId = \"%s\")".formatted(register, group.toLowerCase(Locale.ROOT), interfaceId);
}
String serviceInterfaceContent = """
package %s.usecase;
import org.springaicommunity.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
import %s.dto.%sRequest;
import %s.dto.%sResponse;

View File

@@ -3,7 +3,7 @@ package io.shinhanlife.dap.lib.util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.lib.annotation.McpOutputSchema;
import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.lib.annotation.GrowToolHint;
import java.io.InputStream;
import java.util.Map;
import org.springframework.core.io.ClassPathResource;
@@ -18,7 +18,7 @@ public class ToolSchemaResolver {
}
public Map<String, Object> resolve(org.springaicommunity.mcp.annotation.McpTool function,
ToolHint hint, Class<?> requestType) {
GrowToolHint hint, Class<?> requestType) {
if (hint != null && !hint.inputSchemaResource().isBlank()) {
return loadResource(hint.inputSchemaResource());
}
@@ -30,7 +30,7 @@ public class ToolSchemaResolver {
* A JSON resource has precedence over a DTO marker annotation.
*/
public Map<String, Object> resolveOutput(org.springaicommunity.mcp.annotation.McpTool function,
Class<?> responseType, ToolHint hint) {
Class<?> responseType, GrowToolHint hint) {
if (hint != null && !hint.outputSchemaResource().isBlank()) {
return loadResource(hint.outputSchemaResource());
}

View File

@@ -63,15 +63,15 @@ public final class ToolSourceUpdater {
}
private static String updateToolHint(String content, String categoryKey, boolean register, Boolean requiresApproval) {
AnnotationRange range = annotationArguments(content, "ToolHint", null);
AnnotationRange range = annotationArguments(content, "GrowToolHint", null);
if (range == null) {
throw new IllegalArgumentException("ToolHint declaration not found next to McpTool");
throw new IllegalArgumentException("GrowToolHint declaration not found next to McpTool");
}
String updated = replaceAttribute(content, range, "register", Boolean.toString(register));
range = annotationArguments(updated, "ToolHint", null);
range = annotationArguments(updated, "GrowToolHint", null);
if (requiresApproval != null) {
updated = replaceAttribute(updated, range, "requiresApproval", Boolean.toString(requiresApproval));
range = annotationArguments(updated, "ToolHint", null);
range = annotationArguments(updated, "GrowToolHint", null);
}
if (categoryKey != null && !categoryKey.isBlank()) {
updated = replaceAttribute(updated, range, "categoryKey", quote(categoryKey));