O que o MCP não diz: Cinco primitivas para infraestrutura MCP em produção

Tiago Gimenes
Tiago Gimenes
6 de abril de 2026
O que o MCP não diz: Cinco primitivas para infraestrutura MCP em produção

MCP te dá três coisas: Client, Server e Transport. A spec é limpa. O SDK funciona. Mas no momento em que você tenta fazer proxy de um server, agregar ferramentas de cinco upstreams, ou fazer sandbox de código de usuário - você está escrevendo centenas de linhas de cola que o protocolo nunca previu.

A Anthropic publicou recentemente "Code Execution with MCP", mostrando que deixar LLMs escrever código contra ferramentas MCP dentro de um sandbox pode reduzir o uso de tokens em 98,7%. Arquitetura interessante. Mas publicaram um conceito, não uma biblioteca.

Estamos rodando esses padrões em produção como parte do deco CMS's control plane MCP open-source. Extraímos cinco primitivas em @decocms/mcp-utils (source). Aqui está o que a spec de MCP deixa de fora - e o código que preenche a lacuna.

5
Primitivas composáveis
98.7%
Redução de tokens com sandbox
~20
Linhas para um control plane completo

As cinco primitivas

Cada primitiva resolve um problema específico que o SDK de MCP não aborda. São pequenas, composáveis, e extraídas do uso em produção - não desenhadas no vácuo.

1

createBridgeTransportPair()

IPC in-process sem overhead. Conecte um Client e Server no mesmo processo sem precisar girar sockets ou pipes stdio.

2

createServerFromClient()

Transforme qualquer Client em um Server. Faça proxy de um server MCP remoto, adicione auth, re-exponha em um transport diferente, ou componha em um sistema maior.

3

WrapperTransport + composeTransport()

Middleware de transport. Intercepte tráfego MCP para logging, injeção de auth, rate-limiting, ou reescreva requisições com um pipeline composável.

4

GatewayClient

Agregação multi-server. Colete ferramentas de N upstreams, coloque um namespace, e roteeie chamadas para a origem correta.

5

runCodeWithTools()

Execução de código em sandbox. Deixe LLMs escrever código que chama ferramentas programaticamente em um sandbox QuickJS - o padrão por trás da redução de 98,7% de tokens da Anthropic.


1. createBridgeTransportPair() - IPC in-process sem overhead

Problema: Você tem um Client e Server no mesmo processo. Os transports do SDK de MCP assumem limites de rede - stdio, SSE, WebSocket. Girar um par de sockets para comunicação in-process é desperdício.

import { createBridgeTransportPair } from "@decocms/mcp-utils";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";

const { client: clientTransport, server: serverTransport } = createBridgeTransportPair();

const server = new Server({ name: "my-server", version: "1.0.0" }, { capabilities: { tools: {} } });
const client = new Client({ name: "my-client", version: "1.0.0" });

await server.connect(serverTransport);
await client.connect(clientTransport);

const tools = await client.listTools();
info
Nota de design

Mensagens são passadas por referência usando microtask scheduling - sem serialização, sem sockets. Microtask scheduling evita bugs de re-entrância que afligem message passing síncrono in-process.


2. createServerFromClient() - Transforme qualquer Client em um Server

Problema: Você precisa fazer proxy de um server MCP remoto - adicionar auth, re-expor em um transport diferente, ou compor em um sistema maior. O SDK não tem o conceito de "wrapp este client como um server."

import { createServerFromClient, createBridgeTransportPair } from "@decocms/mcp-utils";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";

// Conecte a um server MCP upstream
const upstreamClient = new Client({ name: "upstream", version: "1.0.0" });
await upstreamClient.connect(upstreamTransport);

// Exponha como um novo server
const proxyServer = createServerFromClient(upstreamClient, {
  name: "my-proxy",
  version: "1.0.0",
});

// Conecte o proxy a qualquer transport (SSE, stdio, bridge, etc.)
await proxyServer.connect(downstreamTransport);
info
Nota de design

