
MCP em Produção: Registries, Docker e Padrões Enterprise
Guia completo para deploy de servidores MCP em produção. Cobre registries oficiais, containerização com Docker, autenticação OAuth 2.1, monitoramento,...
✨TL;DR / Sumário Executivo
Guia completo para deploy de servidores MCP em produção. Cobre registries oficiais, containerização com Docker, autenticação OAuth 2.1, monitoramento,...
💡 TL;DR (Resumo)
Deploy de MCP em produção requer: (1) Registries confiáveis - Official MCP Registry para discovery, Docker MCP Catalog para imagens assinadas, GitHub Registry para avaliação; (2) Containerização segura com Docker Gateway ou Kubernetes com network policies, resource limits e probes; (3) Autenticação OAuth 2.1 para clients, service accounts para upstream; (4) Monitoramento de métricas, logs estruturados e anomaly detection; (5) Orquestração multi-servidor com namespacing e collision detection.
Os artigos anteriores desta série cobriram fundamentos do MCP, implementação e segurança. Este faz a ponte entre "funciona na minha máquina" e "roda confiavelmente em produção." Exploraremos o ecossistema de registries, estratégias de containerização, padrões de autenticação e práticas operacionais que separam projetos hobby de deploys enterprise.
O Landscape de Registries
Servidores MCP estão espalhados por repositórios GitHub, pacotes npm, módulos PyPI e imagens Docker. O ecossistema de registries que emergiu em 2025 muda isso.
Official MCP Registry
Em setembro de 2025, o time do Model Context Protocol lançou o MCP Registry oficial em registry.modelcontextprotocol.io. Esta é a fonte canônica de verdade para servidores MCP disponíveis publicamente.
O registry fornece:
- Discovery padronizado: API REST (
GET /v0/servers) que clients podem consultar programaticamente - Consistência de metadados: Cada servidor publica um manifesto
server.jsoncom campos padronizados - Moderação da comunidade: Deny-listing para servidores maliciosos e sinais de qualidade
- Arquitetura federada: Registries downstream podem espelhar e estender o registry oficial
Docker MCP Catalog
O Docker MCP Catalog toma uma abordagem diferente: ao invés de apenas listar servidores, fornece imagens containerizadas e assinadas prontas para deploy.
docker mcp gateway run \
--verify-signatures \
--block-network \
--log-calls \
--cpus 1 \
--memory 2GbQuando você instala do catálogo Docker, você obtém:
- Assinaturas criptográficas verificando que a imagem não foi adulterada
- SBOMs documentando cada componente
- Attestations de provenance linkando a imagem ao código-fonte
- Scanning contínuo de vulnerabilidades
GitHub MCP Registry
O GitHub lançou seu MCP Registry em outubro de 2025, integrado diretamente à experiência GitHub:
- README do repositório exibido proeminentemente
- Instalação one-click para VS Code
- Métricas de stars e atividade da comunidade
- Links diretos para issues, PRs e contributors
Escolhendo Entre Registries
| Registry | Melhor Para | Benefício Chave |
|---|---|---|
| Official MCP Registry | Discovery canônico, acesso via API | Metadados padronizados, arquitetura federada |
| Docker MCP Catalog | Deploy seguro, desenvolvimento local | Imagens assinadas, vulnerability scanning |
| GitHub MCP Registry | Avaliação, servidores open-source | Sinais de confiança, métricas da comunidade |
Padrões de Containerização
Deploy Básico com Docker
docker run -d \
--name mcp-github \
-e GITHUB_TOKEN=$GITHUB_TOKEN \
mcp/github:latestDeploy Hardened para Segurança
docker mcp gateway run \
--verify-signatures \
--block-network \
--log-calls \
--cpus 1 \
--memory 2Gb| Flag | Função |
|---|---|
--verify-signatures | Só roda imagens com assinaturas criptográficas válidas |
--block-network | Restringe acesso de rede outbound |
--log-calls | Registra cada invocação de tool |
--cpus 1 --memory 2Gb | Limites de recursos |
Deploy Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-database-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-database-server
template:
metadata:
labels:
app: mcp-database-server
spec:
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
containers:
- name: mcp-server
image: internal-registry.company.com/mcp/database:v1.2.0
resources:
limits:
cpu: "1"
memory: "2Gi"
requests:
cpu: "500m"
memory: "1Gi"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: database-credentials
key: url
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mcp-server-policy
spec:
podSelector:
matchLabels:
app: mcp-database-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: mcp-client
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432Esta policy garante que o servidor MCP só recebe tráfego do client MCP e só faz conexões outbound para o database.
Padrões de Autenticação
OAuth 2.1 para Autenticação de Client
A especificação MCP recomenda OAuth 2.1 com PKCE para autenticação client-to-server:
- Client descobre endpoints OAuth via
/.well-known/oauth-authorization-server - Client gera PKCE code verifier e challenge
- Client redireciona usuário para endpoint de autorização
- Usuário autentica e concede permissões
- Servidor redireciona de volta com authorization code
- Client troca o code (plus PKCE verifier) por access tokens
- Client inclui access token em requests MCP
API Keys para Casos Simples
app.use((req, res, next) => {
const apiKey = req.headers["x-api-key"];
if (!apiKey || !validateApiKey(apiKey)) {
return res.status(401).json({ error: "Invalid API key" });
}
req.apiKeyInfo = getKeyInfo(apiKey);
next();
});API keys funcionam mas requerem gerenciamento cuidadoso:
- Rotacione keys regularmente
- Use keys diferentes por client/ambiente
- Monitore vazamento de keys
- Implemente rate limiting por key
Service Accounts
// Ruim: Usando token pessoal de desenvolvedor
const client = new DatabaseClient({
token: "ghp_xxxx_personal_token",
});
// Bom: Usando service account com escopo limitado
const client = new DatabaseClient({
serviceAccountPath: "/var/run/secrets/database/service-account.json",
scopes: ["database.read"],
});Monitoramento e Observabilidade
Métricas Essenciais
# Prometheus metrics
mcp_tool_invocations_total{tool="query_database", status="success"} 1234
mcp_tool_latency_seconds{tool="query_database", quantile="0.99"} 0.45| Métrica | Por Que Monitorar |
|---|---|
| Request rate e latência | Mudanças súbitas podem indicar ataques ou degradação |
| Error rates | Erros MCP e falhas upstream |
| Consumo de recursos | CPU, memória, network I/O por instância |
| Eventos de autenticação | Tentativas de login, refreshes de token, falhas de autorização |
Logging Estruturado
{
"timestamp": "2026-01-15T10:23:45Z",
"level": "info",
"event": "tool_invocation",
"tool": "query_database",
"client_id": "claude-desktop-user-123",
"arguments": {
"query": "SELECT * FROM users WHERE email = ?"
},
"duration_ms": 145,
"status": "success",
"result_size_bytes": 2048
}Não logue dados sensíveis diretamente. Hash ou redacte PII, credenciais e outros valores sensíveis:
function sanitizeForLogging(args: Record<string, unknown>) {
const sensitive = ["password", "token", "secret", "key"];
return Object.fromEntries(
Object.entries(args).map(([k, v]) => [
k,
sensitive.some(s => k.toLowerCase().includes(s)) ? "[REDACTED]" : v,
])
);
}Detecção de Anomalias
- Padrões de acesso incomuns: Tool que normalmente recebe 10 calls/hora de repente recebendo 1000
- Combinações de tools inesperadas: Se
read_fileé sempre seguido porsend_emailde um client particular, e esse padrão muda, alerte - Anomalias geográficas: Conexões de clients de localizações inesperadas
- Anomalias temporais: Atividade fora do horário normal
Orquestração Multi-Servidor
Evitando Colisão de Tools
Quando múltiplos servidores expõem tools com nomes similares, clients podem chamar a errada:
function detectCollisions(servers: Server[]): Collision[] {
const toolMap = new Map<string, string[]>();
for (const server of servers) {
for (const tool of server.tools) {
const existing = toolMap.get(tool.name) || [];
existing.push(server.name);
toolMap.set(tool.name, existing);
}
}
return Array.from(toolMap.entries())
.filter(([_, servers]) => servers.length > 1)
.map(([tool, servers]) => ({ tool, servers }));
}Padrões de Orquestração
Orquestração Sequencial:
User → GitHub Server (get PR) → Code Analysis Server (analyze) → ResponseOrquestração Paralela:
User → [GitHub Server, Jira Server, Slack Server] → Aggregate → ResponseOrquestração Condicional:
User → Router → (if code-related) GitHub Server
→ (if data-related) Database Server
→ (if messaging-related) Slack ServerGerenciamento de Custos
Rate Limiting
const rateLimiter = new RateLimiter({
perUser: { requests: 100, windowMs: 60000 },
perTool: {
"expensive_analysis": { requests: 10, windowMs: 3600000 },
},
global: { requests: 10000, windowMs: 60000 },
});
app.use("/mcp", (req, res, next) => {
const allowed = rateLimiter.check(req.user, req.tool);
if (!allowed) {
return res.status(429).json({ error: "Rate limit exceeded" });
}
next();
});Tracking de Uso
interface CostEvent {
timestamp: Date;
userId: string;
teamId: string;
tool: string;
resourceType: "api_call" | "compute" | "storage";
totalCost: number;
}
async function recordCost(event: CostEvent) {
await costStore.insert(event);
// Atualiza totais para dashboards
await updateDailyTotal(event.teamId, event.totalCost);
// Alerta se aproximando do budget
const monthlySpend = await getMonthlySpend(event.teamId);
const budget = await getBudget(event.teamId);
if (monthlySpend > budget * 0.8) {
await sendBudgetAlert(event.teamId, monthlySpend, budget);
}
}Disaster Recovery
Procedimentos de Recovery
| Cenário | Ação |
|---|---|
| Crash de servidor | Kubernetes reinicia pods automaticamente. Verifique com chaos engineering. |
| Corrupção de banco | Restore de backup para point-in-time antes da corrupção. |
| Comprometimento de credenciais | Rotacione todas as credenciais afetadas. Revogue tokens existentes. Audite logs. |
| Supply chain compromise | Rollback para versão conhecidamente boa. Audite atividade durante janela de exposição. |
Juntando Tudo
Deploy de MCP em produção não é uma coisa—é uma combinação de práticas que juntas criam confiabilidade e segurança:
- Source de registries confiáveis com verificação e scanning
- Containerize com controles de segurança: assinaturas, network policies, resource limits
- Autentique apropriadamente: OAuth para clients, service accounts para upstream
- Monitore tudo: métricas, logs, anomaly detection
- Gerencie complexidade: registries internos, collision detection, orquestração
- Controle custos: rate limiting, usage tracking
Nenhum controle único torna MCP seguro. Juntos, eles criam defense in depth que torna ataques difíceis e incidentes gerenciáveis.
"Boa arquitetura balanceia ambição com pragmatismo."
— Hephaestus, The Strategist @ gsstk