diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java index bdb1fa2..28c1427 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java @@ -12,7 +12,6 @@ import io.shinhanlife.axhub.common.mcp.security.SecurityProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; import java.util.Map; import java.util.UUID; @@ -30,7 +29,6 @@ public class McpRouterController { private final ExecuteService executeService; private final SecurityProperties securityProperties; private final ObjectMapper objectMapper; - private final RestTemplate restTemplate = new RestTemplate(); public McpRouterController(RedisRegistryService redisRegistryService, ExecuteService executeService, 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 499d5c1..6b2af24 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 @@ -5,8 +5,7 @@ import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; -import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestClient; import java.util.Map; import java.util.List; @@ -18,7 +17,7 @@ public class ExecuteService { private final ToolPlanner planner; private final KillSwitchService killSwitchService; - private final RestTemplate restTemplate = new RestTemplate(); + private final RestClient restClient = RestClient.create(); public Object execute(Map payload, String tenantId) { log.info(" [ExecuteService] 전체 실행 흐름 제어 시작"); @@ -45,19 +44,33 @@ public class ExecuteService { log.info(" [ExecuteService] 라우팅 목적지: {}", targetUrl); String executeApiUrl = targetUrl + "/mcp/api/v1/tools/call"; - // Forward the request to the target tool pod + // Forward the request to the target tool pod using RestClient with fallback try { - org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders(); - headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON); - headers.set("X-API-KEY", "SHINHAN_MCP_TEST_KEY_9999"); // TODO: Use actual tenant's key - headers.set("X-Trace-Id", java.util.UUID.randomUUID().toString()); - - org.springframework.http.HttpEntity> entity = new org.springframework.http.HttpEntity<>(payload, headers); - ResponseEntity response = restTemplate.postForEntity(executeApiUrl, entity, Object.class); - return response.getBody(); + return executeWithUrl(payload, executeApiUrl); } catch (Exception e) { + if (executeApiUrl.contains("http://tool-")) { + String fallbackUrl = executeApiUrl.replaceAll("http://tool-[a-zA-Z0-9-]+", "http://localhost"); + log.warn(" [ExecuteService] 호스트를 찾을 수 없어 localhost로 재시도합니다: {}", fallbackUrl); + try { + return executeWithUrl(payload, fallbackUrl); + } catch (Exception ex) { + log.error(" [ExecuteService] localhost 재시도 실패: {}", ex.getMessage()); + throw new RuntimeException("Tool Pod 호출 실패 (localhost 재시도 포함): " + ex.getMessage()); + } + } log.error(" [ExecuteService] Tool Pod 호출 실패: {}", e.getMessage()); throw new RuntimeException("Tool Pod 호출 실패: " + e.getMessage()); } } + + private Object executeWithUrl(Map payload, String url) { + return restClient.post() + .uri(url) + .contentType(org.springframework.http.MediaType.APPLICATION_JSON) + .header("X-API-KEY", "SHINHAN_MCP_TEST_KEY_9999") // TODO: Use actual tenant's key + .header("X-Trace-Id", java.util.UUID.randomUUID().toString()) + .body(payload) + .retrieve() + .body(Object.class); + } } \ No newline at end of file diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java index 7ccc81f..8f462f7 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java @@ -100,7 +100,7 @@ public class LegacyEimsConnector { // 2. Circuit Breaker에 의해 차단된 경우 (레거시 시스템 장애/지연) log.error(" [서킷 브레이커 발동] 레거시 통신 차단! 원인: {}", t.getMessage()); return String.format( - "{\"status\":\"CIRCUIT_OPEN\", \"message\":\"신한은행 내부 시스템 장애로 인해 일시적으로 차단되었습니다. 복구 후 재시도 부탁드립니다.\", \"interfaceId\":\"%s\"}", + "{\"status\":\"CIRCUIT_OPEN\", \"message\":\"신한라이프 내부 시스템 장애로 인해 일시적으로 차단되었습니다. 복구 후 재시도 부탁드립니다.\", \"interfaceId\":\"%s\"}", interfaceId ); } diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/ThirdPartySecurityConnector.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/ThirdPartySecurityConnector.java index 7a636d7..6af4545 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/ThirdPartySecurityConnector.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/ThirdPartySecurityConnector.java @@ -21,7 +21,7 @@ public class ThirdPartySecurityConnector { log.info("🔐 [3rd Party Security] 보안 모듈 연동 시작 - Interface: {}", interfaceId); // 보안 모듈 통신을 위한 특수 페이로드 조립 (예시) - // 실제로는 RestTemplate이나 WebClient를 통해 보안 VM의 전용 엔드포인트로 호출합니다. + // 실제로는 RestClient나 WebClient를 통해 보안 VM의 전용 엔드포인트로 호출합니다. String resultJson; diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/util/PiiMaskingUtils.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/util/PiiMaskingUtils.java index 3b11569..a05d846 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/util/PiiMaskingUtils.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/util/PiiMaskingUtils.java @@ -11,8 +11,8 @@ public class PiiMaskingUtils { // 2. 휴대전화번호 패턴 (ex: 010-1234-5678) private static final Pattern PHONE_PATTERN = Pattern.compile("(01[016789])[-]?(\\d{3,4})[-]?(\\d{4})"); - // 3. 신한은행 계좌번호 패턴 (단순 숫자 연속 또는 하이픈 조합으로 11~14자리) - private static final Pattern ACCOUNT_PATTERN = Pattern.compile("(\\d{3})[-]?(\\d{3})[-]?(\\d{5,8})"); + // 3. 신한라이프 계좌/증권번호 패턴 (단순 예시용 계좌번호 11~14자리) + private static final Pattern ACCOUNT_PATTERN = Pattern.compile("(\\d{3}-\\d{3}-\\d{5,8})|(\\d{11,14})"); public static String mask(String input) { if (input == null || input.isEmpty()) {