Delega listTools, callTool, listResources, readResource, listPrompts, e getPrompt. Remove outputSchema de ferramentas repassadas - proxies não devem validar, é trabalho do server de origem.


3. WrapperTransport + composeTransport() - Middleware de Transport

Problema: Você precisa interceptar tráfego MCP para logging, injeção de auth, rate-limiting, ou reescrever requisições. O SDK de MCP trata transports como opacos - não há um modelo de middleware.

import { composeTransport, WrapperTransport } from "@decocms/mcp-utils";
import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";

class LoggingTransport extends WrapperTransport {
  protected handleIncomingMessage(msg: JSONRPCMessage) {
    console.log("←", msg);
    super.handleIncomingMessage(msg);
  }

  protected handleOutgoingMessage(msg: JSONRPCMessage) {
    console.log("→", msg);
    return super.handleOutgoingMessage(msg);
  }
}

class AuthTransport extends WrapperTransport {
  constructor(inner: Transport, private token: string) {
    super(inner);
  }

  protected async handleOutgoingMessage(msg: JSONRPCMessage) {
    // injetar headers de auth, reescrever requisições, etc.
    return super.handleOutgoingMessage(msg);
  }
}

// Componha middlewares - mensagens fluem através de logging, depois auth
const transport = composeTransport(
  baseTransport,
  (t) => new LoggingTransport(t),
  (t) => new AuthTransport(t, "my-token"),
);
info
Nota de design

Composição esquerda-para-direita, como middleware Express. Sobrescreva handleOutgoingMessage (client → server) e/ou handleIncomingMessage (server → client). Métodos auxiliares isRequest() e isResponse() para filtragem.


4. GatewayClient - Agregação multi-server

Problema: Seu agent precisa de ferramentas de N servers. Carregar todas as definições de ferramentas no contexto da LLM incha o uso de tokens - esse é exatamente o problema que a Anthropic identificou. Mas antes de poder otimizar descoberta de ferramentas, você precisa de um jeito de agregar e rotear entre múltiplos upstreams.

import { GatewayClient } from "@decocms/mcp-utils/aggregate";

const gateway = new GatewayClient({
  slack: { client: slackClient },
  google: { client: googleClient },
  github: { client: () => connectToGithub() }, // lazy - conectado no primeiro uso
});

// Lista ferramentas de todos os upstream servers
const { tools } = await gateway.listTools();

// Chame uma ferramenta - automaticamente roteada para o upstream correto
const result = await gateway.callTool({
  name: "slack_send_message", // namespaced: "{key}_{tool}"
  arguments: { channel: "#general", text: "Hello!" },
});

Allowlists por-client deixam você controlar exatamente o que cada upstream expõe:

const gateway = new GatewayClient({
  slack: {
    client: slackClient,
    tools: ["send_message", "list_channels"], // apenas exponha estas
  },
  github: {
    client: () => connectToGithub(),
    resources: ["repo://main"],               // apenas exponha este recurso
  },
});

Inicialização lazy

Funções factory chamadas no primeiro uso, resultados cacheados

Auto-paginação

Busca todas as páginas de clientes upstream automaticamente

Namespacing

Ferramentas e prompts prefixados com chave do client (ex: slack_send_message)

Roteamento

callTool/readResource/getPrompt roteados ao upstream correto

Cache

Resultados de listagem cacheados; chame refresh() para invalidar

Seleção

Allowlists por-client para ferramentas, recursos e prompts

info
Vínculo com a Anthropic

O padrão "progressive disclosure" deles com file-tree resolve descoberta de ferramentas - como a LLM encontra ferramentas relevantes. GatewayClient resolve agregação de ferramentas e roteamento - como a infraestrutura coleta e despacha entre upstreams. Padrões complementares que funcionam juntos.


5. runCodeWithTools() - Execução de código em sandbox

Problema: A insight chave da Anthropic - deixar LLMs escrever código que chama ferramentas programaticamente, filtrando e transformando dados em um sandbox ao invés de queimar tokens em chamadas de ferramentas multi-turn. Seu blog mostrou uma redução de 98,7% em tokens. Nós shippamos isso como uma função.

