refactor: restructure packages, delete ZtUsac, fix gateway context
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m15s
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 2m15s
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -16,7 +16,7 @@ package io.shinhanlife.dap.mcg.presentation;
|
||||
* </pre>
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,7 +15,7 @@ package io.shinhanlife.dap.mcg.sync;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,7 +15,7 @@ package io.shinhanlife.dap.mcg.tool.large;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.shinhanlife.axhub.common.session.domain.repository.ZtUsacRepository">
|
||||
|
||||
<select id="selectZtUsac" resultType="io.shinhanlife.axhub.common.session.dto.ZtUsacOutDto">
|
||||
|
||||
SELECT
|
||||
AU.PRAF_NO, -- 인사번호
|
||||
AU.PRAF_NM, -- 인사명
|
||||
AU.OGNZ_NO, -- 조직번호
|
||||
OG.OGNZ_NM, -- 조직명
|
||||
AU.ADDRE, -- 이메일주소
|
||||
AU.PRAF_OFDU_CD, -- 인사직무코드
|
||||
AU.PRAF_OFDU_NM, -- 인사직무명
|
||||
AU.PRAF_OFLE_CD, -- 인사직급코드
|
||||
AU.PRAF_OFLE_NM, -- 인사직급명
|
||||
AU.PRAF_DUTY_CD, -- 인사직책코드
|
||||
AU.PRAF_DUTY_NM, -- 인사직책명
|
||||
AU.MNGR_PRAF_NO, -- 관리자인사번호
|
||||
AU.PUSE_YN, -- 사용여부
|
||||
LISTAGG(URR.ROLE_NO, ',') WITHIN GROUP (ORDER BY URR.ROLE_NO) AS ROLE_NO_STR_LIST,
|
||||
LISTAGG(UR.ROLE_NM, ',') WITHIN GROUP (ORDER BY URR.ROLE_NO) AS ROLE_NM_STR_LIST,
|
||||
LISTAGG(AM.TGTR_PRAF_NO, ',') WITHIN GROUP (ORDER BY AM.TGTR_PRAF_NO) AS TGTR_PRAF_NO_STR_LIST,
|
||||
LISTAGG(AM.TGTR_OGNZ_NO, ',') WITHIN GROUP (ORDER BY AM.TGTR_PRAF_NO) AS TGTR_OGNZ_NO_STR_LIST
|
||||
FROM
|
||||
S_EIAM_TIS.AA_USAC AU
|
||||
INNER JOIN
|
||||
S_EIAM_TIS.AA_USAC_USER_GROU_RTNS UGR ON AU.PRAF_NO = UGR.PRAF_NO
|
||||
INNER JOIN
|
||||
S_EIAM_TIS.AA_USER_GROU UG ON UGR.USER_GROU_ID = UG.USER_GROU_ID
|
||||
INNER JOIN
|
||||
S_EIAM_TIS.AA_USER_GROU_ROLE_RTNS URR ON UG.USER_GROU_ID = URR.USER_GROU_ID
|
||||
INNER JOIN
|
||||
S_EIAM_TIS.AA_ROLE UR ON URR.ROLE_NO = UR.ROLE_NO
|
||||
LEFT OUTER JOIN
|
||||
S_EIAM_TIS.AA_MNDT AM ON AM.PRAF_NO = AU.PRAF_NO
|
||||
INNER JOIN
|
||||
S_EIAM_TIS.AA_OGNZ OG ON OG.OGNZ_NO = AU.OGNZ_NO
|
||||
WHERE
|
||||
AU.PRAF_NO = #{prafNo}
|
||||
GROUP BY
|
||||
AU.PRAF_NO, AU.PRAF_NM, AU.OGNZ_NO, AU.ADDRE, AU.PRAF_OFDU_CD, AU.PRAF_OFDU_NM, AU.PRAF_OFLE_CD, AU.PRAF_OFLE_NM, AU.PRAF_DUTY_CD, AU.PRAF_DUTY_NM, AU.MNGR_PRAF_NO, AU.PUSE_YN;
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Mapper(componentModel = "spring")
|
||||
public abstract class ZtUsacConverter {
|
||||
|
||||
@Mapping(target = "loginDtm", ignore = true)
|
||||
@Mapping(target = "isManager", ignore = true)
|
||||
public abstract SessionDto toSessionDto(ZtUsacOutDto dto);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@GlowMybatisMapper
|
||||
public interface ZtUsacRepository {
|
||||
|
||||
/**
|
||||
* 사용자 조회 (단건)
|
||||
*
|
||||
* @param dto 사번
|
||||
* @return 인사정보
|
||||
*/
|
||||
ZtUsacOutDto selectZtUsac(ZtUsacInDto dto);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ZtUsacUseCase {
|
||||
|
||||
/**
|
||||
* 사용자 조회 (단건)
|
||||
*
|
||||
* @param dto 사번
|
||||
* @return 인사정보
|
||||
*/
|
||||
ZtUsacOutDto selectZtUsac(ZtUsacInDto dto);
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ZtUsacInDto {
|
||||
/* 인사번호 */
|
||||
private String prafNo;
|
||||
|
||||
/* 사용여부 */
|
||||
@Builder.Default
|
||||
private String puseYn = "Y";
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@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<String> roleNoList;
|
||||
private List<String> roleNmList;
|
||||
private List<String> tgtrPrafNoList;
|
||||
private List<String> tgtrOgnzNoList;
|
||||
|
||||
public void initLists() {
|
||||
this.roleNoList = convertStrToList(roleNoStrList);
|
||||
this.roleNmList = convertStrToList(roleNmStrList);
|
||||
this.tgtrPrafNoList = convertStrToList(tgtrPrafNoStrList);
|
||||
this.tgtrOgnzNoList = convertStrToList(tgtrOgnzNoStrList);
|
||||
}
|
||||
|
||||
private List<String> convertStrToList(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return Arrays.asList(str.split(","));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@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 <T>
|
||||
* @return
|
||||
*/
|
||||
@GlowControllerId("tempLogin")
|
||||
@PostMapping("/tempLogin")
|
||||
public <T> ResponseEntity<BaseResponse<SsoResponse>> 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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <pre>
|
||||
* ---------- 개정이력 ----------
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.09.01 0986406 최초생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SsoResponse {
|
||||
|
||||
private String retCode;
|
||||
private SessionDto userInfo;
|
||||
private String redirectUrl;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)로 사용됩니다.
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -16,7 +16,7 @@ package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl;
|
||||
* </pre>
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
606
manifest_output.json
Normal file
606
manifest_output.json
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
715
recent_changes.diff
Normal file
715
recent_changes.diff
Normal file
@@ -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<String, Object> 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<String, Object> 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<String, Object> resolveOutput(McpFunction function) {
|
||||
+ return resolveOutput(function, null);
|
||||
+ }
|
||||
+
|
||||
private Map<String, Object> 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<String, Object> outputSchema = toolSchemaResolver.resolveOutput(targetFunctionAnnotation, targetMethod.getReturnType());
|
||||
+ if (!outputSchema.isEmpty()) {
|
||||
+ List<Error> outputErrors = toolArgumentSchemaValidator.validateValue(outputSchema, methodResult);
|
||||
+ if (!outputErrors.isEmpty()) {
|
||||
+ log.error("[Tool] Output schema validation failed. tool={}, errors={}",
|
||||
+ functionName, outputErrors);
|
||||
+ Map<String, Object> 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<Error> validate(Map<String, Object> schemaDefinition, Map<String, Object> arguments) throws Exception {
|
||||
+ return validateValue(schemaDefinition, arguments);
|
||||
+ }
|
||||
+
|
||||
+ public List<Error> validateValue(Map<String, Object> 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<String, Object> schema = resolver.resolve(function, AutoGeneratedRequest.class);
|
||||
+ Map<String, Object> 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<String, Object> schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutomaticRequest.class);
|
||||
|
||||
- Map<String, Object> 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<String, Object> 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<String, Object> schema = resolver.resolve(method.getAnnotation(McpFunction.class), AutoGeneratedRequest.class);
|
||||
+ Map<String, Object> 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<String, Object> schema = resolver.resolveOutput(
|
||||
+ method.getAnnotation(McpFunction.class), AutomaticRequest.class);
|
||||
+ assertTrue(schema.isEmpty());
|
||||
+ }
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ private Map<String, Object> properties(Map<String, Object> schema) {
|
||||
+ return (Map<String, Object>) schema.get("properties");
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ private Map<String, Object> property(Map<String, Object> schema, String name) {
|
||||
+ return (Map<String, Object>) 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<ClaimSummary> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Map<String, Object>> properties(Map<String, Object> schema) {
|
||||
return (Map<String, Map<String, Object>>) schema.get("properties");
|
||||
}
|
||||
+
|
||||
+ private Map<String, Object> property(Map<String, Object> schema, String name) {
|
||||
+ return properties(schema).get(name);
|
||||
+ }
|
||||
}
|
||||
Reference in New Issue
Block a user