diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/config/RedisConfig.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/config/RedisConfig.java index b0f11b49..9498936e 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/config/RedisConfig.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/config/RedisConfig.java @@ -1,6 +1,6 @@ package io.shinhanlife.dap.mcg.config; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/GuardrailService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/GuardrailService.java index 00e96673..524f47cc 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/GuardrailService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/GuardrailService.java @@ -17,7 +17,7 @@ package io.shinhanlife.dap.mcg.guardrail; */ import io.shinhanlife.dap.mcg.resilience.FailureType; import io.shinhanlife.dap.mcg.resilience.ToolExecutionException; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.stereotype.Service; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/ToolResponseGuardrailService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/ToolResponseGuardrailService.java index 77592f27..d00902da 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/ToolResponseGuardrailService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/guardrail/ToolResponseGuardrailService.java @@ -17,7 +17,7 @@ package io.shinhanlife.dap.mcg.guardrail; */ import io.shinhanlife.dap.mcg.resilience.FailureType; import io.shinhanlife.dap.mcg.resilience.ToolExecutionException; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/ChatController.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/ChatController.java index 4263a979..492407cf 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/ChatController.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/ChatController.java @@ -16,7 +16,7 @@ package io.shinhanlife.dap.mcg.presentation; * */ import io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.registry.RedisRegistryService; import io.shinhanlife.dap.mcg.service.ExecuteService; import lombok.RequiredArgsConstructor; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/McpRouterController.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/McpRouterController.java index 4cc5ca9f..99773b7a 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/McpRouterController.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/presentation/McpRouterController.java @@ -20,7 +20,7 @@ import io.shinhanlife.dap.lib.adapter.dto.JsonRpcRequest; import io.shinhanlife.dap.lib.adapter.dto.JsonRpcResponse; import io.shinhanlife.dap.lib.adapter.dto.Params; import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.registry.RedisRegistryService; import io.shinhanlife.dap.mcg.service.ExecuteService; import io.shinhanlife.dap.lib.mcp.security.SecurityProperties; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/redis/RedisToolTraceService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/redis/RedisToolTraceService.java index ccd71bd6..ab182375 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/redis/RedisToolTraceService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/redis/RedisToolTraceService.java @@ -17,7 +17,7 @@ package io.shinhanlife.dap.mcg.redis; */ import io.shinhanlife.dap.mcg.config.McpGatewayProperties; import io.shinhanlife.dap.mcg.security.McpRequestContext; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/registry/RedisRegistryService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/registry/RedisRegistryService.java index 55953f29..73c3899f 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/registry/RedisRegistryService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/registry/RedisRegistryService.java @@ -1,6 +1,6 @@ package io.shinhanlife.dap.mcg.registry; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/security/ToolAuthorizationService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/security/ToolAuthorizationService.java index 368f3c76..15b234a6 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/security/ToolAuthorizationService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/security/ToolAuthorizationService.java @@ -19,7 +19,7 @@ import io.shinhanlife.dap.mcg.config.McpGatewayProperties; import io.shinhanlife.dap.mcg.resilience.FailureType; import io.shinhanlife.dap.mcg.resilience.ToolExecutionException; import io.shinhanlife.dap.lib.dto.OperationType; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import org.springframework.stereotype.Service; import java.util.Set; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ExecuteService.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ExecuteService.java index f3f2c380..758dc7c1 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ExecuteService.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ExecuteService.java @@ -17,7 +17,7 @@ package io.shinhanlife.dap.mcg.service; */ import java.util.HashMap; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.resilience.FailureType; import io.shinhanlife.dap.mcg.resilience.RetryPolicy; import io.shinhanlife.dap.mcg.resilience.ToolExecutionException; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ToolPlanner.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ToolPlanner.java index fd27ee12..f5971eab 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ToolPlanner.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/service/ToolPlanner.java @@ -2,7 +2,7 @@ package io.shinhanlife.dap.mcg.service; import io.shinhanlife.dap.lib.mcp.security.SecurityProperties; import io.shinhanlife.dap.mcg.registry.RedisRegistryService; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.config.GatewayFallbackProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/DynamicMcpServerManager.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/DynamicMcpServerManager.java index 0f43697a..e93a2e9d 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/DynamicMcpServerManager.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/DynamicMcpServerManager.java @@ -18,7 +18,7 @@ package io.shinhanlife.dap.mcg.sync; import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities; import io.modelcontextprotocol.server.McpServer; import io.modelcontextprotocol.server.McpSyncServer; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.sync.CustomWebMvcSseServerTransportProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSpecificationFactory.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSpecificationFactory.java index bf8ed511..36d3e43c 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSpecificationFactory.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSpecificationFactory.java @@ -15,7 +15,7 @@ package io.shinhanlife.dap.mcg.sync; * * */ -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.service.ExecuteService; import io.modelcontextprotocol.server.McpServerFeatures; import io.modelcontextprotocol.spec.McpSchema; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSynchronizer.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSynchronizer.java index 73a2a636..06134996 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSynchronizer.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/sync/RegistryMcpToolSynchronizer.java @@ -1,6 +1,6 @@ package io.shinhanlife.dap.mcg.sync; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.registry.RedisRegistryService; import io.modelcontextprotocol.server.McpSyncServer; import org.slf4j.Logger; diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/tool/large/PaginationRequestValidator.java b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/tool/large/PaginationRequestValidator.java index cee3eaf6..57878a2d 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/tool/large/PaginationRequestValidator.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/mcg/tool/large/PaginationRequestValidator.java @@ -15,7 +15,7 @@ package io.shinhanlife.dap.mcg.tool.large; * * */ -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.config.McpGatewayProperties; import io.shinhanlife.dap.mcg.resilience.FailureType; import io.shinhanlife.dap.mcg.resilience.ToolExecutionException; diff --git a/dap-gateway/src/main/resources/mapper/ZtUsacRepository.xml b/dap-gateway/src/main/resources/mapper/ZtUsacRepository.xml deleted file mode 100644 index 285cc09c..00000000 --- a/dap-gateway/src/main/resources/mapper/ZtUsacRepository.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - diff --git a/dap-gateway/src/test/java/io/shinhanlife/dap/biz/mcp/gateway/sync/RegistryMcpToolSpecificationFactoryTest.java b/dap-gateway/src/test/java/io/shinhanlife/dap/biz/mcp/gateway/sync/RegistryMcpToolSpecificationFactoryTest.java index d90be505..bb6d5a40 100644 --- a/dap-gateway/src/test/java/io/shinhanlife/dap/biz/mcp/gateway/sync/RegistryMcpToolSpecificationFactoryTest.java +++ b/dap-gateway/src/test/java/io/shinhanlife/dap/biz/mcp/gateway/sync/RegistryMcpToolSpecificationFactoryTest.java @@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.spec.McpSchema; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcg.sync.RegistryMcpToolSpecificationFactory; import org.junit.jupiter.api.Test; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/manifest/ToolManifestService.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/manifest/ToolManifestService.java index a799bb18..5050a442 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/manifest/ToolManifestService.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/manifest/ToolManifestService.java @@ -2,8 +2,8 @@ package io.shinhanlife.dap.lib.manifest; import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.dap.lib.config.McpProperties; -import io.shinhanlife.dap.lib.dto.ToolMetadata; -import io.shinhanlife.dap.lib.usecase.ToolRegistryHeartbeatSender; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; +import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Comparator; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaderContext.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaderContext.java similarity index 100% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaderContext.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaderContext.java diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaderFilter.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaderFilter.java similarity index 100% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaderFilter.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaderFilter.java diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaders.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaders.java similarity index 100% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/McpRequestHeaders.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpRequestHeaders.java diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/ToolMcpServerConfiguration.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolMcpServerConfiguration.java similarity index 100% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/mcp/ToolMcpServerConfiguration.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolMcpServerConfiguration.java diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolPodMcpToolSynchronizer.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolPodMcpToolSynchronizer.java similarity index 93% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolPodMcpToolSynchronizer.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolPodMcpToolSynchronizer.java index 41ebf4ba..d9f23f01 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolPodMcpToolSynchronizer.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolPodMcpToolSynchronizer.java @@ -1,12 +1,12 @@ -package io.shinhanlife.dap.lib.usecase; +package io.shinhanlife.dap.lib.mcp; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.server.McpServerFeatures; import io.modelcontextprotocol.server.McpSyncServer; import io.modelcontextprotocol.spec.McpSchema; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.mcc.presentation.BusinessToolController; -import io.shinhanlife.dap.lib.usecase.ToolRegistryHeartbeatSender; +import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender; import io.shinhanlife.dap.lib.mcp.McpRequestHeaderContext; import io.shinhanlife.dap.lib.mcp.McpRequestHeaders; import java.util.LinkedHashMap; @@ -16,8 +16,11 @@ import org.springframework.context.event.EventListener; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; + /** Registers the Tool Pod's existing annotated tools with its MCP SDK server. */ @Component +@ConditionalOnBean(BusinessToolController.class) public class ToolPodMcpToolSynchronizer { private final McpSyncServer mcpServer; private final ToolRegistryHeartbeatSender heartbeatSender; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolRegistryHeartbeatSender.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolRegistryHeartbeatSender.java similarity index 96% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolRegistryHeartbeatSender.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolRegistryHeartbeatSender.java index f3acc4ff..1a9a4798 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/ToolRegistryHeartbeatSender.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolRegistryHeartbeatSender.java @@ -1,4 +1,4 @@ -package io.shinhanlife.dap.lib.usecase; +package io.shinhanlife.dap.lib.mcp; /** @@ -19,7 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.dap.lib.annotation.McpFunction; import io.shinhanlife.dap.lib.annotation.McpTool; import io.shinhanlife.dap.lib.config.McpProperties; -import io.shinhanlife.dap.lib.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import io.shinhanlife.dap.lib.util.ToolSchemaResolver; import jakarta.annotation.PostConstruct; import java.lang.reflect.Method; @@ -43,11 +43,15 @@ import org.springframework.stereotype.Component; import org.springframework.util.ClassUtils; import org.springframework.web.client.RestClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import io.shinhanlife.dap.mcc.presentation.BusinessToolController; + @Slf4j @Component @Configuration @EnableScheduling @RequiredArgsConstructor +@ConditionalOnBean(BusinessToolController.class) public class ToolRegistryHeartbeatSender { private final ApplicationContext applicationContext; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/converter/ZtUsacConverter.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/converter/ZtUsacConverter.java deleted file mode 100644 index f70d1d39..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/converter/ZtUsacConverter.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.shinhanlife.dap.lib.session.converter; - -import io.shinhanlife.dap.lib.session.dto.SessionDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacOutDto; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * @package io.shinhanlife.dap.lib.session.converter - * @className ZtUsacConverter - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Mapper(componentModel = "spring") -public abstract class ZtUsacConverter { - - @Mapping(target = "loginDtm", ignore = true) - @Mapping(target = "isManager", ignore = true) - public abstract SessionDto toSessionDto(ZtUsacOutDto dto); - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/model/ZtUsacModel.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/model/ZtUsacModel.java deleted file mode 100644 index 7c16b1c4..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/model/ZtUsacModel.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.shinhanlife.dap.lib.session.domain.model; - -import io.shinhanlife.glow.db.dto.AuditInfo; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * @package io.shinhanlife.dap.lib.session.domain.model - * @className ZtUsacModel - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Getter -@Builder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class ZtUsacModel extends AuditInfo { - - /* 인사번호 */ - private String prafNo; - /* 인사명 */ - private String prafNm; - /* 조직번호 */ - private String ognzNo; - /* 이메일주소 */ - private String addre; - /* 인사직무코드 */ - private String prafOfduCd; - /* 인사직무명 */ - private String prafOfduNm; - /* 인사직급코드 */ - private String prafOfleCd; - /* 인사직급명 */ - private String prafOfleNm; - /* 인사직책코드 */ - private String prafDutyCd; - /* 인사직책명 */ - private String prafDutyNm; - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/repository/ZtUsacRepository.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/repository/ZtUsacRepository.java deleted file mode 100644 index c300bbb4..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/repository/ZtUsacRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.shinhanlife.dap.lib.session.domain.repository; - -import io.shinhanlife.glow.GlowMybatisMapper; -import io.shinhanlife.dap.lib.session.dto.ZtUsacInDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacOutDto; - - -/** - * @package io.shinhanlife.dap.lib.session.domain.repository - * @className ZtUsacRepository - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@GlowMybatisMapper -public interface ZtUsacRepository { - - /** - * 사용자 조회 (단건) - * - * @param dto 사번 - * @return 인사정보 - */ - ZtUsacOutDto selectZtUsac(ZtUsacInDto dto); - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/ZtUsacUseCase.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/ZtUsacUseCase.java deleted file mode 100644 index 235a75d1..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/ZtUsacUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.shinhanlife.dap.lib.session.domain.usecase; - -import io.shinhanlife.dap.lib.session.dto.ZtUsacInDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacOutDto; - -/** - * @package io.shinhanlife.dap.lib.session.domain.service - * @className ZtUsacUseCase - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -public interface ZtUsacUseCase { - - /** - * 사용자 조회 (단건) - * - * @param dto 사번 - * @return 인사정보 - */ - ZtUsacOutDto selectZtUsac(ZtUsacInDto dto); -} diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/impl/ZtUsacUseCaseImpl.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/impl/ZtUsacUseCaseImpl.java deleted file mode 100644 index 5486fb8b..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/domain/usecase/impl/ZtUsacUseCaseImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.shinhanlife.dap.lib.session.domain.usecase.impl; - -import io.shinhanlife.dap.lib.session.domain.repository.ZtUsacRepository; -import io.shinhanlife.dap.lib.session.domain.usecase.ZtUsacUseCase; -import io.shinhanlife.dap.lib.session.dto.ZtUsacInDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacOutDto; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * @package io.shinhanlife.dap.lib.session.domain.usecase.impl - * @className ZtUsacUseCaseImpl - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Service -@RequiredArgsConstructor -public class ZtUsacUseCaseImpl implements ZtUsacUseCase { - - private final ZtUsacRepository ztUsacRepository; - - /** - * 사용자 조회 (단건) - * - * @param dto 사번 - * @return 인사정보 - */ - @Override - public ZtUsacOutDto selectZtUsac(ZtUsacInDto dto) { - ZtUsacOutDto result = ztUsacRepository.selectZtUsac(dto); - result.initLists(); - return result; - } -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacInDto.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacInDto.java deleted file mode 100644 index 954b9715..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacInDto.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.shinhanlife.dap.lib.session.dto; - -import lombok.NoArgsConstructor; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -/** - * @package io.shinhanlife.dap.lib.session.dto - * @className ZtUsacInDto - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class ZtUsacInDto { - /* 인사번호 */ - private String prafNo; - - /* 사용여부 */ - @Builder.Default - private String puseYn = "Y"; - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacOutDto.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacOutDto.java deleted file mode 100644 index b52e3b76..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/dto/ZtUsacOutDto.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.shinhanlife.dap.lib.session.dto; - -import lombok.Setter; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * @package io.shinhanlife.dap.lib.session.dto - * @className ZtUsacOutDto - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Getter -@Builder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -@Setter -public class ZtUsacOutDto { - - /* 인사번호 */ - private String prafNo; - /* 인사명 */ - private String prafNm; - /* 조직번호 */ - private String ognzNo; - /* 조직명 */ - private String ognzNm; - /* 이메일주소 */ -// @GlowSecureField(type = DataSecureType.DECRYPT_DB, direction = SafeDBType.COMM) TODO 방화벽 뚫리면 확인 - private String addre; - /* 인사직무코드 */ - private String prafOfduCd; - /* 인사직무명 */ - private String prafOfduNm; - /* 인사직급코드 */ - private String prafOfleCd; - /* 인사직급명 */ - private String prafOfleNm; - /* 인사직책코드 */ - private String prafDutyCd; - /* 인사직책명 */ - private String prafDutyNm; - /* 사용여부 */ - private String puseYn; - - private String roleNoStrList; - private String roleNmStrList; - private String tgtrPrafNoStrList; - private String tgtrOgnzNoStrList; - - private List roleNoList; - private List roleNmList; - private List tgtrPrafNoList; - private List tgtrOgnzNoList; - - public void initLists() { - this.roleNoList = convertStrToList(roleNoStrList); - this.roleNmList = convertStrToList(roleNmStrList); - this.tgtrPrafNoList = convertStrToList(tgtrPrafNoStrList); - this.tgtrOgnzNoList = convertStrToList(tgtrOgnzNoStrList); - } - - private List convertStrToList(String str) { - if (str == null || str.isEmpty()) { - return new ArrayList<>(); - } - return Arrays.asList(str.split(",")); - } - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/SsoRestController.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/SsoRestController.java deleted file mode 100644 index b98c76bf..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/SsoRestController.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.shinhanlife.dap.lib.session.presentation; - -import io.micrometer.common.util.StringUtils; -import io.shinhanlife.glow.BaseResponse; -import io.shinhanlife.glow.BizException; -import io.shinhanlife.glow.GlowControllerId; -import io.shinhanlife.glow.ResponseUtil; -import io.shinhanlife.dap.lib.session.converter.ZtUsacConverter; -import io.shinhanlife.dap.lib.session.domain.usecase.ZtUsacUseCase; -import io.shinhanlife.dap.lib.session.dto.SessionDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacInDto; -import io.shinhanlife.dap.lib.session.dto.ZtUsacOutDto; -import io.shinhanlife.dap.lib.session.presentation.io.SsoResponse; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.javassist.NotFoundException; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Objects; - -/** - * @package io.shinhanlife.dap.lib.session.presentation - * @className SsoRestController - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@RestController -@RequiredArgsConstructor -@Slf4j -@RequestMapping("/sso") -public class SsoRestController { - - private static final String NLS_LOGIN_URL = ""; - private final ZtUsacUseCase ztUsacService; - private final ZtUsacConverter ztUsacConverter; - - /** - * sso 연동 전 임시 로그인 - * - * @param request - * @param response - * @param session - * @param - * @return - */ - @GlowControllerId("tempLogin") - @PostMapping("/tempLogin") - public ResponseEntity> tempLogin(HttpServletRequest request, HttpServletResponse response, - HttpSession session, @RequestBody SessionDto requestDto) { - try { - if (StringUtils.isEmpty(requestDto.getPrafNo())) { - throw new NotFoundException("SSO >> not found sso id"); - } - - // DB 유저 가져오기 - ZtUsacOutDto ztUsacOutDto = ztUsacService.selectZtUsac(ZtUsacInDto.builder().prafNo(requestDto.getPrafNo()).puseYn("Y") - .build()); - if (Objects.isNull(ztUsacOutDto) || StringUtils.isEmpty(ztUsacOutDto.getPrafNo())) { - throw new BizException("SSO >> not found UserInfo >> retCode:"); - } - - SessionDto sessionDto = ztUsacConverter.toSessionDto(ztUsacOutDto); - sessionDto.setLoginDtm(); // 로그인 시점 세팅 - session.setAttribute("userInfo", sessionDto); - return ResponseUtil.ok(SsoResponse.builder().retCode("0").userInfo(sessionDto).build()); - - } catch (Exception e) { - log.error("로그인 실패", e); - session.invalidate(); - } - - return ResponseUtil.ok(SsoResponse.builder().redirectUrl(NLS_LOGIN_URL).build()); - - } - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/io/SsoResponse.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/io/SsoResponse.java deleted file mode 100644 index 10594ebd..00000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/session/presentation/io/SsoResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.shinhanlife.dap.lib.session.presentation.io; - -import io.shinhanlife.dap.lib.session.dto.SessionDto; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * @package io.shinhanlife.dap.lib.session.presentation.io - * @className SsoResponse - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class SsoResponse { - - private String retCode; - private SessionDto userInfo; - private String redirectUrl; - -} \ No newline at end of file diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java index 3fa3eebf..80357e4f 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java @@ -330,7 +330,7 @@ public class ToolScaffolder { import %s.dto.%sRequest; import %s.dto.%sResponse; import %s.usecase.%sUseCase; - import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; + import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import %s.converter.%sConverter; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/dto/ToolMetadata.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/dto/ToolMetadata.java similarity index 98% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/dto/ToolMetadata.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/dto/ToolMetadata.java index b498032d..44e9f7d9 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/dto/ToolMetadata.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/dto/ToolMetadata.java @@ -1,4 +1,4 @@ -package io.shinhanlife.dap.lib.dto; +package io.shinhanlife.dap.mcc.dto; import lombok.Getter; import lombok.Setter; @@ -12,6 +12,7 @@ import java.util.Map; import java.util.Set; import java.util.List; import java.util.HashSet; +import io.shinhanlife.dap.lib.dto.OperationType; /** * Tool(Agent)의 명세 및 라우팅 정보를 담고 있는 메타데이터 클래스 * Redis 레지스트리에 저장되며, Planner와 Router 간의 통신 객체(Plan)로 사용됩니다. 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 5eb1db02..a998ad79 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 @@ -21,8 +21,8 @@ import io.shinhanlife.dap.lib.annotation.McpFunction; 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.lib.dto.ToolMetadata; -import io.shinhanlife.dap.lib.usecase.ToolRegistryHeartbeatSender; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; +import io.shinhanlife.dap.lib.mcp.ToolRegistryHeartbeatSender; import io.shinhanlife.dap.lib.util.ToolSchemaResolver; import java.lang.reflect.Method; import java.util.ArrayList; diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/AbstractMcpToolUseCase.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/usecase/AbstractMcpToolUseCase.java similarity index 98% rename from dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/AbstractMcpToolUseCase.java rename to dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/usecase/AbstractMcpToolUseCase.java index 8dbb8210..a8729653 100644 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/usecase/AbstractMcpToolUseCase.java +++ b/dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/usecase/AbstractMcpToolUseCase.java @@ -1,4 +1,4 @@ -package io.shinhanlife.dap.lib.usecase; +package io.shinhanlife.dap.mcc.usecase; import io.shinhanlife.dap.lib.adapter.connector.LegacyEimsConnector; import io.shinhanlife.dap.lib.adapter.util.PiiMaskingUtils; 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 a17c484b..6efc38ec 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 @@ -6,7 +6,7 @@ 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.dto.ToolMetadata; +import io.shinhanlife.dap.mcc.dto.ToolMetadata; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; 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 87071e90..59bc1597 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 @@ -11,7 +11,7 @@ import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.server.McpSyncServer; import io.shinhanlife.dap.mcc.presentation.BusinessToolController; -import io.shinhanlife.dap.lib.usecase.ToolRegistryHeartbeatSender; +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-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BalanceUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BalanceUseCaseImpl.java index 7e9e0c46..0c49a90a 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BalanceUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BalanceUseCaseImpl.java @@ -16,7 +16,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; * */ import io.shinhanlife.dap.mcc.biz.cmm.usecase.BalanceUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import io.shinhanlife.dap.mcc.biz.cmm.dto.BalanceRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BillingProcessUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BillingProcessUseCaseImpl.java index 890c07bc..bf81db59 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BillingProcessUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BillingProcessUseCaseImpl.java @@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.dap.mcc.biz.cmm.usecase.BillingProcessUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.cmm.dto.BillingProcessRequest; import io.shinhanlife.dap.mcc.biz.cmm.dto.BillingStatusRequest; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BondIssueUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BondIssueUseCaseImpl.java index 2d74f8e6..9851714b 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BondIssueUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/BondIssueUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import io.shinhanlife.dap.mcc.biz.cmm.usecase.BondIssueUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.cmm.dto.BondCheckRequest; import io.shinhanlife.dap.mcc.biz.cmm.dto.BondIssueRequest; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CommonUtilityUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CommonUtilityUseCaseImpl.java index aad892a7..56a600a3 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CommonUtilityUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CommonUtilityUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import io.shinhanlife.dap.mcc.biz.cmm.usecase.CommonUtilityUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.cmm.dto.LeaveCountRequest; import io.shinhanlife.dap.mcc.biz.cmm.dto.VacationRegisterRequest; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ContractInquiryUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ContractInquiryUseCaseImpl.java index 17b858a3..403f1556 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ContractInquiryUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ContractInquiryUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import io.shinhanlife.dap.mcc.biz.cmm.usecase.ContractInquiryUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.cmm.dto.ContractDetailRequest; import io.shinhanlife.dap.mcc.biz.cmm.dto.ContractStatusRequest; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CustomerInfoUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CustomerInfoUseCaseImpl.java index f5cc9a44..cb06f623 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CustomerInfoUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/CustomerInfoUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import io.shinhanlife.dap.mcc.biz.cmm.usecase.CustomerInfoUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.cmm.dto.CustomerDetailRequest; import io.shinhanlife.dap.mcc.biz.cmm.dto.CustomerGradeRequest; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/TemplateUtilityUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/TemplateUtilityUseCaseImpl.java index 13594d63..42a9505b 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/TemplateUtilityUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/TemplateUtilityUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; import io.shinhanlife.dap.mcc.biz.cmm.usecase.TemplateUtilityUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import io.shinhanlife.dap.mcc.biz.cmm.dto.TemplateDownloadRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/DailyQuoteToolUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/DailyQuoteToolUseCaseImpl.java index a65f537b..36059326 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/DailyQuoteToolUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/DailyQuoteToolUseCaseImpl.java @@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.smp.usecase.impl; import io.shinhanlife.dap.mcc.biz.smp.dto.DailyQuoteRequest; import io.shinhanlife.dap.mcc.biz.smp.dto.DailyQuoteResponse; import io.shinhanlife.dap.mcc.biz.smp.usecase.DailyQuoteToolUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/ExchangeRateToolUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/ExchangeRateToolUseCaseImpl.java index d7ac0421..10853b02 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/ExchangeRateToolUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/ExchangeRateToolUseCaseImpl.java @@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.smp.usecase.impl; 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.usecase.ExchangeRateToolUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/TeamMemberUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/TeamMemberUseCaseImpl.java index a6f79be1..19d1e25f 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/TeamMemberUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/TeamMemberUseCaseImpl.java @@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.smp.usecase.impl; import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberRequest; import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberResponse; import io.shinhanlife.dap.mcc.biz.smp.usecase.TeamMemberUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/WeatherToolUseCaseImpl.java b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/WeatherToolUseCaseImpl.java index 05c38727..b581199c 100644 --- a/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/WeatherToolUseCaseImpl.java +++ b/dap-was-oth/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/WeatherToolUseCaseImpl.java @@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.smp.usecase.impl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.dap.mcc.biz.smp.usecase.WeatherToolUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import io.shinhanlife.dap.mcc.biz.smp.dto.WeatherRequest; import io.shinhanlife.dap.mcc.biz.smp.dto.WeatherResponse; import lombok.extern.slf4j.Slf4j; diff --git a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/impl/SmsToolUseCaseImpl.java b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/impl/SmsToolUseCaseImpl.java index 35708843..38585687 100644 --- a/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/impl/SmsToolUseCaseImpl.java +++ b/dap-was-sms/src/main/java/io/shinhanlife/dap/mcc/biz/sms/usecase/impl/SmsToolUseCaseImpl.java @@ -1,7 +1,7 @@ package io.shinhanlife.dap.mcc.biz.sms.usecase.impl; import io.shinhanlife.dap.mcc.biz.sms.usecase.SmsToolUseCase; -import io.shinhanlife.dap.lib.usecase.AbstractMcpToolUseCase; +import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; import org.springframework.stereotype.Service; import io.shinhanlife.dap.mcc.biz.sms.converter.SmsLegacyConverter; import io.shinhanlife.dap.mcc.biz.sms.dto.SmsSendRequest; diff --git a/manifest_output.json b/manifest_output.json new file mode 100644 index 00000000..b8125795 --- /dev/null +++ b/manifest_output.json @@ -0,0 +1,606 @@ +{ + "bundleId": "tool-oth", + "revision": "1785826298946", + "tools": [ + { + "name": "balance", + "endpoint": "http://localhost:8084/mcp/balance", + "title": "balance 툴", + "description": "고객의 계좌 잔액을 조회합니다.", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "accountNumber": { + "type": "string", + "pattern": "\\S", + "description": "고객의 계좌번호 (- 제외) " + } + }, + "required": [ + "accountNumber" + ] + }, + "annotations": { + "title": "balance 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "billing_process", + "endpoint": "http://localhost:8084/mcp/billing_process", + "title": "process 툴", + "description": "청구 처리", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "approvalStatus": { + "type": "string", + "description": "심사 승인 여부 (예: APPROVE, REJECT)", + "enum": [ + "APPROVE", + "REJECT" + ] + }, + "billingId": { + "type": "string", + "pattern": "\\S", + "description": "처리할 청구 접수 번호" + } + }, + "required": [ + "billingId", + "approvalStatus" + ] + }, + "annotations": { + "title": "process 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "bond_issue", + "endpoint": "http://localhost:8084/mcp/bond_issue", + "title": "issue 툴", + "description": "증권 발행 í\u0085ŒìŠ¤íŠ¸1", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "amount": { + "type": "integer", + "description": "발행할 디지털 증권 금액", + "minimum": 1 + }, + "targetAccount": { + "type": "string", + "pattern": "\\S", + "description": "발행 대상 계좌 번호" + } + }, + "required": [ + "amount", + "targetAccount" + ] + }, + "annotations": { + "title": "issue 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "contract_detail", + "endpoint": "http://localhost:8084/mcp/contract_detail", + "title": "contract_detail 툴", + "description": "계약상세 조회", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "contractId": { + "type": "string", + "description": "조회할 계약 번호" + }, + "customerName": { + "type": "string", + "description": "고객ëª\u0085" + } + }, + "required": [ + "customerName", + "contractId" + ] + }, + "annotations": { + "title": "contract_detail 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "customer_detail", + "endpoint": "http://localhost:8084/mcp/customer_detail", + "title": "detail 툴", + "description": "고객상세 정보 조회", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "고객 식별 번호 (CID)" + }, + "customerName": { + "type": "string", + "description": "고객ëª\u0085" + } + }, + "required": [ + "customerName" + ] + }, + "annotations": { + "title": "detail 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "daily_quote", + "endpoint": "http://localhost:8084/mcp/daily_quote", + "title": "랜덤 ëª\u0085언 툴", + "description": "무작위로 영감을 주는 ëª\u0085언을 하나 가져옵니다.", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "category": { + "type": "string", + "description": "category" + } + } + }, + "annotations": { + "title": "랜덤 ëª\u0085언 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "exchange_rate", + "endpoint": "http://localhost:8084/mcp/exchange_rate", + "title": "실시간 환율 조회 툴", + "description": "원하는 통화의 실시간 환율을 조회합니다. (예: USD, EUR, JPY)", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "currencyCode": { + "type": "string", + "description": "currencyCode" + } + } + }, + "annotations": { + "title": "실시간 환율 조회 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "get_leave_count", + "endpoint": "http://localhost:8084/mcp/get_leave_count", + "title": "get_leave_count 툴", + "description": "연차 갯수 조회", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "employeeId": { + "type": "string", + "description": "연차 내역을 조회할 사원 번호" + } + }, + "required": [ + "employeeId" + ] + }, + "annotations": { + "title": "get_leave_count 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "get_smp_members", + "endpoint": "http://localhost:8084/mcp/get_smp_members", + "title": "신한라이프 MCP, TOOL 파트 구성원 조회", + "description": "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "teamName": { + "type": "string", + "description": "조회할 팀 이름 (예: AX, MCP, TOOL, 전체 등)" + } + } + }, + "annotations": { + "title": "신한라이프 MCP, TOOL 파트 구성원 조회", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "get_template_file_url", + "endpoint": "http://localhost:8084/mcp/get_template_file_url", + "title": "í\u0085œí”Œë¦¿ 유틸리티", + "description": "요청한 í\u0085œí”Œë¦¿(엑ì\u0085€, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스í\u0085œ URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "templateId": { + "type": "string", + "description": "templateId" + } + } + }, + "annotations": { + "title": "í\u0085œí”Œë¦¿ 유틸리티", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "metaCommonCode", + "endpoint": "http://localhost:8084/mcp/metaCommonCode", + "title": "메타 통합코드 조회 툴", + "description": "메타 통합코드 목록을 조회해줘", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "codeName": { + "type": "string", + "description": "코드ëª\u0085 검색 키워드 (예: 사용, 상태)" + }, + "useYn": { + "type": "string", + "description": "사용여부 (예: Y, N)" + }, + "groupCode": { + "type": "string", + "description": "통합코드 그룹 ID (예: GRP_SYS_01, GRP_COMM_CD)" + } + } + }, + "annotations": { + "title": "메타 통합코드 조회 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "metaTable", + "endpoint": "http://localhost:8084/mcp/metaTable", + "title": "메타 í\u0085Œì´ë¸” 조회 툴", + "description": "메타 í\u0085Œì´ë¸” 정보 목록을 조회해줘", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "tableLogicalName": { + "type": "string", + "description": "í\u0085Œì´ë¸” ë\u0085¼ë¦¬ëª\u0085(한글) 키워드 (예: 고객기본, 계약)" + }, + "owner": { + "type": "string", + "description": "스키마/소유자ëª\u0085 (예: DAPADM, SHLOWN)" + }, + "tableName": { + "type": "string", + "description": "í\u0085Œì´ë¸” 물리ëª\u0085 키워드 (예: TB_CUST_BAS, TB_CONT)" + } + } + }, + "annotations": { + "title": "메타 í\u0085Œì´ë¸” 조회 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "sample.claim.search.resource", + "endpoint": "http://localhost:8084/mcp/sample.claim.search.resource", + "title": "Claim search JSON Schema sample", + "description": "Claim search Tool sample using input and output JSON Schema resources.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "claimNo": { + "type": "string", + "description": "청구번호. CLM 다음 숫자 13자리 형식이다.", + "pattern": "^CLM[0-9]{13}$", + "examples": [ + "CLM2026070100123" + ] + }, + "contractNo": { + "type": "string", + "description": "계약번호. 숫자 11자리 형식이다.", + "pattern": "^[0-9]{11}$", + "examples": [ + "10023456789" + ] + }, + "status": { + "type": "string", + "enum": [ + "RECEIVED", + "REVIEWING", + "ADDITIONAL_DOC_REQUIRED", + "APPROVED", + "PAID", + "REJECTED", + "WITHDRAWN" + ] + }, + "size": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 20 + } + }, + "required": [ + + ], + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "claimNo" + ] + }, + { + "required": [ + "contractNo" + ] + } + ] + }, + "annotations": { + "title": "Claim search JSON Schema sample", + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "secret_tool", + "endpoint": "http://localhost:8084/mcp/secret_tool", + "title": "secret_tool 툴", + "description": "비공개 툴 í\u0085ŒìŠ¤íŠ¸", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "employeeId": { + "type": "string", + "description": "연차 내역을 조회할 사원 번호" + } + }, + "required": [ + "employeeId" + ] + }, + "annotations": { + "title": "secret_tool 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "solReqDetail", + "endpoint": "http://localhost:8084/mcp/solReqDetail", + "title": "SolReqDetail 툴", + "description": "SOL 의뢰서 상세 조회", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "srId": { + "type": "string", + "description": "상세 조회할 SOL 의뢰서 ID" + } + }, + "required": [ + "srId" + ] + }, + "annotations": { + "title": "SolReqDetail 툴", + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "solReqList", + "endpoint": "http://localhost:8084/mcp/solReqList", + "title": "SolReqList 툴", + "description": "SOL 의뢰서 목록 조회해줘", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "period": { + "type": "string", + "description": "조회기간 (예: 1개월, 3개월 등)" + }, + "status": { + "type": "string", + "description": "진행상태 (예: 진행중, 완료 등)" + }, + "target": { + "type": "string", + "description": "조회대상 (예: 나의 ì—\u0085무, 전체 등)" + } + } + }, + "annotations": { + "title": "SolReqList 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + }, + { + "name": "weather", + "endpoint": "http://localhost:8084/mcp/weather", + "title": "날씨 조회 툴", + "description": "특정 도시의 현재 날씨, 온도, 풍속 정보를 조회합니다.", + "inputSchema": { + "additionalProperties": false, + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "날씨를 조회할 도시 이름 (예: 서울, 부산, 제주)" + } + }, + "required": [ + "city" + ] + }, + "annotations": { + "title": "날씨 조회 툴", + "readOnlyHint": false, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": false + }, + "_meta": { + "version": "1.0.0", + "timeoutMillis": 300000, + "enabled": true + } + } + ] +} \ No newline at end of file diff --git a/recent_changes.diff b/recent_changes.diff new file mode 100644 index 00000000..119d7ac8 --- /dev/null +++ b/recent_changes.diff @@ -0,0 +1,715 @@ +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpFunction.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpFunction.java +index c7251dd..6ee5f33 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpFunction.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpFunction.java +@@ -39,6 +39,17 @@ public @interface McpFunction { + */ + // 異붽?: Redis ?먮룞 ?깅줉 諛?Heartbeat ?€???щ? ?쒖뼱 + String inputSchemaResource() default ""; ++ ++ /** ++ * Tool response JSON Schema. When unset, output validation is skipped. ++ */ ++ String outputSchema() default "{}"; ++ ++ /** ++ * Classpath resource for a complex Tool response JSON Schema. ++ * This value has priority over outputSchema. ++ */ ++ String outputSchemaResource() default ""; + boolean register() default false; + + // 異붽?: ??紐⑸줉 ?몄텧 ?щ? ?쒖뼱 (false ???쇱슦?낆? ?섎굹 紐⑸줉?먯꽌 ?④?) +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpOutputSchema.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpOutputSchema.java +new file mode 100644 +index 0000000..cfb37dc +--- /dev/null ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpOutputSchema.java +@@ -0,0 +1,17 @@ ++package io.shinhanlife.dap.lib.annotation; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++ ++/** ++ * Marks a Tool response DTO for automatic output JSON Schema generation. ++ * Field constraints are declared with {@link McpValidation}. ++ */ ++@Target(ElementType.TYPE) ++@Retention(RetentionPolicy.RUNTIME) ++@Documented ++public @interface McpOutputSchema { ++} +\ No newline at end of file +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpValidation.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpValidation.java +index ecf23c8..4353edf 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpValidation.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/annotation/McpValidation.java +@@ -31,6 +31,6 @@ public @interface McpValidation { + int maxLength() default -1; + String[] allowedValues() default {}; + String format() default ""; +- String defaultValue() default ""; ++ boolean nullable() default false; String defaultValue() default ""; + String[] examples() default {}; + } +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/JsonSchemaGenerator.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/JsonSchemaGenerator.java +index a90efa0..d95dae6 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/JsonSchemaGenerator.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/JsonSchemaGenerator.java +@@ -103,6 +103,14 @@ public class JsonSchemaGenerator { + if (validation != null && validation.examples().length > 0) { + fieldSchema.put("examples", List.of(validation.examples())); + } ++ if (validation != null && validation.nullable()) { ++ Map nonNullSchema = new HashMap<>(fieldSchema); ++ fieldSchema = new HashMap<>(); ++ fieldSchema.put("anyOf", List.of( ++ nonNullSchema, ++ Map.of("type", "null") ++ )); ++ } + + properties.put(field.getName(), fieldSchema); + } +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/ToolSchemaResolver.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/ToolSchemaResolver.java +index 787cbc1..5ea54df 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/ToolSchemaResolver.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/lib/util/ToolSchemaResolver.java +@@ -3,7 +3,7 @@ package io.shinhanlife.dap.lib.util; + import com.fasterxml.jackson.core.type.TypeReference; + import com.fasterxml.jackson.databind.ObjectMapper; + import io.shinhanlife.dap.lib.annotation.McpFunction; +-import java.io.InputStream; ++import io.shinhanlife.dap.lib.annotation.McpOutputSchema;import java.io.InputStream; + import java.util.Map; + import org.springframework.core.io.ClassPathResource; + +@@ -27,19 +27,44 @@ public class ToolSchemaResolver { + return JsonSchemaGenerator.generateSchema(requestType); + } + ++ /** ++ * Resolves an explicitly declared response schema. ++ * Response schemas are opt-in so existing tools keep their current response behavior. ++ */ ++ public Map resolveOutput(McpFunction function, Class responseType) { ++ if (function != null && !function.outputSchemaResource().isBlank()) { ++ return loadResource(function.outputSchemaResource()); ++ } ++ if (function != null && !function.outputSchema().isBlank() ++ && !"{}".equals(function.outputSchema().trim())) { ++ return parse(function.outputSchema(), "McpFunction.outputSchema"); ++ } ++ if (responseType != null && responseType.isAnnotationPresent(McpOutputSchema.class)) { ++ return JsonSchemaGenerator.generateSchema(responseType); ++ } ++ return Map.of(); ++ } ++ ++ /** ++ * Retained for callers that use only explicit output schemas. ++ */ ++ public Map resolveOutput(McpFunction function) { ++ return resolveOutput(function, null); ++ } ++ + private Map loadResource(String location) { + String path = location.startsWith("classpath:") + ? location.substring("classpath:".length()) + : location; + ClassPathResource resource = new ClassPathResource(path); + if (!resource.exists()) { +- throw new IllegalStateException("MCP input schema resource not found: " + location); ++ throw new IllegalStateException("MCP schema resource not found: " + location); + } + + try (InputStream inputStream = resource.getInputStream()) { + return objectMapper.readValue(inputStream, new TypeReference<>() { }); + } catch (Exception e) { +- throw new IllegalStateException("Failed to load MCP input schema resource: " + location, e); ++ throw new IllegalStateException("Failed to load MCP schema resource: " + location, e); + } + } + +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java +index daf0018..ec840ed 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java +@@ -192,14 +192,30 @@ public class BusinessToolController { + } else { + methodResult = targetMethod.invoke(targetBean, invokeArgument); + } ++ ++ Map outputSchema = toolSchemaResolver.resolveOutput(targetFunctionAnnotation, targetMethod.getReturnType()); ++ if (!outputSchema.isEmpty()) { ++ List outputErrors = toolArgumentSchemaValidator.validateValue(outputSchema, methodResult); ++ if (!outputErrors.isEmpty()) { ++ log.error("[Tool] Output schema validation failed. tool={}, errors={}", ++ functionName, outputErrors); ++ Map errorBody = new HashMap<>(); ++ errorBody.put("code", "INVALID_TOOL_RESPONSE"); ++ errorBody.put("message", "Tool response does not match its output schema"); ++ if (finalRequestId != null) { ++ errorBody.put("request_id", finalRequestId); ++ } ++ return ResponseEntity.internalServerError().body(errorBody); ++ } ++ } + + long elapsed = System.currentTimeMillis() - startTime; + + // 5. 寃곌낵 諛섑솚 (?쒖닔 REST ?묐떟) + try { +- log.info("[Tool -> MCP Gateway] ?숈쟻 ???ㅽ뻾 寃곌낵 諛섑솚: {}", objectMapper.writeValueAsString(methodResult)); ++ log.info("[Tool -> MCP Gateway] Output Schema Result: {}", objectMapper.writeValueAsString(methodResult)); + } catch (Exception e) { +- log.info("[Tool -> MCP Gateway] ?숈쟻 ???ㅽ뻾 寃곌낵 諛섑솚: {}", methodResult); ++ log.info("[Tool -> MCP Gateway] Output Schema Result: {}", methodResult); + } + + log.info(" [Tool] OUT - trace-id: {}, request-id: {}", traceId, requestId); +diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/ToolArgumentSchemaValidator.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/ToolArgumentSchemaValidator.java +index 876144c..59c68ff 100644 +--- a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/ToolArgumentSchemaValidator.java ++++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/presentation/ToolArgumentSchemaValidator.java +@@ -21,8 +21,12 @@ public class ToolArgumentSchemaValidator { + } + + public List validate(Map schemaDefinition, Map arguments) throws Exception { ++ return validateValue(schemaDefinition, arguments); ++ } ++ ++ public List validateValue(Map schemaDefinition, Object value) throws Exception { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = schemaRegistry.getSchema(objectMapper.writeValueAsString(schemaDefinition)); +- return schema.validate(objectMapper.writeValueAsString(arguments), InputFormat.JSON); ++ return schema.validate(objectMapper.writeValueAsString(value), InputFormat.JSON); + } + } +diff --git a/dap-tool-core/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java b/dap-tool-core/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java +index 6737a00..bc05f05 100644 +--- a/dap-tool-core/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java ++++ b/dap-tool-core/src/test/java/io/shinhanlife/dap/lib/util/ToolSchemaResolverTest.java +@@ -5,6 +5,8 @@ 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; +@@ -15,66 +17,103 @@ class ToolSchemaResolverTest { + private final ToolSchemaResolver resolver = new ToolSchemaResolver(new ObjectMapper()); + + @Test +- void usesExplicitSchemaResourceBeforeAutomaticDtoSchema() throws Exception { +- Method method = SchemaBackedTool.class.getDeclaredMethod("search", AutoGeneratedRequest.class); +- McpFunction function = method.getAnnotation(McpFunction.class); ++ void usesInlineSchemaBeforeAutomaticDtoSchema() throws Exception { ++ Method method = InlineSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class); + +- Map schema = resolver.resolve(function, AutoGeneratedRequest.class); ++ Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutomaticRequest.class); + + assertEquals(false, schema.get("additionalProperties")); +- assertTrue(schema.containsKey("anyOf")); +- assertEquals(50, ((Map) ((Map) schema.get("properties")).get("size")).get("maximum")); +- assertEquals(List.of(Map.of("required", List.of("claimNo"))), schema.get("anyOf")); ++ assertTrue(!properties(schema).containsKey("differentField")); + } + ++ @Test ++ void generatesSchemaFromRequestDtoWhenNoExplicitSchemaIsConfigured() throws Exception { ++ Method method = AutomaticSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class); + +- /* Inline schema resolution is covered by the same resolver branch at integration level. +- void usesInlineSchemaBeforeAutomaticDtoSchema() throws Exception { +- Method method = InlineSchemaTool.class.getDeclaredMethod("search", AutoGeneratedRequest.class); ++ Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutomaticRequest.class); + +- Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutoGeneratedRequest.class); ++ assertTrue(properties(schema).containsKey("differentField")); ++ } + +- assertEquals("object", schema.get("type")); ++ @Test ++ void resolvesExplicitOutputSchema() throws Exception { ++ Method method = OutputSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class); ++ Map schema = resolver.resolveOutput(method.getAnnotation(McpFunction.class)); + assertEquals(false, schema.get("additionalProperties")); +- assertTrue(!((Map) schema.get("properties")).containsKey("differentField")); ++ assertTrue(properties(schema).containsKey("resultCode")); + } + +- */ + @Test +- void generatesSchemaFromRequestDtoWhenNoExplicitSchemaIsConfigured() throws Exception { +- Method method = SchemaBackedTool.AutomaticSchemaTool.class.getDeclaredMethod("search", AutoGeneratedRequest.class); ++ void generatesOutputSchemaFromMarkedResponseDto() throws Exception { ++ Method method = AutomaticOutputSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class); + +- Map schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutoGeneratedRequest.class); ++ Map schema = resolver.resolveOutput( ++ method.getAnnotation(McpFunction.class), SimpleResponse.class); + +- assertTrue(((Map) schema.get("properties")).containsKey("differentField")); ++ assertEquals(List.of("resultCode"), schema.get("required")); ++ assertEquals(List.of("SUCCESS", "FAILURE"), property(schema, "resultCode").get("enum")); + } + +- static class InlineSchemaTool { ++ @Test ++ void doesNotEnableOutputValidationWhenOutputSchemaIsNotDeclared() throws Exception { ++ Method method = AutomaticSchemaTool.class.getDeclaredMethod("search", AutomaticRequest.class); ++ Map schema = resolver.resolveOutput( ++ method.getAnnotation(McpFunction.class), AutomaticRequest.class); ++ assertTrue(schema.isEmpty()); ++ } ++ @SuppressWarnings("unchecked") ++ private Map properties(Map schema) { ++ return (Map) schema.get("properties"); ++ } ++ ++ @SuppressWarnings("unchecked") ++ private Map property(Map schema, String name) { ++ return (Map) properties(schema).get(name); ++ } + +- @McpFunction(displayName = "inline", name = "sample.inline", description = "inline", inputSchema = "{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{},\\\"additionalProperties\\\":false}") +- void search(AutoGeneratedRequest request) { ++ static class InlineSchemaTool { ++ @McpFunction( ++ displayName = "inline", ++ name = "sample.inline", ++ description = "inline schema", ++ inputSchema = "{\"type\":\"object\",\"properties\":{\"keyword\":{\"type\":\"string\"}},\"additionalProperties\":false}") ++ void search(AutomaticRequest request) { + } + } +- static class SchemaBackedTool { + + static class AutomaticSchemaTool { ++ @McpFunction(displayName = "automatic", name = "sample.automatic", description = "automatic schema") ++ void search(AutomaticRequest request) { ++ } ++ } + +- @McpFunction(displayName = "automatic", name = "sample.automatic", description = "automatic") +- void search(AutoGeneratedRequest request) { ++ static class AutomaticOutputSchemaTool { ++ @McpFunction(displayName = "automatic-output", name = "sample.automatic-output", description = "automatic output") ++ 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 = "泥?뎄 議고쉶", +- name = "processing.claim.search", +- description = "蹂댄뿕湲?泥?뎄瑜?議고쉶?쒕떎.", +- inputSchemaResource = "classpath:tool-schemas/claim-search-input-schema.json") +- void search(AutoGeneratedRequest request) { ++ displayName = "output", ++ name = "sample.output", ++ description = "output schema", ++ outputSchema = "{\"type\":\"object\",\"properties\":{\"resultCode\":{\"type\":\"string\"}},\"required\":[\"resultCode\"],\"additionalProperties\":false}") ++ void search(AutomaticRequest request) { + } + } + +- static class AutoGeneratedRequest { ++ static class AutomaticRequest { + private String differentField; + } + } +diff --git a/dap-tool-core/src/test/resources/tool-schemas/claim-search-input-schema.json b/dap-tool-core/src/test/resources/tool-schemas/claim-search-input-schema.json +deleted file mode 100644 +index e595b42..0000000 +--- a/dap-tool-core/src/test/resources/tool-schemas/claim-search-input-schema.json ++++ /dev/null +@@ -1,20 +0,0 @@ +-{ +- "$schema": "https://json-schema.org/draft/2020-12/schema", +- "type": "object", +- "properties": { +- "claimNo": { +- "type": "string", +- "pattern": "^CLM[0-9]{13}$" +- }, +- "size": { +- "type": "integer",R +- "minimum": 1, +- "maximum": 50, +- "default": 20 +- } +- }, +- "additionalProperties": false, +- "anyOf": [ +- { "required": ["claimNo"] } +- ] +-} +diff --git a/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java +new file mode 100644 +index 0000000..abd2d2d +--- /dev/null ++++ b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchResponse.java +@@ -0,0 +1,88 @@ ++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 java.util.List; ++import lombok.AllArgsConstructor; ++import lombok.Builder; ++import lombok.Getter; ++import lombok.NoArgsConstructor; ++import lombok.Setter; ++ ++/** ++ * Claim search response sample. ++ * Complex response rules are defined by outputSchemaResource; annotations document ++ * the same simple field constraints for automatic schema generation examples. ++ */ ++@Getter ++@Setter ++@Builder ++@NoArgsConstructor ++@AllArgsConstructor ++@McpOutputSchema ++public class ClaimSearchResponse { ++ ++ @McpParameter(description = "Execution result code.") ++ @McpValidation(required = true, allowedValues = {"SUCCESS", "FAILURE"}) ++ private String resultCode; ++ ++ @McpParameter(description = "User-readable label for resultCode.") ++ @McpValidation(required = true, maxLength = 100) ++ private String resultLabel; ++ ++ @McpParameter(description = "Current claim processing status code.") ++ @McpValidation(required = true, allowedValues = { ++ "RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", ++ "APPROVED", "PAID", "REJECTED", "WITHDRAWN" ++ }) ++ private String status; ++ ++ @McpParameter(description = "User-readable label for status.") ++ @McpValidation(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) ++ private Long approvedAmount; ++ ++ @McpParameter(description = "Present only when status is REJECTED; otherwise null.") ++ @McpValidation(maxLength = 200, nullable = true) ++ private String rejectionReason; ++ ++ @McpParameter(description = "Claim summaries, ordered by received date descending.") ++ @McpValidation(required = true) ++ private List items; ++ ++ @McpParameter(description = "True when additional results exist beyond this response.") ++ @McpValidation(required = true) ++ private Boolean hasMore; ++ ++ @McpParameter(description = "Total number of matched claims.") ++ @McpValidation(required = true, minimum = 0) ++ private Integer totalCount; ++ ++ @Getter ++ @Setter ++ @Builder ++ @NoArgsConstructor ++ @AllArgsConstructor ++ public static class ClaimSummary { ++ ++ @McpParameter(description = "Claim processing status code.") ++ @McpValidation(required = true) ++ private String status; ++ ++ @McpParameter(description = "User-readable label for status.") ++ @McpValidation(required = true) ++ private String statusLabel; ++ ++ @McpParameter(description = "Received date in YYYY-MM-DD format.") ++ @McpValidation(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) ++ private Long approvedAmount; ++ } ++} +\ No newline at end of file +diff --git a/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java +index 16d1aa0..9a55c1a 100644 +--- a/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java ++++ b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/ClaimSearchSchemaSampleUseCase.java +@@ -3,6 +3,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase; + import io.shinhanlife.dap.lib.annotation.McpFunction; + import io.shinhanlife.dap.lib.annotation.McpTool; + import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchRequest; ++import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse; + + @McpTool( + routingType = "DIRECT", +@@ -12,13 +13,14 @@ public interface ClaimSearchSchemaSampleUseCase { + + @McpFunction( + register = false, +- displayName = "泥?뎄 議고쉶 JSON Schema ?섑뵆", ++ displayName = "Claim search JSON Schema sample", + name = "sample.claim.search.resource", +- description = "inputSchemaResource瑜??ъ슜?섎뒗 泥?뎄 議고쉶 Tool ?섑뵆?낅땲??", +- prompt = "泥?뎄踰덊샇 ?먮뒗 怨꾩빟踰덊샇濡?蹂댄뿕湲?泥?뎄瑜?議고쉶?댁쨾.", +- inputSchemaResource = "classpath:tool-schemas/claim-search-resource-input-schema.json", ++ 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 + ) +- Object search(ClaimSearchRequest request); +-} ++ ClaimSearchResponse search(ClaimSearchRequest request); ++} +\ No newline at end of file +diff --git a/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ClaimSearchSchemaSampleUseCaseImpl.java b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ClaimSearchSchemaSampleUseCaseImpl.java +index e6cd98b..1a817f5 100644 +--- a/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ClaimSearchSchemaSampleUseCaseImpl.java ++++ b/dap-tool-oth/src/main/java/io/shinhanlife/dap/mcc/biz/cmm/usecase/impl/ClaimSearchSchemaSampleUseCaseImpl.java +@@ -1,22 +1,36 @@ + package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl; + + import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchRequest; ++import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse; + import io.shinhanlife.dap.mcc.biz.cmm.usecase.ClaimSearchSchemaSampleUseCase; +-import java.util.Map; ++import java.util.List; + import org.springframework.stereotype.Service; + + /** +- * inputSchemaResource ?곸슜 諛⑹떇??蹂댁뿬二쇰뒗 鍮꾨끂異??섑뵆 Tool?대떎. +- * ?ㅼ젣 MCI/EIMS ?곕룞?€ 異붽??섏? ?딅뒗?? ++ * Non-exposed sample Tool. It does not call MCI or EIMS. + */ + @Service + public class ClaimSearchSchemaSampleUseCaseImpl implements ClaimSearchSchemaSampleUseCase { + + @Override +- public Object search(ClaimSearchRequest request) { +- return Map.of( +- "message", "inputSchemaResource JSON Schema sample", +- "request", request == null ? Map.of() : request +- ); ++ public ClaimSearchResponse search(ClaimSearchRequest request) { ++ ClaimSearchResponse.ClaimSummary item = ClaimSearchResponse.ClaimSummary.builder() ++ .status("REVIEWING") ++ .statusLabel("Under review") ++ .receivedDate("2026-08-04") ++ .approvedAmount(null) ++ .build(); ++ ++ return ClaimSearchResponse.builder() ++ .resultCode("SUCCESS") ++ .resultLabel("Success") ++ .status("REVIEWING") ++ .statusLabel("Under review") ++ .approvedAmount(null) ++ .rejectionReason(null) ++ .items(List.of(item)) ++ .hasMore(false) ++ .totalCount(1) ++ .build(); + } +-} ++} +\ No newline at end of file +diff --git a/dap-tool-oth/src/main/resources/tool-schemas/claim-search-resource-input-schema.json b/dap-tool-oth/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json +similarity index 100% +rename from dap-tool-oth/src/main/resources/tool-schemas/claim-search-resource-input-schema.json +rename to dap-tool-oth/src/main/resources/tool-schemas/cmm/claim-search-resource-input-schema.json +diff --git a/dap-tool-oth/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json b/dap-tool-oth/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json +new file mode 100644 +index 0000000..f94c661 +--- /dev/null ++++ b/dap-tool-oth/src/main/resources/tool-schemas/cmm/claim-search-resource-output-schema.json +@@ -0,0 +1,81 @@ ++{ ++ "$schema": "https://json-schema.org/draft/2020-12/schema", ++ "type": "object", ++ "description": "Claim search response. This schema intentionally excludes employee identifiers, customer names, contact details, account information, and other PII.", ++ "properties": { ++ "resultCode": { ++ "type": "string", ++ "enum": ["SUCCESS", "FAILURE"], ++ "description": "Machine-readable execution result code." ++ }, ++ "resultLabel": { ++ "type": "string", ++ "description": "User-readable label for resultCode." ++ }, ++ "status": { ++ "type": "string", ++ "enum": ["RECEIVED", "REVIEWING", "ADDITIONAL_DOC_REQUIRED", "APPROVED", "PAID", "REJECTED", "WITHDRAWN"], ++ "description": "Current claim processing status code." ++ }, ++ "statusLabel": { ++ "type": "string", ++ "description": "User-readable label for status." ++ }, ++ "approvedAmount": { ++ "anyOf": [ ++ { "type": "number", "minimum": 0 }, ++ { "type": "null" } ++ ], ++ "description": "Approved amount. It is null before review and must not be interpreted as zero." ++ }, ++ "rejectionReason": { ++ "type": ["string", "null"], ++ "maxLength": 200, ++ "description": "Has a value only when status is REJECTED. It is null for every other status." ++ }, ++ "items": { ++ "type": "array", ++ "description": "Claim summaries ordered by receivedDate descending. No personally identifiable information is included.", ++ "items": { ++ "type": "object", ++ "properties": { ++ "status": { "type": "string", "description": "Claim status code." }, ++ "statusLabel": { "type": "string", "description": "User-readable label for status." }, ++ "receivedDate": { "type": "string", "format": "date", "description": "Claim received date." }, ++ "approvedAmount": { ++ "anyOf": [ ++ { "type": "number", "minimum": 0 }, ++ { "type": "null" } ++ ], ++ "description": "Null before review; do not interpret as zero." ++ } ++ }, ++ "required": ["status", "statusLabel", "receivedDate"], ++ "additionalProperties": false ++ } ++ }, ++ "hasMore": { ++ "type": "boolean", ++ "description": "True when additional results exist beyond this response." ++ }, ++ "totalCount": { ++ "type": "integer", ++ "minimum": 0, ++ "description": "Total number of matched claims." ++ } ++ }, ++ "required": ["resultCode", "resultLabel", "status", "statusLabel", "items", "hasMore", "totalCount"], ++ "allOf": [ ++ { ++ "if": { ++ "properties": { "status": { "const": "REJECTED" } }, ++ "required": ["status"] ++ }, ++ "then": { ++ "properties": { "rejectionReason": { "type": "string", "minLength": 1 } }, ++ "required": ["rejectionReason"] ++ } ++ } ++ ], ++ "additionalProperties": false ++} +\ No newline at end of file +diff --git a/dap-tool-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java b/dap-tool-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java +index b52e10c..cead062 100644 +--- a/dap-tool-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java ++++ b/dap-tool-oth/src/test/java/io/shinhanlife/dap/mcc/biz/cmm/dto/ClaimSearchRequestSchemaTest.java +@@ -3,7 +3,13 @@ package io.shinhanlife.dap.mcc.biz.cmm.dto; + 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.mcc.biz.cmm.usecase.impl.ClaimSearchSchemaSampleUseCaseImpl; ++import io.shinhanlife.dap.mcc.presentation.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; +@@ -24,8 +30,59 @@ class ClaimSearchRequestSchemaTest { + Map.of("required", List.of("contractNo"))), schema.get("anyOf")); + } + ++ @Test ++ void resolvesSchemaFromToolModuleResource() throws Exception { ++ Method method = ClaimSearchSchemaSampleUseCase.class ++ .getDeclaredMethod("search", ClaimSearchRequest.class); ++ McpFunction function = method.getAnnotation(McpFunction.class); ++ ++ Map schema = new ToolSchemaResolver(new ObjectMapper()) ++ .resolve(function, ClaimSearchRequest.class); ++ ++ assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema")); ++ assertTrue(schema.containsKey("anyOf")); ++ assertEquals(50, property(schema, "size").get("maximum")); ++ } ++ ++ @Test ++ 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); ++ assertEquals("https://json-schema.org/draft/2020-12/schema", schema.get("$schema")); ++ assertTrue(properties(schema).containsKey("resultCode")); ++ assertTrue(properties(schema).containsKey("statusLabel")); ++ assertTrue(properties(schema).containsKey("hasMore")); ++ assertTrue(schema.containsKey("allOf")); ++ } ++ ++ @Test ++ void sampleResponseConformsToOutputSchema() throws Exception { ++ Method method = ClaimSearchSchemaSampleUseCase.class ++ .getDeclaredMethod("search", ClaimSearchRequest.class); ++ Map schema = new ToolSchemaResolver(new ObjectMapper()) ++ .resolveOutput(method.getAnnotation(McpFunction.class)); ++ ++ ClaimSearchResponse response = new ClaimSearchSchemaSampleUseCaseImpl().search(new ClaimSearchRequest()); ++ ToolArgumentSchemaValidator validator = new ToolArgumentSchemaValidator(new ObjectMapper()); ++ ++ assertTrue(validator.validateValue(schema, response).isEmpty()); ++ } ++ @Test ++ void sampleResponseConformsToAutomaticallyGeneratedOutputSchema() throws Exception { ++ Map schema = JsonSchemaGenerator.generateSchema(ClaimSearchResponse.class); ++ ClaimSearchResponse response = new ClaimSearchSchemaSampleUseCaseImpl().search(new ClaimSearchRequest()); ++ ToolArgumentSchemaValidator validator = new ToolArgumentSchemaValidator(new ObjectMapper()); ++ ++ assertTrue(validator.validateValue(schema, response).isEmpty()); ++ } + @SuppressWarnings("unchecked") + private Map> properties(Map schema) { + return (Map>) schema.get("properties"); + } ++ ++ private Map property(Map schema, String name) { ++ return properties(schema).get(name); ++ } + }