MCP (Protocolo de Contexto de Modelo) ¿Qué es? Explicación para devs Java

1. Descripción general

MCP (Protocolo de Contexto de Modelo) es un estándar abierto que ayuda a las LLM (large language model) a conectarse con datos, herramientas y sistemas externos de manera unificada, en lugar de que cada aplicación de IA tenga que escribir integraciones separadas para cada fuente de datos. Este artículo explica qué es MCP, cómo es su arquitectura, y te guía para escribir un servidor MCP simple con Spring Boot (a través de Spring AI) que exponga una herramienta para que la LLM la llame. Después de leerlo, entenderás cuándo deberías usar MCP y cuándo es solo sobrecarga de ingeniería.

2. El problema que MCP resuelve

Antes de que MCP existiera, cada aplicación de IA (chatbot, agente) que quisiera acceder a base de datos, sistema de archivos, APIs internas… tenía que escribir adaptadores separados. Si tenías M aplicaciones de IA y N fuentes de datos, necesitabas hasta M × N códigos de integración diferentes.

MCP estandariza esta capa de comunicación: la aplicación de IA (llamada Host) solo necesita hablar el estándar MCP una vez, y cualquier sistema que exponga un servidor MCP puede “conversar” con ella. Es como USB-C para dispositivos electrónicos — un conector estándar único en lugar de docenas de tipos de puertos diferentes.

Nota: MCP no es un framework para reemplazar REST o gRPC en comunicación servicio a servicio ordinaria. Fue creado para que la LLM/agente llame herramientas, no para que dos microservicios backend se comuniquen entre sí.

3. Arquitectura de MCP

MCP tiene 3 roles principales:

  • Host: aplicación que contiene la LLM (por ejemplo Claude Desktop, un agente que escribiste).
  • Cliente: componente dentro de la Host, mantiene una conexión 1-1 con un servidor MCP.
  • Servidor: proceso que expone capacidades (herramientas, recursos, prompts) según el estándar MCP.
┌──────────────┐        ┌──────────────┐        ┌──────────────────┐
│     Host     │  1-1   │  MCP Client  │  JSON-RPC  │   MCP Server   │
│  (contiene   │◄──────►│              │◄──────────►│ (BD, API, arch)│
│    LLM)      │        └──────────────┘        └──────────────────┘
└──────────────┘

La comunicación entre cliente y servidor usa JSON-RPC 2.0, transmitida a través de uno de dos transportes comunes:

  • stdio: el servidor se ejecuta como un proceso hijo, cliente/servidor se comunican a través de stdin/stdout. Adecuado cuando el servidor se ejecuta localmente.
  • SSE/HTTP (HTTP transmisible): se usa cuando el servidor se ejecuta remotamente, a través de red.

3.1. Tres tipos de capacidades

Capacidad Significado Ejemplo
Herramientas Funciones que la LLM puede llamar para realizar acciones getWeather(city), createOrder(...)
Recursos Datos que la LLM puede leer (similar a GET) Archivo de registro, registro de base de datos
Prompts Plantilla de prompt predefinida por el servidor “Resumir orden según la plantilla X”

La mayoría de casos de uso reales giran alrededor de Herramientas, así que el ejemplo a continuación se enfoca en eso.

4. Escribir servidor MCP con Spring AI

Spring AI (desde la versión 1.0.0-M6) soporta MCP a través de un starter separado, que te permite exponer un bean de Java como herramienta MCP usando anotación, sin necesidad de implementar JSON-RPC por tu cuenta.

4.1. Agregar dependencia

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

4.2. Definir herramienta

@Service
public class WeatherService {

    @Tool(description = "Obtener la temperatura actual de una ciudad")
    public String getTemperature(String city) {
        return switch (city.toLowerCase()) {
            case "ha noi" -> "28°C, nublado";
            case "sai gon" -> "32°C, soleado";
            default -> "Sin datos para la ciudad: " + city;
        };
    }
}
  • @Tool marca este método como una herramienta MCP. El atributo description es muy importante — la LLM usa esta descripción para decidir si debe llamar o no a la herramienta, y con qué parámetros.
  • getTemperature toma un String city, devuelve una cadena que describe el clima. El parámetro y el tipo de retorno, el servidor MCP genera automáticamente un esquema JSON para que la LLM entienda.

4.3. Registrar herramienta con servidor MCP

@Configuration
public class McpServerConfig {

    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(weatherService)
                .build();
    }
}

MethodToolCallbackProvider escanea los métodos con @Tool en weatherService y los registra en el servidor MCP automáticamente cuando el contexto de la aplicación se inicia.

4.4. Configurar servidor

spring.ai.mcp.server.name=weather-mcp-server
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.stdio=true

Con stdio=true, el servidor se ejecuta como un proceso independiente, se comunica a través de stdin/stdout — adecuado para pruebas rápidas con Claude Desktop o un cliente MCP que escribiste. Si deseas desplegar el servidor como un servicio independiente que se ejecuta remotamente, cambias al transporte SSE y lo expones a través de un punto final HTTP en lugar de stdio.

Iniciar servidor:

