feat: Add property-based fallback routing for unregistered tools
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
package io.shinhanlife.axhub.biz.mcp.gateway.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "mcp.gateway.fallback")
|
||||||
|
public class GatewayFallbackProperties {
|
||||||
|
private Map<String, String> routes = new HashMap<>();
|
||||||
|
private String defaultUrl;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package io.shinhanlife.axhub.biz.mcp.gateway.service;
|
|||||||
import io.shinhanlife.axhub.common.mcp.security.SecurityProperties;
|
import io.shinhanlife.axhub.common.mcp.security.SecurityProperties;
|
||||||
import io.shinhanlife.axhub.biz.mcp.gateway.registry.RedisRegistryService;
|
import io.shinhanlife.axhub.biz.mcp.gateway.registry.RedisRegistryService;
|
||||||
import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata;
|
import io.shinhanlife.axhub.biz.mcp.gateway.dto.ToolMetadata;
|
||||||
|
import io.shinhanlife.axhub.biz.mcp.gateway.config.GatewayFallbackProperties;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -17,6 +18,7 @@ public class ToolPlanner {
|
|||||||
|
|
||||||
private final RedisRegistryService redisRegistryService;
|
private final RedisRegistryService redisRegistryService;
|
||||||
private final SecurityProperties securityProperties;
|
private final SecurityProperties securityProperties;
|
||||||
|
private final GatewayFallbackProperties fallbackProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 요청(payload)을 분석하여 실행해야 할 Tool의 계획을 생성합니다.
|
* 요청(payload)을 분석하여 실행해야 할 Tool의 계획을 생성합니다.
|
||||||
@@ -37,10 +39,32 @@ public class ToolPlanner {
|
|||||||
var toolMetadata = redisRegistryService.getTool(toolName);
|
var toolMetadata = redisRegistryService.getTool(toolName);
|
||||||
|
|
||||||
if (toolMetadata == null) {
|
if (toolMetadata == null) {
|
||||||
log.warn(" [Planner] 등록되지 않은 툴 요청: {}", toolName);
|
log.warn(" [Planner] 등록되지 않은 툴 요청: {}. Fallback 라우팅 규칙을 확인합니다.", toolName);
|
||||||
|
|
||||||
|
String fallbackPodUrl = fallbackProperties.getDefaultUrl();
|
||||||
|
if (fallbackProperties.getRoutes() != null) {
|
||||||
|
for (Map.Entry<String, String> entry : fallbackProperties.getRoutes().entrySet()) {
|
||||||
|
if (toolName.contains(entry.getKey())) {
|
||||||
|
fallbackPodUrl = entry.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackPodUrl == null || fallbackPodUrl.isEmpty()) {
|
||||||
|
log.error(" [Planner] Fallback 라우팅 대상이 아닙니다. 툴: {}", toolName);
|
||||||
throw new RuntimeException("해당 툴(" + toolName + ")이 레지스트리에 존재하지 않습니다.");
|
throw new RuntimeException("해당 툴(" + toolName + ")이 레지스트리에 존재하지 않습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info(" [Planner] Fallback 라우팅 매칭됨: {} -> {}", toolName, fallbackPodUrl);
|
||||||
|
|
||||||
|
toolMetadata = ToolMetadata.builder()
|
||||||
|
.toolName(toolName)
|
||||||
|
.integrationType("DIRECT")
|
||||||
|
.podUrl(fallbackPodUrl)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
// 2-1. [신규] 도메인 그룹핑 기반 권한 검증
|
// 2-1. [신규] 도메인 그룹핑 기반 권한 검증
|
||||||
if (tenantId != null && toolMetadata.getDomainGroup() != null) {
|
if (tenantId != null && toolMetadata.getDomainGroup() != null) {
|
||||||
List<String> allowedDomains = securityProperties.getTenantDomains().get(tenantId);
|
List<String> allowedDomains = securityProperties.getTenantDomains().get(tenantId);
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
spring.application.name=axhub-admin
|
spring.application.name=axhub-admin
|
||||||
|
spring.main.web-application-type=reactive
|
||||||
|
|
||||||
|
# Gateway Fallback Routing (For unregistered tools)
|
||||||
|
mcp.gateway.fallback.routes.email=http://tool-email:8083
|
||||||
|
mcp.gateway.fallback.routes.sms=http://tool-sms:8082
|
||||||
|
mcp.gateway.fallback.default-url=http://tool-other:8084
|
||||||
|
|
||||||
server.port=8081
|
server.port=8081
|
||||||
server.http2.enabled=true
|
server.http2.enabled=true
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class TemplateUtilityService extends AbstractMcpToolService {
|
|||||||
name = "get_template_file_url",
|
name = "get_template_file_url",
|
||||||
description = "특정 템플릿의 양식 파일(엑셀, 워드 등)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
|
description = "특정 템플릿의 양식 파일(엑셀, 워드 등)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
|
||||||
prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:",
|
prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:",
|
||||||
visible = false
|
register = false
|
||||||
)
|
)
|
||||||
public Map<String, Object> getTemplateFileUrl(TemplateDownloadReq data) {
|
public Map<String, Object> getTemplateFileUrl(TemplateDownloadReq data) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user