MCP con Spring AI: cómo crear clientes y servidores en Java

En el artículo sobre Tool Calling expusimos un método Java como herramienta: el modelo lo solicitaba y Spring AI lo ejecutaba. Dentro de una aplicación eso funciona y, para la mayoría de los casos, sobra.
El problema aparece cuando a esa misma capacidad —consultar el estado de un pedido— le salen consumidores: un asistente de soporte, un agente interno, el IDE del equipo, otro backend que ya no es Java. Sin un protocolo común, cada uno necesita su integración y alguien que la mantenga.
MCP no hace que el modelo sepa usar herramientas; eso ya lo resolvía Tool Calling. Lo que aporta es un contrato interoperable: publicas la capacidad una vez y la consume cualquier cliente compatible.
Este artículo explica cómo encaja Model Context Protocol en una aplicación Java con Spring AI 2.0 (la versión estable es la 2.0.1): cómo se monta un servidor MCP, cómo se configura un cliente, cómo acaban esas herramientas dentro del bucle de Tool Calling y, sobre todo, cuándo merece la pena cruzar esa frontera y cuándo no.
MCP en Spring AI, en 30 segundos
- Añades un starter: uno de cliente o uno de servidor, según el papel que juegue la aplicación.
- El servidor publica tools, resources y prompts con anotaciones declarativas.
- El cliente abre una o varias conexiones con nombre y descubre las capacidades de cada servidor.
- Spring AI adapta las tools MCP a ToolCallback, así que entran en el mismo bucle de Tool Calling.
- El transporte es STDIO para procesos locales o Streamable HTTP para servicios remotos.
- Los endpoints HTTP no llevan autenticación por defecto: la frontera de seguridad la pones tú.
En este artículo
Qué es Model Context Protocol
Model Context Protocol (MCP) es un protocolo abierto que estandariza cómo una aplicación cliente descubre y consume capacidades ofrecidas por un servidor: herramientas que ejecutan algo, recursos que se leen y plantillas de prompt reutilizables. La documentación de Spring AI lo describe como un puente entre los modelos y los sistemas reales a través de una interfaz consistente.
Conviene no mezclar los tres papeles, porque luego se confunden en las discusiones de arquitectura:
- Host
la aplicación donde vive la experiencia o el agente
- Cliente MCP
la conexión del host con un servidor concreto
- Servidor MCP
el proceso que publica tools, resources y prompts
Un host puede tener varios clientes, uno por servidor: en Spring AI cada conexión configurada crea su propia instancia.
MCP Client vs MCP Server: cuál es la diferencia
Un MCP Client consume capacidades: vive en la aplicación de IA, abre la conexión y descubre lo que el otro lado publica. Un MCP Server las ofrece: vive junto al sistema proveedor y expone tools, resources y prompts. Una misma aplicación Spring Boot puede ser cliente de unos servidores y servidor para otros, pero son papeles distintos y cada uno tiene su starter.
| Aspecto | MCP Client | MCP Server |
|---|---|---|
| Papel | Consume capacidades | Publica capacidades |
| Dónde vive | En el host o aplicación de IA | Junto al sistema proveedor |
| Qué hace | Descubre y solicita | Expone tools, resources y prompts |
| Quién manda la petición | El cliente | El servidor responde |
| En Spring AI | Starter de cliente MCP | Starter de servidor MCP |
MCP no sustituye a Tool Calling
Es la confusión más extendida. Tool Calling es un mecanismo de invocación: el modelo solicita usar una capacidad y aporta los argumentos. MCP es un protocolo de interoperabilidad: permite publicar esa capacidad y descubrirla desde fuera. Uno vive en el bucle del modelo; el otro, en la integración entre aplicaciones.
La diferencia tampoco es local frente a remoto: una herramienta local anotada con @Tool puede llamar perfectamente a un ERP al otro lado de la red. Lo que cambia es quién define el contrato y quién puede consumirlo.
| Tool Calling | MCP |
|---|---|
| Mecanismo de invocación | Protocolo de interoperabilidad |
| El modelo solicita una herramienta | El cliente descubre y consume capacidades |
| El contrato vive en tu código | El contrato es público para cualquier cliente compatible |
| Forma parte del bucle del LLM | Forma parte de la integración entre sistemas |
Y se combinan: una herramienta publicada por un servidor MCP acaba convertida en un ToolCallback y entra en el mismo bucle que las locales.
Tools, resources y prompts: tres primitivas, no una
Un servidor MCP no solo publica herramientas. El protocolo distingue tres primitivas, y usarlas bien evita que todo acabe siendo una tool con un nombre raro.
| Primitiva | Para qué | Ejemplo |
|---|---|---|
| Tool | Hacer algo: ejecutar una operación con argumentos | get_order_status |
| Resource | Leer algo: contenido identificado por una URI | order://48392 |
| Prompt | Guiar: una plantilla de interacción reutilizable | analyze-delayed-order |
Convertir una lectura en herramienta funciona, pero pierde semántica: el cliente ya no distingue lo que se consulta de lo que actúa, y los controles de cada cosa deberían ser distintos.
¿Herramienta local o servidor MCP?
La pregunta que decide es si la capacidad existe solo para tu aplicación o tiene que sobrevivir a quien la consume. MCP añade protocolo, ciclo de vida, configuración, normalmente red, seguridad y versionado: debería aportar algo a cambio.
| Mantenla local si… | Publícala por MCP si… |
|---|---|
| Solo la usa una aplicación | La necesitan dos agentes, un IDE u otro backend |
| Está acoplada al dominio y usa tipos internos | Quien la ofrece no es quien la consume |
| La latencia manda y el salto no se justifica | Los consumidores están en otras tecnologías |
| No quieres operar otro despliegue | Quieres ownership claro sobre un conjunto de capacidades |
Spring AI sobre el MCP Java SDK: qué starter necesitas
Spring AI no implementa el protocolo: lo integra. Debajo está el MCP Java SDK y, según las notas de migración de Spring AI 2.0.0, esta versión lo actualizó de la rama 1.1.x a la 2.0.0, con cambios que afectan a quien manipula los tipos del SDK directamente. Encima, los starters de Spring Boot aportan autoconfiguración y anotaciones.
La elección del starter depende del papel y del transporte; en cliente, la documentación recomienda la variante WebFlux para producción con transportes HTTP.
| Papel | Starter | Transporte |
|---|---|---|
| Cliente | spring-ai-starter-mcp-client | STDIO y HTTP con el cliente del JDK |
| Cliente | spring-ai-starter-mcp-client-webflux | HTTP reactivo, recomendado en producción |
| Servidor | spring-ai-starter-mcp-server | STDIO, en proceso |
| Servidor | spring-ai-starter-mcp-server-webmvc | HTTP sobre Spring MVC |
| Servidor | spring-ai-starter-mcp-server-webflux | HTTP reactivo |
Cliente y servidor funcionan en modo SYNC o ASYNC y no se mezclan: un servidor síncrono registra solo métodos síncronos.
Cómo crear un MCP Server con Spring Boot y Spring AI
El caso que seguimos: un servidor que publica el estado de un pedido y la búsqueda de pedidos de un cliente, sobre el servicio de dominio que ya existe. Con el starter de WebMVC y el protocolo STREAMABLE, el endpoint queda publicado en /mcp.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>spring.ai.mcp.server.name=orders-mcp-server
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.protocol=STREAMABLE
spring.ai.mcp.server.type=SYNCPara un servidor que vive en el proceso del host, el starter es spring-ai-starter-mcp-server y la propiedad, spring.ai.mcp.server.stdio=true.
@McpTool: publicar una herramienta
La anotación declara la herramienta y Spring AI genera el JSON Schema de los argumentos a partir de la firma del método, como detallan las anotaciones de servidor MCP. El handler no implementa reglas: delega en el servicio de aplicación, igual que un controlador REST.
@Component
class OrderMcpTools {
private final OrderService orderService;
OrderMcpTools(OrderService orderService) {
this.orderService = orderService;
}
@McpTool(
name = "get_order_status",
description = "Obtiene el estado actual de un pedido existente",
title = "Estado de un pedido",
annotations = @McpTool.McpAnnotations(
readOnlyHint = true,
destructiveHint = false,
idempotentHint = true))
OrderStatus getOrderStatus(
@McpToolParam(description = "Identificador interno del pedido", required = true)
Long orderId) {
return orderService.getStatus(orderId);
}
}@Tool y @McpTool no son la misma anotación
Las dos describen una capacidad, pero viven en planos distintos. @Tool registra una herramienta dentro de tu aplicación Spring AI; @McpTool publica una operación en el protocolo, para quien se conecte al servidor.
| @Tool | @McpTool |
|---|---|
| Herramienta local de Spring AI | Operación publicada por un servidor MCP |
| Se registra en el ChatClient | Se descubre a través del protocolo |
| No necesita protocolo ni endpoint | Vive detrás de un transporte MCP |
| Capacidad interna de la aplicación | Capacidad pensada para ser consumida desde fuera |
No son excluyentes: una @McpTool consumida por un cliente acaba convertida en ToolCallback y participa en el mismo bucle que una @Tool local.
Los hints de una herramienta no son autorización
@McpTool admite anotaciones de comportamiento —readOnlyHint, destructiveHint, idempotentHint, openWorldHint y un title legible— que describen la operación para que el cliente decida cómo tratarla: pedir confirmación, avisar, permitir reintentos.
Son pistas, no controles. El propio javadoc es explícito: estas propiedades son hints, no garantizan una descripción fiel del comportamiento y un cliente no debería tomar decisiones de uso basándose en las anotaciones de un servidor en el que no confía. Marcar readOnlyHint = true no impide que la herramienta escriba. La autorización sigue viviendo en el método, con los permisos del usuario y las reglas del dominio.
@McpResource: no todo lo que se lee es una herramienta
Un resource es contenido identificado por una URI que el cliente puede leer: una ficha, un documento, una configuración, un esquema. La anotación admite plantillas de URI con variables, un mimeType y una descripción.
La diferencia con una tool no es técnica, es semántica, y el cliente la usa: una lectura puede cachearse, mostrarse al usuario o adjuntarse al contexto sin que nadie considere que el agente ha ejecutado una acción.
@McpResource(
uri = "order://{orderId}",
name = "Ficha de pedido",
description = "Datos básicos del pedido en texto plano",
mimeType = "text/plain")
String orderCard(String orderId) {
return orderService.renderCard(orderId);
}@McpPrompt y @McpComplete: plantillas y autocompletado
Un prompt MCP es una plantilla de interacción con argumentos que el servidor publica para que cualquier cliente la reutilice: «analiza este pedido retrasado», «resume esta incidencia», «genera las notas de versión». El servidor que conoce el dominio es quien mejor puede mantener esa plantilla.
@McpComplete añade autocompletado para los argumentos de un prompt o para las variables de una URI de recurso. Es una mejora de experiencia del cliente, no una capacidad de negocio, pero evita que el usuario tenga que adivinar valores válidos.
Cómo crear un MCP Client con Spring AI
En el lado cliente, cada conexión configurada crea una instancia de cliente MCP, y las conexiones llevan nombre, así que una misma aplicación puede hablar con varios servidores a la vez. La referencia completa está en el MCP Client Boot Starter.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>spring.ai.mcp.client.name=support-assistant
spring.ai.mcp.client.type=SYNC
spring.ai.mcp.client.request-timeout=20s
spring.ai.mcp.client.streamable-http.connections.orders.url=http://orders-mcp:8080
spring.ai.mcp.client.streamable-http.connections.orders.endpoint=/mcprequest-timeout vale 20 segundos por defecto y es global: para afinarlo por conexión hay que registrar un customizer de cliente. Es el primer valor que conviene revisar, porque un servidor MCP es una dependencia externa dentro del bucle del modelo y su latencia se suma a la de cada iteración.
Lo que el servidor puede pedirle al cliente: sampling, elicitation y progreso
El protocolo no es unidireccional: un servidor con sesión puede pedirle cosas al cliente, y Spring AI expone esos papeles con anotaciones del lado cliente, cada una asociada al nombre de su conexión.
Sampling es que el servidor pida una generación al modelo del cliente, sin credenciales propias: el control del modelo y de los permisos se queda en el cliente, y la especificación recomienda que alguien pueda denegar esas peticiones. Elicitation es pedir al usuario un dato que falta —un centro de coste, una confirmación— en lugar de inventarlo. Progress y logging acompañan operaciones largas.
| Anotación de cliente | Para qué |
|---|---|
| @McpSampling | El servidor pide una generación al modelo del cliente |
| @McpElicitation | El servidor pide información adicional al usuario |
| @McpProgress | Avance de operaciones largas |
| @McpLogging | Mensajes de log estructurados del servidor |
| @McpToolListChanged y equivalentes | El catálogo de tools, resources o prompts cambió |
Las notificaciones de cambio de catálogo evitan reiniciar un cliente cuando el servidor publica o retira capacidades.
STDIO o Streamable HTTP: qué transporte usar
STDIO encaja cuando el servidor MCP es un proceso local que gestiona el host. Streamable HTTP es la opción habitual cuando el servidor se despliega como servicio remoto y debe atender a varios clientes.
Con STDIO no hay endpoint de red que proteger, pero sí ciclo de vida del proceso, rutas y variables de entorno que gestionar, y no está pensado para compartirse entre máquinas. Streamable HTTP funciona sobre POST y GET, con streaming opcional mediante SSE cuando el servidor necesita enviar varios mensajes, y es el transporte que sustituye al SSE original, según la documentación de los starters de servidor.
| Criterio | STDIO | Streamable HTTP |
|---|---|---|
| Dónde vive el servidor | En la misma máquina que el host | Como servicio independiente |
| Consumidores | El proceso que lo lanza | Varios clientes a la vez |
| Qué hay que operar | Ciclo de vida del proceso | Endpoint, red y seguridad |
| Caso típico | IDE, escritorio, herramienta local | Capacidad compartida en la empresa |
Streamable y stateless: dos formas de servir por HTTP
Con el mismo starter HTTP, la propiedad spring.ai.mcp.server.protocol decide el modo. STREAMABLE mantiene sesión entre peticiones, lo que habilita los flujos interactivos del protocolo; STATELESS no la mantiene y simplifica el despliegue.
No es que uno sea mejor. La documentación concreta el precio: un servidor stateless no admite peticiones hacia el cliente —ni elicitation, ni sampling, ni ping— ni contexto de herramienta, y los métodos anotados que reciben el contexto de petición se descartan al registrar, con un aviso en el log.
| STREAMABLE | STATELESS |
|---|---|
| Mantiene sesión entre peticiones | Sin estado de sesión |
| Admite peticiones hacia el cliente | Sin peticiones hacia el cliente |
| Sampling y elicitation posibles | No disponibles |
| Más estado operativo que sostener | Despliegue más sencillo |
De herramienta MCP a ToolCallback: así entra en el bucle
Cuando el cliente descubre las herramientas de los servidores conectados, Spring AI las adapta a su abstracción de herramientas y las expone como un ToolCallbackProvider. A partir de ahí son herramientas normales para el ChatClient.
Los proveedores MCP no se registran solos en el ChatClient: listar herramientas al arrancar obligaría a una llamada de red a cada servidor. Se inyectan y se pasan de forma explícita, lo que además te deja decidir qué conversación recibe qué catálogo.
@Service
class SupportAssistant {
private final ChatClient chatClient;
SupportAssistant(ChatClient.Builder builder,
SyncMcpToolCallbackProvider mcpTools) {
this.chatClient = builder
.defaultSystem("Eres el asistente de soporte. Consulta siempre el estado real.")
.defaultTools(mcpTools)
.build();
}
String responder(String mensaje) {
return chatClient.prompt().user(mensaje).call().content();
}
}- Servidor MCP
publica la herramienta
- Cliente MCP
la descubre al conectarse
- ToolCallback
Spring AI la adapta a su framework de tools
- ChatClient
la recibe en .tools() o .defaultTools()
- Bucle de Tool Calling
el modelo la solicita y el advisor la ejecuta
Se desactiva con spring.ai.mcp.client.toolcallback.enabled=false: entonces no se crea ningún ToolCallbackProvider a partir de las herramientas MCP.
Varios servidores MCP: nombres, filtros y catálogos grandes
Conectar cuatro servidores es fácil; convivir con ellos, menos. Dos herramientas de servidores distintos pueden llamarse igual, y el catálogo total crece rápido. Spring AI aporta dos mecanismos: un generador de prefijos que por defecto garantiza nombres únicos entre todas las conexiones MCP, y un filtro para incluir o excluir las herramientas que descubre cada cliente. Conviene saber su alcance: ese generador solo desambigua entre servidores MCP, no sabe nada de tus herramientas locales anotadas con @Tool.
El segundo problema no lo resuelve MCP: cinco servidores con treinta herramientas cada uno son ciento cincuenta definiciones compitiendo por el contexto. Las estrategias son las de Tool Calling: filtrar por dominio, catálogos pequeños por conversación y divulgación progresiva cuando el catálogo es grande.
Seguridad: publicar un servidor MCP no es publicar una API segura
Este es el punto que más disgustos da, y la documentación es explícita: los transportes HTTP exponen un endpoint JSON-RPC sin autenticar por defecto, los starters no aplican autenticación ni autorización por su cuenta, y cualquier cliente que alcance el endpoint puede listar e invocar todas las herramientas, recursos y prompts registrados.
Antes de exponerlo más allá de localhost hay que poner delante una frontera de seguridad, como con cualquier endpoint web: Spring Security con OAuth 2.0 o claves de API según el caso, más límites de tasa, red privada o gateway. No afecta a STDIO, que corre en proceso y no es accesible por red.
También ayuda reducir lo publicado: las capacidades —tools, resources, prompts y completions— se desactivan una a una, y reexponer herramientas que el servidor consume de otros servidores viene desactivado por defecto.
Autenticación no es autorización
Que el cliente se autentique no significa que pueda ejecutar todo lo que el servidor publica: un usuario de soporte puede consultar un pedido y no debería poder reembolsarlo. La herramienta sigue aplicando permisos y reglas, como en Tool Calling: el modelo solicita, el backend autoriza. Y la sesión MCP no es una frontera de usuario: si varias personas comparten un cliente, la identidad tiene que viajar por otro sitio.
Para la autenticación existe el módulo de MCP Security, con OAuth 2.0 y claves de API para servidores y clientes, y la opción de anotar una herramienta con @PreAuthorize. Conviene saber qué es antes de adoptarlo: la documentación lo publica como trabajo en curso, pertenece al proyecto spring-ai-community/mcp-security, lo dirige la comunidad y no cuenta todavía con respaldo oficial de Spring AI ni del proyecto MCP. Sus limitaciones declaradas acotan el terreno —servidores WebMVC, cliente síncrono, tokens JWT y sin el transporte SSE deprecado—, así que conviene comprobar en su repositorio qué versión de Spring AI soporta antes de adoptarlo.
Tiempos de espera, resiliencia y versionado del contrato
Un servidor MCP es una dependencia externa dentro del bucle del modelo: timeouts, caídas parciales, latencia acumulada y coste. Spring AI deja configurable el tiempo de espera del cliente; el resto —reintentos solo donde sean seguros, idempotencia, corte de circuito, degradación— es arquitectura tuya, no autoconfiguración.
Y hay una dimensión que se olvida: el contrato. El servidor tiene nombre y versión, pero eso no es una estrategia de compatibilidad. Renombrar una herramienta o cambiar sus argumentos rompe a consumidores que no controlas, así que valen las reglas de cualquier API pública: nombres estables, evolución aditiva, deprecación avisada y pruebas de contrato.
Observabilidad: una frontera distribuida más
Con MCP, el tiempo de una respuesta se reparte entre tramos que conviene medir por separado: la llamada al modelo, el bucle de Tool Calling, el transporte MCP, el servidor y el sistema que hay detrás. Cuando algo va lento, la pregunta útil no es «tarda el agente», sino en qué tramo se va el tiempo.
Spring AI documenta observabilidad para el tool calling, así que una herramienta MCP adaptada a ToolCallback entra en ese nivel de trazas: nombre de la herramienta, duración, errores y el identificador de la llamada cuando procede. El transporte, la disponibilidad del servidor y sus dependencias son otra frontera distribuida que conviene instrumentar por separado, con los criterios de observabilidad de agentes de IA en producción. Y una frontera más es también un sitio más donde pueden acabar registrados datos sensibles.
Caso práctico: el servidor MCP de pedidos
Juntando las piezas: un servidor de dominio que publica dos herramientas de lectura, un recurso con la ficha del pedido y un prompt de análisis. La cancelación no se publica como acción automática; si hiciera falta, se expone en una herramienta aparte, con autorización explícita y aprobación humana.
El servicio de dominio no sabe que existe MCP, y esa es la idea: la anotación es la capa de publicación, no el sitio donde viven las reglas.
@Component
class OrderMcpPrompts {
@McpPrompt(
name = "analyze-delayed-order",
description = "Analiza por qué un pedido va con retraso y propone el siguiente paso")
GetPromptResult analyzeDelayedOrder(
@McpArg(name = "orderId", description = "Identificador del pedido", required = true)
String orderId) {
String instruccion = """
Analiza el pedido %s. Revisa su estado, las fechas comprometidas
y las incidencias asociadas. Indica la causa más probable del retraso
y el siguiente paso, sin prometer fechas que no estén confirmadas.
""".formatted(orderId);
return GetPromptResult.builder(
List.of(new PromptMessage(Role.USER, new TextContent(instruccion))))
.description("Análisis de pedido retrasado")
.build();
}
}- Servicio de pedidos
reglas y datos
- Servidor MCP
tools, resource y prompt
- Streamable HTTP
transporte con seguridad delante
- Cliente MCP
descubre el catálogo
- ChatClient
ejecuta dentro del bucle
Arquitectura: MCP como frontera de interoperabilidad
La imagen mental útil no es «el modelo llama a una API», sino dos planos separados por un contrato. Arriba, los hosts y sus clientes MCP. Abajo, servidores organizados por dominio, cada uno con su propietario, sus permisos y su ciclo de despliegue.
Esa organización importa: agrupar los servidores por tecnología —uno de base de datos, otro de REST— reparte mal la propiedad y mezcla permisos; agruparlos por capacidad deja claro quién mantiene cada contrato y limita el radio de impacto.
Si tu plataforma ya es Java y Spring, esta frontera encaja dentro de la arquitectura existente sin montar un stack paralelo. Es el enfoque con el que trabajamos en desarrollo de soluciones con Spring AI.