import { runCodeWithTools } from "@decocms/mcp-utils/sandbox";

const result = await runCodeWithTools({
  code: `export default async (tools) => {
    const items = await tools.list_items({});
    return items.filter(i => i.status === "active");
  }`,
  client: mcpClient,
  timeoutMs: 5000,
});

console.log(result.returnValue);  // itens filtrados
console.log(result.consoleLogs);  // chamadas console.log/warn/error capturadas

Para controle de nível mais baixo, runCode deixa você injetar funções de ferramenta arbitrárias:

import { runCode } from "@decocms/mcp-utils/sandbox";

const result = await runCode({
  code: `export default async (tools) => {
    const data = await tools.fetch_data({ query: "active" });
    console.log("Found", data.length, "items");
    return data;
  }`,
  tools: {
    fetch_data: async (args) => fetchFromDatabase(args.query),
  },
  timeoutMs: 10_000,
  memoryLimitBytes: 16 * 1024 * 1024, // 16 MB
  stackSizeBytes: 256 * 1024,          // 256 KB
});
info
Nota de design

QuickJS ao invés de V8 isolates. Compila para WASM, roda em qualquer lugar (Node, Deno, edge workers, browsers). Limites de memória determinísticos sem escapes FFI. O sandbox literalmente não pode acessar o host além das funções de ferramenta que você injeta.


Composição - Onde clica

As cinco primitivas são desenhadas para se encaixarem. Aqui está um control plane MCP completo em ~20 linhas:

import { GatewayClient } from "@decocms/mcp-utils/aggregate";
import { createServerFromClient, composeTransport, createBridgeTransportPair } from "@decocms/mcp-utils";

// 1. Agregue múltiplos upstreams
const gateway = new GatewayClient({
  slack: { client: slackClient },
  github: { client: () => connectToGithub() },
  db: { client: dbClient, tools: ["query", "list_tables"] },
});

// 2. Exponha como um server
const server = createServerFromClient(gateway, {
  name: "my-gateway",
  version: "1.0.0",
});

// 3. Adicione middleware e conecte
const transport = composeTransport(
  baseTransport,
  (t) => new LoggingTransport(t),
  (t) => new AuthTransport(t, userToken),
);

await server.connect(transport);

GatewayClient agrega ferramentas de três upstreams. createServerFromClient wrappa o gateway como um server MCP standard. composeTransport coloca camadas de logging e auth. O resultado é um gateway MCP completo com auth, observabilidade e roteamento multi-server - construído de cinco peças composáveis.


Como isso se relaciona com a arquitetura da Anthropic

close

Abordagem da Anthropic (cêntrica em agent)

  • Gera file-tree de stubs TypeScript para descoberta de ferramentas
  • LLM lê stubs para descobrir capacidades
  • LLM escreve código contra as ferramentas
  • Sandbox executa o código gerado
  • LLM orquestra tudo através de código gerado
check

@decocms/mcp-utils (cêntrica em infraestrutura)

  • GatewayClient agrega e roteia entre upstreams
  • Middleware de transport cuida de auth, logging, rate-limiting
  • Sandbox fornece a camada de execução de código
  • LLM apenas chama ferramentas ou escreve código sandbox
  • Infraestrutura faz o trabalho pesado

Essas abordagens são complementares, não em competição. Você poderia usar @decocms/mcp-utils para construir a infraestrutura que a arquitetura da Anthropic fica em cima: GatewayClient agrega seus upstreams, middleware de transport adiciona auth e observabilidade, e runCodeWithTools fornece a camada de sandbox que sua arquitetura requer.


Comece agora

Licença MIT. Extraído do uso em produção no MCP Mesh do deco CMS - um control plane open-source para gerenciar acesso de AI agents a ferramentas em escala.

npm install @decocms/mcp-utils @modelcontextprotocol/sdk

Para suporte a sandbox:

npm install quickjs-emscripten-core @jitl/quickjs-wasmfile-release-sync

MCP é um protocolo, não um framework. Essas são as peças que faltam.