Diseña APIs para la era de la IA con Spring AI y MCP

Diseña APIs para la era de la IA con Spring AI y MCP

Como desarrolladores backend, llevamos años construyendo robustas APIs REST. Las diseñamos para que las consuman nuestras UIs, aplicaciones móviles u otros microservicios. Es un paradigma que dominamos. Pero, ¿y si te dijera que con un esfuerzo mínimo, esa misma API podría tener una segunda interfaz, una que permita a agentes de IA interactuar con tu lógica de negocio usando lenguaje natural?

Hoy en día, pensar en la inteligencia artificial no es una ocurrencia tardía, es una estrategia de diseño. No se trata solo de crear un servicio que responda a peticiones GET o POST, sino de preguntarnos: ¿cómo puede un modelo de IA consumir mi servicio para aportar un valor extra?

Para los que desarrollamos con Java, gracias a Spring AI, esta idea ha dejado de ser una tarea compleja para convertirse en una simple extensión de lo que ya hacemos. En este post, vamos a explorar lo increíblemente fácil que es añadir un Servidor MCP (Model Context Protocol) a una aplicación Spring Boot existente, usando como ejemplo una API real para gestionar un catálogo de productos.

El paradigma de la API dual: REST para máquinas, MCP para la IA 🤖

Una API REST es genial para la comunicación estructurada máquina a máquina. Pero un agente de IA no piensa en términos de JSON o endpoints.

Aquí es donde entra el Servidor MCP. Actúa como un traductor, exponiendo la lógica de tu aplicación de una manera que un LLM (Large Language Model) puede entender y utilizar. Esto te permite tener lo mejor de ambos mundos:

  • Tu API REST tradicional, estable y fiable para tus aplicaciones.
  • Un Servidor MCP, que ofrece una interfaz nativa para la integración con la IA.

Este enfoque te obliga a diseñar pensando desde el principio en las funciones (Tools), los datos (Resources) y las guías (Prompts) que un agente inteligente necesitaría para operar de forma autónoma sobre tu dominio.

¿Qué es el Model Context Protocol?

El Model Context Protocol (MCP) es el estándar que define cómo un modelo de IA puede descubrir y utilizar las capacidades de tu aplicación de forma segura y estructurada. Le proporciona a la IA el contexto necesario sobre qué acciones puede realizar y qué información puede consultar.

Este protocolo se basa en tres pilares: Tools, Resources y Prompts. Si quieres profundizar en cómo funciona y qué significa cada uno de estos conceptos, puedes leer uno de mis posts donde entro en más detalle:

Model Context Protocol al Descubierto: El Poder de Resources y Prompts más allá de las Tools
Una guía práctica para dejar de centrarte solo en ‘function calling’ y construir servidores MCP de gran valor con el poder de Resources y Prompts Como desarrollador en el mundo de la IA, seguro que te has enfrentado a este problema: conectar un LLM con aplicaciones y datos del mundo

Para este artículo, lo importante es que ahora veremos lo fácil que es implementar estos tres pilares con Spring AI.

Manos a la obra: De @RestController a Servidor MCP

Para demostrarlo, usaré mi proyecto de Catálogo de Productos.

GitHub - The-Dave-Stack/product-catalog: A comprehensive, enterprise-grade RESTful API for product catalog management using Spring Boot.
A comprehensive, enterprise-grade RESTful API for product catalog management using Spring Boot. - The-Dave-Stack/product-catalog

Paso 0: Crea tu servicio Spring Boot tradicional

No me voy a extender nada en este punto porque crear la base para un proyecto con spring boot es casi trivial usando https://start.spring.io/. Igualmente también os dejo el enlace a su documentación por si queréis mas detalle:

Getting Started | Building an Application with Spring Boot
Learn how to build an application with minimal configuration.

Paso 1: La configuración es trivial

Una vez ya tienes tu servicio Spring Boot, sólo hay que añadir la dependencia de Spring AI y activar el servidor.

Para gestionar las versiones de forma centralizada, añadimos el "Bill of Materials" (BOM) de Spring AI en la sección <dependencyManagement> de tu pom.xml:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Y luego, en tu sección de <dependencies>, solo necesitas añadir el starter del servidor MCP, que en este caso será spring-ai-starter-mcp-server-webmvc:

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
</dependencies>

