From 41fed9a03d00280f4d77a06bd1a35365d51a3915 Mon Sep 17 00:00:00 2001 From: hemsej018 Date: Tue, 12 Aug 2025 15:43:17 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=EA=B3=A0=EC=A0=95=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=82=AC=ED=95=AD=20=EC=B6=94=EC=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs25-service/Dockerfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cs25-service/Dockerfile b/cs25-service/Dockerfile index be93749d..b134928b 100644 --- a/cs25-service/Dockerfile +++ b/cs25-service/Dockerfile @@ -30,10 +30,7 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates gnupg bash \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ - && npm install -g @modelcontextprotocol/server-brave-search@0.2.1 \ - && ln -sf "$(npm root -g)/.bin/server-brave-search" /usr/local/bin/server-brave-search \ - && chmod +x /usr/local/bin/server-brave-search \ - && /usr/local/bin/server-brave-search --help || true \ + && npm install -g @modelcontextprotocol/server-brave-search \ && npm cache clean --force \ && apt-get purge -y gnupg \ && apt-get autoremove -y --purge \ From e886494c1045601998d17acab14b8bfbe554bdd7 Mon Sep 17 00:00:00 2001 From: hemsej018 Date: Tue, 12 Aug 2025 15:50:08 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor=20:=2010=EC=B0=A8=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=EB=A1=9C=20=ED=9A=8C=EA=B7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs25-service/Dockerfile | 9 ++------- cs25-service/src/main/resources/application.properties | 6 ++++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cs25-service/Dockerfile b/cs25-service/Dockerfile index b134928b..e962b60f 100644 --- a/cs25-service/Dockerfile +++ b/cs25-service/Dockerfile @@ -11,12 +11,7 @@ COPY cs25-entity cs25-entity/ COPY cs25-common cs25-common/ # 테스트 생략하여 빌드 안정화 -# (빌드 시 MCP 비활성화 + gradlew 실행 권한 + 테스트 스킵) -ENV SPRING_AI_MCP_CLIENT_ENABLED=false \ - SPRING_AI_MCP_CLIENT_INITIALIZED=false -RUN chmod +x ./gradlew -RUN ./gradlew :cs25-service:bootJar --stacktrace --no-daemon -x test - +RUN ./gradlew :cs25-service:bootJar --stacktrace --no-daemon FROM eclipse-temurin:17-jre-jammy # 메타 정보 @@ -44,4 +39,4 @@ COPY --from=builder /build/cs25-service/build/libs/*.jar app.jar EXPOSE 8080 # 실행 -ENTRYPOINT ["java", "-jar", "/apps/app.jar"] +ENTRYPOINT ["java", "-jar", "/apps/app.jar"] \ No newline at end of file diff --git a/cs25-service/src/main/resources/application.properties b/cs25-service/src/main/resources/application.properties index b96ef567..0ad81543 100644 --- a/cs25-service/src/main/resources/application.properties +++ b/cs25-service/src/main/resources/application.properties @@ -65,12 +65,14 @@ spring.ai.chat.client.enabled=false # MCP spring.ai.mcp.client.enabled=true spring.ai.mcp.client.type=SYNC -spring.ai.mcp.client.request-timeout=60s +spring.ai.mcp.client.request-timeout=45s spring.ai.mcp.client.root-change-notification=false # STDIO Connect: Brave Search -spring.ai.mcp.client.stdio.connections.brave.command=/usr/local/bin/server-brave-search +spring.ai.mcp.client.stdio.connections.brave.command=server-brave-search spring.ai.mcp.client.stdio.connections.brave.args[0]=--stdio spring.ai.mcp.client.stdio.connections.brave.env.BRAVE_API_KEY=${BRAVE_API_KEY} +spring.ai.mcp.client.initialized=false +spring.autoconfigure.exclude=org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration #MAIL spring.mail.host=smtp.gmail.com spring.mail.port=587 From 716bc22c21a0356ef39dbb3cc26eb46ef940b38d Mon Sep 17 00:00:00 2001 From: hemsej018 Date: Tue, 12 Aug 2025 16:00:45 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore/385=2010=EC=B0=A8=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=EC=84=9C=EB=B9=84=EC=8A=A4=EB=A1=9C=20=ED=9A=8C?= =?UTF-8?q?=EA=B7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/service/BraveSearchMcpService.java | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/cs25-service/src/main/java/com/example/cs25service/domain/ai/service/BraveSearchMcpService.java b/cs25-service/src/main/java/com/example/cs25service/domain/ai/service/BraveSearchMcpService.java index 4f6bb103..7a31cce3 100644 --- a/cs25-service/src/main/java/com/example/cs25service/domain/ai/service/BraveSearchMcpService.java +++ b/cs25-service/src/main/java/com/example/cs25service/domain/ai/service/BraveSearchMcpService.java @@ -6,7 +6,6 @@ import io.modelcontextprotocol.spec.McpSchema.CallToolRequest; import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.ListToolsResult; -import java.time.Duration; import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -19,8 +18,9 @@ public class BraveSearchMcpService { private static final String BRAVE_WEB_TOOL = "brave_web_search"; - private static final Duration INIT_TIMEOUT = Duration.ofSeconds(60); + private final List mcpClients; + private final ObjectMapper objectMapper; public JsonNode search(String query, int count, int offset) { @@ -40,36 +40,23 @@ public JsonNode search(String query, int count, int offset) { var root = objectMapper.createObjectNode(); root.set("results", content); return root; - } - } - private void ensureInitialized(McpSyncClient client) { - if (!client.isInitialized()) { - synchronized (client) { // 다중 스레드 초기화 경합 방지 - if (!client.isInitialized()) { - log.debug("MCP 클라이언트 초기화 시작…"); - client.initialize(); // 매개변수 없는 버전 - log.debug("MCP 클라이언트 초기화 완료"); - } - } - } + return content != null ? content : objectMapper.createObjectNode(); } private McpSyncClient resolveBraveClient() { for (McpSyncClient client : mcpClients) { - try { - ensureInitialized(client); // 초기화 - ListToolsResult tools = client.listTools(); - if (tools != null && tools.tools() != null && - tools.tools().stream() - .anyMatch(t -> BRAVE_WEB_TOOL.equalsIgnoreCase(t.name()))) { + ListToolsResult tools = client.listTools(); + if (tools != null && tools.tools() != null) { + boolean found = tools.tools().stream() + .anyMatch(tool -> BRAVE_WEB_TOOL.equalsIgnoreCase(tool.name())); + if (found) { return client; } - } catch (Exception e) { - log.debug("Brave MCP 클라이언트 후보 실패: {}", e.toString()); } } - throw new IllegalStateException("Brave MCP 서버에서 '" + BRAVE_WEB_TOOL + "' 툴을 찾을 수 없습니다."); + + throw new IllegalStateException("Brave MCP 서버에서 brave_web_search 툴을 찾을 수 없습니다."); } } \ No newline at end of file