forked from kimhyungsik/ax_hub_mcp_tool
Fix: remove remaining dap-tool and gateway legacy strings
This commit is contained in:
@@ -232,7 +232,7 @@ was-oth: http://was-oth:8084
|
|||||||
|
|
||||||
### 현재 Docker 이미지 빌드 제약
|
### 현재 Docker 이미지 빌드 제약
|
||||||
|
|
||||||
`docker-compose.yml`은 새 모듈 경로의 Dockerfile을 사용하지만, 두 Dockerfile 내부의 `COPY` 대상은 여전히 이전 경로인 `dap-tool-oth/build/libs`와 `dap-tool-sms/build/libs`입니다. 따라서 현재 모듈명으로 빌드한 jar를 이미지에 복사하지 못할 수 있습니다. 이 불일치를 수정하기 전에는 `docker compose up --build`를 정상 배포 절차로 간주하면 안 됩니다.
|
`docker-compose.yml`은 새 모듈 경로의 Dockerfile을 사용하지만, 두 Dockerfile 내부의 `COPY` 대상은 여전히 이전 경로인 `dap-was-oth/build/libs`와 `dap-was-sms/build/libs`입니다. 따라서 현재 모듈명으로 빌드한 jar를 이미지에 복사하지 못할 수 있습니다. 이 불일치를 수정하기 전에는 `docker compose up --build`를 정상 배포 절차로 간주하면 안 됩니다.
|
||||||
|
|
||||||
또한 Compose의 Gitea Runner 등록 토큰은 저장소에 직접 두지 말고 배포 환경의 Secret 또는 환경 변수로 주입해야 합니다.
|
또한 Compose의 Gitea Runner 등록 토큰은 저장소에 직접 두지 말고 배포 환경의 Secret 또는 환경 변수로 주입해야 합니다.
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class EaiEimsSender implements EimsSender {
|
|||||||
log.warn(" 로컬 환경이거나 Ka<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
|
log.warn(" 로컬 환경이거나 Ka<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
|
||||||
"<EaiMessage>\n" +
|
"<EaiMessage>\n" +
|
||||||
" <Header>\n" +
|
" <Header>\n" +
|
||||||
" <ChannelId>MCP_GATEWAY_ASYNC</ChannelId>\n" +
|
" <ChannelId>MCP_WAS_ASYNC</ChannelId>\n" +
|
||||||
" <InterfaceId>EAI_BATCH_JOB</InterfaceId>\n" +
|
" <InterfaceId>EAI_BATCH_JOB</InterfaceId>\n" +
|
||||||
" <Timestamp>1782705901850</Timestamp>\n" +
|
" <Timestamp>1782705901850</Timestamp>\n" +
|
||||||
" <TransferType>ASYNC</TransferType>\n" +
|
" <TransferType>ASYNC</TransferType>\n" +
|
||||||
@@ -91,7 +91,7 @@ public class EaiEimsSender implements EimsSender {
|
|||||||
return String.format(
|
return String.format(
|
||||||
"<EaiMessage>" +
|
"<EaiMessage>" +
|
||||||
"<Header>" +
|
"<Header>" +
|
||||||
"<ChannelId>MCP_GATEWAY_ASYNC</ChannelId>" +
|
"<ChannelId>MCP_WAS_ASYNC</ChannelId>" +
|
||||||
"<InterfaceId>%s</InterfaceId>" +
|
"<InterfaceId>%s</InterfaceId>" +
|
||||||
"<Timestamp>%d</Timestamp>" +
|
"<Timestamp>%d</Timestamp>" +
|
||||||
"<TransferType>ASYNC</TransferType>" +
|
"<TransferType>ASYNC</TransferType>" +
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class SwaggerConfig {
|
|||||||
.info(new Info()
|
.info(new Info()
|
||||||
.title("Shinhan MCP WAS API 명세서")
|
.title("Shinhan MCP WAS API 명세서")
|
||||||
.version("v1.0")
|
.version("v1.0")
|
||||||
.description("AI Agent와 신한라이프 내부망(EIMS/EAI)을 연결하는 Adapter Gateway API 문서입니다."))
|
.description("AI Agent와 신한라이프 내부망(EIMS/EAI)을 연결하는 Adapter WAS API 문서입니다."))
|
||||||
.addServersItem(new io.swagger.v3.oas.models.servers.Server().url("http://localhost:8080").description("Adapter Pod (8080)"))
|
.addServersItem(new io.swagger.v3.oas.models.servers.Server().url("http://localhost:8080").description("Adapter Pod (8080)"))
|
||||||
.addServersItem(new io.swagger.v3.oas.models.servers.Server().url("http://localhost:8081").description("WAS Pod"))
|
.addServersItem(new io.swagger.v3.oas.models.servers.Server().url("http://localhost:8081").description("WAS Pod"))
|
||||||
// 전역적으로 X-API-KEY 보안 설정을 Swagger UI에 추가합니다.
|
// 전역적으로 X-API-KEY 보안 설정을 Swagger UI에 추가합니다.
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
// Swagger UI(8080)에서 Gateway(8081)로 API 호출 시 발생하는 CORS 에러 해결
|
// Swagger UI(8080)에서 WAS로 API 호출 시 발생하는 CORS 에러 해결
|
||||||
registry.addMapping("/**")
|
registry.addMapping("/**")
|
||||||
.allowedOriginPatterns("*")
|
.allowedOriginPatterns("*")
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ logging:
|
|||||||
pattern:
|
pattern:
|
||||||
console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger{36} - %msg%n"
|
console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger{36} - %msg%n"
|
||||||
|
|
||||||
# 2. Redis 공통 설정 (Gateway 연동 및 캐싱)
|
# 2. Redis 공통 설정 (WAS 연동 및 캐싱)
|
||||||
spring:
|
spring:
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<div class="flex items-center space-x-5">
|
<div class="flex items-center space-x-5">
|
||||||
<a href="/index.html" class="flex items-center group" style="text-decoration:none;">
|
<a href="/index.html" class="flex items-center group" style="text-decoration:none;">
|
||||||
<div class="w-2 h-2 rounded-full mr-2" style="background:#3b82f6; box-shadow: 0 0 8px rgba(59,130,246,0.8);"></div>
|
<div class="w-2 h-2 rounded-full mr-2" style="background:#3b82f6; box-shadow: 0 0 8px rgba(59,130,246,0.8);"></div>
|
||||||
<span class="font-semibold tracking-tight text-sm" style="color:#f4f4f5;">AXHUB Gateway</span>
|
<span class="font-semibold tracking-tight text-sm" style="color:#f4f4f5;">AXHUB WAS</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="h-4 w-px" style="background:#27272a;"></div>
|
<div class="h-4 w-px" style="background:#27272a;"></div>
|
||||||
<nav class="flex space-x-5 text-[13px] font-medium">
|
<nav class="flex space-x-5 text-[13px] font-medium">
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
function requestId() { return crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(16).slice(2)}`; }
|
function requestId() { return crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(16).slice(2)}`; }
|
||||||
function escapeHtml(value) { return String(value).replace(/[&<>]/g, item => ({'&':'&','<':'<','>':'>'}[item])); }
|
function escapeHtml(value) { return String(value).replace(/[&<>]/g, item => ({'&':'&','<':'<','>':'>'}[item])); }
|
||||||
|
|
||||||
let isGatewayMode = false;
|
let isWasMode = false;
|
||||||
|
|
||||||
async function loadManifest() {
|
async function loadManifest() {
|
||||||
$('manifestStatus').textContent = 'Manifest loading';
|
$('manifestStatus').textContent = 'Manifest loading';
|
||||||
@@ -90,13 +90,13 @@
|
|||||||
if (!response.ok && response.status === 404) {
|
if (!response.ok && response.status === 404) {
|
||||||
// Gateway 환경 감지 및 Fallback 처리
|
// Gateway 환경 감지 및 Fallback 처리
|
||||||
response = await fetch('/mcp/api/v1/tools/list');
|
response = await fetch('/mcp/api/v1/tools/list');
|
||||||
if (!response.ok) throw new Error(`Gateway HTTP ${response.status}`);
|
if (!response.ok) throw new Error(`WAS HTTP ${response.status}`);
|
||||||
|
|
||||||
const rpcData = await response.json();
|
const rpcData = await response.json();
|
||||||
state.tools = rpcData.result?.tools || [];
|
state.tools = rpcData.result?.tools || [];
|
||||||
isGatewayMode = true;
|
isWasMode = true;
|
||||||
|
|
||||||
$('manifestStatus').textContent = `${state.tools.length} tools · Gateway Mode`;
|
$('manifestStatus').textContent = `${state.tools.length} tools · WAS Mode`;
|
||||||
$('manifestStatus').className = 'badge ok';
|
$('manifestStatus').className = 'badge ok';
|
||||||
renderTools();
|
renderTools();
|
||||||
return;
|
return;
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
$('executeButton').disabled = true; $('httpStatus').textContent = '실행 중'; $('httpStatus').className = 'badge';
|
$('executeButton').disabled = true; $('httpStatus').textContent = '실행 중'; $('httpStatus').className = 'badge';
|
||||||
try {
|
try {
|
||||||
let response;
|
let response;
|
||||||
if (isGatewayMode) {
|
if (isWasMode) {
|
||||||
const reqPayload = { jsonrpc: "2.0", method: "tools/call", params: { name: tool.name, arguments: payload }, id: Date.now() };
|
const reqPayload = { jsonrpc: "2.0", method: "tools/call", params: { name: tool.name, arguments: payload }, id: Date.now() };
|
||||||
response = await fetch('/mcp/api/v1/tools/call', {
|
response = await fetch('/mcp/api/v1/tools/call', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -192,7 +192,7 @@
|
|||||||
|
|
||||||
let isOk = response.ok;
|
let isOk = response.ok;
|
||||||
let displayStatus = response.status;
|
let displayStatus = response.status;
|
||||||
if (isGatewayMode && isOk && data?.result?.isError) {
|
if (isWasMode && isOk && data?.result?.isError) {
|
||||||
isOk = false;
|
isOk = false;
|
||||||
displayStatus = "MCP ERR";
|
displayStatus = "MCP ERR";
|
||||||
}
|
}
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
$('httpStatus').textContent = `HTTP ${displayStatus}`; $('httpStatus').className = `badge ${isOk ? 'ok' : 'fail'}`;
|
$('httpStatus').textContent = `HTTP ${displayStatus}`; $('httpStatus').className = `badge ${isOk ? 'ok' : 'fail'}`;
|
||||||
$('latency').textContent = `${elapsed}ms`; $('traceId').textContent = `trace-id: ${response.headers.get('trace-id') || trace}`; $('requestId').textContent = `request-id: ${response.headers.get('request-id') || request}`;
|
$('latency').textContent = `${elapsed}ms`; $('traceId').textContent = `trace-id: ${response.headers.get('trace-id') || trace}`; $('requestId').textContent = `request-id: ${response.headers.get('request-id') || request}`;
|
||||||
let displayData = data;
|
let displayData = data;
|
||||||
if (isGatewayMode && data && typeof data === 'object') {
|
if (isWasMode && data && typeof data === 'object') {
|
||||||
if (data.result && data.result.result) {
|
if (data.result && data.result.result) {
|
||||||
displayData = data.result.result.data !== undefined ? data.result.result.data : data.result.result;
|
displayData = data.result.result.data !== undefined ? data.result.result.data : data.result.result;
|
||||||
} else if (data.error) {
|
} else if (data.error) {
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ class McpRequestHeaderFilterTest {
|
|||||||
@Test
|
@Test
|
||||||
void capturesOptionalMcpHeadersOnlyForTheCurrentRequest() throws Exception {
|
void capturesOptionalMcpHeadersOnlyForTheCurrentRequest() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/mcp");
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/mcp");
|
||||||
request.addHeader("X-Request-Id", "gateway-request-id");
|
request.addHeader("X-Request-Id", "was-request-id");
|
||||||
request.addHeader("trace-id", "trace-001");
|
request.addHeader("trace-id", "trace-001");
|
||||||
request.addHeader("request-id", "tool-request-001");
|
request.addHeader("request-id", "tool-request-001");
|
||||||
request.addHeader("employee-id", "encrypted-employee-id");
|
request.addHeader("employee-id", "encrypted-employee-id");
|
||||||
|
|
||||||
new McpRequestHeaderFilter().doFilter(request, new MockHttpServletResponse(), (req, res) -> {
|
new McpRequestHeaderFilter().doFilter(request, new MockHttpServletResponse(), (req, res) -> {
|
||||||
McpRequestHeaders headers = McpRequestHeaderContext.current();
|
McpRequestHeaders headers = McpRequestHeaderContext.current();
|
||||||
assertEquals("gateway-request-id", headers.headerRequestId());
|
assertEquals("was-request-id", headers.headerRequestId());
|
||||||
assertEquals("trace-001", headers.traceId());
|
assertEquals("trace-001", headers.traceId());
|
||||||
assertEquals("tool-request-001", headers.requestId());
|
assertEquals("tool-request-001", headers.requestId());
|
||||||
assertEquals("encrypted-employee-id", headers.encryptedEmployeeId());
|
assertEquals("encrypted-employee-id", headers.encryptedEmployeeId());
|
||||||
@@ -44,7 +44,7 @@ class McpRequestHeaderFilterTest {
|
|||||||
void forwardsCapturedHeadersToBusinessToolExecution() throws Exception {
|
void forwardsCapturedHeadersToBusinessToolExecution() throws Exception {
|
||||||
BusinessToolController controller = mock(BusinessToolController.class);
|
BusinessToolController controller = mock(BusinessToolController.class);
|
||||||
doReturn(ResponseEntity.ok(Map.of("result", "ok")))
|
doReturn(ResponseEntity.ok(Map.of("result", "ok")))
|
||||||
.when(controller).executeDynamicTool(eq("sampleTool"), eq("gateway-request-id"), eq("trace-001"),
|
.when(controller).executeDynamicTool(eq("sampleTool"), eq("was-request-id"), eq("trace-001"),
|
||||||
eq("tool-request-001"), eq("encrypted-employee-id"), eq(Map.of("key", "value")));
|
eq("tool-request-001"), eq("encrypted-employee-id"), eq(Map.of("key", "value")));
|
||||||
ToolPodMcpToolSynchronizer synchronizer = new ToolPodMcpToolSynchronizer(
|
ToolPodMcpToolSynchronizer synchronizer = new ToolPodMcpToolSynchronizer(
|
||||||
mock(McpSyncServer.class), mock(LocalToolScanner.class), controller, new ObjectMapper());
|
mock(McpSyncServer.class), mock(LocalToolScanner.class), controller, new ObjectMapper());
|
||||||
@@ -53,10 +53,10 @@ class McpRequestHeaderFilterTest {
|
|||||||
"invoke", String.class, McpRequestHeaders.class, Map.class);
|
"invoke", String.class, McpRequestHeaders.class, Map.class);
|
||||||
invoke.setAccessible(true);
|
invoke.setAccessible(true);
|
||||||
invoke.invoke(synchronizer, "sampleTool",
|
invoke.invoke(synchronizer, "sampleTool",
|
||||||
new McpRequestHeaders("gateway-request-id", "trace-001", "tool-request-001", "encrypted-employee-id"),
|
new McpRequestHeaders("was-request-id", "trace-001", "tool-request-001", "encrypted-employee-id"),
|
||||||
Map.of("key", "value"));
|
Map.of("key", "value"));
|
||||||
|
|
||||||
verify(controller).executeDynamicTool("sampleTool", "gateway-request-id", "trace-001",
|
verify(controller).executeDynamicTool("sampleTool", "was-request-id", "trace-001",
|
||||||
"tool-request-001", "encrypted-employee-id", Map.of("key", "value"));
|
"tool-request-001", "encrypted-employee-id", Map.of("key", "value"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ FROM eclipse-temurin:21-jre-alpine
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
ENV TZ=Asia/Seoul
|
ENV TZ=Asia/Seoul
|
||||||
COPY dap-tool-oth/build/libs/*-SNAPSHOT.jar app.jar
|
COPY dap-was-oth/build/libs/*-SNAPSHOT.jar app.jar
|
||||||
EXPOSE 8084
|
EXPOSE 8084
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class SolReqDetailUseCaseImpl implements SolReqDetailUseCase {
|
|||||||
response.setSrName("SOL 연동 모듈 추가 개발");
|
response.setSrName("SOL 연동 모듈 추가 개발");
|
||||||
response.setProcess("진행중");
|
response.setProcess("진행중");
|
||||||
response.setDevStage("분석/설계");
|
response.setDevStage("분석/설계");
|
||||||
response.setAppName("MCP Gateway");
|
response.setAppName("MCP WAS");
|
||||||
response.setRequester("고석민");
|
response.setRequester("고석민");
|
||||||
response.setRequestDate("2026-07-15");
|
response.setRequestDate("2026-07-15");
|
||||||
response.setDueDate("2026-09-30");
|
response.setDueDate("2026-09-30");
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class SolReqListUseCaseImpl implements SolReqListUseCase {
|
|||||||
item2.setSrName("툴 연동 모듈 추가 개발");
|
item2.setSrName("툴 연동 모듈 추가 개발");
|
||||||
item2.setProcess("진행중");
|
item2.setProcess("진행중");
|
||||||
item2.setDevStage("분석/설계");
|
item2.setDevStage("분석/설계");
|
||||||
item2.setAppName("MCP Gateway");
|
item2.setAppName("MCP WAS");
|
||||||
item2.setRequester("고석민");
|
item2.setRequester("고석민");
|
||||||
list.add(item2);
|
list.add(item2);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM eclipse-temurin:21-jre-alpine
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
ENV TZ=Asia/Seoul
|
ENV TZ=Asia/Seoul
|
||||||
COPY dap-tool-sms/build/libs/*-SNAPSHOT.jar app.jar
|
COPY dap-was-sms/build/libs/*-SNAPSHOT.jar app.jar
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user