Finalmente, en tu application.properties, activas y configuras el servidor. Así de simple:

# application.properties

# Activa el servidor MCP
spring.ai.mcp.server.enabled=true
spring.ai.mcp.server.name=product-catalog-mcp-server
spring.ai.mcp.server.version=1.0.0

# Define las instrucciones generales para la IA
spring.ai.mcp.server.instructions=Servidor para la gestión de un catálogo de productos con herramientas, recursos y guías impulsadas por IA.

# Activa las capacidades que quieres exponer
spring.ai.mcp.server.capabilities.tool=true
spring.ai.mcp.server.capabilities.resource=true
spring.ai.mcp.server.capabilities.prompt=true

Con solo estas líneas, tu aplicación ya tiene un servidor MCP funcional.

Paso 2: Implementando el servidor MCP

Ahora que ya tenemos las dependencias de Spring AI y el starter para MCP, es hora de entrar en faena.

Paso 2.1: Expón tus servicios como Tools

Ya tienes la lógica en tus clases @Service. Para exponer un método como una herramienta para la IA, solo necesitas una anotación: @Tool.

@Tool(description = "Creates a new product in the catalog with comprehensive validation and audit logging. Required fields: name, price, category, stockQuantity, minStockLevel. Optional fields: description, SKU (auto-generated if not provided), weight, dimensions, imageUrl. SKU must be globally unique if provided. Automatically creates audit log entry. Throws DuplicateSkuException for duplicate SKUs. Use this for adding new products to the inventory system.")
@Transactional
public Product createProduct(@ToolParam(description = "Product object with required fields: name, price, category, stockQuantity, minStockLevel. Optional: description, sku, weight, dimensions, imageUrl") Product product) {
    ...
}

¡Listo! Tu método createProduct ya es una herramienta que cualquier agente de IA puede invocar.

Paso 2.2: Expón los datos estáticos con Resources

Un Resource actúa como una fuente de datos en vivo para la IA. En lugar de tener datos estáticos en un prompt, puedes exponer información que cambia en tu aplicación, como una lista de categorías de productos.

