McpService.java

package fr.tiogars.chat.domains.mcp.services;

import fr.tiogars.chat.domains.mcp.models.McpActionRequest;
import fr.tiogars.chat.domains.mcp.models.McpActionResponse;
import fr.tiogars.chat.domains.mcp.models.McpResource;
import fr.tiogars.chat.domains.mcp.models.McpServiceConfig;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Service for managing MCP services and executing actions.
 */
@Service
public class McpService {

    private final Map<String, McpServiceConfig> serviceConfigs = new ConcurrentHashMap<>();

    public McpService() {
        // Initialize with some default MCP services
        registerDefaultServices();
    }

    private void registerDefaultServices() {
        // Filesystem MCP server
        McpServiceConfig filesystemConfig = new McpServiceConfig(
                "filesystem",
                "File System Access",
                "Access to local file system operations",
                "npx @modelcontextprotocol/server-filesystem",
                Map.of(),
                true,
                30
        );
        serviceConfigs.put(filesystemConfig.id(), filesystemConfig);

        // Process MCP server
        McpServiceConfig processConfig = new McpServiceConfig(
                "process",
                "Process Management",
                "Execute system processes and commands",
                "npx @modelcontextprotocol/server-process",
                Map.of(),
                true,
                30
        );
        serviceConfigs.put(processConfig.id(), processConfig);

        // HTTP MCP server
        McpServiceConfig httpConfig = new McpServiceConfig(
                "http",
                "HTTP Requests",
                "Make HTTP requests to external services",
                "npx @modelcontextprotocol/server-http",
                Map.of(),
                true,
                60
        );
        serviceConfigs.put(httpConfig.id(), httpConfig);
    }

    /**
     * Get all registered MCP service configurations.
     *
     * @return list of all MCP service configs
     */
    public List<McpServiceConfig> getAllServices() {
        return serviceConfigs.values().stream().toList();
    }

    /**
     * Get a specific MCP service configuration by ID.
     *
     * @param serviceId the service ID
     * @return the service configuration or null if not found
     */
    public McpServiceConfig getService(String serviceId) {
        return serviceConfigs.get(serviceId);
    }

    /**
     * Register a new MCP service.
     *
     * @param config the service configuration
     * @return the registered configuration
     */
    public McpServiceConfig registerService(McpServiceConfig config) {
        serviceConfigs.put(config.id(), config);
        return config;
    }

    /**
     * Execute an action on an MCP service.
     * This is a simplified implementation that simulates MCP calls.
     * In a real implementation, this would connect to the actual MCP server.
     *
     * @param request the action request
     * @return the action response
     */
    public McpActionResponse executeAction(McpActionRequest request) {
        Instant start = Instant.now();
        McpServiceConfig config = serviceConfigs.get(request.serviceId());

        if (config == null || !config.enabled()) {
            Instant end = Instant.now();
            return new McpActionResponse(
                    false,
                    Map.of(),
                    List.of(),
                    "Service not found or disabled: " + request.serviceId(),
                    Duration.between(start, end).toMillis()
            );
        }

        // Simulate action execution based on service type
        McpActionResponse response = switch (request.serviceId()) {
            case "filesystem" -> executeFilesystemAction(request);
            case "process" -> executeProcessAction(request);
            case "http" -> executeHttpAction(request);
            default -> executeGenericAction(request, config);
        };

        Instant end = Instant.now();
        return new McpActionResponse(
                response.success(),
                response.data(),
                response.resources(),
                response.error(),
                Duration.between(start, end).toMillis()
        );
    }

    private McpActionResponse executeFilesystemAction(McpActionRequest request) {
        String action = request.action();
        Map<String, Object> params = request.parameters() != null ? request.parameters() : Map.of();

        if ("list_resources".equals(action)) {
            String path = (String) params.getOrDefault("path", ".");
            // Simulate listing files
            McpResource resource1 = new McpResource(
                    "file://" + path + "/file1.txt",
                    "file1.txt",
                    "file",
                    "text/plain",
                    1024L
            );
            McpResource resource2 = new McpResource(
                    "file://" + path + "/file2.txt",
                    "file2.txt",
                    "file",
                    "text/plain",
                    2048L
            );
            return new McpActionResponse(true, Map.of("path", path), List.of(resource1, resource2), null, 0);
        } else if ("read_resource".equals(action)) {
            String uri = (String) params.get("uri");
            if (uri != null) {
                return new McpActionResponse(
                        true,
                        Map.of("uri", uri, "content", "Sample content from " + uri),
                        List.of(),
                        null,
                        0
                );
            }
        }

        return new McpActionResponse(false, Map.of(), List.of(), "Unknown action: " + action, 0);
    }

    private McpActionResponse executeProcessAction(McpActionRequest request) {
        String action = request.action();
        if ("list_processes".equals(action)) {
            return new McpActionResponse(
                    true,
                    Map.of("count", 3),
                    List.of(),
                    null,
                    0
            );
        }
        return new McpActionResponse(false, Map.of(), List.of(), "Unknown action: " + action, 0);
    }

    private McpActionResponse executeHttpAction(McpActionRequest request) {
        String action = request.action();
        if ("get".equals(action)) {
            String url = (String) request.parameters().get("url");
            return new McpActionResponse(
                    true,
                    Map.of("url", url, "status", 200, "body", "Sample response"),
                    List.of(),
                    null,
                    0
            );
        }
        return new McpActionResponse(false, Map.of(), List.of(), "Unknown action: " + action, 0);
    }

    private McpActionResponse executeGenericAction(McpActionRequest request, McpServiceConfig config) {
        return new McpActionResponse(
                true,
                Map.of("service", config.name(), "action", request.action()),
                List.of(),
                null,
                0
        );
    }
}