package com.cloudhandson.vpdbackoffice.web; import com.cloudhandson.vpdbackoffice.config.McpProperties; import com.cloudhandson.vpdbackoffice.domain.mcp.McpReasoningCommand; import com.cloudhandson.vpdbackoffice.mapper.UserMapper; import com.cloudhandson.vpdbackoffice.service.BearerTokenService; import com.cloudhandson.vpdbackoffice.service.McpReasoningService; import com.cloudhandson.vpdbackoffice.service.McpSseService; import com.cloudhandson.vpdbackoffice.service.McpToolRegistry; import java.util.List; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class McpReasoningController { private final McpToolRegistry toolRegistry; private final McpSseService mcpSseService; private final McpReasoningService reasoningService; private final BearerTokenService tokenService; private final UserMapper userMapper; private final McpProperties mcpProperties; public McpReasoningController( McpToolRegistry toolRegistry, McpSseService mcpSseService, McpReasoningService reasoningService, BearerTokenService tokenService, UserMapper userMapper, McpProperties mcpProperties ) { this.toolRegistry = toolRegistry; this.mcpSseService = mcpSseService; this.reasoningService = reasoningService; this.tokenService = tokenService; this.userMapper = userMapper; this.mcpProperties = mcpProperties; } @GetMapping("/mcp-reasoning") public String page(Model model) { try { model.addAttribute("tools", toolRegistry.listTools()); model.addAttribute("users", userMapper.findAll()); } catch (DataAccessException e) { RuntimeErrorMessage message = RuntimeErrorMessages.dataAccess(e); model.addAttribute("tools", List.of()); model.addAttribute("users", List.of()); model.addAttribute("runtimeError", message); } return "mcp-reasoning"; } @GetMapping("/mcp/tools") @ResponseBody public Object tools() { return mcpSseService.registeredTools(); } @GetMapping("/mcp-sse") public String ssePage(Model model) { model.addAttribute("tools", mcpSseService.registeredTools()); model.addAttribute("hmmMcpPublicUrl", mcpProperties.resolvedPublicUrl()); return "mcp-sse"; } @PostMapping("/mcp-reasoning") public String reason( @RequestParam(defaultValue = "") String bearerToken, @RequestParam(required = false) Long tempUserId, @RequestParam(defaultValue = "50") int limit, @RequestParam(defaultValue = "") String question, Model model ) { String effectiveToken = bearerToken; Long temporaryKeyId = null; try { if (tempUserId != null) { var issued = tokenService.issueTemporaryToken(tempUserId, "MCP Reasoning 임시 실행"); effectiveToken = issued.plainToken(); temporaryKeyId = issued.keyId(); } model.addAttribute("result", reasoningService.reason( new McpReasoningCommand(temporaryKeyId, effectiveToken, limit, question))); } catch (Exception exception) { model.addAttribute("errorMessage", exception.getMessage()); } finally { if (temporaryKeyId != null) { tokenService.revokeToken(temporaryKeyId, "temporary reasoning completed"); } } return "fragments/mcp-reasoning-result :: result"; } }