From 9b0ed9dd517862de26bd5cbe0137251fd3ac2b52 Mon Sep 17 00:00:00 2001 From: jade Date: Thu, 16 Jul 2026 18:03:59 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B2=84=EC=A0=84111?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ustomWebMvcSseServerTransportProvider.java | 32 +++++++++++++++++++ .../gateway/sync/DynamicMcpController.java | 27 ++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/CustomWebMvcSseServerTransportProvider.java b/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/CustomWebMvcSseServerTransportProvider.java index b7b476a..22405d6 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/CustomWebMvcSseServerTransportProvider.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/CustomWebMvcSseServerTransportProvider.java @@ -87,6 +87,38 @@ public class CustomWebMvcSseServerTransportProvider implements McpServerTranspor return emitter; } + public org.springframework.web.servlet.mvc.method.annotation.SseEmitter handleCustomSse(String sessionId, String body) { + if (sessionFactory == null) { + throw new IllegalStateException("SessionFactory not configured"); + } + + org.springframework.web.servlet.mvc.method.annotation.SseEmitter emitter = new org.springframework.web.servlet.mvc.method.annotation.SseEmitter(-1L); + + CustomMcpSessionTransport sessionTransport = new CustomMcpSessionTransport(emitter, sessionId); + McpServerSession session = sessionFactory.create(sessionTransport); + sessions.put(sessionId, session); + + emitter.onCompletion(() -> sessions.remove(sessionId)); + emitter.onTimeout(() -> sessions.remove(sessionId)); + + new Thread(() -> { + try { + // 커스텀 클라이언트는 endpoint 이벤트를 무시할 수 있지만, 표준 호환성을 위해 전송 + Thread.sleep(100); + emitter.send(org.springframework.web.servlet.mvc.method.annotation.SseEmitter.event().name("endpoint").data(messageEndpoint + "?sessionId=" + sessionId)); + + // Body로 들어온 initialize 등 즉시 처리 + if (body != null && !body.trim().isEmpty()) { + handleMessage(sessionId, body); + } + } catch (Exception e) { + emitter.completeWithError(e); + } + }).start(); + + return emitter; + } + public org.springframework.http.ResponseEntity handleMessage(String sessionId, String body) { log.info("Received POST message for sessionId: " + sessionId + ", body: " + body); if (sessionId == null || !sessions.containsKey(sessionId)) { diff --git a/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/DynamicMcpController.java b/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/DynamicMcpController.java index fd39a92..94ec729 100644 --- a/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/DynamicMcpController.java +++ b/dap-gateway/src/main/java/io/shinhanlife/dap/biz/mcp/gateway/sync/DynamicMcpController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @@ -57,4 +58,30 @@ public class DynamicMcpController { } return transport.handleMessage(sessionId, body); } + + @PostMapping("/mcp/custom/{category}") + public ResponseEntity handleCustomMcp( + @PathVariable("category") String category, + @RequestHeader(value = "Mcp-Session-Id", required = false) String sessionId, + @RequestBody(required = false) String body) { + + CustomWebMvcSseServerTransportProvider transport = manager.getTransport(category); + if (transport == null) { + return ResponseEntity.badRequest().body("Unknown category: " + category); + } + + if (sessionId == null || sessionId.isEmpty()) { + // 새 세션 생성 (initialize 요청) + String newSessionId = java.util.UUID.randomUUID().toString(); + SseEmitter emitter = transport.handleCustomSse(newSessionId, body); + + return ResponseEntity.ok() + .header("Mcp-Session-Id", newSessionId) + .body(emitter); + } else { + // 기존 세션 메시지 전송 (tools/call 등) + transport.handleMessage(sessionId, body); + return ResponseEntity.accepted().build(); + } + } }