refactor: apply Option B, remove heartbeat and register tools once on startup
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 44s
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 44s
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package io.shinhanlife.dap.lib.mcp;
|
||||
|
||||
import io.modelcontextprotocol.server.McpServer;
|
||||
import io.modelcontextprotocol.server.McpSyncServer;
|
||||
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -28,6 +31,15 @@ public class ToolMcpServerConfiguration {
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Creates the Tool Pod MCP server directly with MCP Java SDK 2.0.0. */
|
||||
@Bean(destroyMethod = "close")
|
||||
public McpSyncServer toolMcpServer(HttpServletStreamableServerTransportProvider transportProvider) {
|
||||
return McpServer.sync(transportProvider)
|
||||
.serverInfo("dap-tool-pod", "2.0.0")
|
||||
.capabilities(McpSchema.ServerCapabilities.builder().tools(true).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<HttpServletStreamableServerTransportProvider> toolMcpServlet(
|
||||
HttpServletStreamableServerTransportProvider transportProvider) {
|
||||
|
||||
@@ -24,6 +24,9 @@ import io.shinhanlife.dap.lib.util.ToolSchemaResolver;
|
||||
import io.shinhanlife.dap.lib.metadata.ToolDefinition;
|
||||
import io.shinhanlife.dap.lib.metadata.ToolDefinitionRepository;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -110,12 +113,12 @@ public class ToolRegistryHeartbeatSender {
|
||||
String subToolName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
|
||||
? mcpProperties.getNamespace() + "_" + rawSubToolName
|
||||
: rawSubToolName;
|
||||
// @GrowToolHint(register = false)인 Tool은 메타데이터 조회에는 남기되,
|
||||
// @GrowToolHint인 Tool은 메타데이터 조회에는 남기되,
|
||||
// Gateway 등록 및 heartbeat 전송 대상에서는 제외합니다.
|
||||
// ToolHint가 없는 기존 Tool은 이전 동작과 동일하게 등록합니다.
|
||||
boolean isRegister = hintAnnotation == null || hintAnnotation.register();
|
||||
if (!isRegister) {
|
||||
log.info(" [HeartbeatSender] '{}' Tool is excluded from Gateway registration because register=false. (tool name: {})",
|
||||
log.info(" [HeartbeatSender] '{}' Tool is excluded from Gateway registration because . (tool name: {})",
|
||||
baseName, subToolName);
|
||||
}
|
||||
|
||||
@@ -223,26 +226,30 @@ public class ToolRegistryHeartbeatSender {
|
||||
meta.setOwnerOrg(definition.ownerOrg());
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 30000)
|
||||
public void sendHeartbeats() {
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void registerAllTools() {
|
||||
if (registeredTools.isEmpty()) return;
|
||||
|
||||
for (ToolMetadata tool : registeredTools) {
|
||||
registerTool(tool);
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void deregisterAllTools() {
|
||||
if (registeredTools.isEmpty()) return;
|
||||
|
||||
for (ToolMetadata tool : registeredTools) {
|
||||
try {
|
||||
ResponseEntity<String> response = restClient.post()
|
||||
.uri(gatewayUrl + "/mcp/api/v1/registry/heartbeat")
|
||||
restClient.post()
|
||||
.uri(gatewayUrl + "/mcp/api/v1/registry/deregister")
|
||||
.header("Content-Type", "application/json")
|
||||
|
||||
.body(tool.getUid())
|
||||
.retrieve()
|
||||
.toEntity(String.class);
|
||||
|
||||
if (response.getStatusCode().is2xxSuccessful()) {
|
||||
log.info(" [HeartbeatSender] 하트비트 전송 성공: {}", tool.getUid());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(" [HeartbeatSender] 하트비트 전송 실패 ({}): {}. 재등록을 시도합니다.", tool.getUid(), e.getMessage());
|
||||
registerTool(tool);
|
||||
.toBodilessEntity();
|
||||
log.info(" [HeartbeatSender] 툴 삭제(Deregister) 성공: {}", tool.getUid());
|
||||
} catch (Exception ex) {
|
||||
log.warn(" [HeartbeatSender] 툴 삭제 실패: {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,13 +337,8 @@ public class PodScaffolder {
|
||||
dockerfile: %s/Dockerfile
|
||||
ports:
|
||||
- "%s:%s"
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- TZ=Asia/Seoul
|
||||
- SPRING_REDIS_HOST=redis
|
||||
- SPRING_REDIS_PORT=6379
|
||||
- SPRING_DATA_REDIS_PORT=6379
|
||||
- AXHUB_GATEWAY_URL=http://gateway:8081
|
||||
- AXHUB_TOOL_URL=http://%s:%s
|
||||
- GLOW_COMMUNICATION_MCI_HOST=http://mci-mock
|
||||
|
||||
@@ -425,9 +425,9 @@ public class ToolScaffolder {
|
||||
if (routingType.trim().isEmpty()) {
|
||||
routingType = "HTTP";
|
||||
}
|
||||
String moduleName = getOrAsk(args, 6, scanner, "7. Target module (default dap-was-oth): ");
|
||||
String moduleName = getOrAsk(args, 6, scanner, "7. Target module (default dap-was-cus): ");
|
||||
if (moduleName.trim().isEmpty()) {
|
||||
moduleName = "dap-was-oth";
|
||||
moduleName = "dap-was-cus";
|
||||
}
|
||||
|
||||
String defaultAuthor = System.getProperty("user.name");
|
||||
|
||||
Reference in New Issue
Block a user