diff --git a/axhub-common/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java b/axhub-common/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java index c3350bb..9492b45 100644 --- a/axhub-common/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java +++ b/axhub-common/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java @@ -62,6 +62,10 @@ public class ToolMetadata { @Builder.Default private Boolean isRegistered = true; + // 2-6. HITL 승인 필요 여부 + @Builder.Default + private Boolean requiresApproval = false; + public boolean isVisible() { return visible != null ? visible : true; } @@ -74,6 +78,10 @@ public class ToolMetadata { this.isRegistered = isRegistered; } + public boolean isRequiresApproval() { + return requiresApproval != null ? requiresApproval : false; + } + // 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI) private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI" diff --git a/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolScaffolder.java b/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolScaffolder.java index 3836b60..ef318c9 100644 --- a/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolScaffolder.java +++ b/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolScaffolder.java @@ -190,7 +190,8 @@ public class ToolScaffolder { description = "%s", prompt = "%s", mappingId = "%s", - register = %s + register = %s, + requiresApproval = false ) public Object execute(%sReq req) { return executeLegacy("%s", "%s", req); diff --git a/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolSourceUpdater.java b/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolSourceUpdater.java index eae8a86..15d518a 100644 --- a/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolSourceUpdater.java +++ b/axhub-common/src/main/java/io/shinhanlife/axhub/common/util/ToolSourceUpdater.java @@ -12,7 +12,7 @@ import java.util.stream.Stream; public class ToolSourceUpdater { - public static void updateToolSource(String toolName, String domainGroup, String description, boolean register) throws Exception { + public static void updateToolSource(String toolName, String domainGroup, String description, boolean register, Boolean requiresApproval) throws Exception { // 1. Find all *Service.java files in axhub-tool-* directories String envSourceDir = System.getenv("AXHUB_SOURCE_DIR"); Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get("."); @@ -87,6 +87,21 @@ public class ToolSourceUpdater { } } + // 5.5 Update requiresApproval flag + if (requiresApproval != null) { + Pattern appPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"[^)]*requiresApproval\\s*=\\s*)(true|false)([^a-zA-Z0-9])", Pattern.DOTALL); + Matcher appMatcher = appPattern.matcher(content); + if (appMatcher.find()) { + content = appMatcher.replaceFirst("$1" + requiresApproval + "$3"); + } else { + Pattern addAppPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\")", Pattern.DOTALL); + Matcher addAppMatcher = addAppPattern.matcher(content); + if (addAppMatcher.find()) { + content = addAppMatcher.replaceFirst("$1, requiresApproval = " + requiresApproval); + } + } + } + // 6. Write back to file Files.writeString(targetFile, content); } diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java index 08060aa..c0ee30c 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java @@ -62,6 +62,10 @@ public class ToolMetadata { @Builder.Default private Boolean isRegistered = true; + // 2-6. HITL 승인 필요 여부 + @Builder.Default + private Boolean requiresApproval = false; + public boolean isVisible() { return visible != null ? visible : true; } @@ -74,6 +78,10 @@ public class ToolMetadata { this.isRegistered = isRegistered; } + public boolean isRequiresApproval() { + return requiresApproval != null ? requiresApproval : false; + } + // 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI) private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI" 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 0ab7c20..96dff74 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 @@ -51,8 +51,9 @@ public class ScaffoldingController { String domainGroup = req.get("domainGroup"); String description = req.get("description"); 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); + io.shinhanlife.axhub.common.util.ToolSourceUpdater.updateToolSource(toolName, domainGroup, description, register, requiresApproval); return "성공"; } catch (Exception e) { return "오류 발생: " + e.getMessage(); diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java index 8ee4db3..0997418 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java @@ -19,4 +19,7 @@ public @interface McpFunction { // 추가: 툴 목록 노출 여부 제어 (false 시 라우팅은 되나 목록에서 숨김) boolean visible() default true; + + // 추가: HITL 승인 체계 지원 (실행 전 사용자 승인 필요 여부) + boolean requiresApproval() default false; } diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java index ac84b20..6a767b5 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java @@ -45,6 +45,9 @@ public class ToolMetadata { @Builder.Default private Boolean isRegistered = true; + @Builder.Default + private Boolean requiresApproval = false; + public boolean isVisible() { return visible != null ? visible : true; } @@ -57,4 +60,8 @@ public class ToolMetadata { this.isRegistered = isRegistered; } + public boolean isRequiresApproval() { + return requiresApproval != null ? requiresApproval : false; + } + } \ 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 a44c5bf..23c750c 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 @@ -101,6 +101,7 @@ public class ToolRegistryHeartbeatSender { boolean isVisible = functionAnnotation.visible(); meta.setVisible(isVisible); meta.setRegistered(isRegister); + meta.setRequiresApproval(functionAnnotation.requiresApproval()); Map prompts = new HashMap<>(); String promptText = functionAnnotation.prompt();