From dc8eaaa17bd983343e9d4cb4edadae3798820ba4 Mon Sep 17 00:00:00 2001 From: jade Date: Fri, 28 Aug 2026 15:10:24 +0900 Subject: [PATCH] fix: remove mcp-annotations and use local annotations --- dat-was-lib/build.gradle | 2 +- .../dat/lib/annotation/McpTool.java | 36 +++++++++++++++++++ .../dat/lib/annotation/McpToolParam.java | 16 +++++++++ .../dat/lib/aop/ToolSlaMonitoringAspect.java | 4 +-- .../dat/lib/mcp/McpToolMethodRegistry.java | 2 +- .../lib/mcp/ToolMcpServerConfiguration.java | 1 + .../lib/mcp/ToolRegistryHeartbeatSender.java | 2 +- .../dat/lib/util/JsonSchemaGenerator.java | 2 +- .../dat/lib/util/ToolScaffolder.java | 4 +-- .../dat/lib/util/ToolSchemaResolver.java | 8 ++--- .../lib/mcp/McpToolMethodRegistryTest.java | 2 +- .../mcp/ToolRegistryHeartbeatSenderTest.java | 2 +- .../dat/lib/util/JsonSchemaGeneratorTest.java | 2 +- .../dat/lib/util/ToolSchemaResolverTest.java | 2 +- .../dat/lib/util/ToolSourceUpdaterTest.java | 2 +- .../validation/McpToolNameValidatorTest.java | 2 +- .../mcc/mcp/McpRequestHeaderFilterTest.java | 2 +- 17 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpTool.java create mode 100644 dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpToolParam.java diff --git a/dat-was-lib/build.gradle b/dat-was-lib/build.gradle index c8c2cf0f..e6cc339a 100644 --- a/dat-was-lib/build.gradle +++ b/dat-was-lib/build.gradle @@ -49,7 +49,7 @@ dependencies { api 'io.modelcontextprotocol.sdk:mcp-json-jackson2' // Boot 3.5 호환 Spring AI 어노테이션 API를 유지합니다. - api 'org.springaicommunity:mcp-annotations:0.9.0' + // api 'org.springaicommunity:mcp-annotations:0.9.0' // 이벤트 기반 확장이 필요한 Tool의 공통 Kafka 연동 기능입니다. api 'org.springframework.kafka:spring-kafka:3.2.0' diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpTool.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpTool.java new file mode 100644 index 00000000..f358d441 --- /dev/null +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpTool.java @@ -0,0 +1,36 @@ +package io.shinhanlife.dat.lib.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(value={ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface McpTool { + String name() default ""; + + String description() default ""; + + McpAnnotations annotations() default @McpAnnotations; + + boolean generateOutputSchema() default false; + + String title() default ""; + + @Retention(value=RetentionPolicy.RUNTIME) + @Target(value={ElementType.ANNOTATION_TYPE}) + public static @interface McpAnnotations { + String title() default ""; + + boolean readOnlyHint() default false; + + boolean destructiveHint() default true; + + boolean idempotentHint() default false; + + boolean openWorldHint() default true; + } +} \ No newline at end of file diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpToolParam.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpToolParam.java new file mode 100644 index 00000000..75570aae --- /dev/null +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/annotation/McpToolParam.java @@ -0,0 +1,16 @@ +package io.shinhanlife.dat.lib.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(value={ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface McpToolParam { + boolean required() default true; + + String description() default ""; +} \ No newline at end of file diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/aop/ToolSlaMonitoringAspect.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/aop/ToolSlaMonitoringAspect.java index 3b73ed6d..f01fffff 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/aop/ToolSlaMonitoringAspect.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/aop/ToolSlaMonitoringAspect.java @@ -23,7 +23,7 @@ import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @@ -36,7 +36,7 @@ public class ToolSlaMonitoringAspect { private final McpProperties mcpProperties; // @McpTool 어노테이션이 붙은 모든 비즈니스 툴 메서드 실행을 가로챕니다. - @Around("@annotation(org.springaicommunity.mcp.annotation.McpTool)") + @Around("@annotation(io.shinhanlife.dat.lib.annotation.McpTool)") public Object monitorToolSla(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistry.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistry.java index 55d53d21..2816c0c6 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistry.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistry.java @@ -9,7 +9,7 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; import org.springframework.aop.support.AopUtils; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationContext; diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolMcpServerConfiguration.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolMcpServerConfiguration.java index 88ef705f..e57a75f6 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolMcpServerConfiguration.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolMcpServerConfiguration.java @@ -33,6 +33,7 @@ public class ToolMcpServerConfiguration { /** Creates the Tool Pod MCP server directly with MCP Java SDK 2.0.0. */ @Bean(destroyMethod = "close") + @Primary public McpSyncServer toolMcpServer(HttpServletStreamableServerTransportProvider transportProvider) { return McpServer.sync(transportProvider) .serverInfo("dap-tool-pod", "2.0.0") diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSender.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSender.java index 3c3b0a19..ec009ba7 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSender.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSender.java @@ -16,7 +16,7 @@ package io.shinhanlife.dat.lib.mcp; * */ import com.fasterxml.jackson.databind.ObjectMapper; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; import io.shinhanlife.dat.lib.annotation.GrowToolHint; import io.shinhanlife.dat.lib.config.McpProperties; import io.shinhanlife.dat.mcc.dto.ToolMetadata; diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/JsonSchemaGenerator.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/JsonSchemaGenerator.java index f81cf929..8616297e 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/JsonSchemaGenerator.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/JsonSchemaGenerator.java @@ -2,7 +2,7 @@ package io.shinhanlife.dat.lib.util; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import org.springaicommunity.mcp.annotation.McpToolParam; +import io.shinhanlife.dat.lib.annotation.McpToolParam; import io.swagger.v3.oas.annotations.media.Schema; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java index e9b9a47f..fd67572e 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java @@ -274,7 +274,7 @@ public class ToolScaffolder { .append(baseName).append("Request req);\n\n"); } return "package " + bizPackage + ".usecase;\n\n" - + "import org.springaicommunity.mcp.annotation.McpTool;\n" + + "import io.shinhanlife.dat.lib.annotation.McpTool;\n" + "import io.shinhanlife.dat.lib.annotation.GrowToolHint;\n" + imports + "\npublic interface " + useCaseBaseName + "UseCase {\n\n" + methods + "}\n"; } @@ -819,7 +819,7 @@ public class ToolScaffolder { String serviceInterfaceContent = """ package %s.usecase; - import org.springaicommunity.mcp.annotation.McpTool; + import io.shinhanlife.dat.lib.annotation.McpTool; import io.shinhanlife.dat.lib.annotation.GrowToolHint; import %s.dto.%sRequest; import %s.dto.%sResponse; diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolSchemaResolver.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolSchemaResolver.java index 8169dbf7..e985b985 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolSchemaResolver.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolSchemaResolver.java @@ -17,7 +17,7 @@ public class ToolSchemaResolver { this.objectMapper = objectMapper; } - public Map resolve(org.springaicommunity.mcp.annotation.McpTool function, + public Map resolve(io.shinhanlife.dat.lib.annotation.McpTool function, GrowToolHint hint, Class requestType) { if (hint != null && !hint.inputSchemaResource().isBlank()) { return loadResource(hint.inputSchemaResource()); @@ -29,7 +29,7 @@ public class ToolSchemaResolver { * Resolves a response schema only when it is explicitly declared. * A JSON resource has precedence over a DTO marker annotation. */ - public Map resolveOutput(org.springaicommunity.mcp.annotation.McpTool function, + public Map resolveOutput(io.shinhanlife.dat.lib.annotation.McpTool function, Class responseType, GrowToolHint hint) { if (hint != null && !hint.outputSchemaResource().isBlank()) { return loadResource(hint.outputSchemaResource()); @@ -40,7 +40,7 @@ public class ToolSchemaResolver { /** * Generates a response schema only for DTOs marked with {@link McpOutputSchema}. */ - public Map resolveOutput(org.springaicommunity.mcp.annotation.McpTool function, + public Map resolveOutput(io.shinhanlife.dat.lib.annotation.McpTool function, Class responseType) { if (responseType == null || responseType == Object.class @@ -56,7 +56,7 @@ public class ToolSchemaResolver { /** * Retained for callers that use only explicit output schemas. */ - public Map resolveOutput(org.springaicommunity.mcp.annotation.McpTool function) { + public Map resolveOutput(io.shinhanlife.dat.lib.annotation.McpTool function) { return Map.of(); } diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistryTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistryTest.java index 8a09edc9..b31dfbeb 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistryTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/McpToolMethodRegistryTest.java @@ -6,7 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import io.shinhanlife.dat.lib.config.McpProperties; import org.junit.jupiter.api.Test; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; import org.springframework.context.support.StaticApplicationContext; class McpToolMethodRegistryTest { diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSenderTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSenderTest.java index 67eae195..ea6edc1a 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSenderTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/mcp/ToolRegistryHeartbeatSenderTest.java @@ -15,7 +15,7 @@ import java.lang.reflect.Field; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; import org.springframework.context.ApplicationContext; class ToolRegistryHeartbeatSenderTest { diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/JsonSchemaGeneratorTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/JsonSchemaGeneratorTest.java index c49c88e6..b1ffae01 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/JsonSchemaGeneratorTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/JsonSchemaGeneratorTest.java @@ -1,7 +1,7 @@ package io.shinhanlife.dat.lib.util; -import org.springaicommunity.mcp.annotation.McpToolParam; +import io.shinhanlife.dat.lib.annotation.McpToolParam; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSchemaResolverTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSchemaResolverTest.java index acc24554..8762e1a7 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSchemaResolverTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSchemaResolverTest.java @@ -10,7 +10,7 @@ import java.lang.reflect.Method; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; -import org.springaicommunity.mcp.annotation.McpTool; +import io.shinhanlife.dat.lib.annotation.McpTool; class ToolSchemaResolverTest { diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSourceUpdaterTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSourceUpdaterTest.java index 9fc53510..9cc19821 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSourceUpdaterTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolSourceUpdaterTest.java @@ -18,7 +18,7 @@ class ToolSourceUpdaterTest { Files.createDirectories(source.getParent()); Files.writeString(source, """ package example; - import org.springaicommunity.mcp.annotation.McpTool; + import io.shinhanlife.dat.lib.annotation.McpTool; import io.shinhanlife.dat.lib.annotation.GrowToolHint; interface SampleUseCase { @McpTool(name = "cmm_sample_search", description = "old") diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/validation/McpToolNameValidatorTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/validation/McpToolNameValidatorTest.java index ce93ec24..04f93ec6 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/validation/McpToolNameValidatorTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/validation/McpToolNameValidatorTest.java @@ -90,7 +90,7 @@ class McpToolNameValidatorTest { Files.writeString(source, """ package example; - import org.springaicommunity.mcp.annotation.McpTool; + import io.shinhanlife.dat.lib.annotation.McpTool; class %s { @McpTool(name = "%s") diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/mcc/mcp/McpRequestHeaderFilterTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/mcc/mcp/McpRequestHeaderFilterTest.java index fd826410..59000135 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/mcc/mcp/McpRequestHeaderFilterTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/mcc/mcp/McpRequestHeaderFilterTest.java @@ -24,7 +24,7 @@ class McpRequestHeaderFilterTest { request.addHeader("employee-no", "ENC(employee)"); request.addHeader("virtual-employee-no", "ENC(virtual)"); - new McpRequestHeaderFilter().doFilter(request, new MockHttpServletResponse(), (req, res) -> + new McpRequestHeaderFilter(null).doFilter(request, new MockHttpServletResponse(), (req, res) -> assertThat(asMap(McpRequestHeaderContext.current())).containsExactly( Map.entry("requestId", "request-001"), Map.entry("guid", "guid-001"),