From 1a704956865a8dbc1be263d42671f8cfef3d2a7e Mon Sep 17 00:00:00 2001 From: jade Date: Tue, 4 Aug 2026 18:24:52 +0900 Subject: [PATCH] feat(ui): add tool-test-console and tester dashboards - Add Auto-Tester Dashboard (tester.html) in gateway for batch testing tools - Add standalone Tool Test Console (tool-test-console.html) in core - Fix Tailwind CSS Preflight conflicts in console UI - Update console payload schema resolution to support both gateway and pod modes - Strip JSON-RPC metadata from tool payload output in console - Add unified navigation headers across all static HTML pages --- README.md | 16 + .../main/resources/static/admin/scaffold.html | 2 + .../src/main/resources/static/catalog.html | 2 + .../src/main/resources/static/chat.html | 2 + .../src/main/resources/static/playground.html | 2 + .../src/main/resources/static/tester.html | 347 ++++++++++++++++++ .../dap/mcc/manifest/ToolManifestService.java | 9 +- .../resources/static/tool-test-console.html | 260 +++++++++++++ .../ToolTestConsoleResourceTest.java | 24 ++ 9 files changed, 660 insertions(+), 4 deletions(-) create mode 100644 dap-gateway/src/main/resources/static/tester.html create mode 100644 dap-tool-core/src/main/resources/static/tool-test-console.html create mode 100644 dap-tool-core/src/test/java/io/shinhanlife/dap/mcc/presentation/ToolTestConsoleResourceTest.java diff --git a/README.md b/README.md index acc561d2..650cddc6 100644 --- a/README.md +++ b/README.md @@ -588,3 +588,19 @@ oth.smp.weather.inquiry ``` When Scaffold receives `dap-tool-oth`, `cmm`, and `ClaimSearch`, it generates `oth.cmm.claim.search`. The `validateMcpToolNames` Gradle task rejects both a duplicate name and any name outside this format before packaging, including its source file and line number. + +### Tool Test Console + +각 Tool Pod는 공통 테스트 화면을 제공합니다. + +```text +http://localhost:8084/tool-test-console.html +``` + +화면은 현재 Pod의 `/tool-manifest`에서 Tool 목록과 `inputSchema`를 읽습니다. Tool을 선택한 뒤 `Schema 샘플 채우기`로 요청 JSON을 만들고 실행할 수 있습니다. 업무에 맞게 보정한 요청은 `현재 요청 저장`으로 브라우저의 `localStorage`에 보관합니다. + +`Run saved cases`는 저장된 테스트 케이스를 순차 실행해 성공/실패, HTTP 상태, 소요 시간을 보여줍니다. 따라서 Tool이 수백 개여도 각 Tool마다 테스트 화면을 만들 필요 없이, 유효한 업무 테스트 데이터만 한 번 저장하면 이후에는 몇 번의 클릭으로 회귀 테스트할 수 있습니다. + +- Tool 호출은 현재 Pod의 `/mcp/{toolName}`로 수행합니다. +- 매 실행마다 `trace-id`, `request-id`를 새로 생성하여 응답과 함께 표시합니다. +- 외부 MCI/EAI Tool은 샘플값 대신 개발계에서 허용된 테스트 데이터를 저장해서 사용해야 합니다. diff --git a/dap-gateway/src/main/resources/static/admin/scaffold.html b/dap-gateway/src/main/resources/static/admin/scaffold.html index cea50134..1c05d10e 100644 --- a/dap-gateway/src/main/resources/static/admin/scaffold.html +++ b/dap-gateway/src/main/resources/static/admin/scaffold.html @@ -381,6 +381,8 @@ Catalog Playground Chat + Tester + Console
diff --git a/dap-gateway/src/main/resources/static/catalog.html b/dap-gateway/src/main/resources/static/catalog.html index 11371ef1..b13da770 100644 --- a/dap-gateway/src/main/resources/static/catalog.html +++ b/dap-gateway/src/main/resources/static/catalog.html @@ -70,6 +70,8 @@ Catalog Playground Chat + Tester + Console
diff --git a/dap-gateway/src/main/resources/static/chat.html b/dap-gateway/src/main/resources/static/chat.html index d166de4d..70b21172 100644 --- a/dap-gateway/src/main/resources/static/chat.html +++ b/dap-gateway/src/main/resources/static/chat.html @@ -57,6 +57,8 @@ Catalog Playground Chat + Tester + Console
diff --git a/dap-gateway/src/main/resources/static/playground.html b/dap-gateway/src/main/resources/static/playground.html index 028d8590..4c2a7efe 100644 --- a/dap-gateway/src/main/resources/static/playground.html +++ b/dap-gateway/src/main/resources/static/playground.html @@ -112,6 +112,8 @@ Catalog Playground Chat + Tester + Console
diff --git a/dap-gateway/src/main/resources/static/tester.html b/dap-gateway/src/main/resources/static/tester.html new file mode 100644 index 00000000..3e21e53a --- /dev/null +++ b/dap-gateway/src/main/resources/static/tester.html @@ -0,0 +1,347 @@ + + + + + + Tool Auto Tester + + + + + + +
+
+ +
+ v0.0.1 +
+
+
+ +
+
+
+

