MCP vs RAG vs AI Agent: explicación detallada
1. Descripción general
Los nombres MCP, RAG e AI Agent aparecen por todas partes cuando hablamos de aplicaciones LLM, y es fácil confundirlos como “tres opciones en competencia”. En realidad, resuelven tres problemas diferentes: RAG ayuda al LLM a responder correctamente basándose en datos propios, AI Agent ayuda al LLM a planificar y actuar por sí mismo, mientras que MCP es un estándar de comunicación para que las aplicaciones LLM se conecten con herramientas y datos de forma unificada. Después de leer este artículo, distinguirás claramente los tres conceptos, sabrás cuándo usar cada uno, y tendrás algunos fragmentos de código Java/Spring AI funcionales para imaginar cómo funciona en la práctica.
2. ¿Qué es RAG?
RAG (Retrieval-Augmented Generation) es una técnica que “incrusta” datos externos en el prompt antes de llamar al LLM, para que el modelo responda basándose en datos reales en lugar de confiar solo en el conocimiento aprendido durante el entrenamiento.
2.1. Flujo de trabajo de RAG
- Convertir documentos de origen (políticas, manuales, preguntas frecuentes) en embeddings (vectores numéricos) y guardarlos en una base de datos vectorial.
- Cuando el usuario hace una pregunta, convertir la pregunta en embedding, buscar los fragmentos de texto más similares (similarity search).
- Incluir los fragmentos encontrados en el prompt, luego enviar al LLM para generar una respuesta.
Ejemplo: un OrderService necesita responder la pregunta “¿cuál es la política de devolución para pedidos en línea?” basándose en la documentación de políticas de la empresa, no en el conocimiento general del modelo.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
2.2. Ejemplo simple de código RAG
@Service
public class ReturnPolicyAssistant {
private final VectorStore vectorStore;
private final ChatClient chatClient;
public ReturnPolicyAssistant(VectorStore vectorStore, ChatClient.Builder builder) {
this.vectorStore = vectorStore;
this.chatClient = builder.build();
}
public String answer(String question) {
List<Document> relevant = vectorStore.similaritySearch(
SearchRequest.query(question).withTopK(3));
String context = relevant.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
String prompt = """
Basándote en la documentación de política que se muestra a continuación,
responde la pregunta del cliente. Si no hay información disponible,
di "no estoy seguro".
Documentación:
%s
Pregunta: %s
""".formatted(context, question);
return chatClient.prompt(prompt).call().content();
}
}
vectorStore.similaritySearchdevuelve los 3 fragmentos de documentación con significado más cercano a la pregunta.- El prompt se “incrementa” (augmented) con el contexto obtenido de la tienda vectorial antes de enviarlo al LLM.
- Si la documentación no contiene información relevante, se instruye al modelo para responder “no estoy seguro” en lugar de inventar (hallucination).
Entrada: "Compré una camisa en línea hace 5 días, ¿puedo cambiarla?"
Salida: "Según la política, puedes cambiar dentro de 7 días desde la recepción,
siempre que el producto tenga su etiqueta. Tu camisa aún está dentro del plazo."
Nota: RAG solo ayuda al modelo a “saber más datos”. No ayuda al modelo a actuar por sí mismo (llamar APIs, actualizar bases de datos). Si necesitas que el modelo haga algo en lugar de solo responder, necesitas un Agent.
3. ¿Qué es AI Agent?
AI Agent es un sistema que usa un LLM como “cerebro” para planificar, seleccionar la herramienta adecuada, llamarla, observar el resultado, y repetir hasta alcanzar el objetivo — diferente de RAG que solo se detiene en responder una pregunta.
3.1. Ciclo de reason → act → observe
El patrón más común es ReAct: el modelo razona (reasoning), elige una herramienta para llamar (action), recibe un resultado (observation), y vuelve a razonar basándose en ese resultado.
public interface AgentTool {
String name();
String description();
String execute(String input);
}
@Component
public class CheckOrderStatusTool implements AgentTool {
private final OrderRepository orderRepository;
public CheckOrderStatusTool(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public String name() { return "checkOrderStatus"; }
public String description() { return "Verificar el estado del pedido por orderId"; }
public String execute(String orderId) {
return orderRepository.findById(orderId)
.map(o -> "El pedido %s está %s".formatted(orderId, o.getStatus()))
.orElse("No se encontró el pedido " + orderId);
}
}
3.2. El Agent selecciona y llama herramientas
@Service
public class SupportAgent {
private final ChatClient chatClient;
private final List<AgentTool> tools;
public SupportAgent(ChatClient.Builder builder, List<AgentTool> tools) {
this.chatClient = builder.build();
this.tools = tools;
}
public String handle(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.tools(tools.toArray()) // Spring AI mapea automáticamente execute() a function-calling
.call()
.content();
}
}
tools(tools.toArray())le indica al modelo que puede llamar estas herramientas; Spring AI genera automáticamente el esquema para function-calling.- El modelo decidirá por sí solo: si la pregunta está relacionada con el estado del pedido, llamará
checkOrderStatuscon elorderIddeducido de la pregunta, recibirá el resultado, y lo reformulará en lenguaje natural.
Usuario: "¿Qué pasó con mi pedido ORD-2024-891?"
Agent: (llama checkOrderStatus("ORD-2024-891"))
→ "Tu pedido ORD-2024-891 está siendo entregado, se espera que llegue en 2 días."
3.3. Probar el comportamiento de selección de herramientas
@Test
void shouldCallCheckOrderStatusWhenAskingAboutOrder() {
AgentTool tool = new CheckOrderStatusTool(orderRepository);
when(orderRepository.findById("ORD-1")).thenReturn(Optional.of(shippedOrder));
String result = tool.execute("ORD-1");
assertThat(result)
.contains("ORD-1")
.contains("SHIPPED");
}
Esta prueba no llama al LLM real, solo verifica que la lógica de la herramienta funciona correctamente — la parte “qué herramienta elige el modelo” debe probarse por separado con un conjunto de evaluación, no como una prueba unitaria rígida porque la salida del LLM no es determinística.
Nota: Los agents son poderosos pero más riesgosos que RAG — si una herramienta tiene permisos de escritura (reembolso, actualización), un razonamiento incorrecto del modelo podría causar consecuencias reales. Siempre añade un paso de confirmación (confirmation) o limita los permisos de las herramientas sensibles.
4. ¿Qué es MCP?
MCP (Model Context Protocol) es un estándar abierto que define cómo una aplicación LLM (llamada host) se conecta con fuentes de datos y herramientas externas (llamadas server) mediante un protocolo unificado, en lugar de que cada integración escriba código propio.
4.1. El problema que MCP resuelve
Antes de MCP, si tenías 5 aplicaciones LLM y querías que cada una usara 10 fuentes de datos/herramientas (base de datos, CRM, sistema de archivos…), tenías que escribir hasta 50 integraciones diferentes — el problema N×M típico. MCP lo convierte en N+M: cada server se escribe una vez, cualquier host que siga el estándar MCP puede llamarlo.
4.2. Arquitectura de MCP
- Host: la aplicación que contiene el LLM (chatbot, asistente IDE…).
- Client: el componente dentro del host que mantiene una conexión 1-1 con un servidor MCP.
- Server: un proceso que expone 3 tipos de “capacidades”:
- Resources: datos que se pueden leer (como endpoints GET).
- Tools: acciones que se pueden invocar (como POST/action).
- Prompts: plantillas de prompt reutilizables.
4.3. Ejemplo: escribir un servidor MCP en Java
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
<version>0.8.0</version>
</dependency>
public class OrderMcpServer {
public static void main(String[] args) {
McpSyncServer server = McpServer.sync(StdioServerTransport.builder().build())
.serverInfo("order-service", "1.0.0")
.tool(orderLookupTool())
.build();
server.start();
}
private static McpServerFeatures.SyncToolSpecification orderLookupTool() {
var schema = """
{
"type": "object",
"properties": { "orderId": { "type": "string" } },
"required": ["orderId"]
}
""";
return new McpServerFeatures.SyncToolSpecification(
new Tool("getOrderById", "Buscar un pedido por orderId", schema),
(exchange, args) -> {
String orderId = (String) args.get("orderId");
String status = OrderLookup.findStatus(orderId);
return new CallToolResult(List.of(new TextContent(status)), false);
});
}
}
McpServer.sync(...)crea un server que usa el transportestdio(el host ejecuta el server como subprocess y se comunica vía stdin/stdout).tool(orderLookupTool())registra una herramientagetOrderByIdcon esquema JSON describiendo la entrada, para que cualquier host siguiendo el estándar MCP pueda leer “qué campos necesita esta herramienta”.- Cuando un cliente llama
getOrderById, el server devuelveCallToolResultcon el contenido de texto.
4.4. Llamar a un servidor MCP desde un cliente Spring AI
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
spring:
ai:
mcp:
client:
stdio:
connections:
order-service:
command: java
args: ["-jar", "order-mcp-server.jar"]
@Service
public class McpAgentBridge {
private final SyncMcpToolCallbackProvider toolCallbackProvider;
private final ChatClient chatClient;
public McpAgentBridge(SyncMcpToolCallbackProvider toolCallbackProvider,
ChatClient.Builder builder) {
this.toolCallbackProvider = toolCallbackProvider;
this.chatClient = builder.build();
}
public String ask(String question) {
return chatClient.prompt()
.user(question)
.tools(toolCallbackProvider.getToolCallbacks())
.call()
.content();
}
}
- Spring AI inicia automáticamente el servidor MCP (
order-mcp-server.jar) como subprocess y mantiene la conexión vía stdio. toolCallbackProvider.getToolCallbacks()obtiene todas las herramientas que expone el server (aquígetOrderById) e las añade al modelo como function-calling, exactamente igual a como registrasteAgentToolmanualmente en la sección 3 — solo que esta herramienta es proporcionada por un proceso independiente siguiendo un estándar común.
Nota: MCP no reemplaza el function-calling del LLM. Es una capa de transporte/estandarización por debajo del function-calling, que permite que las herramientas se escriban una sola vez y se reutilicen en muchos hosts (Claude Desktop, IDE, tu aplicación) sin necesidad de cambiar el código de integración cada vez.
5. Comparación entre MCP, RAG e AI Agent
| Criterio | RAG | AI Agent | MCP |
|---|---|---|---|
| Qué problema resuelve | El modelo carece de datos propios/nuevos | El modelo no puede actuar por sí solo, no planifica múltiples pasos | Código de integración duplicado de herramientas/datos, falta de estandarización |
| Unidad de operación | Recuperación + augment del prompt | Ciclo reason-act-observe | Protocolo de conexión host ↔ server |
| ¿Llama herramientas/acciones? | No (solo lectura) | Sí | Sí (expone herramientas para que el agent las llame) |
| Nivel de riesgo | Bajo (solo respuestas incorrectas si la recuperación es pobre) | Alto (puede ejecutar acciones incorrectas) | Depende de las herramientas subyacentes, el protocolo en sí es neutral |
| Relación entre ellos | Es una “fuente de datos” que el Agent puede usar | Puede usar RAG como una herramienta, usar MCP para llamar herramientas estandarizadas | Es la “tubería” para que el Agent llame RAG/herramientas de forma unificada |
En resumen: RAG da al modelo conocimiento, AI Agent le da capacidad de actuar, MCP es el estándar de comunicación para que esas acciones/búsquedas no tengan que reescribirse cada vez que cambias de host o herramienta.
6. Combinar los tres en un sistema real
En proyectos grandes, no eliges uno de los tres, sino que los apilas:
Usuario → AI Agent (planificación, ciclo ReAct)
├─ llama MCP Client → MCP Server "knowledge-base" → devuelve resultado de RAG similarity search
├─ llama MCP Client → MCP Server "order-service" → herramienta getOrderById
└─ llama MCP Client → MCP Server "payment-service" → herramienta refundPayment (requiere confirmación)
En esta arquitectura:
- RAG está dentro de un servidor MCP separado (por ejemplo, server “knowledge-base” que expone recursos como resultados de similarity search).
- AI Agent es la parte que orquesta (orchestrator) que ejecuta el ciclo de razonamiento, sin preocuparse por cómo están escritas las herramientas, solo que sigan MCP.
- MCP es la capa de comunicación unificada entre Agent y todos los servers, permitiéndote añadir nuevos servers (por ejemplo “shipping-service”) sin modificar el código del Agent.
7. Errores comunes
- Usar RAG cuando necesitas acciones: llenar el prompt con datos esperando que el modelo actualice la base de datos por sí solo — RAG no puede hacer esto, necesitas un Agent con herramientas que tengan permisos de escritura.
- Agent sin límites de permisos en herramientas: permitir que el agent llame directamente herramientas como
deleteOrderorefundPaymentsin confirmación humana, causando daño cuando el razonamiento del modelo es incorrecto. - Confundir MCP con un “framework de IA”: MCP es solo un protocolo de conexión, no razona, no recupera. Si tu servidor no expone herramientas/recursos útiles, tener MCP no hará al modelo más inteligente.
- Top-k demasiado pequeño o demasiado grande en RAG: top-k pequeño (1-2) tiende a perder contexto, top-k grande (10+) hace el prompt demasiado largo, consume tokens y diluye señales importantes. Comienza con 3-5 y ajusta con un conjunto de evaluación real.
- No versionar el esquema de herramientas MCP: al cambiar el esquema de entrada de una herramienta sin incrementar la versión, otros hosts usando el servidor anterior llamarán con parámetros incorrectos.
8. Conclusión
RAG, AI Agent y MCP no compiten entre sí — están en tres capas diferentes de un sistema LLM: RAG proporciona datos, Agent proporciona capacidad de razonamiento y acción, MCP proporciona un estándar de conexión para que eso no tenga que reescribirse cada vez que cambias de herramienta o host. Al diseñar un sistema de IA real, deberías empezar preguntándote “¿qué más necesita saber el modelo?” (RAG), “¿qué necesita hacer el modelo?” (Agent), y solo luego “¿cómo hacer que esa herramienta/dato sea reutilizable en muchos lugares?” (MCP) — este orden ayuda a evitar sobre-ingeniería desde el inicio.