Existe uma forma de expor qualquer serviço Spring Boot 4 como ferramenta de um agente de IA sem escrever uma linha de código de infraestrutura, e a maioria dos devs Java ainda não sabe que ela chegou de vez. Com o Spring AI 2.0, três anotações (@McpTool, @McpToolParam e @McpResource) fazem um método comum virar uma tool que o Claude, o ChatGPT ou qualquer cliente MCP enxerga e chama sozinho.
Neste artigo a gente vai do zero a um MCP Server rodando: o starter no build, o serviço anotado, a configuração de produção e o cliente consumindo. Tudo com código que parece de produção, do jeito que os sêniores fazem. Bora construir.
O problema: integrar serviço a agente de IA na unha
Quem já tentou conectar um backend a um agente de IA conhece o roteiro. Você cria um endpoint REST, escreve um schema JSON na mão pra descrever os parâmetros, monta um prompt gigante explicando pro modelo "quando a pergunta for sobre estoque, chame este endpoint com este corpo", e ainda assim o agente inventa o nome do campo, manda o tipo errado e ninguém sabe por que a chamada falhou.
O ponto é que o agente não tem como descobrir, em tempo de execução, quais funções existem, o que cada uma faz e quais argumentos ela aceita. Essa lacuna é justamente o que o Model Context Protocol (MCP) resolve. Criado pela Anthropic e adotado como padrão aberto, o MCP é um protocolo cliente-servidor onde o seu serviço (o MCP Server) publica um catálogo de tools e resources, e o cliente (o agente) descobre e invoca essas capacidades de forma estruturada. Pense no MCP como o "USB-C" da integração de IA: uma porta padrão em vez de um adaptador diferente pra cada modelo.
Até pouco tempo, montar isso em Java era trabalhoso. O suporte a MCP no Spring AI existia como starter experimental e exigia bastante configuração manual. Com o lançamento do Spring AI 2.0, isso mudou: o MCP virou cidadão de primeira classe do framework. A versão exige Spring Boot 4 como dependência, eleva o MCP Java SDK para a linha 0.18.x e introduz anotações declarativas. É sobre essas anotações que a gente vai falar.
Contexto técnico: o starter e a arquitetura MCP
A arquitetura do MCP tem três papéis. O host é a aplicação de IA (o Claude Desktop, uma IDE, um agente custom). O cliente vive dentro do host e fala o protocolo. O servidor é o seu Spring Boot, que expõe tools (ações que o agente pode executar) e resources (dados que o agente pode ler). O fluxo é sempre o mesmo: o cliente conecta, pede a lista de capacidades (tools/list), e depois invoca o que precisar (tools/call).
No Spring AI 2.0 você escolhe o servidor MCP pelo starter. Para um servidor HTTP de produção, o recomendado é o starter WebMVC, que já entrega o transporte novo. No Maven fica assim:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
E no application.yaml você identifica seu servidor. Esse nome e versão são o que o agente vê quando se conecta, então trate como contrato público:
spring:
ai:
mcp:
server:
name: catalogo-mcp-server
version: 1.0.0
# Streamable HTTP e o transporte padrao no Spring AI 2.0
protocol: streamable
Uma observação que vale ouro aqui, e que eu aprendi na marra ajudando um time a migrar: o transporte SSE (Server-Sent Events) foi depreciado no Spring AI 2.0 em favor do Streamable HTTP. Se você seguir um tutorial de 2025 que configura SSE, vai compilar, vai subir, e vai falhar na hora que o cliente MCP moderno tentar negociar o transporte. Já volto nesse ponto na seção de produção.
A solução: tools e resources com 3 anotações
Agora a parte boa. Imagine um serviço de catálogo de produtos que já existe na sua aplicação. Sem MCP, o jeito errado de expor isso pra um agente seria escrever um controller REST e descrever tudo num prompt externo:
// Jeito ERRADO: contrato vive fora do codigo, no prompt do agente
@RestController
public class CatalogoController {
@GetMapping("/produtos/{id}")
public Produto buscar(@PathVariable Long id) {
return repositorio.findById(id).orElseThrow();
}
// O agente nao sabe que este endpoint existe nem o que ele faz
}
Com o Spring AI 2.0, você anota o método de serviço diretamente. A anotação @McpTool publica o método como uma ferramenta, e a description é o que o agente lê pra decidir quando chamá-la. A @McpToolParam descreve cada argumento. Repare como o contrato passa a viver junto do código:
@Service
public class CatalogoTools {
private final ProdutoRepository repositorio;
public CatalogoTools(ProdutoRepository repositorio) {
this.repositorio = repositorio;
}
@McpTool(name = "buscar_produto",
description = "Busca um produto do catalogo pelo seu identificador numerico. "
+ "Retorna nome, preco e quantidade em estoque.")
public Produto buscarProduto(
@McpToolParam(description = "ID numerico do produto, ex: 42")
Long id) {
return repositorio.findById(id)
.orElseThrow(() -> new ProdutoNaoEncontradoException(id));
}
@McpTool(name = "verificar_estoque",
description = "Verifica se ha estoque suficiente de um produto "
+ "para uma quantidade desejada antes de fechar o pedido.")
public ResultadoEstoque verificarEstoque(
@McpToolParam(description = "ID do produto") Long id,
@McpToolParam(description = "Quantidade desejada pelo cliente") int quantidade) {
Produto p = buscarProduto(id);
boolean disponivel = p.estoque() >= quantidade;
return new ResultadoEstoque(disponivel, p.estoque());
}
}
Falta registrar essas tools no servidor. No Spring AI 2.0 isso é um bean de uma linha, que varre o objeto e expõe todo método anotado com @McpTool:
@Configuration
public class McpConfig {
@Bean
public List<ToolCallback> catalogoToolCallbacks(CatalogoTools tools) {
// Registra todos os metodos @McpTool do bean informado
return List.of(ToolCallbacks.from(tools));
}
}
E a terceira anotação, a @McpResource, serve para expor dados que o agente pode ler como contexto (em vez de uma ação). É perfeita para coisas como uma política de troca, um manual ou um catálogo em texto. O agente acessa por um URI, no estilo catalogo://politicas/troca:
@Service
public class PoliticasResource {
@McpResource(uri = "catalogo://politicas/troca",
name = "politica_troca",
description = "Politica oficial de troca e devolucao da loja.")
public String politicaDeTroca() {
return String.join("\n",
"Trocas em ate 7 dias corridos apos o recebimento.",
"Produto deve estar lacrado e com nota fiscal.");
}
}
Pronto. Sem controller, sem schema JSON na mão, sem prompt externo descrevendo a API. Três anotações e o seu serviço virou um catálogo de capacidades que qualquer agente MCP descobre sozinho.
Impacto prático: o detalhe da description e o transporte
Tem uma armadilha que derruba quase todo mundo no primeiro MCP Server, e ela não dá erro: tratar a description como comentário opcional. No mundo REST a documentação é pra humano. No mundo MCP, a description da tool e dos parâmetros é o código que o modelo executa mentalmente pra decidir se e como chamar a função. Uma tool chamada verificar_estoque com description vazia simplesmente não é invocada, ou é invocada na hora errada, e você acaba culpando o modelo por um contrato que você escreveu mal. Capriche na description como se fosse a assinatura do método, porque pro agente é exatamente isso.
O segundo ponto é o transporte. Como falei lá em cima, o Spring AI 2.0 depreciou o SSE em favor do Streamable HTTP. Na prática, o que muda pra você:
- Streamable HTTP usa um único endpoint HTTP que suporta tanto requisição/resposta quanto streaming, o que simplifica firewall, proxy reverso e load balancer. É o padrão que os clientes MCP novos negociam.
- SSE ainda funciona por compatibilidade, mas vai sair. Não comece projeto novo nele.
- Use o starter
spring-ai-starter-mcp-server-webmvcpara servidores stateful tradicionais, ou o WebFlux quando precisar de reativo de ponta a ponta.
Do lado de quem consome, conectar um cliente Spring AI ao seu servidor é igualmente declarativo. Um agente que usa o seu MCP Server lista as tools e deixa o modelo escolher:
@Bean
public CommandLineRunner demo(ChatClient.Builder builder,
SyncMcpToolCallbackProvider mcpTools) {
return args -> {
ChatClient chat = builder
.defaultToolCallbacks(mcpTools.getToolCallbacks())
.build();
String resposta = chat.prompt()
.user("Tem 3 unidades do produto 42 em estoque?")
.call()
.content();
// O modelo decide chamar verificar_estoque(42, 3) sozinho
System.out.println(resposta);
};
}
Note como o provider de options do chat agora segue o padrão builder: o Spring AI 2.0 removeu os setters dos options dos provedores (OpenAI, Anthropic, Gemini). Código 1.x que fazia options.setTemperature(...) compila e quebra na migração, então prefira sempre o builder, como o time recomenda no release.
Sobre quando vale a pena: exponha como MCP os serviços que um agente realmente se beneficiaria de orquestrar (consultas, verificações, ações idempotentes e seguras). Evite expor operações destrutivas sem uma camada de confirmação, e nunca mande dado sensível numa @McpResource aberta sem autenticação, porque o resource é legível pelo host.
Conclusão e próximos passos
O Spring AI 2.0 tirou a integração com agentes de IA do território do "gambiarra com prompt" e colocou no território do Spring de sempre: anotação, bean, configuração. Os três pontos pra levar pra casa:
- 3 anotações resolvem:
@McpToolpublica ações,@McpToolParamdescreve argumentos e@McpResourceexpõe dados de contexto, tudo junto do seu código de serviço. - A description é contrato, não comentário: é ela que o agente usa pra decidir a chamada. Trate com o mesmo cuidado de uma assinatura de método público.
- Streamable HTTP é o novo padrão: o SSE foi depreciado, então comece projeto novo já no transporte certo e use o builder dos options no lugar dos setters removidos.
Como Tech Leader, o que mais me chama atenção aqui é o quanto isso muda a conversa em entrevista e em arquitetura: dá pra transformar um microserviço legado numa ferramenta de agente sem reescrever a regra de negócio. Isso é diferencial de quem leu o release notes contra quem só ouviu falar.
Você já está expondo serviços como MCP Server na sua stack, ou ainda tá na fase do wrapper REST na unha? Conta nos comentários como tem sido a adoção do Spring AI 2.0 no seu time. E se quiser ir mais fundo, na próxima a gente mostra como proteger o MCP Server com Spring Security 7 e autenticação por token, que mudou no Spring Boot 4. Quer ver os fundamentos de IA no Spring antes? Dá uma olhada nos nossos artigos sobre Spring AI e integração com LLMs, sobre Virtual Threads no Spring Boot 4 e sobre a migração do Spring Boot 3 para o 4. Documentação oficial completa do protocolo está no site do Model Context Protocol.
Perguntas frequentes (FAQ)
Preciso do Spring Boot 4 para usar o Spring AI 2.0?
Sim. O Spring AI 2.0 tem o Spring Boot 4 como dependência obrigatória e mira o Java 25 LTS como runtime de produção. Para projetos ainda em Spring Boot 3.x, use a linha 1.x do Spring AI ou planeje a migração antes.
Qual a diferença entre @McpTool e @McpResource?
A @McpTool expõe uma ação que o agente pode executar (e que pode ter efeito colateral), enquanto a @McpResource expõe dados somente leitura que o agente acessa por um URI como contexto. Tool é verbo, resource é substantivo.
O transporte SSE ainda funciona no Spring AI 2.0?
Funciona por compatibilidade, mas foi depreciado em favor do Streamable HTTP. Para qualquer projeto novo, use Streamable HTTP, que é o transporte que os clientes MCP atuais negociam por padrão.
Como o agente sabe quando chamar minha tool?
Pela description da @McpTool e de cada @McpToolParam. O modelo lê esses textos junto com a pergunta do usuário e decide a chamada. Descrições vagas resultam em tools que nunca são invocadas.
Dá para expor um serviço legado como MCP sem reescrever a regra de negócio?
Sim, esse é o ponto forte. Você cria um bean fino que anota com @McpTool os métodos do serviço existente e registra com ToolCallbacks.from(...), sem tocar na lógica original.