paths = Files.walk(rootDir)) {
- javaFiles = paths
- .filter(Files::isRegularFile)
- .filter(p -> p.toString().endsWith("UseCase.java"))
- .filter(p -> p.toString().contains("dap-was-") || p.toString().contains("axhub-tool-"))
- .collect(Collectors.toList());
- }
+ private ToolSourceUpdater() {
+ }
- Path targetFile = null;
- String content = null;
-
- // 2. Find the specific file for the tool
- String functionName = toolName;
- if (toolName.contains("_")) {
- functionName = toolName.substring(toolName.indexOf("_") + 1);
- }
-
- Pattern namePattern = Pattern.compile("@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"", Pattern.DOTALL);
- Pattern namePattern2 = Pattern.compile("@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(functionName) + "\"", Pattern.DOTALL);
-
- for (Path path : javaFiles) {
- String text = Files.readString(path);
- if (namePattern.matcher(text).find()) {
- targetFile = path;
- content = text;
- break;
- } else if (namePattern2.matcher(text).find()) {
- targetFile = path;
- content = text;
- toolName = functionName; // Use baseName for subsequent replacements
- break;
- }
- }
+ public static void updateToolSource(String toolName, String categoryKey, String description,
+ boolean register, Boolean requiresApproval) throws IOException {
+ String configuredSourceDirectory = System.getenv("AXHUB_SOURCE_DIR");
+ Path rootDirectory = configuredSourceDirectory == null || configuredSourceDirectory.isBlank()
+ ? Paths.get(".") : Paths.get(configuredSourceDirectory);
+ updateToolSource(rootDirectory, toolName, categoryKey, description, register, requiresApproval);
+ }
+ static void updateToolSource(Path rootDirectory, String toolName, String categoryKey, String description,
+ boolean register, Boolean requiresApproval) throws IOException {
+ Path targetFile = findToolSource(rootDirectory, toolName);
if (targetFile == null) {
- throw new Exception("소스 코드를 찾을 수 없습니다: " + toolName);
+ throw new IllegalArgumentException("Tool source not found: " + toolName);
}
- // 3. Update @McpTool group
- if (domainGroup != null && !domainGroup.trim().isEmpty()) {
- Pattern groupPattern = Pattern.compile("(@McpTool\\s*\\([^)]*group\\s*=\\s*\")([^\"]+)(\")", Pattern.DOTALL);
- Matcher groupMatcher = groupPattern.matcher(content);
- if (groupMatcher.find()) {
- content = groupMatcher.replaceFirst("$1" + domainGroup + "$3");
- }
- }
-
- // 4. Update @McpFunction description
- if (description != null) {
- Pattern funcPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"[^)]*description\\s*=\\s*\")([^\"]+)(\")", Pattern.DOTALL);
- Matcher funcMatcher = funcPattern.matcher(content);
- if (funcMatcher.find()) {
- content = funcMatcher.replaceFirst("$1" + description.replace("\\", "\\\\").replace("$", "\\\\$") + "$3");
- }
- }
-
- // 5. Update register flag
- Pattern regPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"[^)]*register\\s*=\\s*)(true|false)([^a-zA-Z0-9])", Pattern.DOTALL);
- Matcher regMatcher = regPattern.matcher(content);
- if (regMatcher.find()) {
- content = regMatcher.replaceFirst("$1" + register + "$3");
- } else {
- Pattern addRegPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\")", Pattern.DOTALL);
- Matcher addRegMatcher = addRegPattern.matcher(content);
- if (addRegMatcher.find()) {
- content = addRegMatcher.replaceFirst("$1, register = " + register);
- }
- }
-
- // 5.5 Update requiresApproval flag
- if (requiresApproval != null) {
- Pattern appPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"[^)]*requiresApproval\\s*=\\s*)(true|false)([^a-zA-Z0-9])", Pattern.DOTALL);
- Matcher appMatcher = appPattern.matcher(content);
- if (appMatcher.find()) {
- content = appMatcher.replaceFirst("$1" + requiresApproval + "$3");
- } else {
- Pattern addAppPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\")", Pattern.DOTALL);
- Matcher addAppMatcher = addAppPattern.matcher(content);
- if (addAppMatcher.find()) {
- content = addAppMatcher.replaceFirst("$1, requiresApproval = " + requiresApproval);
- }
- }
- }
-
- // 6. Write back to file
+ String content = Files.readString(targetFile);
+ content = updateMcpTool(content, toolName, description);
+ content = updateToolHint(content, categoryKey, register, requiresApproval);
Files.writeString(targetFile, content);
}
+
+ private static Path findToolSource(Path rootDirectory, String toolName) throws IOException {
+ try (var paths = Files.walk(rootDirectory)) {
+ return paths.filter(Files::isRegularFile)
+ .filter(path -> path.getFileName().toString().endsWith("UseCase.java"))
+ .filter(path -> path.toString().contains("dap-was-") || path.toString().contains("axhub-tool-"))
+ .sorted(Comparator.naturalOrder())
+ .filter(path -> containsMcpTool(path, toolName))
+ .findFirst()
+ .orElse(null);
+ }
+ }
+
+ private static boolean containsMcpTool(Path path, String toolName) {
+ try {
+ return annotationArguments(Files.readString(path), "McpTool", toolName) != null;
+ } catch (IOException exception) {
+ throw new IllegalStateException("Failed to read tool source: " + path, exception);
+ }
+ }
+
+ private static String updateMcpTool(String content, String toolName, String description) {
+ AnnotationRange range = annotationArguments(content, "McpTool", toolName);
+ if (range == null) {
+ throw new IllegalArgumentException("McpTool declaration not found: " + toolName);
+ }
+ return description == null ? content : replaceAttribute(content, range, "description", quote(description));
+ }
+
+ private static String updateToolHint(String content, String categoryKey, boolean register, Boolean requiresApproval) {
+ AnnotationRange range = annotationArguments(content, "ToolHint", null);
+ if (range == null) {
+ throw new IllegalArgumentException("ToolHint declaration not found next to McpTool");
+ }
+ String updated = replaceAttribute(content, range, "register", Boolean.toString(register));
+ range = annotationArguments(updated, "ToolHint", null);
+ if (requiresApproval != null) {
+ updated = replaceAttribute(updated, range, "requiresApproval", Boolean.toString(requiresApproval));
+ range = annotationArguments(updated, "ToolHint", null);
+ }
+ if (categoryKey != null && !categoryKey.isBlank()) {
+ updated = replaceAttribute(updated, range, "categoryKey", quote(categoryKey));
+ }
+ return updated;
+ }
+
+ private static String replaceAttribute(String content, AnnotationRange range, String attribute, String value) {
+ String arguments = content.substring(range.argumentsStart(), range.argumentsEnd());
+ String pattern = "\\b" + attribute + "\\s*=\\s*(?:true|false|\\\"(?:\\\\.|[^\\\"\\\\])*\\\")";
+ String replacement = arguments.replaceFirst(pattern, attribute + " = " + value);
+ if (replacement.equals(arguments)) {
+ replacement = arguments.isBlank() ? attribute + " = " + value : arguments + ", " + attribute + " = " + value;
+ }
+ return content.substring(0, range.argumentsStart()) + replacement + content.substring(range.argumentsEnd());
+ }
+
+ private static String quote(String value) {
+ return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
+ }
+
+ private static AnnotationRange annotationArguments(String content, String annotationName, String toolName) {
+ int offset = content.indexOf("@" + annotationName);
+ while (offset >= 0) {
+ int openingParenthesis = content.indexOf('(', offset);
+ int closingParenthesis = findAnnotationEnd(content, openingParenthesis);
+ if (openingParenthesis < 0 || closingParenthesis < 0) {
+ return null;
+ }
+ AnnotationRange range = new AnnotationRange(openingParenthesis + 1, closingParenthesis);
+ if (toolName == null || content.substring(range.argumentsStart(), range.argumentsEnd())
+ .matches("(?s).*\\bname\\s*=\\s*\\\"" + java.util.regex.Pattern.quote(toolName) + "\\\".*")) {
+ return range;
+ }
+ offset = content.indexOf("@" + annotationName, closingParenthesis + 1);
+ }
+ return null;
+ }
+
+ private static int findAnnotationEnd(String content, int openingParenthesis) {
+ int depth = 0;
+ boolean inString = false;
+ boolean escaped = false;
+ for (int index = openingParenthesis; index < content.length(); index++) {
+ char character = content.charAt(index);
+ if (inString) {
+ if (escaped) {
+ escaped = false;
+ } else if (character == '\\') {
+ escaped = true;
+ } else if (character == '\"') {
+ inString = false;
+ }
+ } else if (character == '\"') {
+ inString = true;
+ } else if (character == '(') {
+ depth++;
+ } else if (character == ')' && --depth == 0) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ private record AnnotationRange(int argumentsStart, int argumentsEnd) {
+ }
}
diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/validation/McpToolNameValidator.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/validation/McpToolNameValidator.java
index f491fd87..89aea24d 100644
--- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/validation/McpToolNameValidator.java
+++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/validation/McpToolNameValidator.java
@@ -15,7 +15,7 @@ import java.util.regex.Pattern;
/**
* @package io.shinhanlife.dap.lib.validation
* @className McpToolNameValidator
- * @description Validates unique MCP function names across tool modules
+ * @description Validates unique MCP SDK tool names across tool modules
* @author 0986406
* @create 2026.07.27
*
@@ -88,7 +88,7 @@ public final class McpToolNameValidator {
throw new UncheckedIOException("Failed to read " + source, exception);
}
- int annotationOffset = content.indexOf("@McpFunction");
+ int annotationOffset = content.indexOf("@McpTool");
while (annotationOffset >= 0) {
int openingParenthesis = content.indexOf('(', annotationOffset);
int closingParenthesis = findAnnotationEnd(content, openingParenthesis);
@@ -103,7 +103,7 @@ public final class McpToolNameValidator {
declarationsByName.computeIfAbsent(toolName, ignored -> new ArrayList<>())
.add(new ToolDeclaration(moduleName, source, line));
}
- annotationOffset = content.indexOf("@McpFunction", closingParenthesis + 1);
+ annotationOffset = content.indexOf("@McpTool", closingParenthesis + 1);
}
}
diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java
index a998ad79..c3f42a2b 100644
--- a/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java
+++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java
@@ -17,9 +17,8 @@ package io.shinhanlife.dap.mcc.presentation;
*/
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.Error;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+import org.springframework.ai.mcp.annotation.McpTool;
import io.shinhanlife.dap.lib.validation.ToolArgumentSchemaValidator;
-import io.shinhanlife.dap.lib.annotation.McpTool;
import io.shinhanlife.dap.lib.config.McpProperties;
import io.shinhanlife.dap.mcc.dto.ToolMetadata;
import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender;
@@ -88,15 +87,15 @@ public class BusinessToolController {
}
Object targetBean = null;
Method targetMethod = null;
- McpFunction targetFunctionAnnotation = null;
+ McpTool targetFunctionAnnotation = null;
- // McpTool 어노테이션 기반 조회가 프록시 문제로 누락될 수 있으므로, 전체 빈을 순회하며 @McpFunction을 찾습니다.
+ // McpTool 어노테이션 기반 조회가 프록시 문제로 누락될 수 있으므로, 전체 빈을 순회하며 @McpTool을 찾습니다.
Map allBeans = applicationContext.getBeansOfType(Object.class);
outerLoop:
for (Object bean : allBeans.values()) {
Class> targetClass = AopUtils.getTargetClass(bean);
for (Method targetMethodOfClass : targetClass.getDeclaredMethods()) {
- McpFunction mcpFunc = AnnotationUtils.findAnnotation(targetMethodOfClass, McpFunction.class);
+ McpTool mcpFunc = AnnotationUtils.findAnnotation(targetMethodOfClass, McpTool.class);
if (mcpFunc != null) {
String baseName = mcpFunc.name();
String expectedName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
@@ -122,7 +121,7 @@ public class BusinessToolController {
for (Object bean : allBeans.values()) {
Class> targetCls = AopUtils.getTargetClass(bean);
for (Method m : targetCls.getDeclaredMethods()) {
- McpFunction func = AnnotationUtils.findAnnotation(m, McpFunction.class);
+ McpTool func = AnnotationUtils.findAnnotation(m, McpTool.class);
if (func != null) {
String baseName = func.name();
String expName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
@@ -149,7 +148,8 @@ public class BusinessToolController {
Class> paramType = targetMethod.getParameterTypes()[0];
if (!Map.class.isAssignableFrom(paramType)) {
try {
- Map inputSchema = toolSchemaResolver.resolve(targetFunctionAnnotation, paramType);
+ io.shinhanlife.dap.lib.annotation.ToolHint hint = AnnotationUtils.findAnnotation(targetMethod, io.shinhanlife.dap.lib.annotation.ToolHint.class);
+ Map inputSchema = toolSchemaResolver.resolve(targetFunctionAnnotation, hint, paramType);
List errors = toolArgumentSchemaValidator.validate(inputSchema, arguments);
if (!errors.isEmpty()) {
log.error("[Tool] 파라미터 유효성 검증 실패: {}", errors);
@@ -194,7 +194,8 @@ public class BusinessToolController {
methodResult = targetMethod.invoke(targetBean, invokeArgument);
}
- Map outputSchema = toolSchemaResolver.resolveOutput(targetFunctionAnnotation, targetMethod.getReturnType());
+ io.shinhanlife.dap.lib.annotation.ToolHint outputHint = AnnotationUtils.findAnnotation(targetMethod, io.shinhanlife.dap.lib.annotation.ToolHint.class);
+ Map outputSchema = toolSchemaResolver.resolveOutput(targetFunctionAnnotation, targetMethod.getReturnType(), outputHint);
if (!outputSchema.isEmpty()) {
List outputErrors = toolArgumentSchemaValidator.validateValue(outputSchema, methodResult);
if (!outputErrors.isEmpty()) {
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/common/adapter/sender/ShinhanMciSenderTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/common/adapter/sender/ShinhanMciSenderTest.java
index 011b5715..9ee767a2 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/common/adapter/sender/ShinhanMciSenderTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/common/adapter/sender/ShinhanMciSenderTest.java
@@ -1,4 +1,4 @@
-package io.shinhanlife.dap.lib.adapter.sender;
+package io.shinhanlife.dap.lib.common.adapter.sender;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.lib.integration.mci.dto.MciRequestWrapper;
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/JsonSchemaGeneratorTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/JsonSchemaGeneratorTest.java
index aa6529da..df20d796 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/JsonSchemaGeneratorTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/JsonSchemaGeneratorTest.java
@@ -1,5 +1,7 @@
package io.shinhanlife.dap.lib.util;
+
+import org.springframework.ai.mcp.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;
@@ -10,8 +12,6 @@ import com.networknt.schema.InputFormat;
import com.networknt.schema.Schema;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.SpecificationVersion;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
@@ -90,24 +90,19 @@ class JsonSchemaGeneratorTest {
}
private static class ValidatedRequest {
- @McpParameter(description = "recipient phone number", required = true)
- @McpValidation(pattern = "^01[0-9]{8,9}$")
+ @McpToolParam(description = "recipient phone number", required = true)
private String phoneNumber;
- @McpParameter(description = "issue amount", required = true)
- @McpValidation(minimum = 1)
+ @McpToolParam(description = "issue amount", required = true)
private Long amount;
- @McpParameter(description = "approval result")
- @McpValidation(required = true, allowedValues = {"APPROVE", "REJECT"})
+ @McpToolParam(description = "approval result")
private String approvalStatus;
- @McpParameter(description = "page size")
- @McpValidation(minimum = 1, maximum = 50, defaultValue = "20")
+ @McpToolParam(description = "page size")
private Integer pageSize;
- @McpParameter(description = "reference")
- @McpValidation(minLength = 1, maxLength = 30)
+ @McpToolParam(description = "reference")
private String reference;
}
@@ -120,7 +115,6 @@ class JsonSchemaGeneratorTest {
}
private static class NestedChild {
- @McpValidation(required = true, pattern = "^\\d{8}$")
private String businessDate;
}
}
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java
index 09cbe51d..46f72a3c 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java
@@ -22,8 +22,8 @@ class ToolScaffolderTest {
assertTrue(useCase.contains("name = \"oth.cmm.claim.search\""));
assertTrue(useCase.contains("version = \"1.0.0\""));
assertTrue(useCase.contains("timeoutMillis = 300000L"));
- assertTrue(response.contains("@McpOutputSchema"));
- assertTrue(response.contains("@McpValidation"));
+ assertTrue(response.contains(""));
+ assertTrue(response.contains(""));
}
@Test
void usesWasModuleNameAsToolPodPrefix() throws Exception {
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java
index b6d02d1b..166c7fad 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java
@@ -4,33 +4,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpOutputSchema;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.springframework.ai.mcp.annotation.McpTool;
class ToolSchemaResolverTest {
private final ToolSchemaResolver resolver = new ToolSchemaResolver(new ObjectMapper());
- @Test
- void usesInlineSchemaBeforeAutomaticDtoSchema() throws Exception {
- Method method = InlineSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class);
-
- Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutomaticRequest.class);
-
- assertEquals(false, schema.get("additionalProperties"));
- assertTrue(!properties(schema).containsKey("differentField"));
- }
-
@Test
void generatesSchemaFromRequestDtoWhenNoExplicitSchemaIsConfigured() throws Exception {
Method method = AutomaticSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class);
- Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutomaticRequest.class);
+ Map schema = resolver.resolve(method.getAnnotation(McpTool.class), null, AutomaticRequest.class);
assertTrue(properties(schema).containsKey("differentField"));
}
@@ -38,7 +26,7 @@ class ToolSchemaResolverTest {
@Test
void resolvesExplicitOutputSchema() throws Exception {
Method method = OutputSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class);
- Map schema = resolver.resolveOutput(method.getAnnotation(McpFunction.class));
+ Map schema = resolver.resolveOutput(method.getAnnotation(McpTool.class));
assertEquals(false, schema.get("additionalProperties"));
assertTrue(properties(schema).containsKey("resultCode"));
}
@@ -48,7 +36,7 @@ class ToolSchemaResolverTest {
Method method = AutomaticOutputSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class);
Map schema = resolver.resolveOutput(
- method.getAnnotation(McpFunction.class), SimpleResponse.class);
+ method.getAnnotation(McpTool.class), SimpleResponse.class);
assertEquals(List.of("resultCode"), schema.get("required"));
assertEquals(List.of("SUCCESS", "FAILURE"), property(schema, "resultCode").get("enum"));
@@ -58,7 +46,7 @@ class ToolSchemaResolverTest {
void doesNotEnableOutputValidationWhenOutputSchemaIsNotDeclared() throws Exception {
Method method = AutomaticSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class);
Map schema = resolver.resolveOutput(
- method.getAnnotation(McpFunction.class), AutomaticRequest.class);
+ method.getAnnotation(McpTool.class), AutomaticRequest.class);
assertTrue(schema.isEmpty());
}
@SuppressWarnings("unchecked")
@@ -71,44 +59,27 @@ class ToolSchemaResolverTest {
return (Map) properties(schema).get(name);
}
- static class InlineSchemaTool {
- @McpFunction(
- displayName = "inline",
- name = "test.schema.inline",
- description = "inline schema",
- inputSchema = "{\"type\":\"object\",\"properties\":{\"keyword\":{\"type\":\"string\"}},\"additionalProperties\":false}")
- void search(AutomaticRequest request) {
- }
- }
-
static class AutomaticSchemaTool {
- @McpFunction(displayName = "automatic", name = "test.schema.automatic", description = "automatic schema")
+ @McpTool(name = "oth.test.automatic.search")
void search(AutomaticRequest request) {
}
}
static class AutomaticOutputSchemaTool {
- @McpFunction(displayName = "automatic-output", name = "test.schema.automatic-output", description = "automatic output")
+ @McpTool(name = "oth.test.output.search")
SimpleResponse search(AutomaticRequest request) {
return null;
}
}
- @McpOutputSchema
static class SimpleResponse {
- @McpValidation(required = true, allowedValues = {"SUCCESS", "FAILURE"})
private String resultCode;
- @McpValidation(maxLength = 200)
private String message;
}
static class OutputSchemaTool {
- @McpFunction(
- displayName = "output",
- name = "test.schema.output",
- description = "output schema",
- outputSchema = "{\"type\":\"object\",\"properties\":{\"resultCode\":{\"type\":\"string\"}},\"required\":[\"resultCode\"],\"additionalProperties\":false}")
+ @McpTool(name = "oth.test.explicit.search")
void search(AutomaticRequest request) {
}
}
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSourceUpdaterTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSourceUpdaterTest.java
new file mode 100644
index 00000000..b9c15443
--- /dev/null
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolSourceUpdaterTest.java
@@ -0,0 +1,37 @@
+package io.shinhanlife.dap.lib.util;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class ToolSourceUpdaterTest {
+
+ @TempDir
+ Path temporaryRoot;
+
+ @Test
+ void updatesSdkAndProjectOwnedMetadataOnTheSameToolMethod() throws Exception {
+ Path source = temporaryRoot.resolve("dap-was-oth/src/main/java/example/SampleUseCase.java");
+ Files.createDirectories(source.getParent());
+ Files.writeString(source, """
+ package example;
+ import org.springframework.ai.mcp.annotation.McpTool;
+ import io.shinhanlife.dap.lib.annotation.ToolHint;
+ interface SampleUseCase {
+ @McpTool(name = "oth.cmm.sample.search", description = "old")
+ @ToolHint(register = false, requiresApproval = false)
+ void search();
+ }
+ """);
+
+ ToolSourceUpdater.updateToolSource(temporaryRoot, "oth.cmm.sample.search", "customer", "new", true, true);
+
+ String updated = Files.readString(source);
+ assertTrue(updated.contains("@McpTool(name = \"oth.cmm.sample.search\", description = \"new\")"));
+ assertTrue(updated.contains("@ToolHint(register = true, requiresApproval = true"));
+ assertTrue(updated.contains("categoryKey = \"customer\""), updated);
+ }
+}
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/validation/McpToolNameValidatorTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/validation/McpToolNameValidatorTest.java
index 626817ef..93e37aee 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/validation/McpToolNameValidatorTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/validation/McpToolNameValidatorTest.java
@@ -30,7 +30,7 @@ class McpToolNameValidatorTest {
Path temporaryRoot;
@Test
- void rejectsDuplicateMcpFunctionNamesAcrossToolModules() throws IOException {
+ void rejectsDuplicateMcpToolNamesAcrossToolModules() throws IOException {
writeToolSource("dap-was-first", "FirstTool.java", "first", "oth.sms.notification.send");
writeToolSource("dap-was-second", "SecondTool.java", "second", "oth.sms.notification.send");
@@ -43,7 +43,7 @@ class McpToolNameValidatorTest {
}
@Test
- void validationRunnerRejectsDuplicateMcpFunctionNamesBeforePackaging() throws IOException {
+ void validationRunnerRejectsDuplicateMcpToolNamesBeforePackaging() throws IOException {
writeToolSource("dap-was-first", "FirstTool.java", "first", "oth.sms.notification.send");
writeToolSource("dap-was-second", "SecondTool.java", "second", "oth.sms.notification.send");
@@ -90,11 +90,13 @@ class McpToolNameValidatorTest {
Files.writeString(source, """
package example;
+ import org.springframework.ai.mcp.annotation.McpTool;
+
class %s {
- @McpFunction(displayName = "%s", name = "%s", description = "test")
+ @McpTool(name = "%s")
void execute() { }
}
- """.formatted(className, className, toolName));
+ """.formatted(className, toolName));
}
private Path findProjectRoot() {
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/manifest/ToolManifestServiceTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/manifest/ToolManifestServiceTest.java
index 6efc38ec..8d09ca36 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/manifest/ToolManifestServiceTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/manifest/ToolManifestServiceTest.java
@@ -1,4 +1,4 @@
-package io.shinhanlife.dap.lib.manifest;
+package io.shinhanlife.dap.mcc.manifest;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -6,6 +6,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.shinhanlife.dap.lib.config.McpProperties;
+import io.shinhanlife.dap.lib.manifest.ToolManifestItem;
+import io.shinhanlife.dap.lib.manifest.ToolManifestResponse;
+import io.shinhanlife.dap.lib.manifest.ToolManifestService;
import io.shinhanlife.dap.mcc.dto.ToolMetadata;
import java.util.List;
import java.util.Map;
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/McpRequestHeaderFilterTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/McpRequestHeaderFilterTest.java
index 59bc1597..059174e5 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/McpRequestHeaderFilterTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/McpRequestHeaderFilterTest.java
@@ -1,4 +1,4 @@
-package io.shinhanlife.dap.lib.mcp;
+package io.shinhanlife.dap.mcc.mcp;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -10,8 +10,9 @@ import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.server.McpSyncServer;
+import io.shinhanlife.dap.lib.mcp.*;
import io.shinhanlife.dap.mcc.presentation.BusinessToolController;
-import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender;
+
import java.lang.reflect.Method;
import java.util.Map;
import org.junit.jupiter.api.Test;
diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/ToolMcpServerConfigurationTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/ToolMcpServerConfigurationTest.java
index b12a9375..82fe9796 100644
--- a/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/ToolMcpServerConfigurationTest.java
+++ b/dap-was-lib/src/test/java/io/shinhanlife/dap/mcc/mcp/ToolMcpServerConfigurationTest.java
@@ -1,9 +1,11 @@
-package io.shinhanlife.dap.lib.mcp;
+package io.shinhanlife.dap.mcc.mcp;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.assertj.core.api.Assertions.assertThat;
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
+import io.shinhanlife.dap.lib.mcp.ToolMcpServerConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
@@ -16,7 +18,6 @@ class ToolMcpServerConfigurationTest {
HttpServletStreamableServerTransportProvider transport = configuration.toolMcpTransportProvider();
ServletRegistrationBean registration = configuration.toolMcpServlet(transport);
- assertEquals("/mcp", registration.getUrlMappings().iterator().next());
- assertFalse(registration.getUrlMappings().contains("/mcp/*"));
+ assertThat(registration.getUrlMappings()).containsExactlyInAnyOrder("/mcp", "/mcp/message");
}
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BalanceRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BalanceRequest.java
index 483198cd..aff6ae40 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BalanceRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BalanceRequest.java
@@ -1,6 +1,11 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
/**
* @package io.shinhanlife.dap.mcc.dto
* @className BalanceRequest
@@ -15,13 +20,12 @@ package io.shinhanlife.dap.mcc.biz.cmm.dto;
*
*
*/
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
+
@Data
public class BalanceRequest {
- @McpParameter(description = "고객의 계좌번호 (- 제외) ", required = true)
- @McpValidation(pattern = "\\S", examples = {"1234567890"})
+ @McpToolParam(description = "고객의 계좌번호 (- 제외) ", required = true)
+ @Schema(pattern = "\\S", example = "1234567890")
private String accountNumber;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingProcessRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingProcessRequest.java
index 2839b58b..3d72b062 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingProcessRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingProcessRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Getter;
import lombok.Setter;
@@ -30,11 +33,12 @@ import lombok.Setter;
@AllArgsConstructor
public class BillingProcessRequest {
- @McpParameter(description = "처리할 청구 접수 번호", required = true)
- @McpValidation(pattern = "\\S", examples = {"BILL20260805"})
+ @McpToolParam(description = "처리할 청구 접수 번호", required = true)
+ @Schema(pattern = "\\S", example = "BILL20260805")
private String billingId;
- @McpParameter(description = "심사 승인 여부 (예: APPROVE, REJECT)")
- @McpValidation(required = true, allowedValues = {"APPROVE", "REJECT"}, examples = {"APPROVED"})
+
+ @McpToolParam(description = "승인 처리 구분 (예: APPROVE, REJECT)")
+ @Schema(required = true, allowableValues = {"APPROVE", "REJECT"}, example = "APPROVE")
private String approvalStatus;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingStatusRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingStatusRequest.java
index 18f10f91..c2cff692 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingStatusRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BillingStatusRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,7 +33,8 @@ import lombok.Setter;
@AllArgsConstructor
public class BillingStatusRequest {
- @McpParameter(description = "조회할 청구 접수 번호", required = true)
- @McpValidation(examples = {"BILL20260805"})
+ @McpToolParam(description = "조회할 청구 접수 번호", required = true)
+ @Schema(example = "BILL20260805")
private String billingId;
+
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondCheckRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondCheckRequest.java
index 49b560aa..28560ecb 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondCheckRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondCheckRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,7 +33,8 @@ import lombok.Setter;
@AllArgsConstructor
public class BondCheckRequest {
- @McpParameter(description = "확인하고자 하는 디지털 증권 발행 금액", required = true)
- @McpValidation(examples = {"1000000"})
- private Long amount;
+ @McpToolParam(description = "확인하고자 하는 디지털 증권 발행 금액", required = true)
+ @Schema(pattern = "^[0-9]+$", example = "1000000")
+ private String amount;
+
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondIssueRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondIssueRequest.java
index 9b5e73e4..69dea77a 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondIssueRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/BondIssueRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Getter;
import lombok.Setter;
@@ -30,11 +33,12 @@ import lombok.Setter;
@AllArgsConstructor
public class BondIssueRequest {
- @McpParameter(description = "발행할 디지털 증권 금액", required = true)
- @McpValidation(minimum = 1, examples = {"1000000"})
- private Long amount;
+ @McpToolParam(description = "발행할 증권 금액 (숫자 문자열)", required = true)
+ @Schema(pattern = "^[0-9]+$", example = "1000000")
+ private String amount;
- @McpParameter(description = "발행 대상 계좌 번호", required = true)
- @McpValidation(pattern = "\\S", examples = {"1234567890"})
+
+ @McpToolParam(description = "발행 대상 계좌 번호", required = true)
+ @Schema(pattern = "\\S", example = "1234567890")
private String targetAccount;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequest.java
index eb731e80..093c73e7 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequest.java
@@ -1,8 +1,10 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpAnyOf;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -18,40 +20,39 @@ import lombok.Setter;
@Builder
@NoArgsConstructor
@AllArgsConstructor
-@McpAnyOf({"claimNo", "contractNo"})
public class ClaimSearchRequest {
- @McpParameter(description = "청구번호. CLM 다음 숫자 13자리 형식이다.")
- @McpValidation(pattern = "^CLM[0-9]{13}$", examples = {"CLM2026070100123"})
+ @McpToolParam(description = "청구번호. CLM 다음 숫자 13자리 형식이다.")
+ @Schema(pattern = "^CLM[0-9]{13}$", example = "CLM2026070100123")
private String claimNo;
- @McpParameter(description = "계약번호. 숫자 11자리 형식이다.")
- @McpValidation(pattern = "^[0-9]{11}$", examples = {"10023456789"})
+ @McpToolParam(description = "계약번호. 숫자 11자리 형식이다.")
+ @Schema(pattern = "^[0-9]{11}$", example = "10023456789")
private String contractNo;
- @McpParameter(description = "청구 상태 필터")
- @McpValidation(examples = {"RECEIVED"}, allowedValues = {
+ @McpToolParam(description = "청구 상태 필터")
+ @Schema(example = "RECEIVED", allowableValues = {
"RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED",
"APPROVED", "PAID", "REJECTED", "WITHDRAWN"
})
private String status;
- @McpParameter(description = "청구 유형 필터")
- @McpValidation(examples = {"MEDICAL"}, allowedValues = {
+ @McpToolParam(description = "청구 유형 필터")
+ @Schema(example = "MEDICAL", allowableValues = {
"MEDICAL", "SURGERY", "HOSPITALIZATION",
"DIAGNOSIS", "DEATH", "DISABILITY"
})
private String claimType;
- @McpParameter(description = "접수일 조회 시작일(YYYY-MM-DD)")
- @McpValidation(format = "date", examples = {"2026-01-01"})
+ @McpToolParam(description = "접수일 조회 시작일(YYYY-MM-DD)")
+ @Schema(format = "date", example = "2026-01-01")
private String fromDate;
- @McpParameter(description = "접수일 조회 종료일(YYYY-MM-DD)")
- @McpValidation(format = "date", examples = {"2026-07-31"})
+ @McpToolParam(description = "접수일 조회 종료일(YYYY-MM-DD)")
+ @Schema(format = "date", example = "2026-07-31")
private String toDate;
- @McpParameter(description = "반환할 최대 건수")
- @McpValidation(minimum = 1, maximum = 50, defaultValue = "20", examples = {"20"})
- private Integer size;
+ @McpToolParam(description = "반환할 최대 건수 (기본값: 20, 최대: 50)")
+ @Schema(pattern = "^[1-9][0-9]?$|^50$", defaultValue = "20", example = "20")
+ private String size;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java
index abd2d2d8..cd5ed033 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java
@@ -1,8 +1,10 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpOutputSchema;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -20,46 +22,45 @@ import lombok.Setter;
@Builder
@NoArgsConstructor
@AllArgsConstructor
-@McpOutputSchema
public class ClaimSearchResponse {
- @McpParameter(description = "Execution result code.")
- @McpValidation(required = true, allowedValues = {"SUCCESS", "FAILURE"})
+ @McpToolParam(description = "Execution result code.")
+ @Schema(required = true, allowableValues = {"SUCCESS", "FAILURE"})
private String resultCode;
- @McpParameter(description = "User-readable label for resultCode.")
- @McpValidation(required = true, maxLength = 100)
+ @McpToolParam(description = "User-readable label for resultCode.")
+ @Schema(required = true, maxLength = 100)
private String resultLabel;
- @McpParameter(description = "Current claim processing status code.")
- @McpValidation(required = true, allowedValues = {
+ @McpToolParam(description = "Current claim processing status code.")
+ @Schema(required = true, allowableValues = {
"RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED",
"APPROVED", "PAID", "REJECTED", "WITHDRAWN"
})
private String status;
- @McpParameter(description = "User-readable label for status.")
- @McpValidation(required = true, maxLength = 100)
+ @McpToolParam(description = "User-readable label for status.")
+ @Schema(required = true, maxLength = 100)
private String statusLabel;
- @McpParameter(description = "Approved amount. Null before review; do not interpret null as zero.")
- @McpValidation(minimum = 0, nullable = true)
+ @McpToolParam(description = "Approved amount. Null before review; do not interpret null as zero.")
+ @Schema(minimum = "0", nullable = true)
private Long approvedAmount;
- @McpParameter(description = "Present only when status is REJECTED; otherwise null.")
- @McpValidation(maxLength = 200, nullable = true)
+ @McpToolParam(description = "Present only when status is REJECTED; otherwise null.")
+ @Schema(maxLength = 200, nullable = true)
private String rejectionReason;
- @McpParameter(description = "Claim summaries, ordered by received date descending.")
- @McpValidation(required = true)
+ @McpToolParam(description = "Claim summaries, ordered by received date descending.")
+ @Schema(required = true)
private List items;
- @McpParameter(description = "True when additional results exist beyond this response.")
- @McpValidation(required = true)
+ @McpToolParam(description = "True when additional results exist beyond this response.")
+ @Schema(required = true)
private Boolean hasMore;
- @McpParameter(description = "Total number of matched claims.")
- @McpValidation(required = true, minimum = 0)
+ @McpToolParam(description = "Total number of matched claims.")
+ @Schema(required = true, nullable = true)
private Integer totalCount;
@Getter
@@ -69,20 +70,18 @@ public class ClaimSearchResponse {
@AllArgsConstructor
public static class ClaimSummary {
- @McpParameter(description = "Claim processing status code.")
- @McpValidation(required = true)
+ @McpToolParam(description = "Claim processing status code.")
private String status;
- @McpParameter(description = "User-readable label for status.")
- @McpValidation(required = true)
+ @McpToolParam(description = "User-readable label for status.")
private String statusLabel;
- @McpParameter(description = "Received date in YYYY-MM-DD format.")
- @McpValidation(required = true, format = "date")
+ @McpToolParam(description = "Received date in YYYY-MM-DD format.")
+ @Schema(required = true, format = "date")
private String receivedDate;
- @McpParameter(description = "Approved amount. Null before review; do not interpret null as zero.")
- @McpValidation(minimum = 0, nullable = true)
+ @McpToolParam(description = "Approved amount. Null before review; do not interpret null as zero.")
+ @Schema(nullable = true)
private Long approvedAmount;
}
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractDetailRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractDetailRequest.java
index 815493ae..3fe86720 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractDetailRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractDetailRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,11 +33,12 @@ import lombok.Setter;
@AllArgsConstructor
public class ContractDetailRequest {
- @McpParameter(description = "고객명", required = true)
- @McpValidation(examples = {"홍길동"})
+ @McpToolParam(description = "고객명", required = true)
+ @Schema(example = "홍길동")
private String customerName;
- @McpParameter(description = "조회할 계약 번호", required = true)
- @McpValidation(examples = {"1234567890"})
+
+@McpToolParam(description = "조회할 계약 번호", required = true)
+ @Schema(example = "1234567890")
private String contractId;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractStatusRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractStatusRequest.java
index 3926b2ca..01281c42 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractStatusRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ContractStatusRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,10 +33,11 @@ import lombok.Setter;
@AllArgsConstructor
public class ContractStatusRequest {
- @McpParameter(description = "고객명", required = true)
- @McpValidation(examples = {"홍길동"})
+ @McpToolParam(description = "고객명", required = true)
+ @Schema(example = "홍길동")
private String customerName;
- @McpParameter(description = "조회할 계약 번호")
+
+@McpToolParam(description = "조회할 계약 번호")
private String contractId;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerDetailRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerDetailRequest.java
index 3abaa6f9..92c690d3 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerDetailRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerDetailRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,10 +33,11 @@ import lombok.Setter;
@AllArgsConstructor
public class CustomerDetailRequest {
- @McpParameter(description = "고객명", required = true)
- @McpValidation(examples = {"홍길동"})
+ @McpToolParam(description = "고객명", required = true)
+ @Schema(example = "홍길동")
private String customerName;
- @McpParameter(description = "고객 식별 번호 (CID)")
+
+@McpToolParam(description = "고객 식별 번호 (CID)")
private String customerId;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerGradeRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerGradeRequest.java
index f2071c45..8ba28a81 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerGradeRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/CustomerGradeRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,10 +33,11 @@ import lombok.Setter;
@AllArgsConstructor
public class CustomerGradeRequest {
- @McpParameter(description = "고객 이름 (예: 김신한)", required = true)
- @McpValidation(examples = {"홍길동"})
+ @McpToolParam(description = "고객 이름 (예: 김신한)", required = true)
+ @Schema(example = "홍길동")
private String customerName;
- @McpParameter(description = "고객 식별 번호 (CID)")
+
+@McpToolParam(description = "고객 식별 번호 (CID)")
private String customerId;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/LeaveCountRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/LeaveCountRequest.java
index 9c2a1c83..c6af49c0 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/LeaveCountRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/LeaveCountRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
import lombok.Getter;
import lombok.Setter;
@@ -30,7 +33,8 @@ import lombok.Setter;
@AllArgsConstructor
public class LeaveCountRequest {
- @McpParameter(description = "연차 내역을 조회할 사원 번호", required = true)
- @McpValidation(examples = {"EMP12345"})
+ @McpToolParam(description = "연차 내역을 조회할 사원 번호", required = true)
+ @Schema(example = "EMP12345")
private String employeeId;
+
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaCommonCodeRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaCommonCodeRequest.java
index f01b5335..5466af2c 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaCommonCodeRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaCommonCodeRequest.java
@@ -1,8 +1,11 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -22,14 +25,15 @@ import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MetaCommonCodeRequest {
- @McpParameter(description = "통합코드 그룹 ID (예: GRP_SYS_01, GRP_COMM_CD)", required = false)
- @McpValidation(examples = {"GRP_001"})
+ @McpToolParam(description = "통합코드 그룹 ID (예: GRP_SYS_01, GRP_COMM_CD)", required = false)
+ @Schema(example = "GRP_001")
private String groupCode;
- @McpParameter(description = "코드명 검색 키워드 (예: 사용, 상태)", required = false)
+
+@McpToolParam(description = "코드명 검색 키워드 (예: 사용, 상태)", required = false)
private String codeName;
- @McpParameter(description = "사용여부 (예: Y, N)", required = false)
- @McpValidation(examples = {"Y"})
+ @McpToolParam(description = "사용여부 (예: Y, N)", required = false)
+ @Schema(example = "Y")
private String useYn;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaTableRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaTableRequest.java
index a4108504..304dc6cd 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaTableRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/MetaTableRequest.java
@@ -1,8 +1,11 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -22,15 +25,16 @@ import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MetaTableRequest {
- @McpParameter(description = "테이블 물리명 키워드 (예: TB_CUST_BAS, TB_CONT)", required = false)
- @McpValidation(examples = {"TB_USER"})
+ @McpToolParam(description = "테이블 물리명 키워드 (예: TB_CUST_BAS, TB_CONT)", required = false)
+ @Schema(example = "TB_USER")
private String tableName;
- @McpParameter(description = "테이블 논리명(한글) 키워드 (예: 고객기본, 계약)", required = false)
- @McpValidation(examples = {"고객기본"})
+
+@McpToolParam(description = "테이블 논리명(한글) 키워드 (예: 고객기본, 계약)", required = false)
+ @Schema(example = "고객기본")
private String tableLogicalName;
- @McpParameter(description = "스키마/소유자명 (예: DAPADM, SHLOWN)", required = false)
- @McpValidation(examples = {"DAPADM"})
+ @McpToolParam(description = "스키마/소유자명 (예: DAPADM, SHLOWN)", required = false)
+ @Schema(example = "DAPADM")
private String owner;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/SampleStringRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/SampleStringRequest.java
index c2489154..8553125e 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/SampleStringRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/SampleStringRequest.java
@@ -1,7 +1,8 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -21,6 +22,6 @@ import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SampleStringRequest {
- @McpValidation(examples = {"test query"})
+ @Schema(example = "test query")
private String query;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/TemplateDownloadRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/TemplateDownloadRequest.java
index 4ef4b71b..96340c54 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/TemplateDownloadRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/TemplateDownloadRequest.java
@@ -1,6 +1,7 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
+
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -32,6 +33,6 @@ public class TemplateDownloadRequest {
/**
* 다운로드할 템플릿의 종류 ID (예: CUSTOMER_EXCEL, PRODUCT_PDF 등)
*/
- @McpValidation(examples = {"TPL_001"})
+ @Schema(example = "TPL_001")
private String templateId;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/VacationRegisterRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/VacationRegisterRequest.java
index 316d48ab..184d0dea 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/VacationRegisterRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/VacationRegisterRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Getter;
import lombok.Setter;
@@ -30,11 +33,12 @@ import lombok.Setter;
@AllArgsConstructor
public class VacationRegisterRequest {
- @McpParameter(description = "연차를 등록할 사원 번호", required = true)
- @McpValidation(pattern = "\\S", examples = {"EMP12345"})
+ @McpToolParam(description = "연차를 등록할 사원 번호", required = true)
+ @Schema(pattern = "\\S", example = "EMP12345")
private String employeeId;
- @McpParameter(description = "휴가 일자 (YYYY-MM-DD 형식)", required = true)
- @McpValidation(pattern = "^\\d{4}-\\d{2}-\\d{2}$", examples = {"2026-08-05"})
+
+@McpToolParam(description = "휴가 일자 (YYYY-MM-DD 형식)", required = true)
+ @Schema(pattern = "^\\d{4}-\\d{2}-\\d{2}$", example = "2026-08-05")
private String date;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BalanceUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BalanceUseCase.java
index 1966f9df..8935f29b 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BalanceUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BalanceUseCase.java
@@ -1,15 +1,12 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(routingType = "MCI", categoryKey = "cmm")
public interface BalanceUseCase {
- @McpFunction(register = false, displayName = "balance 툴", name = "oth.cmm.balance.inquiry",
- description = "고객의 계좌 잔액을 조회합니다.",
- prompt = "고객 계좌 잔액을 조회해줘.",
- mappingId = "ACC_001"
- )
+ @McpTool(name = "oth.cmm.balance.inquiry", title = "잔고 조회 툴", description = "고객의 계좌 잔액을 조회합니다.")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "ACC_001")
Object execute(BalanceRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BillingProcessUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BillingProcessUseCase.java
index 3071df0c..9d0fec93 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BillingProcessUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BillingProcessUseCase.java
@@ -1,16 +1,13 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(
- routingType = "MCI",
- categoryKey = "cmm"
-)
public interface BillingProcessUseCase {
Object getStatus(BillingStatusRequest req);
- @McpFunction(register = false, displayName = "process 툴", name = "oth.cmm.billing.process", description = "청구 처리", prompt = "현재 접수된 청구건에 대한 심사 처리를 진행해.", mappingId = "BILL_002")
+ @McpTool(name = "oth.cmm.billing.process", title = "청구 프로세스 툴", description = "청구 처리")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "BILL_002")
Object processBilling(BillingProcessRequest data);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BondIssueUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BondIssueUseCase.java
index 1290b73f..7c92a949 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BondIssueUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/BondIssueUseCase.java
@@ -1,16 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(
- routingType = "EAI",
- categoryKey = "cmm"
-)
public interface BondIssueUseCase {
Object check(BondCheckRequest req);
- @McpFunction(displayName = "issue 툴", name = "oth.cmm.bond.issue", register = false, description = "증권 발행 테스트1", prompt = "디지털 증권 발행 프로세스를 실행해.", mappingId = "BOND_002")
+ @McpTool(name = "oth.cmm.bond.issue", title = "채권 발행 툴", description = "증권 발행 테스트1")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "BOND_002")
Object issue(BondIssueRequest data);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java
index 8e0dea3f..c55be3a0 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java
@@ -1,26 +1,16 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchRequest;
import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse;
-@McpTool(
- routingType = "DIRECT",
- categoryKey = "cmm"
-)
public interface ClaimSearchSchemaSampleUseCase {
- @McpFunction(
- register = false,
- displayName = "Claim search JSON Schema sample",
- name = "oth.cmm.claim.search",
- description = "Claim search Tool sample using input and output JSON Schema resources.",
- prompt = "Search an insurance claim by claim number or contract number.",
- inputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-input-schema.json",
- outputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-output-schema.json",
- readOnlyHint = true,
- idempotentHint = true
- )
+ @McpTool(name = "oth.cmm.claim.search", title = "청구 조회 스키마 샘플", description = "Claim search Tool sample using input and output JSON Schema resources.", annotations = @McpTool.McpAnnotations(readOnlyHint = true, idempotentHint = true))
+ @ToolHint(register = false, categoryKey = "cmm",
+ inputSchemaResource = "classpath:mcp/schema/claim-search-resource-input-schema.json",
+ outputSchemaResource = "classpath:mcp/schema/claim-search-resource-output-schema.json")
ClaimSearchResponse search(ClaimSearchRequest request);
-}
\ No newline at end of file
+}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CommonUtilityUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CommonUtilityUseCase.java
index 200534b5..b7d2d2eb 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CommonUtilityUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CommonUtilityUseCase.java
@@ -1,19 +1,18 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(
- routingType = "HTTP",
- categoryKey = "cmm"
-)
public interface CommonUtilityUseCase {
Object registerVacation(VacationRegisterRequest req);
- @McpFunction(register = false, displayName = "get_leave_count 툴", name = "oth.cmm.leave.count", description = "연차 갯수 조회", prompt = "현재 사용 가능한 남은 연차 일수를 알려줘.", mappingId = "HR_VAC_02")
+ @McpTool(name = "oth.cmm.leave.count", title = "공통 유틸리티 툴", description = "연차 갯수 조회")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "HR_VAC_02")
Object getLeaveCount(LeaveCountRequest data);
- @McpFunction(register = false, displayName = "secret_tool 툴", name = "oth.cmm.secret.execute", description = "비공개 툴 테스트", prompt = "숨겨진 툴 강제 호출", mappingId = "SECRET_001", visible = false)
+ @McpTool(name = "oth.cmm.secret.execute", title = "공통 유틸리티 툴", description = "비공개 툴 테스트")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "SECRET_001")
Object secretTool(LeaveCountRequest data);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ContractInquiryUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ContractInquiryUseCase.java
index 87dfcdd3..f3eee3e5 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ContractInquiryUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ContractInquiryUseCase.java
@@ -1,16 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(
- routingType = "HTTP",
- categoryKey = "cmm"
-)
public interface ContractInquiryUseCase {
Object getStatus(ContractStatusRequest req);
- @McpFunction(register = false, displayName = "contract_detail 툴", name = "oth.cmm.contract.detail", description = "계약상세 조회", prompt = "김신한 고객의 계약 상세 내역을 알려줘.", mappingId = "CNTR_002")
+ @McpTool(name = "oth.cmm.contract.detail", title = "계약 상세조회 툴", description = "계약상세 조회")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "CNTR_002")
Object getDetail(ContractDetailRequest data);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CustomerInfoUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CustomerInfoUseCase.java
index faf82c0a..1847f93c 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CustomerInfoUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/CustomerInfoUseCase.java
@@ -1,16 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
-@McpTool(
- routingType = "TCP",
- categoryKey = "cmm"
-)
public interface CustomerInfoUseCase {
Object getGrade(CustomerGradeRequest req);
- @McpFunction(register = false, displayName = "detail 툴", name = "oth.cmm.customer.detail", description = "고객상세 정보 조회", prompt = "이 고객의 상세 기본정보(주소, 연락처 등)를 알려줘.", mappingId = "CRM_002")
+ @McpTool(name = "oth.cmm.customer.detail", title = "고객 상세조회 툴", description = "고객상세 정보 조회")
+ @ToolHint(register = false, categoryKey = "cmm", mappingId = "CRM_002")
Object getDetail(CustomerDetailRequest data);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaCommonCodeUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaCommonCodeUseCase.java
index dd5d7ddc..8ff9ce8a 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaCommonCodeUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaCommonCodeUseCase.java
@@ -1,7 +1,8 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
/**
@@ -18,20 +19,8 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
*
*
*/
-@McpTool(
- routingType = "MCI",
- categoryKey = "cmm"
-)
public interface MetaCommonCodeUseCase {
- @McpFunction(
- displayName = "메타 통합코드 조회 툴",
- name = "oth.cmm.common-code.lookup",
- description = "메타 통합코드 목록을 조회해줘",
- prompt = "메타 통합코드 목록을 조회해줘",
- mappingId = "CLCNNB00001",
- register = false,
- requiresApproval = false,
- openWorldHint = true
- )
+ @McpTool(name = "oth.cmm.common-code.lookup", title = "메타 공통코드 조회 툴", description = "메타 통합코드 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
+ @ToolHint(register = false, requiresApproval = false, categoryKey = "cmm", mappingId = "CLCNNB00001")
Object execute(MetaCommonCodeRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaTableUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaTableUseCase.java
index 0d7616c9..7eec1a6e 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaTableUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/MetaTableUseCase.java
@@ -1,7 +1,8 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaTableRequest;
/**
@@ -18,20 +19,8 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaTableRequest;
*
*
*/
-@McpTool(
- routingType = "MCI",
- categoryKey = "cmm"
-)
public interface MetaTableUseCase {
- @McpFunction(
- displayName = "메타 테이블 조회 툴",
- name = "oth.cmm.meta.table",
- description = "메타 테이블 정보 목록을 조회해줘",
- prompt = "메타 테이블 정보 목록을 조회해줘",
- mappingId = "CLCNNB00001",
- register = false,
- requiresApproval = false,
- openWorldHint = true
- )
+ @McpTool(name = "oth.cmm.meta.table", title = "메타 테이블 조회 툴", description = "메타 테이블 정보 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
+ @ToolHint(register = false, requiresApproval = false, categoryKey = "cmm", mappingId = "CLCNNB00001")
Object execute(MetaTableRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/TemplateUtilityUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/TemplateUtilityUseCase.java
index 1612921c..63015f61 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/TemplateUtilityUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/TemplateUtilityUseCase.java
@@ -1,21 +1,14 @@
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
import java.util.Map;
-@McpTool(
- routingType = "HTTP",
- categoryKey = "cmm"
-)
public interface TemplateUtilityUseCase {
- @McpFunction(
- displayName = "템플릿 유틸리티",
- name = "oth.cmm.template.url",
- description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
- prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:"
- )
+ @McpTool(name = "oth.cmm.template.url", title = "템플릿 유틸리티 툴", description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.")
+ @ToolHint(categoryKey = "cmm")
Map getTemplateFileUrl(TemplateDownloadRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/Onnba3011UseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/Onnba3011UseCase.java
index b214d073..bd75039b 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/Onnba3011UseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/Onnba3011UseCase.java
@@ -1,10 +1,11 @@
package io.shinhanlife.dap.mcc.biz.oth.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.oth.dto.*;
-@McpTool(routingType = "MCI", categoryKey = "oth")
public interface Onnba3011UseCase {
- Object callOnnba3011(Onnba3011Request req);
+ @McpTool(name = "oth.onnba3011.call", description = "Onnba3011 호출 툴")
+ @ToolHint(categoryKey = "oth")
+ Object execute(Onnba3011Request req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/impl/Onnba3011UseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/impl/Onnba3011UseCaseImpl.java
index c96edf38..bf8e2138 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/impl/Onnba3011UseCaseImpl.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/oth/usecase/impl/Onnba3011UseCaseImpl.java
@@ -35,11 +35,9 @@ public class Onnba3011UseCaseImpl implements Onnba3011UseCase {
private final Onnba3011Converter onnba3011Converter;
/**
* AI Agent가 호출하게 될 메서드입니다.
- * @McpFunction 어노테이션 하나로 AI 도구로 자동 노출 및 라우팅됩니다.
*/
-
@Override
- public Object callOnnba3011(Onnba3011Request req) {
+ public Object execute(Onnba3011Request req) {
log.info("[MCI Tool] 보종By가입설계한도계산조회 요청 수신.");
try {
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/DailyQuoteRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/DailyQuoteRequest.java
index 94f98f50..36e5e2a6 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/DailyQuoteRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/DailyQuoteRequest.java
@@ -1,16 +1,19 @@
package io.shinhanlife.dap.mcc.biz.smp.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DailyQuoteRequest {
- @McpParameter(description = "카테고리 (예: 속담 등)", required = false)
- @McpValidation(examples = {"속담"})
+ @McpToolParam(description = "카테고리 (예: 속담 등)", required = false)
+ @Schema(example = "속담")
private String category;
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/ExchangeRateRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/ExchangeRateRequest.java
index 3a2abf34..366c175d 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/ExchangeRateRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/ExchangeRateRequest.java
@@ -1,15 +1,18 @@
package io.shinhanlife.dap.mcc.biz.smp.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ExchangeRateRequest {
- @McpParameter(description = "환율 코드 (예: USD 등)", required = false)
- @McpValidation(examples = {"USD"})
+ @McpToolParam(description = "환율 코드 (예: USD 등)", required = false)
+ @Schema(example = "USD")
private String currencyCode;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/TeamMemberRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/TeamMemberRequest.java
index e6d249ba..ea2314bd 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/TeamMemberRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/TeamMemberRequest.java
@@ -1,8 +1,11 @@
package io.shinhanlife.dap.mcc.biz.smp.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -22,7 +25,8 @@ import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TeamMemberRequest {
- @McpParameter(description = "조회할 팀 이름 (예: AX, MCP, TOOL, 전체 등)", required = false)
- @McpValidation(examples = {"TOOL"})
+ @McpToolParam(description = "조회할 팀 이름 (예: AX, MCP, TOOL, 전체 등)", required = false)
+ @Schema(example = "TOOL")
private String teamName;
+
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/WeatherRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/WeatherRequest.java
index d2978a30..9ea49678 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/WeatherRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/dto/WeatherRequest.java
@@ -1,9 +1,10 @@
package io.shinhanlife.dap.mcc.biz.smp.dto;
+
+
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
/**
* @package io.shinhanlife.dap.mcc.dto
@@ -20,8 +21,7 @@ import io.shinhanlife.dap.lib.annotation.McpValidation;
*
*/
public record WeatherRequest(
- @McpParameter(description = "도시를 입력하세여(예: 서울)", required = true)
- @McpValidation(examples = {"서울"})
+ @McpToolParam(description = "도시를 입력하세여(예: 서울)", required = true)
String city
) {
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/DailyQuoteToolUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/DailyQuoteToolUseCase.java
index 7c7a88e0..9905e565 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/DailyQuoteToolUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/DailyQuoteToolUseCase.java
@@ -1,19 +1,13 @@
package io.shinhanlife.dap.mcc.biz.smp.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.smp.dto.DailyQuoteRequest;
import io.shinhanlife.dap.mcc.biz.smp.dto.DailyQuoteResponse;
-@McpTool(
- routingType = "DIRECT",
- categoryKey = "smp"
-)
public interface DailyQuoteToolUseCase {
- @McpFunction(register = false, displayName = "랜덤 명언 툴", name = "oth.smp.quote.daily",
- description = "무작위로 영감을 주는 명언을 하나 가져옵니다.",
- prompt = "오늘의 명언 하나 알려줘, 동기부여 명언 등",
- mappingId = "QUOTE_001"
- )
+ @McpTool(name = "oth.smp.quote.daily", title = "오늘의 명언 툴", description = "무작위로 영감을 주는 명언을 하나 가져옵니다.")
+ @ToolHint(register = false, categoryKey = "smp", mappingId = "QUOTE_001")
DailyQuoteResponse execute(DailyQuoteRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/ExchangeRateToolUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/ExchangeRateToolUseCase.java
index 2515d611..ba628bd5 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/ExchangeRateToolUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/ExchangeRateToolUseCase.java
@@ -1,21 +1,15 @@
package io.shinhanlife.dap.mcc.biz.smp.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.smp.dto.ExchangeRateRequest;
import io.shinhanlife.dap.mcc.biz.smp.dto.ExchangeRateResponse;
import io.shinhanlife.dap.mcc.biz.smp.dto.ExchangeRateRequest;
import io.shinhanlife.dap.mcc.biz.smp.dto.ExchangeRateResponse;
-@McpTool(
- routingType = "DIRECT",
- categoryKey = "smp"
-)
public interface ExchangeRateToolUseCase {
- @McpFunction(register = false, displayName = "실시간 환율 조회 툴", name = "oth.smp.exchange-rate.inquiry",
- description = "원하는 통화의 실시간 환율을 조회합니다. (예: USD, EUR, JPY)",
- prompt = "현재 달러 환율 알려줘, 엔화 환율은?",
- mappingId = "EXCHANGE_001"
- )
+ @McpTool(name = "oth.smp.exchange-rate.inquiry", title = "실시간 환율 조회 툴", description = "원하는 통화의 실시간 환율을 조회합니다. (예: USD, EUR, JPY)")
+ @ToolHint(register = false, categoryKey = "smp", mappingId = "EXCHANGE_001")
ExchangeRateResponse execute(ExchangeRateRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/TeamMemberUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/TeamMemberUseCase.java
index 3296f125..5bc204bd 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/TeamMemberUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/TeamMemberUseCase.java
@@ -1,23 +1,12 @@
package io.shinhanlife.dap.mcc.biz.smp.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberRequest;
-@McpTool(
- routingType = "DIRECT",
- categoryKey = "smp"
-)
public interface TeamMemberUseCase {
- @McpFunction(
- displayName = "신한라이프 MCP, TOOL 파트 구성원 조회",
- name = "oth.smp.team.list",
- description = "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.",
- prompt = "신한라이프 MCP, TOOL 파트 구성원을 조회해 줘. (주의: 응답 시 ** 등 마크다운 기호를 절대 사용하지 말고 평문으로만 출력해 줘)",
- mappingId = "DIRECT0001",
- register = false,
- requiresApproval = false,
- openWorldHint = true
- )
+ @McpTool(name = "oth.smp.team.list", title = "신한라이프 MCP, TOOL 파트 구성원 조회", description = "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.", annotations = @McpTool.McpAnnotations(openWorldHint = true))
+ @ToolHint(register = false, requiresApproval = false, categoryKey = "smp", mappingId = "DIRECT0001")
Object execute(TeamMemberRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/WeatherToolUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/WeatherToolUseCase.java
index cd929b31..1252d6a4 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/WeatherToolUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/WeatherToolUseCase.java
@@ -1,18 +1,12 @@
package io.shinhanlife.dap.mcc.biz.smp.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.smp.dto.*;
-@McpTool(
- routingType = "DIRECT",
- categoryKey = "smp"
-)
public interface WeatherToolUseCase {
- @McpFunction(register = false, displayName = "날씨 조회 툴", name = "oth.smp.weather.inquiry",
- description = "특정 도시의 현재 날씨, 온도, 풍속 정보를 조회합니다.",
- prompt = "서울 날씨 알려줘, 부산 기온 알려줘 등 실시간 기상 조회",
- mappingId = "WEATHER_001"
- )
+ @McpTool(name = "oth.smp.weather.inquiry", title = "날씨 조회 툴", description = "특정 도시의 현재 날씨, 온도, 풍속 정보를 조회합니다.")
+ @ToolHint(register = false, categoryKey = "smp", mappingId = "WEATHER_001")
WeatherResponse execute(WeatherRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqDetailRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqDetailRequest.java
index af04360a..98d30aa0 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqDetailRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqDetailRequest.java
@@ -1,8 +1,11 @@
package io.shinhanlife.dap.mcc.biz.sol.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -23,7 +26,8 @@ import lombok.Data;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SolReqDetailRequest {
- @McpParameter(description = "상세 조회할 SOL 의뢰서 ID", required = true)
- @McpValidation(examples = {"SR20260805"})
+ @McpToolParam(description = "상세 조회할 SOL 의뢰서 ID", required = true)
+ @Schema(example = "SR20260805")
private String srId;
+
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqListRequest.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqListRequest.java
index 377b27c7..517418ab 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqListRequest.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/dto/SolReqListRequest.java
@@ -1,8 +1,11 @@
package io.shinhanlife.dap.mcc.biz.sol.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import com.fasterxml.jackson.annotation.JsonInclude;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Data;
/**
@@ -22,14 +25,15 @@ import lombok.Data;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SolReqListRequest {
- @McpParameter(description = "진행상태 (예: 진행중, 완료 등)", required = false)
- @McpValidation(examples = {"RECEIVED"})
+ @McpToolParam(description = "진행상태 (예: 진행중, 완료 등)", required = false)
+ @Schema(example = "RECEIVED")
private String status;
- @McpParameter(description = "조회기간 (예: 1개월, 3개월 등)", required = false)
+
+@McpToolParam(description = "조회기간 (예: 1개월, 3개월 등)", required = false)
private String period;
- @McpParameter(description = "조회대상 (예: 나의 업무, 전체 등)", required = false)
- @McpValidation(examples = {"USER"})
+ @McpToolParam(description = "조회대상 (예: 나의 업무, 전체 등)", required = false)
+ @Schema(example = "USER")
private String target;
}
\ No newline at end of file
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqDetailUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqDetailUseCase.java
index 7ec6ac38..4567e68a 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqDetailUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqDetailUseCase.java
@@ -1,7 +1,8 @@
package io.shinhanlife.dap.mcc.biz.sol.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqDetailRequest;
/**
@@ -18,22 +19,9 @@ import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqDetailRequest;
*
*
*/
-@McpTool(
- routingType = "MCI",
- categoryKey = "sol"
-)
public interface SolReqDetailUseCase {
- @McpFunction(
- displayName = "SolReqDetail 툴",
- name = "oth.sol.request.detail",
- description = "SOL 의뢰서 상세 조회",
- prompt = "SOL 의뢰서 상세 조회해줘",
- mappingId = "SOLG00000002",
- register = false,
- requiresApproval = false,
- readOnlyHint = true,
- openWorldHint = true
- )
+ @McpTool(name = "oth.sol.request.detail", title = "SolReqDetail 툴", description = "SOL 의뢰서 상세 조회", annotations = @McpTool.McpAnnotations(openWorldHint = true, readOnlyHint = true))
+ @ToolHint(register = false, requiresApproval = false, categoryKey = "sol", mappingId = "SOLG00000002")
Object execute(SolReqDetailRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqListUseCase.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqListUseCase.java
index 1a1e9caa..00a7c491 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqListUseCase.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/sol/usecase/SolReqListUseCase.java
@@ -1,23 +1,12 @@
package io.shinhanlife.dap.mcc.biz.sol.usecase;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
-import io.shinhanlife.dap.lib.annotation.McpTool;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
+
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
-@McpTool(
- routingType = "MCI",
- categoryKey = "sol"
-)
public interface SolReqListUseCase {
- @McpFunction(
- displayName = "SolReqList 툴",
- name = "oth.sol.request.list",
- description = "SOL 의뢰서 목록 조회해줘",
- prompt = "SOL 의뢰서 목록 조회해줘",
- mappingId = "SOLG00000001",
- register = false,
- requiresApproval = false,
- openWorldHint = true
- )
+ @McpTool(name = "oth.sol.request.list", title = "SolReqList 툴", description = "SOL 의뢰서 목록 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
+ @ToolHint(register = false, requiresApproval = false, categoryKey = "sol", mappingId = "SOLG00000001")
Object execute(SolReqListRequest req);
}
diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/oth/DapWasOthApplication.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/oth/DapWasOthApplication.java
index e28f3517..4b831fb1 100644
--- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/oth/DapWasOthApplication.java
+++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/oth/DapWasOthApplication.java
@@ -19,10 +19,13 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Import;
+import io.shinhanlife.dap.lib.mcp.ToolMcpServerConfiguration;
@SpringBootApplication(scanBasePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib"})
@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib"})
@EnableCaching
+@Import(ToolMcpServerConfiguration.class)
public class DapWasOthApplication {
public static void main(String[] args) {
SpringApplication.run(DapWasOthApplication.class, args);
diff --git a/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-input-schema.json b/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-input-schema.json
new file mode 100644
index 00000000..56994fb2
--- /dev/null
+++ b/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-input-schema.json
@@ -0,0 +1,49 @@
+{
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "claimNo": {
+ "type": "string",
+ "description": "청구번호. CLM 이후 숫자 13자리 형식입니다.",
+ "pattern": "^CLM[0-9]{13}$",
+ "example": "CLM2026070100123"
+ },
+ "contractNo": {
+ "type": "string",
+ "description": "계약번호. 숫자 11자리 형식입니다.",
+ "pattern": "^[0-9]{11}$",
+ "example": "10023456789"
+ },
+ "status": {
+ "type": "string",
+ "description": "청구 상태 필터",
+ "enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"],
+ "example": "RECEIVED"
+ },
+ "claimType": {
+ "type": "string",
+ "description": "청구 유형 필터",
+ "enum": ["MEDICAL", "SURGERY", "HOSPITALIZATION", "DIAGNOSIS", "DEATH", "DISABILITY"],
+ "example": "MEDICAL"
+ },
+ "fromDate": {
+ "type": "string",
+ "description": "접수일 조회 시작일 (YYYY-MM-DD)",
+ "format": "date",
+ "example": "2026-01-01"
+ },
+ "toDate": {
+ "type": "string",
+ "description": "접수일 조회 종료일 (YYYY-MM-DD)",
+ "format": "date",
+ "example": "2026-07-31"
+ },
+ "size": {
+ "type": "string",
+ "description": "반환할 최대 건수 (기본값: 20, 최대: 50)",
+ "pattern": "^[1-9][0-9]?$|^50$",
+ "default": "20",
+ "example": "20"
+ }
+ }
+}
diff --git a/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-output-schema.json b/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-output-schema.json
new file mode 100644
index 00000000..b7844be3
--- /dev/null
+++ b/dap-was-oth/src/main/resources/mcp/schema/claim-search-resource-output-schema.json
@@ -0,0 +1,83 @@
+{
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "resultCode": {
+ "type": "string",
+ "description": "실행 결과 코드",
+ "enum": ["SUCCESS", "FAILURE"]
+ },
+ "resultLabel": {
+ "type": "string",
+ "description": "resultCode의 사용자 표시 라벨",
+ "maxLength": 100
+ },
+ "status": {
+ "type": "string",
+ "description": "현재 청구 처리 상태 코드",
+ "enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"]
+ },
+ "statusLabel": {
+ "type": "string",
+ "description": "status의 사용자 표시 라벨",
+ "maxLength": 100
+ },
+ "approvedAmount": {
+ "anyOf": [
+ {"type": "integer", "minimum": 0},
+ {"type": "null"}
+ ],
+ "description": "승인 금액. 심사 전에는 null이며 0으로 해석하지 않습니다."
+ },
+ "rejectionReason": {
+ "anyOf": [
+ {"type": "string", "maxLength": 200},
+ {"type": "null"}
+ ],
+ "description": "status가 REJECTED일 때만 존재하며, 그 외에는 null입니다."
+ },
+ "items": {
+ "type": "array",
+ "description": "수령일 내림차순으로 정렬된 청구 요약 목록",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": "string",
+ "description": "청구 처리 상태 코드"
+ },
+ "statusLabel": {
+ "type": "string",
+ "description": "status의 사용자 표시 라벨"
+ },
+ "receivedDate": {
+ "type": "string",
+ "description": "접수일 (YYYY-MM-DD 형식)",
+ "format": "date"
+ },
+ "approvedAmount": {
+ "anyOf": [
+ {"type": "integer", "minimum": 0},
+ {"type": "null"}
+ ],
+ "description": "승인 금액. 심사 전에는 null"
+ }
+ },
+ "required": ["receivedDate"]
+ }
+ },
+ "hasMore": {
+ "type": "boolean",
+ "description": "이 응답 이후 추가 결과가 있는지 여부"
+ },
+ "totalCount": {
+ "anyOf": [
+ {"type": "integer", "minimum": 0},
+ {"type": "null"}
+ ],
+ "description": "매칭된 청구 건수 합계"
+ }
+ },
+ "required": ["resultCode", "resultLabel", "status", "statusLabel", "items", "hasMore"]
+}
diff --git a/dap-was-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java b/dap-was-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java
index aad02162..10f92c57 100644
--- a/dap-was-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java
+++ b/dap-was-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java
@@ -4,15 +4,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
import io.shinhanlife.dap.lib.util.JsonSchemaGenerator;
import io.shinhanlife.dap.lib.util.ToolSchemaResolver;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.cmm.usecase.impl.ClaimSearchSchemaSampleUseCaseImpl;
import io.shinhanlife.dap.lib.validation.ToolArgumentSchemaValidator;import io.shinhanlife.dap.mcc.biz.cmm.usecase.ClaimSearchSchemaSampleUseCase;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.springframework.ai.mcp.annotation.McpTool;
class ClaimSearchRequestSchemaTest {
@@ -34,10 +35,11 @@ class ClaimSearchRequestSchemaTest {
void resolvesSchemaFromToolModuleResource() throws Exception {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
- McpFunction function = method.getAnnotation(McpFunction.class);
+ McpTool function = method.getAnnotation(McpTool.class);
+ ToolHint hint = method.getAnnotation(ToolHint.class);
Map schema = new ToolSchemaResolver(new ObjectMapper())
- .resolve(function, ClaimSearchRequest.class);
+ .resolve(function, hint, ClaimSearchRequest.class);
assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema"));
assertTrue(schema.containsKey("anyOf"));
@@ -48,8 +50,10 @@ class ClaimSearchRequestSchemaTest {
void resolvesOutputSchemaFromToolModuleResource() throws Exception {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
- McpFunction function = method.getAnnotation(McpFunction.class);
- Map schema = new ToolSchemaResolver(new ObjectMapper()).resolveOutput(function);
+ McpTool function = method.getAnnotation(McpTool.class);
+ ToolHint hint = method.getAnnotation(ToolHint.class);
+ Map schema = new ToolSchemaResolver(new ObjectMapper())
+ .resolveOutput(function, ClaimSearchResponse.class, hint);
assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema"));
assertTrue(properties(schema).containsKey("resultCode"));
assertTrue(properties(schema).containsKey("statusLabel"));
@@ -62,7 +66,8 @@ class ClaimSearchRequestSchemaTest {
Method method = ClaimSearchSchemaSampleUseCase.class
.getDeclaredMethod("search", ClaimSearchRequest.class);
Map schema = new ToolSchemaResolver(new ObjectMapper())
- .resolveOutput(method.getAnnotation(McpFunction.class));
+ .resolveOutput(method.getAnnotation(McpTool.class), ClaimSearchResponse.class,
+ method.getAnnotation(ToolHint.class));
ClaimSearchResponse response = new ClaimSearchSchemaSampleUseCaseImpl().search(new ClaimSearchRequest());
ToolArgumentSchemaValidator validator = new ToolArgumentSchemaValidator(new ObjectMapper());
diff --git a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/dto/SmsSendRequest.java b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/dto/SmsSendRequest.java
index 91898078..32bcdbeb 100644
--- a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/dto/SmsSendRequest.java
+++ b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/dto/SmsSendRequest.java
@@ -1,11 +1,14 @@
package io.shinhanlife.dap.mcc.biz.sms.dto;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.ai.mcp.annotation.McpToolParam;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
-import io.shinhanlife.dap.lib.annotation.McpParameter;
-import io.shinhanlife.dap.lib.annotation.McpValidation;
import lombok.Getter;
import lombok.Setter;
@@ -30,12 +33,13 @@ import lombok.Setter;
@AllArgsConstructor
public class SmsSendRequest {
- @McpParameter(description = "수신자 전화번호", required = true)
- @McpValidation(pattern = "^01[0-9]-?\\d{3,4}-?\\d{4}$", examples = {"01012345678"})
+ @McpToolParam(description = "수신자 전화번호", required = true)
+ @Schema(pattern = "^01[0-9]-?\\d{3,4}-?\\d{4}$", example = "01012345678")
private String phoneNumber;
- @McpParameter(description = "전송할 메시지 내용", required = true)
- @McpValidation(pattern = "\\S", examples = {"테스트 메시지입니다."})
+
+@McpToolParam(description = "전송할 메시지 내용", required = true)
+ @Schema(pattern = "\\S", example = "테스트 메시지입니다.")
private String message;
diff --git a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/SmsToolUseCase.java b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/SmsToolUseCase.java
index 74f28f74..0c544e8f 100644
--- a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/SmsToolUseCase.java
+++ b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/SmsToolUseCase.java
@@ -1,10 +1,11 @@
package io.shinhanlife.dap.mcc.biz.sms.usecase;
-import io.shinhanlife.dap.lib.annotation.McpTool;
-import io.shinhanlife.dap.lib.annotation.McpFunction;
+import org.springframework.ai.mcp.annotation.McpTool;
+import io.shinhanlife.dap.lib.annotation.ToolHint;
import io.shinhanlife.dap.mcc.biz.sms.dto.*;
-@McpTool(routingType = "EAI", categoryKey = "notification")
public interface SmsToolUseCase {
+ @McpTool(name = "sms.send", title = "SMS 발송 툴", description = "SMS 발송 기능을 제공합니다.")
+ @ToolHint(register = false, categoryKey = "notification", mappingId = "SMS_SEND")
Object sendSms(SmsSendRequest req);
}
diff --git a/docker-compose.yml b/docker-compose.yml
index 6cc43e68..b241d65f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -31,6 +31,9 @@ services:
- AXHUB_SOURCE_DIR=/src
- JAVA_TOOL_OPTIONS=-Xms64m -Xmx384m
- SPRING_PROFILES_ACTIVE=${ACTIVE_PROFILE:-local}
+ - MCP_GATEWAY_FALLBACK_DEFAULT_URL=http://tool-oth:8084
+ - MCP_GATEWAY_FALLBACK_ROUTES_SMS=http://tool-sms:8082
+ - MCP_GATEWAY_FALLBACK_ROUTES_HR=http://tool-oth:8084
- MCP_GATEWAY_FALLBACK_DEFAULT_URL=http://was-oth:8084
- MCP_GATEWAY_FALLBACK_ROUTES_SMS=http://was-sms:8082
- MCP_GATEWAY_FALLBACK_ROUTES_HR=http://was-oth:8084