Auto-Tester Dashboard

+

Batch execute all registered tools with auto-generated dummy data to verify stability.

+
+
+ + +
+
+ +
+
+
Tool List
+
Total: 0 / Completed: 0
+
+
+ + + + + + + + + + + + + + + +
CategoryTool NameAuto-Generated PayloadStatusAction
Loading tools...
+
+
+
+ + + + diff --git a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/manifest/ToolManifestService.java b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/manifest/ToolManifestService.java index aa3d42db..75df12df 100644 --- a/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/manifest/ToolManifestService.java +++ b/dap-tool-core/src/main/java/io/shinhanlife/dap/mcc/manifest/ToolManifestService.java @@ -12,6 +12,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -21,6 +22,7 @@ import org.springframework.stereotype.Service; public class ToolManifestService { private static final long DEFAULT_TIMEOUT_MILLIS = 300000L; + private static final AtomicLong LAST_ISSUED_REVISION = new AtomicLong(); private final Supplier> toolSupplier; private final ObjectMapper objectMapper; private final McpProperties properties; @@ -89,10 +91,9 @@ public class ToolManifestService { private synchronized String revision(String bundleId, List tools) { String fingerprint = fingerprint(bundleId, tools); if (!fingerprint.equals(lastFingerprint)) { - long nextTimestamp = System.currentTimeMillis(); - if (lastRevision != null) { - nextTimestamp = Math.max(nextTimestamp, Long.parseLong(lastRevision) + 1); - } + long localMinimum = lastRevision == null ? Long.MIN_VALUE : Long.parseLong(lastRevision) + 1; + long nextTimestamp = LAST_ISSUED_REVISION.updateAndGet(previous -> + Math.max(Math.max(System.currentTimeMillis(), localMinimum), previous + 1)); lastFingerprint = fingerprint; lastRevision = Long.toString(nextTimestamp); } diff --git a/dap-tool-core/src/main/resources/static/tool-test-console.html b/dap-tool-core/src/main/resources/static/tool-test-console.html new file mode 100644 index 00000000..951eda99 --- /dev/null +++ b/dap-tool-core/src/main/resources/static/tool-test-console.html @@ -0,0 +1,260 @@ + + + + + + AX HUB Tool Test Console + + + + + +
+
+ +
+ Manifest loading + v0.0.1 +
+
+
+
+

Schema 기반 Tool 테스트

Tool을 선택하고 요청 JSON을 확인한 뒤 실행하세요. 검증한 요청은 브라우저에 저장되며, 저장된 케이스 전체를 한 번에 다시 실행할 수 있습니다.

+
+ +
+

2. 요청 JSON

필수값과 형식은 Tool의 inputSchema 기준입니다. MCI·외부 연동 Tool은 업무에 맞는 테스트 데이터를 입력한 후 저장하세요.
+

3. 실행 결과

대기-trace-id: -request-id: -
Tool을 선택하고 실행하세요.
+
+
+ +
+ + + \ No newline at end of file diff --git a/dap-tool-core/src/test/java/io/shinhanlife/dap/mcc/presentation/ToolTestConsoleResourceTest.java b/dap-tool-core/src/test/java/io/shinhanlife/dap/mcc/presentation/ToolTestConsoleResourceTest.java new file mode 100644 index 00000000..6c21272c --- /dev/null +++ b/dap-tool-core/src/test/java/io/shinhanlife/dap/mcc/presentation/ToolTestConsoleResourceTest.java @@ -0,0 +1,24 @@ +package io.shinhanlife.dap.mcc.presentation; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class ToolTestConsoleResourceTest { + + @Test + void publishesManifestDrivenToolTestConsole() throws Exception { + try (InputStream resource = getClass().getResourceAsStream("/static/tool-test-console.html")) { + assertNotNull(resource); + String html = new String(resource.readAllBytes(), StandardCharsets.UTF_8); + + assertTrue(html.contains("/tool-manifest")); + assertTrue(html.contains("Run saved cases")); + assertTrue(html.contains("localStorage")); + assertTrue(html.contains("request-id")); + } + } +} \ No newline at end of file