¿MCP sustituye a REST?
No. REST sigue siendo el contrato entre servicios y clientes; MCP añade una interfaz pensada para hosts y agentes, con descubrimiento, metadatos de herramientas, schemas, recursos y prompts. La arquitectura sana es que el servidor MCP se apoye en los servicios de aplicación que ya existen y no duplique la lógica de negocio: por debajo seguirá habiendo REST, JDBC o el SDK que corresponda.
¿MCP sustituye a RAG?
Tampoco, porque responden preguntas distintas: RAG decide qué conocimiento recuperar para el contexto del modelo; MCP decide cómo accedes de forma estandarizada a una capacidad o a una fuente. Se combinan sin problema —una herramienta MCP puede ser precisamente la que recupera—, y el criterio para elegir lo tratamos en MCP vs RAG.
| Dimensión | MCP | RAG |
|---|---|---|
| Qué resuelve | Conectar capacidades y fuentes | Recuperar conocimiento relevante |
| Qué hace con ello | Puede ejecutar acciones | Aporta contexto al modelo |
| Qué es | Un protocolo | Un patrón de arquitectura |
| Piezas | Tools, resources y prompts | Embeddings, índice y recuperación |
Errores habituales al llevar MCP a producción
Casi ninguno es culpa del protocolo; son decisiones que se pagan después.
- Exponer el endpoint HTTP sin autenticación: el fallo más grave y el más fácil de cometer.
- Publicar herramientas «por si acaso»: cada registro amplía la superficie expuesta.
- Lógica de negocio en el handler: la anotación publica, el servicio decide.
- Tratar los hints como permisos: readOnlyHint describe, no autoriza.
- Pasar el tenant o el usuario como argumento del modelo: la identidad va por contexto seguro.
- Sin tiempos de espera: un servidor lento bloquea el bucle y dispara el coste.
- Renombrar herramientas sin avisar: rompes a consumidores que no ves.
- Un mega-servidor para toda la empresa: ownership difuso y despliegues acoplados.
- Partir de un transporte deprecado: SSE existe por compatibilidad, no como punto de partida.
- Registrar payloads completos: por el transporte pueden viajar datos personales.
Cuándo usar MCP y cuándo no
Regla práctica: si la capacidad solo existe para una aplicación, una herramienta local basta. Si tiene que sobrevivir a varios consumidores, MCP empieza a pagar su coste.
| Escenario | ¿MCP? | Motivo |
|---|---|---|
| Herramienta privada de una sola aplicación | Probablemente no | Una @Tool local evita el salto de protocolo |
| Capacidad reutilizada por varios agentes o equipos | Sí | El contrato se escribe una vez |
| Herramientas en tecnologías distintas | Sí | El protocolo es independiente del lenguaje |
| Proceso local junto al host: IDE o escritorio | Sí, con STDIO | Sin endpoint de red que proteger |
| Servicio remoto con varios clientes | Sí, con Streamable HTTP | Es el transporte pensado para eso |
| Solo necesitas estructurar la respuesta | No | Eso lo resuelve Structured Output |
| Solo necesitas responder con documentación propia | No | RAG cubre el caso |
| Acción muy acoplada al dominio y sensible a la latencia | Mejor local | El salto de protocolo no compensa |
Conclusión
Tool Calling define cómo el modelo solicita una capacidad. MCP define cómo esa capacidad se publica, se descubre y se reutiliza entre sistemas. Son capas distintas del mismo problema, y en una aplicación Spring AI acaban trabajando juntas: lo que publica un servidor MCP termina ejecutándose en el mismo bucle que una herramienta local.
Si una capacidad solo existe para una aplicación, una @Tool puede ser suficiente. Cuando tiene que compartirse entre hosts, equipos o tecnologías, MCP empieza a tener sentido. La pregunta importante no es si podemos usar MCP, sino qué capacidades merece la pena convertir en un contrato interoperable, y qué controles las acompañan cuando lo hacemos.
Con esto se cierra el recorrido del cluster: Structured Output da forma a los datos, Tool Calling da acceso a las acciones y MCP convierte esas acciones en capacidades que otros pueden consumir.
Fuentes técnicas
- Spring AI — Model Context Protocol (MCP)
- Spring AI — MCP Server Boot Starters
- Spring AI — MCP Client Boot Starter
- Spring AI — MCP Server Annotations
- Spring AI — MCP Client Annotations
- Spring AI — Streamable HTTP MCP Server
- Spring AI — Stateless MCP Server
- Spring AI — MCP Security (trabajo en curso, proyecto de la comunidad)
- Spring AI — Upgrade Notes
- Model Context Protocol — especificación oficial
Preguntas frecuentes
¿Qué es MCP en Spring AI?
Model Context Protocol es un protocolo abierto para publicar y consumir capacidades —tools, resources y prompts— entre aplicaciones. Spring AI lo integra sobre el MCP Java SDK con starters de cliente y de servidor, así que una aplicación Spring Boot puede ejercer cualquiera de los dos papeles.
¿Qué diferencia hay entre MCP y Tool Calling?
Tool Calling es el mecanismo por el que el modelo solicita una herramienta dentro del bucle. MCP es el protocolo que permite publicarla y descubrirla desde otros sistemas. No compiten: lo que descubre un cliente MCP acaba ejecutándose en ese mismo bucle.
¿Qué diferencia hay entre @Tool y @McpTool?
@Tool registra una herramienta dentro de tu aplicación y la consume tu ChatClient. @McpTool publica una operación en un servidor MCP para cualquier cliente compatible. Esa operación puede convertirse en ToolCallback en el cliente y participar en el bucle como una local.
¿Cómo se crea un servidor MCP con Spring AI?
Añadiendo el starter correspondiente —spring-ai-starter-mcp-server para STDIO, o las variantes webmvc y webflux para HTTP—, configurando nombre, versión y protocolo, y anotando métodos con @McpTool, @McpResource o @McpPrompt. El JSON Schema de los argumentos se genera a partir de la firma del método.
¿Cómo se crea un cliente MCP en Spring Boot?
Con spring-ai-starter-mcp-client o su variante WebFlux, declarando conexiones con nombre: una por servidor, con su URL para Streamable HTTP o su comando para STDIO. Cada conexión crea una instancia de cliente y el tiempo de espera es configurable, con 20 segundos por defecto.
¿Qué son tools, resources y prompts en MCP?
Son las tres primitivas del protocolo: una tool ejecuta una operación con argumentos, un resource es contenido identificado por una URI que el cliente puede leer y un prompt es una plantilla de interacción reutilizable.
¿STDIO o Streamable HTTP?
STDIO cuando el servidor vive en la misma máquina que el host —IDE, escritorio, herramienta local—, porque no hay endpoint de red que proteger. Streamable HTTP cuando es un servicio independiente con varios clientes; además sustituye al SSE original.
¿SSE está deprecado en Spring AI?
Sí para los servidores: la documentación de los starters marca SSE WebMVC y SSE WebFlux como deprecados desde la versión 2.0.0 y recomienda usar STREAMABLE. Siguen disponibles por compatibilidad, pero no son el punto de partida para un desarrollo nuevo.
¿Qué diferencia hay entre un servidor STREAMABLE y uno STATELESS?
STREAMABLE mantiene sesión entre peticiones y habilita los flujos interactivos del protocolo. STATELESS no la mantiene: simplifica el despliegue a cambio de renunciar a sampling, elicitation y ping.
¿Un servidor MCP de Spring AI incluye autenticación por defecto?
No. La documentación advierte de que los transportes HTTP exponen un endpoint JSON-RPC sin autenticar y que los starters no aplican autenticación ni autorización: cualquier cliente que alcance el endpoint puede listar e invocar lo registrado. Hay que poner una frontera de seguridad delante antes de exponerlo fuera de localhost.
¿Puede Spring AI conectarse a varios servidores MCP?
Sí: se declaran varias conexiones con nombre y cada una crea su cliente. Para convivir con varios catálogos, Spring AI genera prefijos de nombre que evitan colisiones y permite filtrar qué herramientas se incluyen.
¿Hace falta MCP para construir un agente?
No. Un agente puede funcionar con herramientas locales y Tool Calling. MCP aporta interoperabilidad: tiene sentido cuando la capacidad debe reutilizarse desde varios hosts, equipos o tecnologías.
Sigue leyendo
Ver todos los artículos- Leer artículo
Desarrollo con IA · JavaDesarrollo con IA15 minTool Calling con Spring AI: cómo conectar un LLM con tu backend Java
- Leer artículo
Desarrollo con IA · JavaDesarrollo con IA12 minStructured Output con Spring AI: de texto a objetos Java fiables
- Leer artículo
Spring AI · RAG · AgentesDesarrollo con IA13 minSpring AI, RAG y agentes: cómo construir aplicaciones Java con inteligencia artificial real
