Publicado 22 de set. de 202620 min de leitura
Agentes de IA são os novos consumidores: por que o Vinkius é o runtime seguro para fluxos de trabalho de agentes
Como agentes de IA se tornaram os primeiros consumidores estocásticos de uma plataforma cloud, e por que o Vinkius construiu um runtime em V8 isolates, um plano de controle de governança com doze superfícies e a arquitetura MVA do MCP Fusion como o sistema operacional seguro que agentes não podem ignorar.

Por Renato Marinho
Founder · Vinkius
Tenho estado vivendo dentro de fluxos de trabalho de agentes por seis meses. Não olhando demos em slides. Vivendo isso. Vendo agentes agendar reuniões, escrever código, consultar bancos de dados, mover dinheiro, abrir tickets e esquecer o número do ticket na próxima chamada. E o que eu aprendi é simples: agentes não são modelos mais capazes. São atores que executam escritas no mundo através de ferramentas, e a pergunta deixa de ser se um agente consegue planejar uma tarefa. A pergunta é se a infraestrutura que hospeda essas ferramentas consegue sobreviver ao instante em que o agente decide agir.
Este é o post em que explico como o Vinkius se tornou o sistema operacional para agentes de IA, e por que o vão entre um agente em um demo e um agente com o qual você deixaria passar credenciais de produção não é um problema de modelo. É um problema de infraestrutura. E a resposta mora na arquitetura que construímos para o MCP Fusion.
O agente não é um usuário. É uma nova classe de consumidor.
Toda plataforma SaaS nos últimos vinte anos foi construída para um tipo de chamador: um humano atrás de um navegador, ou uma conta de serviço atrás de um script conhecido. Ambos se comportam como o interior de um sistema. Fazem o que é dito. Falham rápido quando o schema quebra. Não fazem retry numa chamada que retornou erro quatro vezes, porque não esquecem esse erro de três turnos atrás. Não perdem de vista quais ferramentas existem após um handoff para um especialista. Não engolem uma resposta de duzentos kilobytes no contexto e depois resumem uma linha que não existe, porque truncamento é invisível a eles.
Um agente de IA não é nenhuma dessas coisas. Um agente é estocástico por construção. Ele vai mandar "INV-999" como ID de fatura mesmo quando acabou de listar as faturas e viu três delas. Faz retry numa chamada que retornou 404 com a mesma entrada, porque não se lembra daquele 404 de três turnos atrás. Perde de vista quais ferramentas existem após um handoff para um especialista. Fica em loop numa ferramenta quebrada até que o orçamento de tokens colapse.
E aí chama seu banco de dados de produção. Sua API de pagamentos. Seu pipeline de CI.
Os agentes já estão atuando. Estão atuando em registros de CRM, em faturas, em estado de infraestrutura. A pergunta não é mais se eles vão agir. A pergunta é se a superfície sobre a qual eles atuam é construída para um principal não-determinístico que não consegue ler um schema e não consegue lembrar de uma conversa.
Por que o MCP Fusion não é apenas mais um servidor MCP
O MCP resolveu o problema de descoberta que manteve toda integração LLM presa em chains de prompt frágeis. Mas servidores MCP comuns herdam todos os problemas do modelo de servidor cru, e esses problemas se tornam catastróficos quando o consumidor é um agente e não um humano. Um servidor cru vaza o que retorna, porque sua saída é a linha, serializada. Um servidor cru não aplica nada, porque seu middleware é convenção, não garantia. Um servidor cru não vê seu próprio drift, porque não tem mecanismo para detectar que a superfície que expõe hoje difere do que expunha ontem. Um servidor cru responde erros com strings, e o agente faz retry com a mesma string.
O MCP Fusion conserta isso com uma arquitetura chamada MVA, e o nome é o ponto. O corte não é arbitrário. É o corte que o código de aplicação já conhece, mas apontado para um consumidor novo.
O Model define o que os dados são e o que pode sair do processo. Declara campos, tipos e descrições. Essas descrições não são documentação para humanos. Compilam, a tempo, em regras de interpretação que o agente recebe em cada resposta. O model declara campos ocultos, hashes de senha, flags internas, marcadores de tenant, e eles nunca cruzam a fronteira. Uma nova coluna no banco de dados não vaza para um agente até alguém declará-la no model. Um servidor cru não tem essa propriedade.
O Presenter define o que o agente percebe sobre os dados. Antes de qualquer serialização, o presenter roda seu schema sobre o resultado bruto em modo strip. Seja o que o banco devolvia, o agente vê só a superfície declarada. Isso é controle de egresso em nível de RAM, não uma camada de view, não um template, não uma convenção. Um campo que o schema não conhece não cruza. O presenter também anexa regras de sistema, limites de trabalho e afinidades. O suggestActions diz ao agente o que ele pode fazer em seguida com o que acabou de ver. Isso é HATEOAS para agentes. A resposta não é um payload. É uma posição num fluxo. Blocos de gráfico renderizados no servidor são determinísticos: o framework renderiza, o agente lê, e nenhum modelo no meio gera os pixels.
As Ferramentas definem os verbos. f.query é somente leitura por padrão. f.mutation é destrutivo por padrão. f.action é neutro. Esses não são rótulos de metadados. Eles definem o que a plataforma trata como seguro para retry, o que o pipeline de observabilidade marca e o que uma ferramenta de governança acusa quando uma leitura vira escrita.
Uma regra mantém a separação honesta, e é uma propriedade de segurança, não uma regra de estilo. Direção. Ferramentas importam presenters, presenters importam models, models importam o core, e nada importa para trás. A camada que toca seus dados nunca pode ser a camada que um agente dirige.
Essa é a arquitetura na qual cada conector implantado no Vinkius Cloud é construído, e é por isso que o runtime não precisa confiar no código que executa.
A camada de isolate V8: onde o código do cliente encontra o controle da plataforma
Todo servidor MCP que um cliente envia no Vinkius Cloud é, aos poucos, código de terceiros executando na nossa infraestrutura. Não é o nosso. Não é uma biblioteca que controlamos. É dele. Um cloud para agentes de IA só é útil se os clientes podem trazer sua própria lógica, seus próprios conectores, grudar um LLM ao sistema deles. Uma vez que essa capacidade existe, a pergunta vira: como roda JavaScript não confiável para milhares de tenants num pequeno número de servidores sem dar a um só deles um caminho para machucar os outros, a máquina, ou os vizinhos?
A resposta é um isolate V8 por tenant, construído no Node.js com isolated-vm, o binding C++ que deixa um processo Node possuir um isolate V8 nativo. Não um container por tenant. Não um processo por tenant. Um isolate. Um heap com seu próprio coletor de lixo, seu próprio escopo global e um teto de memória duro de 128 MB que o motor aplica, não o aplicativo. Quando o heap de um tenant bate nele, o isolate desse tenant para de servir. Os outros tenants continuam. O globalThis de um tenant não é alcançável pelo isolate de outro, porque não existe limite JavaScript compartilhado nenhum.
O boot é dividido em duas fases, e só a primeira aparece em métricas de cold start. Fase um: o binário V8 e a camada de polyfills inicializam, o que leva de 50 a 100 milissegundos no primeiro contato com um deploy. Fase dois: o bundle do tenant é carregado, embrulhado e executado dentro do isolate, o que acontece em cada request porque o snapshot não consegue capturar estado assíncrono. A plataforma faz snapshot do ambiente, não do programa. A camada de polyfills é estática para um deploy. O que muda por request é o código do tenant. O host roda o construtor de snapshot sobre o ambiente provisionado e cacheia o blob resultante no disco, chaveado pelo ID do deploy e carimbado com a versão do V8. Na restauração, um isolate fresco é criado a partir desse blob em 15 a 25 milissegundos no total. O bundle reexecuta, porque a criação de isolate a partir de um snapshot não consegue lidar com async top-level await, mas o trabalho de polyfill acontece exatamente uma vez por deploy.
A versão do V8 importa. Isolates de V8 não são compatíveis entre versões maiores do motor. Um snapshot feito em V8 versão N não carrega em V8 versão N+1. O host carrega o blob de snapshot com a versão do motor e recusa a carregar um blob cujo carimbo não bate com a versão em execução. Um mismatch é um cache miss, não um crash.
A isolação não é só memória. O ambiente vazio que o isolate V8 dá a você não tem fetch, não tem crypto, não tem timers, não tem process. Nada que toque o mundo lá fora existe dentro do isolate. O fetch num bundle de tenant é um polyfill no lado do guest, mas o request de fato acontece no host, através da ponte do host, como uma cópia ArrayBuffer segura no byte entre as bordas. Crypto.subtle.digest e HMAC, os que a verificação de JWT precisa, são do lado do host também, e o host verifica assinaturas com comparação de tempo constante. Timers são chamadas setTimeout do host que invocam de volta para o guest através de um invoker registrado, limitados a cinco segundos no nível do framework e trinta segundos no nível do dispatch. A regra é simples. O polyfill faz a chamada parecer nativa. O host é o que possui o efeito. Um tenant pode expressar intenção. Não chega ao sistema operacional.
Esse é o design que descrevi em detalhes no post sobre isolates V8. O limite de cinco segundos é o teto de execução por isolate. O limite de trinta segundos é o teto de dispatch. O limite dez megabytes de resposta é o teto de egresso. Os três são políticas nomeadas no config do runtime, não números mágicos, e os três são documentados ao lado da constante que os define.
O guardião SSRF: o tráfego de saída como política, não como padrão
A coisa mais perigosa que um bundle de tenant pode fazer é uma requisição HTTP. Fetch é uma fonte universal de SSRF. Um bundle descuidado ou malicioso apontando uma ferramenta pro serviço de metadados da AWS, no endereço 169.254.169.254, dá ao agente de um cliente um caminho de leitura nas credenciais da instância.
Todo tráfego de saída passa pelo guardião SSRF. O guardião funciona por um princípio. Um endereço é válido por tempo quanto a política que o aprovou for válida. O guardião resolve DNS antes do request e bloqueia ranges privados de cara: loopback, 10 slash 8, 172.16 slash 12, 192.168 slash 16, link-local 169.254 slash 16, zero slash 8 e seus gêmeos IPv6. Depois, fixa o IP aprovado na conexão, de modo que um ataque de rebinding não troque o endereço depois da triagem. E mantém SNI e TLS alinhados com o endereço fixado, porque fixar no nível do socket sem fixar o nome jogaria erros de certificado em cada request.
As respostas fluem para o isolate com um contador de bytes correndo, com teto duro em dez megabytes, e um AbortController ligado ao todo o caminho do dispose. Quando um isolate é desativado, seus requests em voo são abortados na mesma chamada. Quando um dispatch estoura no teto de trinta segundos, um classificador pergunta o que o isolate estava fazendo no momento da falha. I/O de saída em voo, o guest computando, ou pressão de memória. O erro da ferramenta que volta para o agente carrega a resposta, mais uma dica de recuperação.
O tempo de vida do cache de DNS é acoplado ao tempo de vida da conexão. Um endereço triado é cacheado exatamente o tempo que o pool segura um agente keep-alive pra ele, até 65 segundos por padrão. Um endereço não sobrevive à política de conexão que justificou fixá-lo. Não existe TTL independente por design, e essa é a propriedade que fecha totalmente a janela de rebinding.
O caminho de auditoria criptográfica: uma cadeia que você não pode forjar
Todo o tráfego de agentes, todas as chamadas de ferramenta, todos os dados fluindo para e do conectores, fluem para um daemon de streaming single-threaded. Esse daemon forja uma cadeia SHA-256 e assina com uma chave Ed25519 de sessão. A chave de sessão fica em RAM por vinte e quatro horas e é certificada pela chave mestra no boot. Cada hash de chamada é selado na ingestão. Cada registro carrega o hash anterior e sua posição na sequência. A cadeia é assinada. Uma manipulação não é um problema de privacidade. É um evento detectável.
A entrada da cadeia é o payload em base64 concatenado com o hash anterior e o número de sequência. O hash atual é SHA-256 dessa entrada. A assinatura é Ed25519 sobre a mesma entrada, usando a chave privada de sessão. A chave de sessão roda a cada vinte e quatro horas, e a cadeia continua sem lacuna. O estado da cadeia é checkpointado em Redis Streams, de modo que um crash retoma do último evento reconhecido em vez de rederivar a cadeia. Adaptadores SIEM drenam aquele mesmo stream por trás dos próprios disjuntores. Um sink que falhe é isolado em vez de fazer o caminho de auditoria travar.
A auditoria é estruturada sobre o Artigo 73 do GDPR, o direito de acesso do titular. Quando um regulador ou cliente pede o histórico completo de um conector, a resposta é uma única cadeia exportável e verificável, não um projeto.
E aqui é a fronteira que tenho mais orgulho. V8 nunca toca em crypto. O código do tenant consegue computar um hash pelas pontes do host, mas não consegue assinar, certificar ou forjar nada. O caminho de auditoria é algo que a plataforma faz ao runtime, não algo que os tenants do runtime conseguem atingir.
O modelo completo de doze superfícies, a camada de auditoria, a camada de isca e o cofre são descritos no post sobre governança de IA.
As doze superfícies: governança como sistema operacional
Se você leu o post sobre governança de IA, conhece o plano de controle. Doze superfícies, oito que contam e quatro que decidem, assentando em tokens de conexão com escopo, um cofre selado para credenciais, um ledger encadeado por hash e uma camada de isca que contém o dano antes de você perceber. O que eu ainda não disse é como essas doze superfícies se mapeiam no novo consumidor, o próprio agente de IA.
O agente não vê as doze superfícies diretamente. Ele vê elas como restrições no ambiente em que opera. E essas restrições são o que permite entregar o agente no turno da noite, a query de produção, a reconciliação de pagamento.
Atribuição. Toda chamada de ferramenta carrega a identidade do token que a fez, o cliente por trás, o humano ou conta de serviço por trás daquilo. Não existe ação anônima em produção. Um agente que devia rodar a cada hora e está chamando a cada noventa segundos aparece no Mission Control, e é aí que um loop descontrolado é notado, antes de virar fatura.
Blindagem. Campos sensíveis são mascarados em memória, no caminho de saída entre o serviço de fora e o modelo. A blindagem acontece antes que a resposta chegue ao agente. A diferença entre dados que foram mascarados e dados que nunca estiveram no contexto do modelo.
Controle de custo. O disjuntor aplica um orçamento de chamadas em janela deslizante por conector, com padrão de cinco mil chamadas a cada cinco minutos e resfriamento de quinze minutos. Quando o orçamento estoura, o disjuntor dispara e avisa o agente, numa recusa legível por máquina escrita para um modelo, que o recurso está aberto e que ele deve recuar. Um agente bom respeita isso. Um loop que não consegue ler a recusa é parado pelo mesmo disparo, que é o ponto. O estado do disjuntor é compartilhado entre a frota de gateways, então um orçamento é um orçamento, não um limite por processo que reseta quando o tráfego troca de instância.
Recuperação de erro. Um servidor cru responde a uma chamada ruim com uma string plana. O agente faz retry com a mesma string. O MCP Fusion responde com um envelope autorreparável. Um código específico, uma mensagem, uma sugestão e uma lista de ações que o agente pode tomar no lugar. InvoiceNotFound diz algo ao agente que BAD_REQUEST não pode dizer, e a linha de recuperação tira a adivinhação que torna os loops caros. Esse é o assunto do post sobre arquitetura de conectores, onde o padrão MVA completo é explicado.
O capability lockfile: detecção de drift como compile step
Um dos fracassos silenciosos em sistemas agênticos é drift. O servidor que você implantou no mês passado expunha doze ferramentas. Hoje expõe dezessete, porque alguém adicionou cinco. O agente chama as novas. Ninguém revisou. A saída é a mesma linha, e vai pra outro lugar, e o caminho de auditoria registra a chamada, mas a superfície que foi revisada no CI não é a superfície que o agente consegue atingir.
O CLI do MCP Fusion roda uma segunda compilação, introspectiva, de cada bundle. Ele extrai os contratos das ferramentas, os prompts e o schema de credenciais e escreve tudo num capability lockfile. Isso é um snapshot determinístico da superfície comportamental do conector. O lockfile é diffável no git. Um fusion lock check no CI é a porta. A superfície que seu código expõe de fato é comparada com a superfície que você versionou, e o diff é classificado como breaking, risky, safe ou cosmetic.
O runtime que finalmente executa esse programa, selado e restaurado por snapshot, é o mesmo programa que produziu esse lockfile. O código fonte, o bundle compilado e o lockfile comitado são um único artefato. Drift não é possível porque drift significaria o lockfile discordar do código em execução, e isso falha a porta do CI.
O conector viaja como um único artefato. O comando mcpfusion deploy embala o servidor num arquivo autocontido: todas as dependências embutidas, builtins do Node substituídos por stubs que existem só pra satisfazer o bundler e nunca são chamados, e o transporte também stubado, porque a plataforma o fornece. O bundle passa numa porta de tamanho de 1,5 megabytes bruto, que é um orçamento, não uma especificação, depois é comprimido e hashado e vai para a edge. Se o hash bate com o implantado, a plataforma relata um restore instantâneo: os mesmos bytes, sem recarregar.
Orquestração multiagente: o SwarmGateway
Nem toda tarefa pode ser resolvida por um só agente. Alguns problemas precisam de especialistas. Um especialista de finanças, um especialista de devops, um especialista de operações de cliente. Cada um é seu próprio servidor MCP, seu próprio modelo, suas próprias ferramentas.
O SwarmGateway implementa o padrão B2BUA. Ele se apresenta ao agente chamador como um único servidor MCP com uma lista de ferramentas com prefixo. Quando o agente chama uma ferramenta com prefixo, o gateway tira o prefixo e encaminha a chamada pro servidor especialista upstream. Quando o agente termina com o especialista, uma única ferramenta de retorno fecha o túnel e restaura a lista de ferramentas do gateway. Cada handoff gera um token de delegação de curta vida, com escopo apenas a esse domínio, válido por sessenta segundos. O túnel sem atividade expira após cinco minutos.
Duas propriedades de segurança importam aqui. Primeiro, o token de delegação não escapa do seu sandbox, porque o gateway valida o domínio contra seu registry em cada chamada. Segundo, a ferramenta de retorno é injetada pelo gateway, não pelo upstream, o que significa que um especialista comprometido ou com bug não consegue enganar o agente para chamar um gateway diferente. O reescritor de namespace aplica isso no nível do nome da ferramenta.
E porque o gateway fala o mesmo contexto de trace do agente que chegou, cada span de ferramenta através do handoff do especialista se ancora na mesma trace. Você pode seguir o agente da camada de triagem ao especialista de finanças ao especialista de devops e de volta, tudo numa única trace distribuída. Esse trabalho, a propagação do contexto W3C Trace pelo gateway, foi lançado no MCP Fusion 5.1.0, e os detalhes estão no post sobre correlação de trace. Quando o enxame atinge o portão em larga escala, a camada de sessões precisa coalescer cada agente sem deadlock. Os mecanismos por trás do pooling de sessões, invalidação causal e o circuit breaker que mantém um enxame descontrolado sob controle estão no post sobre sessões do SwarmGateway.
O agente como principal governado
A maioria das conversas sobre governança de agentes trata o agente como um risco a conter, e eu não vou fingir ao contrário. O agente é um risco. Um principal não-determinístico chamando ferramentas contra sistemas de terceiros num orçamento. Esse é o risco.
Mas a outra metade do argumento é a que eu colocaria num deck de vendas: governança é o que transforma o agente de demo em funcionário.
Confiança é concedida na proporção da evidência. Um operador entrega o agente no turno da noite, a query de produção, a reconciliação de pagamento, na proporção exata em que cada ação que ele tomou pode ser atribuída, orçada, blindada e verificada depois. O comprovante não é um fardo sobre o agente. É a credencial que dá a ele a sala maior.
O envelope de um agente governado é conhecível. Uma política determinística em torno de um modelo não-determinístico é a única forma sã para produção: o modelo planeja dentro de uma caixa, e a caixa é estável. A recusa do disjuntor está escrita na linguagem do modelo, então o agente aprende o orçamento e o respeita, em vez de descobrir isso na forma de uma fatura. O truncamento do guarda de FinOps faz o modelo receber uma resposta com tamanho, em vez de um blob de trezentos kilobytes, que é um problema de inteligência, não só de custo.
E o agente ganha, ele mesmo, a capacidade que nenhum sistema autônomo teve na prática. Ele pode mostrar o trabalho. Para um agente que opera em fluxos regulados, o caminho de auditoria não é overhead. É o produto. O agente governado é o único tipo de agente ao qual dá pra dar autoridade real, e o agente sem governança é, pra sempre, uma demo.
Direção
O que eu descrevi acima é a stack que roda hoje. Não o plano. Não o roadmap. A stack na qual o servidor MCP de um cliente, construído com MCP Fusion, navega para a edge e executa.
A direção aberta é a stateful. Estado mais longo do tenant viajando pelos hooks de hibernação do isolate. Empacotamento mais denso de isolates vivos por host. Times trazendo seus próprios catálogos de conectores pro marketplace sem esperar no nosso CI. A camada de snapshot já carrega a interface de hibernação. A camada de state sync já entende invalidação causal. O que falta é a densidade e a experiência de desenvolvedor.
A direção mais profunda é a ponte de protocolo A2A. O MCP Fusion já expõe qualquer servidor como um agente compatível com A2A, com o endpoint de descoberta padrão no caminho well-known agent-card.json. O SwarmGateway já fala o padrão B2BUA. Quando o A2A amadurecer e os agentes começarem a se descobrir autonomamente, o gateway não muda. Ele já lida com uma frota de especialistas atrás de uma única superfície, com tokens de delegação com escopo e continuidade de trace em cada handoff.
O limite
Eu não acho que isolates V8 sejam a resposta final para código edge multi-tenant. São a resposta para o formato que essa plataforma tem, e o formato é onde eu quero que ele fique. Tenants baratos. Teto duro. Boot em escala de milissegundos. Porque a paciência de um agente é medida em segundos, e o confiança também.
Os agentes já estão atuando sobre os seus sistemas. A pergunta não é mais se você dá conta de governança. É se você dá conta do dia em que descobrir que não tinha. O Vinkius Cloud é o runtime que embarca essa governança, e o MCP Fusion é o framework que a torna composto. Ambos são o resultado de construir contra um invariante: o consumidor não é um humano lendo uma tela. O consumidor é um modelo que não consegue ler um schema e não consegue lembrar de uma conversa. Tudo o resto flui disso.
Se você está construindo agentes que atuam em sistemas de produção, o sistema operacional em que eles rodam deveria ser feito para esse consumidor, não adaptado depois. É isso que construímos. É isso que o código aplica. E é por isso que o caminho de auditoria é algo que a plataforma faz ao runtime, não algo que os tenants do runtime conseguem atingir.
O runtime por trás dos servidores MCP no cloud.vinkius.com é o que eu descrevi aqui. O framework é open source em github.com/vinkius-labs/mcpfusion. Ambos são escritos no mesmo invariante.