Para ello, definimos un URI (ej: categories://overview/all) y lo asociamos a una función que devuelve los datos.

public List<McpServerFeatures.SyncResourceSpecification> getResourceSpecifications() {
        return List.of(
                // All categories overview resource
                new McpServerFeatures.SyncResourceSpecification(
                        new McpSchema.Resource(
                                "categories://overview/all",
                                "All Categories Overview",
                                "Complete overview of all product categories with descriptions and guidelines",
                                "application/json",
                                null),
                        this::getAllCategoriesResource),
                ...
                );
}

private McpSchema.ReadResourceResult getAllCategoriesResource(
            McpSyncServerExchange exchange, McpSchema.ReadResourceRequest request) {
        try {
            List<Map<String, Object>> categoriesInfo =
                    Arrays.stream(Category.values())
                            .map(this::createCategoryOverview)
                            .collect(Collectors.toList());

            String jsonContent =
                    objectMapper.writeValueAsString(
                            Map.of(
                                    "totalCategories",
                                    Category.values().length,
                                    "categories",
                                    categoriesInfo,
                                    "description",
                                    "Complete catalog of product categories with their descriptions and key characteristics",
                                    "lastUpdated",
                                    Instant.now().toString()));

            return new McpSchema.ReadResourceResult(
                    List.of(
                            new McpSchema.TextResourceContents(
                                    request.uri(), "application/json", jsonContent)));
        } catch (Exception e) {
            log.error("Failed to get all categories resource", e);
            throw new RuntimeException("Failed to retrieve categories overview", e);
        }
}    

Paso 2.3: Expón tus flujos con Prompts

Los Prompts son guías estructuradas que le enseñan a la IA cómo realizar tareas complejas de varios pasos. Son como plantillas de prompts pre-diseñadas que puedes invocar, combinando instrucciones, datos de Resources y Tools.

Imagina que quieres una guía para analizar el inventario. Podrías crear un Prompt llamado inventory-analysis que le indique a la IA que primero obtenga los productos con bajo stock (usando una Tool) y luego genere un informe.

public List<McpServerFeatures.SyncPromptSpecification> getPromptSpecifications() {
        return List.of(
                ...

                // Inventory analysis prompt
                new McpServerFeatures.SyncPromptSpecification(
                        new McpSchema.Prompt(
                                "inventory-analysis",
                                "Inventory Analysis and Recommendations",
                                List.of(
                                        new McpSchema.PromptArgument(
                                                "analysisType",
                                                "Type of analysis (stock-health/reorder/turnover)",
                                                true),
                                        new McpSchema.PromptArgument(
                                                "category", "Focus on specific category", false))),
                        this::createInventoryAnalysisPrompt),
                
                ...
                );
}

private McpSchema.GetPromptResult createInventoryAnalysisPrompt(
            McpSyncServerExchange exchange, McpSchema.GetPromptRequest request) {
        try {
            String analysisType = (String) request.arguments().get("analysisType");
            String category = (String) request.arguments().getOrDefault("category", "ALL");

            String promptText = createInventoryAnalysisPromptText(analysisType, category);

            McpSchema.PromptMessage promptMessage =
                    new McpSchema.PromptMessage(
                            McpSchema.Role.ASSISTANT, new McpSchema.TextContent(promptText));

            return new McpSchema.GetPromptResult(
                    "Inventory analysis guidance for " + analysisType + " analysis",
                    List.of(promptMessage));
        } catch (Exception e) {
            log.error("Failed to create inventory analysis prompt", e);
            throw new RuntimeException("Failed to generate inventory analysis prompt", e);
        }
}

private String createInventoryAnalysisPromptText(String analysisType, String category) {
        return switch (analysisType) {
            case "stock-health" -> """
                You are an inventory management specialist conducting a stock health analysis%s.

                ## Stock Health Analysis Framework

                ### Key Metrics to Evaluate:
                1. **Out of Stock Items** - Immediate attention required
                2. **Low Stock Warnings** - Items below minimum levels
                3. **Overstock Situations** - Items with excessive inventory
                4. **Stock Turnover Rates** - How quickly inventory moves
                5. **Dead Stock** - Items with no recent sales

                ### Analysis Process:
                1. Retrieve current inventory levels using available tools
                2. Compare against minimum stock thresholds
                3. Identify critical alerts requiring immediate action
                4. Calculate stock health scores by category
                5. Generate actionable recommendations

                ### Recommended Actions:
                - **Critical**: Immediate reorders for out-of-stock items
                - **Warning**: Schedule reorders for low-stock items
                - **Optimization**: Review slow-moving inventory for discounts
                - **Planning**: Adjust minimum stock levels based on trends

                Please conduct a comprehensive stock health analysis and provide prioritized recommendations.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            case "reorder" -> """
                You are a procurement specialist developing reorder recommendations%s.

                ## Reorder Analysis Framework

                ### Reorder Triggers:
                1. Current stock ≤ minimum stock level
                2. Projected stockouts based on demand trends
                3. Lead time considerations
                4. Economic order quantities
                5. Seasonal demand adjustments

                ### Analysis Steps:
                1. Identify products below reorder points
                2. Calculate optimal order quantities
                3. Consider supplier minimums and volume discounts
                4. Factor in lead times and safety stock
                5. Prioritize based on sales velocity and margin

                ### Reorder Recommendations:
                - High priority: Fast-moving items near stockout
                - Medium priority: Steady sellers below minimum
                - Low priority: Slow movers with adequate runway

                Please generate a prioritized reorder plan with specific quantities and timing.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            case "turnover" -> """
                You are a financial analyst evaluating inventory turnover performance%s.

                ## Inventory Turnover Analysis

                ### Key Calculations:
                1. **Turnover Ratio** = Cost of Goods Sold / Average Inventory Value
                2. **Days Sales Inventory** = 365 / Turnover Ratio
                3. **Stock Velocity** = Units Sold / Average Units in Stock
                4. **Carrying Cost Impact** = Average Inventory × Carrying Cost Rate

                ### Performance Benchmarks:
                - Electronics: 8-12 turns/year (Fast-moving technology)
                - Books: 3-5 turns/year (Diverse demand patterns)
                - Clothing: 4-6 turns/year (Seasonal collections)
                - General: 6-8 turns/year (Standard retail)

                ### Analysis Focus:
                1. Compare actual vs. target turnover rates
                2. Identify slow-moving inventory
                3. Calculate carrying cost implications
                4. Recommend optimization strategies

                Please analyze turnover performance and suggest improvements for capital efficiency.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            default -> "Please specify analysis type: stock-health, reorder, or turnover.";
        };
}

Paso 3: Configura los Beans para exponer las Tools, Resources y Prompts

Una vez tienes todas las piezas, exponer Tools (herramientas), Resources (datos) y Prompts (guías) es igual de sencillo: solo necesitas crear un Bean de Spring.

@SpringBootApplication
public class ProductCatalogSpringApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductCatalogSpringApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider productCatalogTools(ProductService productService) {
        return MethodToolCallbackProvider.builder().toolObjects(productService).build();
    }

    @Bean
    public List<McpServerFeatures.SyncResourceSpecification> productCatalogResources() {
        List<McpServerFeatures.SyncResourceSpecification> productCatalogResources = new ArrayList<>();
        ...
        return productCatalogResources;
    }

    @Bean
    public List<McpServerFeatures.SyncPromptSpecification> productCatalogPrompts(ProductManagementPromptProvider productManagementPromptProvider) {
        return productManagementPromptProvider.getPromptSpecifications();
    }

}

Con estos simples pasos, has construido un puente directo y seguro entre tu lógica de negocio y el mundo de la IA.

Conclusión: El Siguiente Paso Natural para tus APIs

Como hemos visto, añadir un Servidor MCP a tu aplicación Spring Boot no es una tarea titánica. Es el siguiente paso lógico en la evolución de nuestros servicios. Spring AI abstrae toda la complejidad, permitiéndonos reutilizar el código que ya tenemos para abrir nuestras aplicaciones a un universo de nuevas posibilidades con la inteligencia artificial.

Diseñar pensando en la IA desde el principio ya no es una opción, es una ventaja competitiva y saber usar la tríada del MCP (tools, resources y prompts) seguro que marcará la diferencia p nuestros servicios.

¿Y ahora qué? Tu turno de actuar

Espero que este post te haya inspirado a mirar tus APIs desde una nueva perspectiva. Aquí te dejo algunas ideas para que empieces:

  1. Explora el código fuente: Todo el código de este ejemplo está disponible en mi repositorio de GitHub Product Catalog API. Clónalo, ejecútalo con Docker y experimenta por ti mismo. ¡La mejor forma de aprender es haciendo!
  2. Empieza con algo pequeño: No necesitas una arquitectura compleja. Elige un método clave de una de tus aplicaciones Spring Boot actuales y prueba a exponerlo como una @Tool. Verás lo simple que es.
  3. Únete a la conversación: ¿Qué te parece este enfoque de APIs nativas para IA? ¿Qué otros casos de uso se te ocurren para un Servidor MCP en tus proyectos?
  4. Profundiza en la documentación: Si quieres conocer todos los detalles, la documentación oficial de Spring AI es el mejor lugar para seguir aprendiendo.
Model Context Protocol (MCP) :: Spring AI Reference

Otros posts interesantes

Internet esta plagado de artículos que también os pueden ayudar a aprender más sobre este mundo de Spring AI y MCP. Os dejo un par que he encontrado muy interesantes:

Exploring Model Context Protocol (MCP) With Spring AI | Baeldung
Learn about how to use the Model Context Protocol when integrating with LLMs using Spring AI.
Dynamic Tool Updates in Spring AI’s Model Context Protocol
Level up your Java code and explore what Spring can do for you.
Te suscribiste correctamente a The Dave Stack
¡Excelente! A continuación, complete el proceso de pago para acceder a The Dave Stack
¡Dar una buena acogida! Has iniciado sesión correctamente.
¡Éxito! Su cuenta está completamente activada, ahora tiene acceso a todo el contenido.
¡Éxito! Su información de facturación está actualizada.
Error al actualizar la información de facturación.