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.
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.
createBridgeTransportPair()
IPC in-process sem overhead. Conecte um Client e Server no mesmo processo sem precisar girar sockets ou pipes stdio.
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.
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.
GatewayClient
Agregação multi-server. Colete ferramentas de N upstreams, coloque um namespace, e roteeie chamadas para a origem correta.
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();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);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"),
);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
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 capturadasPara 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
});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
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
@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/sdkPara suporte a sandbox:
npm install quickjs-emscripten-core @jitl/quickjs-wasmfile-release-syncMCP é um protocolo, não um framework. Essas são as peças que faltam.






