# MCP Java SDK como anti-corruption layer: integração LLM sem desmontar a stack enterprise

> 21 de maio de 2026 · https://eldermoraes.dev/mcp-java-sdk-como-anti-corruption-layer-integracao-llm-sem-desmontar-a-stack-enterprise/

Há um padrão recorrente em times Java enterprise nos últimos meses: a pressão pra integrar LLM vem de cima, mas a stack já tem mais de dez anos de investimento em segurança, observabilidade, governança e operação. Quarkus Security, Spring Security, OAuth/OIDC, OpenTelemetry, auditoria por aspecto, deploy em OpenShift, runbooks de SRE. Aí chega o "vamos adicionar IA" e a sugestão default é plugar o LLM direto nos serviços de negócio (_exposing the kitchen_), como se a década anterior de disciplina arquitetural tivesse virado opcional.

Não tem que ser assim. A peça que coloca ordem nessa casa é o MCP Java SDK, mas só funciona se ele for adotado pelo que é arquiteturalmente: uma _anti-corruption layer_ entre LLMs e sistemas core. À primeira vista, parece outra coisa (um think client SDK pra chamar tools de LLM em Java), e é essa leitura que limita o valor extraído dele.

## O reframing que muda a discussão

A InfoQ formula a tese de forma direta: _"MCP servers act as anti-corruption layers between LLMs and core systems, exposing controlled capabilities rather than raw APIs, helping protect legacy and mission-critical systems."_ ([InfoQ: MCP Java SDK como estratégia arquitetural pra integrações LLM](https://www.infoq.com/articles/mcp-java-architectural-strategy-llm-integrations/))

O termo "anti-corruption layer" aqui é literal, no sentido técnico do Eric Evans em Domain-Driven Design: uma camada de tradução deliberada que isola um modelo de outro modelo, impedindo que conceitos, formatos e premissas vazem de um lado pro outro. Em DDD clássico, você usa ACL entre um bounded context novo e um legado, a fim de que o legado não contamine o novo bounded context.

O reframing do MCP pega exatamente esse padrão e aplica entre dois mundos com modelos mentais completamente diferentes:

- De um lado, o **LLM**: um agente probabilístico que opera por linguagem natural, descobre intenção em tempo de execução, e não tem garantias de comportamento sobre quais campos vai querer ler, em que ordem de operações vai propor, ou que dados vai cruzar.
- Do outro, o **sistema core** (banco de dados, serviço de pagamento, sistema de pedidos, ERP), onde cada operação tem contrato fechado, auditoria, permissão, transação, e às vezes vinte anos de cicatrizes que viraram regras de negócio implícitas no código.

Conectar esses dois mundos com um naked adapter é criar uma superfície de contato onde a imprevisibilidade do LLM passa direto pro seu sistema crítico. O MCP server, quando entendido como ACL, faz a tradução: expõe **capacidades controladas** em vez de APIs cruas.

## Por que "thin wrapper" é a leitura errada

A leitura comum do MCP Java SDK quando ele aparece nas pautas é: "ah, é um jeito de chamar tools do modelo em Java, igual o SDK Python." Essa leitura colapsa o MCP em "client library". É verdade que o SDK cobre os dois lados (você pode escrever clients e servers), mas o valor arquitetural está no lado **server**.

Pensar em "thin wrapper" leva a três anti-patterns previsíveis:

1. **Mapear 1-para-1 método de serviço Java → tool MCP.** Seu `PaymentService.processPayment(orderId, amount, method)` vira tool MCP com a mesma assinatura. O LLM agora tem acesso direto a uma operação que assume contexto que ele não tem (status do pedido, permissão do usuário, política de fraude).
2. **Expor entidades de domínio na superfície MCP.** O LLM lê e escreve em representações que existem por razões internas (audit fields, soft delete flags, versionamento ORM). Cada mudança de schema interno vira mudança de comportamento exposto ao modelo.
3. **Confiar em prompt como controle de acesso.** "Diga ao modelo que ele não pode acessar X" é o equivalente LLM de validação no frontend. Não funciona como item de segurança.

Quando o MCP server é desenhado como ACL, surgem três regras de design positivas: - A tool MCP é uma **capacidade de caso de uso** (não uma operação de serviço) - Opera sobre **DTOs de fronteira** (não entidades internas) - O controle de acesso vive na camada Java tradicional **antes** da chamada chegar no core.

## O que isso preserva, e por que importa pra adoção enterprise

O segundo item evidenciado pela InfoQ é, no recorte do dev, ainda mais importante: _"The Java SDK allows teams to integrate LLMs while preserving existing security, observability, and operational practices, aligning with JVM ecosystems and frameworks such as Spring."_

Traduzindo pra realidade de quem opera Java enterprise: o MCP server **é um endpoint JVM como outro qualquer**. Ele roda dentro do seu processo (ou ao lado dele), exposto via STDIO ou Streamable HTTP (o transport SSE original do MCP foi consolidado dentro de Streamable HTTP). E exatamente por ser um endpoint JVM, tudo que você já tem se aplica sem adaptação:

- **Spring Security / Quarkus Security**: autenticação e autorização da chamada que chega no MCP server são a mesma autenticação e autorização que você já configura pros seus REST endpoints. JWT, OIDC, role-based access; não muda nada.
- **OpenTelemetry / Micrometer**: cada invocação de tool é um span. Cada erro é uma métrica. O dashboard de observabilidade que sua plataforma já consome continua sendo a fonte de verdade.
- **Aspectos de auditoria**: `@Audited` ou interceptors que você já roda em métodos de serviço continuam rodando, porque a tool MCP **delega** pro serviço em vez de substituí-lo.
- **Resilience4j, circuit breaker, retry policy**: wraps que vivem nos clientes HTTP/RPC continuam wrapping, porque o LLM nunca toca esses clientes diretamente.
- **Transaction management**: `@Transactional` no método de aplicação continua sendo a fronteira transacional. O MCP server não introduz um novo modelo transacional; ele é cliente do mesmo modelo que seus controllers REST são cliente.

Esse é o ponto que muda a viabilidade política da adoção. O MCP server entra como fachada controlada por cima do que já existe; a stack permanece intacta, e a integração com LLM vira mais um endpoint pra operar com o ferramental que o time já domina.

## Regras concretas pro design da fronteira de tools

A partir do reframing ACL, dá pra extrair regras de design que valem pra qualquer MCP server escrito em Java:

**1\. Cada tool expressa uma intenção de caso de uso, em vez de um endpoint genérico.**

`buscar_pedidos_em_aberto_do_cliente(client_id)` é uma tool. `executar_query_sql(sql)` está do outro lado da fronteira: é abrir o cofre. A granularidade certa é o caso de uso que o modelo precisa expressar, em vez da operação CRUD que o backend suporta.

**2\. O schema de input da tool usa um DTO de fronteira em vez do modelo de domínio.**

Use um record Java dedicado por tool. Versione o schema externamente; mudanças no modelo interno não devem propagar pro contrato MCP automaticamente. O modelo de domínio é seu; o contrato MCP pertence à interação com o LLM.

**3\. Autorização acontece _antes_ do tool body, no idioma da sua stack.**

Se você usa `@PreAuthorize("hasRole('CLIENT_READ')")` nos seus services, aplique a mesma anotação no método que implementa a tool. O MCP server propaga o principal pra frente, em vez de criar um modelo paralelo de permissão.

**4\. Side effects são explícitos no nome e no schema.**

`gerar_relatorio_pdf` (read-only) é diferente de `enviar_email_cliente` (efeito externo), que é diferente de `cancelar_pedido` (mutação de estado de negócio). Convencionar prefixos ou marcações no schema ajuda o operador humano que audita os logs depois.

**5\. Idempotência e correlation ID ficam no MCP server, em vez de serem delegadas ao LLM.**

Tool de mutação recebe (ou gera) um idempotency key. Toda chamada propaga correlation ID pro logging downstream. O LLM não deve "lembrar" se já chamou; assuma que pode chamar duas vezes.

**6\. Erros saem como tipos de domínio, em vez de stacktraces.**

A tool nunca retorna stacktrace pro modelo. Ela deve capturar na camada MCP, traduzir pra um tipo de erro de domínio que o LLM pode raciocinar a respeito (`cliente_nao_encontrado`, `saldo_insuficiente`, `operacao_nao_permitida`), e loga o detalhe técnico no seu sistema de observabilidade tradicional.

## A consequência arquitetural

Com essas regras, a arquitetura que aparece num serviço Java que adota MCP fica assim, conceitualmente:

```text
[LLM client / agente / Bob / Claude / Cursor / Codex]
            │
            ▼
[MCP server: endpoint JVM, mesma stack que REST]
            │
   (ACL: tools = casos de uso, DTOs de fronteira,
    autorização da plataforma, observabilidade,
    erros de domínio, correlation ID)
            │
            ▼
[Application services: sua camada de caso de uso existente]
            │
            ▼
[Domain model + integrações + persistência]
```

O LLM nunca fala com o domain model, nunca fala com o repository, e nunca enxerga o schema do banco. Ele fala com um conjunto deliberado de capacidades expostas por uma camada que existe exatamente pra mediar essa conversa. E essa camada vive na mesma JVM, sob a mesma operação, com a mesma observabilidade, e com as mesmas garantias de segurança que o resto da sua aplicação.

É o que torna a adoção enterprise viável sem precisar pedir desculpa pro time de plataforma ou pro CTO.

## Onde isso recoloca a conversa "LLM & Java"

A narrativa default sobre LLM e Java por muito tempo foi "é só glue, o trabalho de verdade tá no Python." Quando MCP server entra em cena como anti-corruption layer entre o modelo e os sistemas críticos, a história muda: o trabalho de verdade passa a estar **exatamente** onde Java sempre esteve forte: modelagem de domínio, contratos explícitos, controle de acesso, transações, observabilidade em produção.

A pergunta operacional que importa é qual superfície deliberada expor pro modelo e como ela se encaixa na arquitetura que já existe. Stack Java enterprise sabe responder pergunta assim, e o MCP Java SDK existe pra ser o veículo dessa resposta, complementando a stack em vez de tentar substituí-la.

E pra quem quiser aprender a usar não apenas MCP com Java, mas também LangChain4j e todo o seu ecossistema no ambiente enterprise, convido a conhecer o Método Java AI Specialist.

Saiba mais em: [https://eldermoraes.ai](https://eldermoraes.ai)
