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