MCP (Model Context Protocol) se convierte en el estándar de conexión de herramientas para IA
1. Descripción general
Los modelos de lenguaje grande (LLM) solo son realmente útiles cuando pueden leer datos reales y llamar a sistemas reales: consultar pedidos, leer tickets, ejecutar queries. Antes, cada aplicación de IA escribía su propia forma de integración para cada herramienta. Model Context Protocol (MCP) nace para estandarizar esta parte de conexión.
Este artículo explica qué es MCP y por qué está ganando atención. Luego escribirás un pequeño servidor MCP con Spring Boot, configurarás un cliente para llamarlo, y sabrás cuándo no usar MCP.
2. ¿Qué es MCP?
MCP es un protocolo abierto. Define cómo una aplicación de IA descubre y llama capacidades externas: herramientas, datos y prompts predefinidos. Puedes imaginar MCP como un “puerto USB” para IA. Cualquier dispositivo que siga el estándar funciona con cualquier host que lo soporte.
2.1. Tres roles principales
- Host: la aplicación con la que interactúa el usuario, por ejemplo un asistente de IA en escritorio, un IDE o un chatbot interno.
- Client: el componente dentro del host. Cada cliente mantiene una conexión uno-a-uno con un servidor.
- Server: el programa que proporciona capacidades a la IA, por ejemplo un servidor que lee la base de datos de pedidos o uno que accede al sistema de archivos.
2.2. Tres tipos de “primitivas” del lado servidor
- Tools: funciones que el modelo puede decidir llamar, como
findOrderocancelOrder. - Resources: datos de solo lectura, como el contenido de un archivo o un registro de configuración, que se introducen en el contexto.
- Prompts: plantillas de prompt predefinidas que el usuario puede elegir para usar.
2.3. Protocolo subyacente
MCP usa JSON-RPC 2.0. Los dos tipos de transporte más comunes son: stdio, cuando el host inicia el servidor como un proceso hijo, e HTTP, cuando el servidor se ejecuta de forma remota. Una llamada a herramienta se ve así:
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "findOrder",
"arguments": { "orderId": "ORD-1001" }
}
}
El flujo de trabajo básico consta de tres pasos:
- El cliente envía
initializepara que ambos lados intercambien versión del protocolo y capacidades soportadas. - El cliente llama a
tools/listpara obtener la lista de herramientas, con descripción y JSON Schema de los parámetros. - Cuando el modelo decide usar una herramienta, el cliente envía
tools/callcomo en el ejemplo anterior y devuelve el resultado al modelo.
Punto importante: el modelo no llama al servidor directamente. El host está en medio, así que puede pedir al usuario que confirme antes de ejecutar una herramienta sensible.
3. ¿Por qué MCP está ganando atención?
3.1. El problema N × M
Supongamos que hay N aplicaciones de IA y M sistemas para conectar. Sin un estándar común, tendrías que escribir N × M integraciones. Con un protocolo común, cada aplicación solo necesita soportar MCP una vez, y cada sistema solo necesita un servidor MCP. El problema se reduce a N + M.
3.2. Separación de responsabilidades
El equipo que posee el sistema de pedidos escribe y opera su servidor MCP. El equipo que hace el chatbot solo necesita apuntar a ese servidor. La lógica de negocio, el control de acceso y los logs de auditoría residen en el lugar correcto, sin duplicarse en cada prompt o aplicación.
3.3. No quedar atrapado en un proveedor de modelos
El function calling de cada proveedor de LLM tiene su propio formato. MCP se sitúa encima de ese formato. El servidor que escribas hoy sigue siendo válido cuando cambies de modelo o de host.
3.4. El ecosistema está creciendo
Cada vez más asistentes de IA, IDEs y frameworks soportan MCP. Hay SDKs para muchos lenguajes, incluyendo un SDK oficial para Java y Spring AI lo integra nativamente. Esta es la razón por la que muchos ven MCP como un candidato destacado para ser el estándar de conexión de herramientas. Aun así, el protocolo sigue evolucionando, así que necesitas monitorear la especificación para implementaciones a largo plazo.
4. Escribir un servidor MCP con Spring Boot
Vas a construir un servidor que proporciona dos herramientas para consultar y cancelar pedidos, ejecutándose a través de stdio.
4.1. Dependencia
Spring AI proporciona un starter para servidores MCP. Importa el BOM de Spring AI y usa la versión más reciente compatible con tu Spring Boot 3.x:
<properties>
<java.version>21</java.version>
<spring-ai.version><!-- versión actual de Spring AI --></spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
</dependencies>
El starter spring-ai-starter-mcp-server soporta transporte stdio. Si quieres ejecutar el servidor a través de HTTP, Spring AI tiene un starter separado para Web MVC y WebFlux.
Nota: El nombre del artefacto de Spring AI ha cambiado entre versiones milestone. Revisa la documentación correspondiente a la versión que elijas.
4.2. Dominio y herramientas
public record Order(String id, String customerName, double total, String status) {}
@Service
public class OrderTools {
private final Map<String, Order> orders = new ConcurrentHashMap<>(Map.of(
"ORD-1001", new Order("ORD-1001", "Nguyen Van An", 350_000, "SHIPPING"),
"ORD-1002", new Order("ORD-1002", "Tran Thi Binh", 120_000, "PENDING")
));
@Tool(description = "Busca un pedido por código, devuelve cliente, total y estado")
public Order findOrder(@ToolParam(description = "Código del pedido, ej. ORD-1001") String orderId) {
Order order = orders.get(orderId);
if (order == null) {
throw new IllegalArgumentException("Pedido no encontrado: " + orderId);
}
return order;
}
@Tool(description = "Cancela un pedido. Solo se puede cancelar si está en estado PENDING")
public String cancelOrder(@ToolParam(description = "Código del pedido a cancelar") String orderId) {
Order order = findOrder(orderId);
if (!"PENDING".equals(order.status())) {
return "No se puede cancelar: el pedido está en estado " + order.status();
}
orders.put(orderId, new Order(order.id(), order.customerName(), order.total(), "CANCELLED"));
return "Pedido " + orderId + " cancelado";
}
}
Dos anotaciones juegan el rol principal:
@Tool(del paqueteorg.springframework.ai.tool.annotation) marca un método como herramienta. La partedescriptiones lo que el modelo lee para decidir si llamar a la herramienta. Cuanto más clara sea la descripción, mejor elegirá el modelo.@ToolParamdescribe cada parámetro. Spring AI genera JSON Schema a partir del tipo del parámetro y esta descripción.
Nota que cancelOrder devuelve un mensaje en lugar de lanzar una excepción cuando viola una regla de negocio. El modelo lee ese mensaje y lo explica de forma natural al usuario.
4.3. Registrar herramientas con el servidor MCP
@SpringBootApplication
public class OrderMcpServerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderMcpServerApplication.class, args);
}
@Bean
ToolCallbackProvider orderToolProvider(OrderTools orderTools) {
return MethodToolCallbackProvider.builder()
.toolObjects(orderTools)
.build();
}
}
MethodToolCallbackProvider explora los métodos con @Tool en orderTools. La auto-configuración del servidor MCP encontrará todos los beans ToolCallbackProvider y los publicará a través de tools/list.
4.4. Configuración para stdio
spring.ai.mcp.server.name=order-mcp-server
spring.ai.mcp.server.version=0.0.1
spring.ai.mcp.server.stdio=true
spring.main.web-application-type=none
spring.main.banner-mode=off
logging.pattern.console=
logging.file.name=./logs/order-mcp-server.log
Con stdio, stdout es el canal para transmitir JSON-RPC. Cualquier otra cosa impresa en stdout arruinará el protocolo, incluyendo el banner y los logs. Por eso la configuración anterior desactiva el banner, desactiva logs en consola y redirige logs a archivo.
Nota: Este es el error más común cuando empiezas con servidores MCP a través de stdio. Ni una sola línea de
System.out.printlnpara debug es suficiente para que el cliente reporte un error de análisis o se desconecte. Usa un logger que escriba en archivo.
Construye el archivo jar:
./mvnw clean package -DskipTests
5. Conectar desde el cliente
Muchos hosts configuran servidores a través de un archivo JSON con la clave mcpServers. El nombre del archivo y su ubicación dependen de cada host:
{
"mcpServers": {
"orders": {
"command": "java",
"args": ["-jar", "/opt/mcp/order-mcp-server.jar"]
}
}
}
Al iniciar, el host ejecuta el comando java -jar ... como un proceso hijo, envía initialize y luego tools/list. Preguntas: “¿Se puede cancelar el pedido ORD-1002? Si se puede, cancélalo por favor.” El modelo llamará a findOrder y luego a cancelOrder. El resultado de la segunda llamada se ve así:
{"content":[{"type":"text","text":"Pedido ORD-1002 cancelado"}],"isError":false}
Típicamente el host mostrará un diálogo de confirmación antes de ejecutar la herramienta. Deberías mantener este comportamiento con herramientas con efectos secundarios como cancelOrder.
Si quieres que tu aplicación Spring sea el cliente, Spring AI también tiene un starter de cliente MCP. Este starter convierte las herramientas de servidores externos en herramientas usables con ChatClient.
6. Probar el comportamiento de herramientas
Las herramientas son solo métodos Java normales, así que puedes probarlas sin necesidad de iniciar MCP:
class OrderToolsTest {
private final OrderTools tools = new OrderTools();
@Test
void shouldCancelPendingOrder() {
String result = tools.cancelOrder("ORD-1002");
assertThat(result).isEqualTo("Pedido ORD-1002 cancelado");
assertThat(tools.findOrder("ORD-1002").status()).isEqualTo("CANCELLED");
}
@Test
void shouldRefuseToCancelShippingOrder() {
assertThat(tools.cancelOrder("ORD-1001"))
.contains("No se puede cancelar")
.contains("SHIPPING");
}
@Test
void shouldFailWhenOrderNotFound() {
assertThatThrownBy(() -> tools.findOrder("ORD-9999"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("ORD-9999");
}
}
Tres pruebas cubren el flujo exitoso, las reglas de negocio y el caso cuando no se encuentra el pedido. El SDK se encarga de la parte del protocolo. Lo que más necesitas asegurar es que la lógica de negocio devuelva resultados correctos y mensajes claros para el modelo.
Si quieres verificar end-to-end, puedes usar herramientas inspector para MCP. Te permiten listar herramientas y llamarlas manualmente.
7. Aplicación práctica: qué tener en cuenta
- Diseña herramientas según el negocio, no según las tablas.
findOrderes mejor que unexecuteSqluniversal. Las herramientas estrechas son fáciles de controlar en permisos y ayudan al modelo a elegir correctamente. - Principio de mínimo privilegio. El servidor debe usar una cuenta que tenga solo los permisos necesarios. Separa herramientas de lectura y escritura, y considera habilitar herramientas de escritura solo en ciertos ambientes.
- Cuidado con la inyección de prompts. Los datos que devuelven las herramientas, como notas ingresadas por el cliente, pueden contener comandos para manipular el modelo. No dejes que los resultados de una herramienta desencadenen automáticamente acciones peligrosas sin confirmación humana.
- Solo usa servidores de confianza. Un servidor MCP de terceros ejecutado a través de stdio es un proceso en tu máquina, con tus permisos. Las descripciones de herramientas también pueden contener contenido malicioso. Lee el código fuente o usa solo fuentes en las que confías.
- Auténtica para servidores remotos. Cuando se ejecuta a través de HTTP, pon el servidor detrás de un mecanismo de autenticación apropiado y registra en auditoría cada llamada a herramienta.
- Mantén el número de herramientas moderado. Cada herramienta consume contexto para su descripción. Demasiadas herramientas hacen que el modelo elija incorrectamente con más frecuencia.
8. Cuándo NO usar MCP
- Aplicación pequeña, solo un modelo, pocas funciones. El function calling directo del framework, por ejemplo
@Toolusado directamente conChatClient, es más simple. No necesitas un proceso adicional ni una capa de protocolo. - Flujos de procesamiento fijos, el modelo no necesita decidir. Si el paso 1 siempre llama a la API A y el paso 2 siempre llama a la API B, escribe código normal. No dejes que el LLM maneje algo que un simple
ifhace mejor. - Requieres latencia extremadamente baja o alta determinancia. Cada ronda modelo → cliente → servidor suma latencia. Los resultados del modelo tampoco son completamente deterministas.
- Operaciones que no se pueden deshacer sin revisión. Transferencias de dinero o eliminaciones masivas de datos no deben exponerse como herramientas automáticas. Si es absolutamente necesario, siempre requiere un paso de confirmación.
- Necesitas una API para que otros sistemas la llamen. MCP nació para servir a la IA. Entre servicios, REST, gRPC o messaging siguen siendo las opciones correctas.
9. Conclusión
MCP resuelve un problema muy real: conectar IA con herramientas y datos de una forma estándar, en lugar de que cada aplicación escriba la suya. Gracias al modelo host–cliente–servidor, las tres primitivas tools/resources/prompts y la base JSON-RPC, un servidor que escribas puede reutilizarse en muchos hosts diferentes.
Con Spring AI, escribir un servidor MCP solo requiere unas pocas anotaciones @Tool, un bean ToolCallbackProvider y configuración correcta para stdio. La parte difícil está en otro lado: diseñar herramientas estrechas y claras, control de acceso estricto, defensa contra inyección de prompts. También necesitas ser honesto en reconocer casos donde el código normal sigue siendo la mejor solución.