diff --git a/axhub-common/src/main/java/io/shinhanlife/axhub/common/mcp/exception/GlobalExceptionHandler.java b/axhub-common/src/main/java/io/shinhanlife/axhub/common/mcp/exception/GlobalExceptionHandler.java index 18866e2..841fc86 100644 --- a/axhub-common/src/main/java/io/shinhanlife/axhub/common/mcp/exception/GlobalExceptionHandler.java +++ b/axhub-common/src/main/java/io/shinhanlife/axhub/common/mcp/exception/GlobalExceptionHandler.java @@ -6,27 +6,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; -/** - * @package io.shinhanlife.axhub.common.mcp.exception - * @className GlobalExceptionHandler - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @RestControllerAdvice // 이 어노테이션이 전역 적용의 핵심입니다! public class GlobalExceptionHandler { - @ExceptionHandler(org.springframework.web.servlet.resource.NoResourceFoundException.class) - public ResponseEntity handleNoResourceFound(org.springframework.web.servlet.resource.NoResourceFoundException e) { + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity handleNoResourceFound(NoResourceFoundException e) { log.warn(" [Gateway Not Found] 요청하신 리소스를 찾을 수 없습니다: {}", e.getResourcePath()); return ResponseEntity.notFound().build(); } diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/AxHubGatewayApplication.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/AxHubGatewayApplication.java index 15d5b4d..350c71d 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/AxHubGatewayApplication.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/AxHubGatewayApplication.java @@ -2,24 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; -/** - * @package io.shinhanlife.axhub.biz.mcp.gateway - * @className AxHubGatewayApplication - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.gateway", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.gateway", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.gateway", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class AxHubGatewayApplication { public static void main(String[] args) { diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/McpRouterController.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/McpRouterController.java index b819fcb..66b0834 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/McpRouterController.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/McpRouterController.java @@ -4,39 +4,29 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.axhub.biz.mcp.adapter.dto.JsonRpcRequest; import io.shinhanlife.axhub.biz.mcp.adapter.dto.JsonRpcResponse; import io.shinhanlife.axhub.biz.mcp.adapter.dto.Params; -import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata; -import io.shinhanlife.axhub.biz.mcp.gateway.service.ExecuteService; import io.shinhanlife.axhub.biz.mcp.gateway.config.GatewayFallbackProperties; +import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata; import io.shinhanlife.axhub.biz.mcp.gateway.registry.RedisRegistryService; +import io.shinhanlife.axhub.biz.mcp.gateway.service.ExecuteService; import io.shinhanlife.axhub.common.mcp.security.SecurityProperties; - -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.web.client.RestClient; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; -import java.util.UUID; -import java.util.List; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestClient; -/** - * @package io.shinhanlife.axhub.biz.mcp.gateway.presentation - * @className McpRouterController - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @RestController @RequestMapping("/mcp/api/v1") @@ -72,8 +62,8 @@ public class McpRouterController { @RequestBody Map payload, @RequestAttribute(value = "tenantId", required = false) String tenantId) { - java.util.Map meta = new java.util.HashMap<>(); - meta.put("traceId", traceId != null ? traceId : java.util.UUID.randomUUID().toString()); + Map meta = new HashMap<>(); + meta.put("traceId", traceId != null ? traceId : UUID.randomUUID().toString()); meta.put("agentId", agentId != null ? agentId : "UNKNOWN"); meta.put("userPrompt", userPrompt != null ? userPrompt : ""); payload.put("meta", meta); @@ -110,13 +100,13 @@ public class McpRouterController { List activeTools = redisRegistryService.getAllTools() .stream() .filter(ToolMetadata::getVisible) - .collect(java.util.stream.Collectors.toList()); + .collect(Collectors.toList()); - java.util.Set knownTools = activeTools.stream() + Set knownTools = activeTools.stream() .map(ToolMetadata::getUid) - .collect(java.util.stream.Collectors.toSet()); + .collect(Collectors.toSet()); - java.util.Set fallbackUrls = new java.util.HashSet<>(gatewayFallbackProperties.getRoutes().values()); + Set fallbackUrls = new HashSet<>(gatewayFallbackProperties.getRoutes().values()); if (gatewayFallbackProperties.getDefaultUrl() != null) { fallbackUrls.add(gatewayFallbackProperties.getDefaultUrl()); } @@ -153,20 +143,20 @@ public class McpRouterController { List tools = redisRegistryService.getAllTools() .stream() .filter(ToolMetadata::getVisible) - .collect(java.util.stream.Collectors.toList()); + .collect(Collectors.toList()); StringBuilder md = new StringBuilder(); md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n"); md.append("**총 등록된 툴:** ").append(tools.size()).append("개\n"); - java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - md.append("**마지막 업데이트:** ").append(java.time.LocalDateTime.now().format(formatter)).append("\n\n"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + md.append("**마지막 업데이트:** ").append(LocalDateTime.now().format(formatter)).append("\n\n"); md.append("---\n\n"); // Group by Domain Group - Map> groupedTools = new java.util.HashMap<>(); + Map> groupedTools = new HashMap<>(); for (ToolMetadata tool : tools) { String group = tool.getCategoryKey() != null ? tool.getCategoryKey() : "기타 (Others)"; - groupedTools.computeIfAbsent(group, k -> new java.util.ArrayList<>()).add(tool); + groupedTools.computeIfAbsent(group, k -> new ArrayList<>()).add(tool); } for (Map.Entry> entry : groupedTools.entrySet()) { diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/ScaffoldingController.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/ScaffoldingController.java index 65094d4..7bb97e3 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/ScaffoldingController.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/presentation/ScaffoldingController.java @@ -2,12 +2,15 @@ package io.shinhanlife.axhub.biz.mcp.gateway.presentation; import io.shinhanlife.axhub.common.util.PodScaffolder; import io.shinhanlife.axhub.common.util.ToolScaffolder; -import org.springframework.web.bind.annotation.*; -import java.util.Map; -import java.util.List; -import java.util.Arrays; -import java.util.stream.Collectors; +import io.shinhanlife.axhub.common.util.ToolSourceUpdater; import java.io.File; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/v1/scaffold") @@ -23,7 +26,7 @@ public class ScaffoldingController { String author = req.get("author"); if (author == null || author.trim().isEmpty()) author = System.getProperty("user.name"); String date = req.get("date"); - if (date == null || date.trim().isEmpty()) date = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd")); + if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); return PodScaffolder.scaffoldPod(moduleName, port, shortName, author, date); } catch (Exception e) { @@ -43,7 +46,7 @@ public class ScaffoldingController { String author = req.get("author"); if (author == null || author.trim().isEmpty()) author = System.getProperty("user.name"); String date = req.get("date"); - if (date == null || date.trim().isEmpty()) date = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd")); + if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true")); return ToolScaffolder.scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, date, register); @@ -61,7 +64,7 @@ public class ScaffoldingController { boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true")); Boolean requiresApproval = req.containsKey("requiresApproval") ? Boolean.parseBoolean(req.get("requiresApproval")) : null; - io.shinhanlife.axhub.common.util.ToolSourceUpdater.updateToolSource(toolName, domainGroup, description, register, requiresApproval); + ToolSourceUpdater.updateToolSource(toolName, domainGroup, description, register, requiresApproval); return "성공"; } catch (Exception e) { return "오류 발생: " + e.getMessage(); diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ExecuteService.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ExecuteService.java index d4f0886..f6fefce 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ExecuteService.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ExecuteService.java @@ -2,29 +2,15 @@ package io.shinhanlife.axhub.biz.mcp.gateway.service; import io.shinhanlife.axhub.biz.mcp.adapter.dto.Params; import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata; +import java.util.List; +import java.util.Map; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; -import org.springframework.http.MediaType; -import java.util.Map; -import java.util.List; - -/** - * @package io.shinhanlife.axhub.biz.mcp.gateway.service - * @className ExecuteService - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @Service @RequiredArgsConstructor @@ -83,7 +69,7 @@ public class ExecuteService { .uri(url) .contentType(MediaType.APPLICATION_JSON) // TODO: Use actual tenant's key - .header("X-Trace-Id", java.util.UUID.randomUUID().toString()) + .header("X-Trace-Id", UUID.randomUUID().toString()) .body(payload) .retrieve() .body(Object.class); diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/aop/ToolSlaMonitoringAspect.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/aop/ToolSlaMonitoringAspect.java index a88f7f9..70b821a 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/aop/ToolSlaMonitoringAspect.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/aop/ToolSlaMonitoringAspect.java @@ -2,6 +2,7 @@ package io.shinhanlife.axhub.biz.mcp.tool.aop; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction; import io.shinhanlife.axhub.biz.mcp.tool.config.McpProperties; +import java.lang.reflect.Method; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; @@ -11,22 +12,6 @@ import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; -import java.lang.reflect.Method; - -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.aop - * @className ToolSlaMonitoringAspect - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @Aspect @Component @@ -36,7 +21,7 @@ public class ToolSlaMonitoringAspect { private final McpProperties mcpProperties; // @McpFunction 어노테이션이 붙은 모든 비즈니스 툴 메서드 실행을 가로챕니다. - @Around("@annotation(io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction)") + @Around("@annotation(McpFunction)") public Object monitorToolSla(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/presentation/BusinessToolController.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/presentation/BusinessToolController.java index 971f436..bfe12ff 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/presentation/BusinessToolController.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/presentation/BusinessToolController.java @@ -1,53 +1,38 @@ package io.shinhanlife.axhub.biz.mcp.tool.presentation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.List; -import java.util.ArrayList; - import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; - -import org.springframework.context.ApplicationContext; -import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction; +import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool; import io.shinhanlife.axhub.biz.mcp.tool.config.McpProperties; import io.shinhanlife.axhub.biz.mcp.tool.dto.ToolMetadata; import io.shinhanlife.axhub.biz.mcp.tool.service.ToolRegistryHeartbeatSender; -import java.lang.reflect.Method; import io.shinhanlife.axhub.biz.mcp.tool.util.JsonSchemaGenerator; -import org.springframework.util.ClassUtils; -import org.springframework.aop.support.AopUtils; -import org.springframework.core.annotation.AnnotationUtils; - +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.http.ResponseEntity; +import org.springframework.util.ClassUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.presentation - * @className BusinessToolController - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @RestController @RequestMapping("/") @@ -67,8 +52,8 @@ public class BusinessToolController { // JSON RPC 기반 단일 라우팅 엔드포인트 @PostMapping("/mcp/api/v1/tools/call") - public org.springframework.http.ResponseEntity> executeDynamicTool( - @org.springframework.web.bind.annotation.RequestHeader(value = "X-Request-Id", required = false) String headerRequestId, + public ResponseEntity> executeDynamicTool( + @RequestHeader(value = "X-Request-Id", required = false) String headerRequestId, @RequestBody(required = false) Map payload) { String finalRequestId = headerRequestId != null ? headerRequestId : (payload != null && payload.get("id") != null ? String.valueOf(payload.get("id")) : null); @@ -139,7 +124,7 @@ public class BusinessToolController { error.put("jsonrpc", "2.0"); error.put("error", errorBody); error.put("id", payload != null ? payload.get("id") : null); - return org.springframework.http.ResponseEntity.status(404).body(error); + return ResponseEntity.status(404).body(error); } // (기존 차단 로직 제거됨) @@ -173,7 +158,7 @@ public class BusinessToolController { error.put("jsonrpc", "2.0"); error.put("error", errorBody); error.put("id", payload != null ? payload.get("id") : null); - return org.springframework.http.ResponseEntity.status(422).body(error); + return ResponseEntity.status(422).body(error); } } catch (Exception e) { log.error("[Tool] 스키마 검증 중 오류 발생: {}", e.getMessage()); @@ -243,7 +228,7 @@ public class BusinessToolController { } resultPayload.put("original_size", originalSize); - Map rpcResponse = new java.util.LinkedHashMap<>(); // 순서 보장을 위해 LinkedHashMap 사용 + Map rpcResponse = new LinkedHashMap<>(); // 순서 보장을 위해 LinkedHashMap 사용 rpcResponse.put("jsonrpc", "2.0"); rpcResponse.put("result", resultPayload); rpcResponse.put("id", payload != null ? payload.get("id") : null); @@ -255,7 +240,7 @@ public class BusinessToolController { } - return org.springframework.http.ResponseEntity.ok(rpcResponse); + return ResponseEntity.ok(rpcResponse); } catch (Exception e) { log.error("[Tool] 리플렉션 실행 중 예외 발생: {}", e.getMessage()); @@ -272,7 +257,7 @@ public class BusinessToolController { error.put("jsonrpc", "2.0"); error.put("error", errorBody); error.put("id", payload != null ? payload.get("id") : null); - return org.springframework.http.ResponseEntity.status(502).body(error); + return ResponseEntity.status(502).body(error); } } } \ No newline at end of file diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java index 19576f3..8119ef0 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java @@ -1,47 +1,33 @@ package io.shinhanlife.axhub.biz.mcp.tool.service; +import com.fasterxml.jackson.databind.ObjectMapper; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool; +import io.shinhanlife.axhub.biz.mcp.tool.config.McpProperties; import io.shinhanlife.axhub.biz.mcp.tool.dto.ToolMetadata; import io.shinhanlife.axhub.biz.mcp.tool.util.JsonSchemaGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClient; - -import io.shinhanlife.axhub.biz.mcp.tool.config.McpProperties; - import jakarta.annotation.PostConstruct; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.springframework.util.ClassUtils; +import java.util.UUID; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.ClassUtils; +import org.springframework.web.client.RestClient; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.service - * @className ToolRegistryHeartbeatSender - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @Slf4j @Component @Configuration @@ -92,7 +78,7 @@ public class ToolRegistryHeartbeatSender { } ToolMetadata meta = new ToolMetadata(); - meta.setUid(java.util.UUID.nameUUIDFromBytes(subToolName.getBytes()).toString()); + meta.setUid(UUID.nameUUIDFromBytes(subToolName.getBytes()).toString()); meta.setDisplayName(baseName); meta.setName(subToolName); meta.setSemver("1.0.0"); @@ -141,7 +127,7 @@ public class ToolRegistryHeartbeatSender { for (ToolMetadata tool : registeredTools) { try { - org.springframework.http.ResponseEntity response = restClient.post() + ResponseEntity response = restClient.post() .uri(gatewayUrl + "/mcp/api/v1/registry/heartbeat") .header("Content-Type", "application/json") diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/util/JsonSchemaGenerator.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/util/JsonSchemaGenerator.java index 844827c..47aab9e 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/util/JsonSchemaGenerator.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/util/JsonSchemaGenerator.java @@ -3,22 +3,9 @@ package io.shinhanlife.axhub.biz.mcp.tool.util; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpParameter; import java.lang.reflect.Field; import java.util.HashMap; +import java.util.List; import java.util.Map; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.util - * @className JsonSchemaGenerator - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ public class JsonSchemaGenerator { /** @@ -54,7 +41,7 @@ public class JsonSchemaGenerator { if (clazz == Double.class || clazz == double.class) return "number"; if (clazz == Float.class || clazz == float.class) return "number"; if (clazz == Boolean.class || clazz == boolean.class) return "boolean"; - if (java.util.List.class.isAssignableFrom(clazz)) return "array"; + if (List.class.isAssignableFrom(clazz)) return "array"; return "object"; } } \ No newline at end of file diff --git a/axhub-tool-email/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/email/AxHubToolEmailApplication.java b/axhub-tool-email/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/email/AxHubToolEmailApplication.java index 835e27d..0481255 100644 --- a/axhub-tool-email/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/email/AxHubToolEmailApplication.java +++ b/axhub-tool-email/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/email/AxHubToolEmailApplication.java @@ -2,24 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.email; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.email - * @className AxHubToolEmailApplication - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class AxHubToolEmailApplication { public static void main(String[] args) { diff --git a/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SearchDetailHrReq.java b/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SearchDetailHrReq.java index 86769e3..c7f9268 100644 --- a/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SearchDetailHrReq.java +++ b/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SearchDetailHrReq.java @@ -16,7 +16,7 @@ import lombok.Data; * 2026.07.13 root 최초생성 * * - */ + */1 @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class SearchDetailHrReq { diff --git a/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/hr/HrToolApplication.java b/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/hr/HrToolApplication.java index d3da00b..1c7547c 100644 --- a/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/hr/HrToolApplication.java +++ b/axhub-tool-hr/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/hr/HrToolApplication.java @@ -2,24 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.hr; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.hr - * @className HrToolApplication - * @description AX HUB 시스템 처리 클래스 - * @author root - * @create 2026.07.13 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.07.13  root    최초생성
- *
- * 
- */ @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class HrToolApplication { public static void main(String[] args) { diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/other/AxHubToolOtherApplication.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/other/AxHubToolOtherApplication.java index b85efe4..22ac712 100644 --- a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/other/AxHubToolOtherApplication.java +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/other/AxHubToolOtherApplication.java @@ -2,24 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.other; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.other - * @className AxHubToolOtherApplication - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class AxHubToolOtherApplication { public static void main(String[] args) { diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java index 4122a2c..ac8e29c 100644 --- a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java @@ -3,9 +3,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.service; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction; import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool; import io.shinhanlife.axhub.biz.mcp.tool.dto.TemplateDownloadReq; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.Map; @Slf4j @Service @@ -42,16 +44,16 @@ public class TemplateUtilityService extends AbstractMcpToolService { String fileName = "sample_" + templateId + ".xlsx"; String downloadUrl = "https://axhub-file-server.shinhanlife.io/downloads/" + fileName; - Map result = new java.util.HashMap<>(); + Map result = new HashMap<>(); result.put("status", "success"); - Map contract = new java.util.HashMap<>(); + Map contract = new HashMap<>(); contract.put("fileName", fileName); contract.put("downloadUrl", downloadUrl); contract.put("message", "다운로드 링크가 성공적으로 생성되었습니다. AI는 이 링크를 마크다운 형식으로 사용자에게 전달해야 합니다."); contract.put("status", "success"); - result.put("contracts", java.util.Collections.singletonList(contract)); + result.put("contracts", Collections.singletonList(contract)); return result; } catch (Exception e) { diff --git a/axhub-tool-payment/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/payment/PaymentToolApplication.java b/axhub-tool-payment/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/payment/PaymentToolApplication.java index 9249124..9a85778 100644 --- a/axhub-tool-payment/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/payment/PaymentToolApplication.java +++ b/axhub-tool-payment/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/payment/PaymentToolApplication.java @@ -2,10 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.payment; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class PaymentToolApplication { public static void main(String[] args) { diff --git a/axhub-tool-sms/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/sms/AxHubToolSmsApplication.java b/axhub-tool-sms/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/sms/AxHubToolSmsApplication.java index e5974ed..7d67476 100644 --- a/axhub-tool-sms/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/sms/AxHubToolSmsApplication.java +++ b/axhub-tool-sms/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/sms/AxHubToolSmsApplication.java @@ -2,24 +2,11 @@ package io.shinhanlife.axhub.biz.mcp.tool.sms; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.cache.annotation.EnableCaching; -/** - * @package io.shinhanlife.axhub.biz.mcp.tool.sms - * @className AxHubToolSmsApplication - * @description AX HUB 시스템 처리 클래스 - * @author 김형식 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  김형식    최초생성
- * 
- * 
- */ @SpringBootApplication(scanBasePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) -@org.springframework.boot.context.properties.ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) +@ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.axhub.biz.mcp.tool", "io.shinhanlife.axhub.biz.mcp.adapter", "io.shinhanlife.axhub.common.mcp", "io.shinhanlife.axhub.common.config"}) @EnableCaching public class AxHubToolSmsApplication { public static void main(String[] args) { diff --git a/fix_imports.py b/fix_imports.py new file mode 100644 index 0000000..899d23f --- /dev/null +++ b/fix_imports.py @@ -0,0 +1,106 @@ +import os +import re + +root_dir = "." +target_ext = ".java" + +# Regex to find fully qualified class names +fqcn_pattern = re.compile(r'\b(((?:java\.util|java\.time|java\.io|java\.math|java\.net)\.[a-z0-9.]*?([A-Z]\w+))|(org\.springframework\.[a-z0-9.]*?([A-Z]\w+))|(io\.shinhanlife\.[a-z0-9.]*?([A-Z]\w+)))\b') + +count = 0 + +for subdir, dirs, files in os.walk(root_dir): + if '.git' in dirs: dirs.remove('.git') + if 'build' in dirs: dirs.remove('build') + if '.gradle' in dirs: dirs.remove('.gradle') + + for file in files: + if file.endswith(target_ext): + filepath = os.path.join(subdir, file) + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + lines = content.split('\n') + new_imports = set() + new_lines = [] + modified = False + + in_block_comment = False + + for line in lines: + stripped = line.strip() + + if stripped.startswith('/*'): + in_block_comment = True + + is_comment = in_block_comment or stripped.startswith('//') or stripped.startswith('*') + + if stripped.endswith('*/'): + in_block_comment = False + + if stripped.startswith('import ') or stripped.startswith('package '): + new_lines.append(line) + continue + + if is_comment: + new_lines.append(line) + continue + + def repl(match): + fqcn = match.group(1) + # Extract the simple class name + class_name = match.group(3) or match.group(5) or match.group(7) + + if class_name: + new_imports.add(f"import {fqcn};") + return class_name + return fqcn + + new_line = fqcn_pattern.sub(repl, line) + if new_line != line: + modified = True + new_lines.append(new_line) + + if modified: + existing_imports = set() + insert_idx = 0 + package_line = "" + + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith('package '): + package_line = line + elif stripped.startswith('import '): + existing_imports.add(stripped) + elif stripped == '' or stripped.startswith('//') or stripped.startswith('/*') or stripped.startswith('*'): + continue + elif package_line and not stripped.startswith('import '): + insert_idx = i + break + + all_imports = existing_imports.union(new_imports) + sorted_imports = sorted(list(all_imports)) + + res_lines = [] + if package_line: + res_lines.append(package_line) + res_lines.append('') + + for imp in sorted_imports: + res_lines.append(imp) + + res_lines.append('') + + res_lines.extend(new_lines[insert_idx:]) + + new_content = '\n'.join(res_lines) + + with open(filepath, 'w', encoding='utf-8') as f: + f.write(new_content) + print(f"Fixed imports in: {filepath}") + count += 1 + except Exception as e: + print(f"Error processing {filepath}: {e}") + +print(f"\nTotal files fixed: {count}")