Como construí uma integração de LLMs via MCP para um MES on-premise
Como construí um MCP para conectar um MES on-premise a GPT, Claude e Gemini
Quando começamos a levar IA para o nosso MES, a ideia parecia simples: permitir que alguém perguntasse em português “qual foi o OEE da linha 3 ontem?” e recebesse a resposta com os dados reais da fábrica.
O problema é que esse MES não roda em uma nuvem central. Ele roda dentro da infraestrutura de cada cliente, muitas vezes em um servidor que não pode ser atualizado a qualquer hora e cuja saída para a internet é bastante controlada.
Então a pergunta deixou de ser “qual modelo vamos usar?” e passou a ser outra:
Como fazer uma IA consultar dados industriais sem dar acesso direto ao banco, respeitando as permissões existentes e ainda permitindo que o cliente escolha o modelo?
A solução acabou envolvendo MCP, um serviço de IA separado e algumas decisões de arquitetura que só apareceram quando o projeto começou a funcionar de verdade.
Antes do MCP: um JSON gigante
Antes de existir o MCP, já tínhamos uma primeira versão da integração com IA.
A ideia era relativamente simples: a tela do MES sabia quais dados o usuário estava visualizando e enviava esse conteúdo para o serviço de IA em um JSON grande com os dados daquele contexto.
Para perguntas sobre aquela tela, funcionava.
Se o usuário estivesse olhando um relatório de produção e perguntasse algo sobre aqueles dados, o modelo conseguia responder.
Mas existia uma limitação importante: o modelo só sabia aquilo que a tela tinha enviado.
Se a pessoa perguntasse:
“E quais foram os principais motivos de parada dessa máquina?”
mas a tela atual não continha essas informações, a IA não tinha como descobrir.
Ela não tinha acesso ao banco.
Também não tinha uma ferramenta para pedir ao MES uma informação adicional.
Na prática, o fluxo era:
Usuário
│
▼
Tela do MES
│
│ JSON com os dados visíveis
▼
Serviço de IA
│
▼
ModeloEra uma abordagem segura, porque o modelo recebia somente os dados que já estavam no contexto da tela.
Mas também era bastante limitada.
A IA conseguia interpretar os dados que recebia, mas não conseguia buscar novos dados.
Foi justamente essa limitação que levou ao MCP.
MCP como camada entre a IA e o MES
Em vez de continuar aumentando o tamanho do JSON enviado para cada tela, a ideia passou a ser permitir que o modelo pudesse pedir informações adicionais de maneira controlada.
O MES passou então a expor funcionalidades específicas como tools:
O modelo não precisa saber como o dado é armazenado.
Para responder sobre o OEE, ele pode pedir algo como:
get_daily_oee
line = 3
date = 2026-09-21A execução acontece dentro do próprio MES.
Isso cria uma separação importante:
Modelo de IA
│
│ tool call
▼
MCP
│
│ regras de negócio
▼
MES
│
▼
BancoO modelo não acessa o banco e não executa SQL arbitrário.
A regra que virou princípio
Existe uma regra que considero especialmente importante:
a IA não pode discordar da tela.
O MES já possui a lógica usada pelos relatórios. Se um relatório de paradas mostra 42 minutos, não faz sentido implementar outro cálculo para a IA e correr o risco de ela responder 39.
As tools reutilizam as regras existentes.
A IA deve ser uma nova interface para a fonte de verdade do sistema, não uma segunda implementação dela.
Onde colocar a IA?
O próximo problema era arquitetural.
O MES é uma aplicação Java madura. Colocar dentro dele os SDKs da Anthropic, OpenAI e Google funcionaria, mas criaria um acoplamento ruim.
Modelos e SDKs mudam rapidamente. Um sistema industrial precisa de outro ritmo.
Então a IA ganhou um serviço próprio, instalado na mesma infraestrutura do cliente.
A arquitetura ficou aproximadamente assim:
┌─────────────────────────────────────────────────────┐
│ infraestrutura do cliente │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ MES │ │ AI Service │ │
│ │ │◀─MCP──│ │───┼──▶ GPT
│ │ /mcp │ │ orquestrador │───┼──▶ Claude
│ │ │ │ │───┼──▶ Gemini
│ └──────┬───────┘ └──────────────────────┘ │
│ │ │
│ ▼ │
│ Banco │
└─────────────────────────────────────────────────────┘O MES continua responsável pelos dados e pelas regras.
O serviço de IA conversa com os modelos e executa as tools através do MCP.
Assim, o banco continua isolado e apenas o componente que precisa falar com a internet faz chamadas externas.
Um serviço, três provedores
Outro requisito era não ficar preso a um único modelo.
O cliente pode já ter um contrato corporativo com um provedor, ou simplesmente preferir um modelo diferente.
Por isso, provedor, modelo e chave passaram a ser configurações do cliente.
Por baixo existem os SDKs oficiais dos três provedores, mas o serviço trabalha com uma abstração comum.
Isso trouxe um benefício importante: trocar de modelo não exige alterar ou reinstalar o MES.
O loop de tool calling
Uma pergunta também pode exigir mais de uma consulta.
Por exemplo:
“Quais foram as principais perdas da linha 3 ontem e qual foi o impacto delas no OEE?”
O modelo pode pedir os motivos de parada, receber os dados, perceber que precisa do OEE e fazer outra chamada.
O serviço então executa um loop:
pergunta
│
▼
modelo
│
├── precisa de dados? ── sim ──▶ tool
│ │
│ ▼
│ resultado
│ │
└──────────────────────────────────┘
│
▼
resposta finalMas existe um limite de iterações.
Perguntas normais usam poucas chamadas. O limite existe para impedir que o modelo entre em um ciclo de chamadas que aumenta desnecessariamente latência e custo.
Também surgiu outro problema: não dá para simplesmente mandar o resultado bruto de qualquer consulta para o modelo.
Um relatório de um mês, com dezenas de máquinas, pode gerar milhares de linhas.
Então alguns resultados são compactados antes de voltar para o modelo. O objetivo é manter a informação necessária para o raciocínio sem transformar o contexto em uma cópia do banco.
Menos tools também pode ser melhor
Outra decisão foi fazer o catálogo de tools depender do contexto.
Se o usuário está dentro de um relatório de paradas, não existe motivo para apresentar ao modelo todas as ferramentas disponíveis no MES.
Ele recebe apenas as relacionadas àquele contexto.
Isso reduz a quantidade de decisões que o modelo precisa tomar.
A mesma lógica vale para gráficos: a tool que permite pedir uma visualização só é disponibilizada quando a interface atual consegue renderizá-la.
Em vez de dizer ao modelo “você pode fazer tudo”, a arquitetura tenta dizer:
neste contexto, estas são as coisas que você pode fazer.
Segurança: principalmente o que a IA não pode fazer
Em um sistema industrial, dar liberdade demais para um modelo é uma decisão difícil de justificar.
Por isso, várias restrições foram colocadas diretamente na arquitetura.
O modelo:
- não acessa o banco;
- não executa SQL arbitrário;
- não possui tools de escrita;
- não recebe automaticamente as permissões do serviço;
- não pode consultar recursos que o usuário não poderia acessar no MES.
O endpoint MCP possui autenticação própria. Token ausente não significa acesso aberto: significa acesso negado.
E existe uma separação importante entre a sessão do serviço de IA e a autorização do usuário.
A conexão entre os serviços pode ser compartilhada, mas cada chamada de tool leva a identificação de quem fez a pergunta. O MES então aplica as regras de acesso existentes.
Assim, a IA não vira um atalho para acessar dados que o usuário normalmente não poderia visualizar.
E os dados que saem da fábrica?
Como o serviço de IA pode conversar com provedores externos, surgiu outra questão: e se o cliente não quiser enviar determinados nomes para o modelo?
Foi implementada uma opção de anonimização.
Antes de a conversa sair, nomes de máquinas, itens e motivos podem ser substituídos por identificadores.
CNC-04
↓
MACHINE_001
Produto ABC-123
↓
ITEM_014Na volta, esses identificadores podem ser reconstruídos.
O MCP acabou sendo maior que o chatbot
Talvez a consequência mais interessante do projeto tenha aparecido depois.
Quando o MES passou a expor suas capacidades através de MCP, ele deixou de depender da nossa própria interface para ser consumido por uma IA.
O mesmo endpoint pode ser utilizado por outros clientes compatíveis com o protocolo.
A arquitetura deixou de ser:
MES → nosso chatbote passou a ser:
┌── nosso chat
│
MES ── MCP ──────┼── cliente MCP externo
│
└── futuras IAsFoi aí que o MCP deixou de parecer apenas uma tecnologia para conectar um chatbot ao sistema.
Ele passou a ser uma interface padronizada para as capacidades do MES.
O que ficou de aprendizado
No começo, o problema parecia ser integrar um LLM com um sistema industrial.
Não era.
O problema era criar uma fronteira segura entre um modelo probabilístico e um sistema que precisa continuar sendo previsível.
O modelo pode mudar.
O provedor pode mudar.
O SDK pode mudar.
Mas a regra de negócio do MES precisa continuar sendo a mesma.
Por isso, talvez a decisão mais importante do projeto não tenha sido escolher entre GPT, Claude ou Gemini.
Foi decidir o que nenhum deles poderia fazer.
A IA não precisa conhecer a fábrica inteira.
Ela precisa conhecer exatamente aquilo que o sistema decidiu mostrar.
E, em software industrial, talvez seja essa a diferença entre simplesmente colocar IA em um produto e realmente construir uma arquitetura de IA.
Stack: Java/Spring · MCP sobre HTTP e stdio · SDKs oficiais da Anthropic, OpenAI e Google · Angular · Docker Compose · PostgreSQL · MES on-premise