mvn spring-boot:run
Started WeatherMcpApplication in 1.124 seconds
Herramienta MCP registrada: getTemperature

5. Llamar servidor MCP desde cliente

Supongamos que escribes una aplicación Host (por ejemplo un agente interno) que necesita llamar a la herramienta getTemperature arriba.

5.1. Dependencia del cliente

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

5.2. Llamar herramienta

@Component
public class WeatherAgent {

    private final McpSyncClient mcpClient;

    public WeatherAgent(McpSyncClient mcpClient) {
        this.mcpClient = mcpClient;
    }

    public String askTemperature(String city) {
        CallToolRequest request = new CallToolRequest(
                "getTemperature",
                Map.of("city", city));

        CallToolResult result = mcpClient.callTool(request);
        return result.content().get(0).text();
    }
}
  • McpSyncClient es un cliente de Spring AI que crea automáticamente un bean basado en la configuración de transporte (stdio o SSE) declarada en application.yml.
  • CallToolRequest encapsula el nombre de la herramienta (getTemperature) y los parámetros (city) en una llamada JSON-RPC.
  • result.content() devuelve una lista de contenido de respuesta; aquí toma la primera parte de texto.

Configuración del cliente (por ejemplo, conectarse al servidor a través de stdio ejecutando nuevamente el jar del servidor como subproceso):

spring:
  ai:
    mcp:
      client:
        stdio:
          connections:
            weather-server:
              command: java
              args: -jar weather-mcp-server.jar

6. Probar herramienta con JUnit 5 + AssertJ

Dado que @Tool es solo una anotación en un método Java ordinario, puedes probar la lógica comercial independientemente de MCP — sin necesidad de construir un servidor completo:

class WeatherServiceTest {

    private final WeatherService weatherService = new WeatherService();

    @Test
    void shouldReturnTemperatureForKnownCity() {
        String result = weatherService.getTemperature("Ha Noi");

        assertThat(result).contains("28°C");
    }

    @Test
    void shouldReturnFallbackMessageForUnknownCity() {
        String result = weatherService.getTemperature("Tokyo");

        assertThat(result)
                .startsWith("Sin datos para la ciudad:")
                .contains("Tokyo");
    }
}

Si deseas probar también la parte de integración de MCP (la herramienta se registra con el nombre correcto, el esquema correcto o no), puedes escribir una prueba a nivel @SpringBootTest y verificar ToolCallbackProvider:

@SpringBootTest
class McpServerConfigTest {

    @Autowired
    private ToolCallbackProvider toolCallbackProvider;

    @Test
    void shouldExposeTemperatureTool() {
        var toolNames = toolCallbackProvider.getToolCallbacks().stream()
                .map(callback -> callback.getToolDefinition().name())
                .toList();

        assertThat(toolNames).contains("getTemperature");
    }
}

Esta prueba garantiza que cada vez que refactorices WeatherService, la herramienta siga siendo expuesta con el nombre correcto — evita el caso donde cambias el nombre del método pero olvidas actualizar los lugares donde la LLM la está referenciando.

7. Errores comunes y cuándo no usar MCP

Descripción de herramienta demasiado vaga. Si la descripción solo dice “obtener datos”, la LLM muy fácilmente elegirá la herramienta incorrecta cuando hay muchas herramientas similares. Escribe una descripción específica, especifica claramente las entrada/salida esperadas.

Usar MCP para reemplazar REST/gRPC internos. MCP añade una capa JSON-RPC y un transporte separado, optimizado para el contexto de la LLM llamando herramientas dinámicamente — no optimizado para dos servicios backend llamándose entre sí con alta frecuencia y baja latencia. Usar MCP aquí es sobrecarga de ingeniería.

No controlar los permisos de la herramienta. El servidor MCP generalmente se ejecuta con los permisos del proceso que lo aloja. Si expones una herramienta que puede eliminar archivos o ejecutar comandos shell sin limitar los parámetros de entrada, la LLM (o inyección de prompt) puede abusar de esa herramienta. Siempre valida los parámetros en la herramienta, no confíes ciegamente en las entradas de la LLM.

Ejecutar servidor stdio en entorno sin servidor. El transporte stdio requiere generar un proceso hijo — no funciona bien en entornos sin servidor/contenedor de corta duración. En este caso, debes usar el transporte SSE/HTTP.

No sincronizar versiones entre cliente y servidor. MCP sigue en desarrollo rápido (muchos cambios radicales entre versiones de especificación). Cuando actualices el SDK, revisa cuidadosamente el changelog antes de desplegar en producción.

8. Conclusión

MCP estandariza cómo la LLM llama herramientas y lee datos externos, resuelve el problema de integración M × N entre aplicaciones de IA y fuentes de datos. Con Spring AI, puedes exponer un servicio Java como herramienta MCP solo con la anotación @Tool, sin necesidad de implementar JSON-RPC por tu cuenta. Usa MCP cuando construyas agentes/chatbots que necesiten llamar herramientas dinámicamente según las decisiones de la LLM — y evita usarlo para comunicación servicio a servicio ordinaria, donde REST o gRPC siguen siendo opciones más adecuadas.

mcpspring-aillmjavaai-integration