mcp2cli
Ponte CLI que encapsula servidores MCP como comandos invocáveis via bash, recuperando ~11K tokens de janela de contexto por sessão https://github.com/rodaddy/mcp2cli
Documentação
mcp2cli
Ponte CLI que encapsula servidores MCP (Model Context Protocol) como comandos invocáveis via bash. Em vez de carregar todas as definições de ferramentas MCP no prompt de sistema de um LLM (~13K+ tokens permanentemente), agentes invocam ferramentas via bash com custo zero de contexto.
Inspirado no Google Workspace CLI, que encapsulava as APIs complexas do Google em comandos CLI simples — toda a funcionalidade, sem complicação. O mcp2cli faz o mesmo para servidores MCP.
Início Rápido
# Install
git clone <repo-url>
cd mcp2cli
bun install
bun run build # produces dist/mcp2cli
# Bootstrap from existing Claude config
mcp2cli bootstrap # reads ~/.claude.json mcpServers -> ~/.config/mcp2cli/services.json
# Use it
mcp2cli services # list available services
mcp2cli n8n --help # list tools for a service
mcp2cli n8n n8n_list_workflows --params '{}' # invoke a tool
mcp2cli schema n8n.n8n_list_workflows # inspect tool schema
Para desenvolvimento sem compilar:
bun run dev -- services
bun run dev -- n8n n8n_list_workflows --params '{}'
Instalação
Pré-requisitos: Bun v1.0+
git clone <repo-url>
cd mcp2cli
bun install
bun run build
O binário compilado fica em dist/mcp2cli. Adicione-o ao seu PATH ou crie um symlink.
Atualizações do Binário no macOS
No macOS, não sobrescreva um binário compilado existente no mesmo local com cp new dist/mcp2cli. Substituir o conteúdo do mesmo inode pode invalidar a assinatura de código ad-hoc e fazer a próxima execução ser encerrada com SIGKILL / código de saída 137.
Use um novo inode:
rm dist/mcp2cli
cp /path/to/new/mcp2cli dist/mcp2cli
Se o daemon da UI local for gerenciado pelo launchd, reinicie-o após substituir o binário:
launchctl kickstart -k gui/501/com.mcp2cli.local-ui
O daemon já em execução mantém o inode antigo aberto até a reinicialização, então isso é seguro de fazer enquanto o daemon está ativo.
Configuração
Registro de Serviços
O mcp2cli descobre servidores MCP a partir de ~/.config/mcp2cli/services.json:
{
"services": {
"n8n": {
"description": "n8n workflow automation",
"backend": "stdio",
"command": "npx",
"args": ["-y", "@anthropic-ai/n8n-mcp"],
"env": {
"N8N_BASE_URL": "https://n8n.example.com",
"N8N_API_KEY": "your-api-key"
}
},
"homekit": {
"description": "HomeKit smart home control",
"backend": "stdio",
"command": "node",
"args": ["/path/to/homekit-mcp/dist/index.js"],
"env": {}
}
}
}
Cada entrada de serviço espelha o formato do Claude Desktop mcpServers — mesmos campos command, args e env.
Bootstrap a partir da Config do Claude
Se você já tem servidores MCP configurados em ~/.claude.json:
mcp2cli bootstrap
Isso lê suas entradas mcpServers e gera services.json automaticamente.
Comandos
Listar Serviços
mcp2cli services
Listar Ferramentas de um Serviço
mcp2cli <service> --help
Invocar uma Ferramenta
mcp2cli <service> <tool> --params '<json>'
O valor --params deve ser JSON válido correspondente ao esquema de entrada da ferramenta.
Inspecionar Esquema da Ferramenta
mcp2cli schema <service>.<tool>
Retorna o JSON Schema para os parâmetros de entrada da ferramenta — útil para descobrir campos obrigatórios.
Execução Simulada (Dry Run)
mcp2cli <service> <tool> --params '{"query": "test"}' --dry-run
Valida a entrada e mostra o que seria enviado sem executar a chamada da ferramenta.
Filtragem de Campos
mcp2cli <service> <tool> --params '{}' --fields "id,name,status"
Extrai apenas os campos especificados da resposta — reduz ruído na saída para scripts.
Gerar Arquivos de Skill
mcp2cli generate-skills <service>
Gera arquivos de skill PAI a partir dos esquemas de ferramentas MCP, tornando as ferramentas detectáveis por agentes de IA.
Gerenciamento do Daemon
mcp2cli daemon status # check if daemon is running, connection pool stats
mcp2cli daemon stop # graceful shutdown
Formato de Saída
Todas as respostas são JSON estruturado no stdout. Logs vão para o stderr.
// Success
{ "success": true, "result": { "workflows": [...] } }
// Error
{ "error": true, "code": "TOOL_ERROR", "message": "Workflow not found", "reason": "..." }
Isso torna o mcp2cli componível com jq, pipes e scripts:
# Get workflow names
mcp2cli n8n n8n_list_workflows --params '{}' | jq '.result.workflows[].name'
# Check for errors
mcp2cli n8n n8n_get_workflow --params '{"id": "123"}' | jq 'if .error then .message else .result end'
Códigos de Saída
| Código | Significado |
|---|---|
| 0 | Sucesso |
| 1 | Erro de validação (entrada inválida, incompatibilidade de esquema) |
| 2 | Erro de autenticação (credenciais ausentes, permissão negada) |
| 3 | Erro de ferramenta (a ferramenta MCP retornou um erro) |
| 4 | Erro de conexão (daemon inacessível, falha de transporte) |
| 5 | Erro interno |
Use os códigos de saída para scripts:
mcp2cli n8n n8n_get_workflow --params '{"id": "123"}' 2>/dev/null
if [ $? -eq 4 ]; then
echo "Connection failed -- is the MCP server configured?"
fi
Variáveis de Ambiente
| Variável | Padrão | Descrição |
|---|---|---|
MCP2CLI_LOG_LEVEL | silent | Nível de log: silent, error, warn, info, debug |
MCP2CLI_IDLE_TIMEOUT | 60 | Tempo limite de inatividade do daemon em segundos |
MCP2CLI_STARTUP_TIMEOUT | 10000 | Tempo de espera do CLI pela prontidão de inicialização do daemon em milissegundos |
MCP2CLI_TOOL_TIMEOUT | 60000 | Tempo limite de chamada de ferramenta em milissegundos. Um timeout por serviço em services.json o substitui, e o valor resolvido é passado ao SDK MCP, então ele limita a chamada de verdade |
MCP2CLI_REQUEST_TIMEOUT_MS | 60000 | Tempo limite de solicitação do CLI para chamadas locais ao daemon via socket Unix em milissegundos. Aumente junto com um timeout longo por serviço, caso contrário o CLI desiste antes do verbo terminar |
MCP2CLI_REMOTE_REQUEST_TIMEOUT_MS | 60000 | Tempo limite de solicitação HTTP do CLI para chamadas remotas explícitas ao daemon em milissegundos |
MCP2CLI_REMOTE_RETRIES | 3 | Tentativas de solicitação remota para chamadas remotas explícitas ao daemon |
MCP2CLI_REMOTE_FALLBACK_TIMEOUT_MS | 10000 | Tempo limite HTTP do CLI para cada sonda remote-local antes de recorrer ao daemon local |
MCP2CLI_REMOTE_FALLBACK_RETRIES | 1 | Tentativas de sonda remota antes que chamadas remote-local recorram ao daemon local |
MCP2CLI_POOL_MAX | 50 | Máximo de conexões MCP simultâneas no pool |
MCP2CLI_LOG_DIR | ~/.cache/mcp2cli/logs | Diretório para logs de captura do stderr |
MCP2CLI_NO_DAEMON | (não definido) | Se definido, ignora o daemon e conecta diretamente |
MCP2CLI_DEBUG | (não definido) | Se 1, imprime linhas descartadas do stdout de servidores MCP |
Exemplo:
MCP2CLI_LOG_LEVEL=debug mcp2cli n8n n8n_list_workflows --params '{}'
MCP2CLI_NO_DAEMON=1 mcp2cli n8n n8n_list_workflows --params '{}'
Chamadas de ferramenta com mais de 60 segundos
Um verbo lento passa por dois prazos independentes, e aumentar apenas um não muda nada — o outro dispara primeiro:
- Daemon → servidor MCP. O
timeoutpor serviço emservices.json(recorrendo aMCP2CLI_TOOL_TIMEOUT, padrão 60s) é passado ao SDK MCP em cada chamada de ferramenta. Sem ele, o SDK aplica seu próprioDEFAULT_REQUEST_TIMEOUT_MSECde 60s e falha comMCP error -32001: Request timed out. - CLI → daemon.
MCP2CLI_REQUEST_TIMEOUT_MS(padrão 60s) limita a solicitação local via socket Unix. Quando dispara, o CLI reportaCONNECTION_ERROR: The operation timed out.mesmo que o daemon e o servidor MCP ainda estejam trabalhando.
Então, um verbo que pode rodar por 20 minutos precisa de ambos:
// services.json
{ "services": { "runner-boxes": { "timeout": 1200000 /* ...*/ } } }
MCP2CLI_REQUEST_TIMEOUT_MS=1200000 mcp2cli runner-boxes runner_done --params '{}'
Uma chamada com tempo esgotado não é um verbo falho: o trabalho no lado do servidor pode muito bem ter sido concluído depois que o cliente parou de esperar. Não tente novamente às cegas um verbo não idempotente em caso de timeout.
Arquitetura
CLI Entry (src/cli/index.ts)
|-- Command Dispatch (services, schema, bootstrap, generate-skills, daemon)
|-- Tool Call Handler -> Daemon Client (Unix socket)
| \-- Daemon Server (src/daemon/server.ts)
| |-- Connection Pool (src/daemon/pool.ts)
| | \-- MCP Transport (src/connection/transport.ts)
| |-- Idle Timer (src/daemon/idle.ts)
| \-- Health Endpoint (/health with memory stats)
|-- Input Validation (src/validation/) -- 48 adversarial patterns
|-- Schema Introspection (src/schema/)
|-- Skill Generation (src/generation/)
\-- Structured Logger (src/logger/) -- JSON on stderr
Principais Decisões de Design
Daemon persistente. Servidores MCP têm um custo de inicialização de 2 a 5 segundos por conexão. O daemon mantém conexões ativas em um pool, então chamadas subsequentes retornam em milissegundos em vez de segundos. O daemon sai automaticamente após o tempo limite de inatividade (padrão 60s).
Pool de conexões com verificações de saúde. Conexões são validadas antes do uso e recicladas em caso de falha. O pool impõe um tamanho máximo para evitar esgotamento de recursos.
JSON estruturado em todo lugar. O stdout é sempre JSON analisável — sem saída de texto misturada. Logs (quando habilitados) vão para o stderr como linhas JSON estruturadas. Isso torna o mcp2cli confiável para scripts e pipes.
Códigos de saída semânticos. Diferentes modos de falha recebem diferentes códigos de saída para que chamadores possam ramificar com base no tipo de erro sem analisar a saída.
Validação de entrada. Todos os parâmetros de ferramentas são validados contra o esquema MCP antes de a chamada ser despachada. A camada de validação lida com 48 padrões adversários (tentativas de injeção, coerção de tipo, estouro) para falhar rapidamente com erros claros.
Integração com Agentes
O mcp2cli é projetado para ser chamado por agentes de IA via uso de ferramenta bash. Um fluxo de trabalho típico de agente:
# Agent discovers available tools
mcp2cli n8n --help
# Agent reads the schema to understand parameters
mcp2cli schema n8n.n8n_get_workflow
# Agent invokes the tool
mcp2cli n8n n8n_get_workflow --params '{"id": "abc123"}'
Esse padrão mantém as definições de ferramentas MCP completamente fora do prompt de sistema do agente. O agente só paga custo de contexto quando realmente precisa chamar uma ferramenta, e mesmo assim apenas para o esquema da ferramenta específica — não todas as ferramentas de todos os servidores.
Autenticação Multiusuário
O mcp2cli suporta RBAC multiusuário via ~/.config/mcp2cli/tokens.json. Cada usuário ou agente recebe um token de portador com um papel.
tokens.json
{
"tokens": [
{
"id": "rico",
"token": "your-admin-token-here",
"role": "admin",
"description": "Full admin access",
"username": "rico",
"password": "your-web-ui-password",
"expiresAt": "2026-07-01T00:00:00.000Z"
},
{
"id": "skippy",
"token": "your-agent-token-here",
"role": "agent",
"description": "AI agent - tools + read, no config mutations",
"expiresAt": "2026-07-01T00:00:00.000Z"
},
{
"id": "viewer01",
"token": "your-viewer-token-here",
"role": "viewer",
"description": "Read-only access"
}
]
}
Gere tokens seguros: openssl rand -base64 32
Papéis RBAC
| Permissão | viewer | agent | admin |
|---|---|---|---|
| Listar serviços, status | sim | sim | sim |
| Chamar ferramentas, listar ferramentas, esquema | não | sim | sim |
| Ler credenciais | não | sim | sim |
| Adicionar/atualizar/remover serviços | não | não | sim |
| Escrever credenciais, gerenciar grupos | não | não | sim |
| Recarregar, importar, encerrar | não | não | sim |
Os campos username/password habilitam login na web UI na URL raiz do daemon. Autenticação baseada em token (cabeçalho Bearer) funciona para todo acesso à API e CLI.
O campo opcional expiresAt habilita expiração e renovação de tokens. Tokens expirados são rejeitados. Tokens próximos da expiração de tokens.json podem ser rotacionados via POST /api/auth/refresh; o daemon grava o novo token de volta em tokens.json e recarrega edições do arquivo de tokens a quente. Clientes CLI locais renovam proativamente tokens admin próximos da expiração antes de chamadas à API do daemon.
Comportamento de Fallback
- Sem tokens.json, sem token de ambiente: Autenticação desabilitada, todas as solicitações tratadas como admin (compatível com versões anteriores)
- Apenas variável de ambiente
MCP2CLI_AUTH_TOKEN: Modo legado de token único, tratado como admin - tokens.json existe: RBAC multiusuário completo
Gerenciamento de Credenciais por Identidade
Diferentes usuários e agentes podem ter suas próprias chaves de API para serviços de backend. Quando o rico chama o open-brain, ele usa a chave dele. Quando o skippy chama, a chave compartilhada dos agentes é usada.
credentials.json
Crie ~/.config/mcp2cli/credentials.json:
{
"groups": {
"ai_agents": ["skippy", "bilby", "nagatha", "claude"]
},
"credentials": {
"rico": {
"open-brain": { "headers": { "Authorization": "Bearer ricos-ob-key" } }
},
"ai_agents": {
"open-brain": { "headers": { "Authorization": "Bearer agents-shared-ob-key" } },
"n8n": { "env": { "N8N_API_KEY": "agents-n8n-key" } }
}
},
"defaults": {
"proxmox": { "headers": { "Authorization": "PVEAPIToken=shared-token" } }
}
}
Cadeia de Resolução
Quando uma chamada de ferramenta chega, as credenciais são resolvidas em ordem de prioridade:
- Específica do usuário —
credentials[userId][service] - Grupo — primeiro grupo correspondente ao qual o usuário pertence
- Padrões —
defaults[service] - services.json — o que estiver embutido na configuração do serviço (compatível com versões anteriores)
Para serviços http/websocket, cabeçalhos de credenciais são mesclados na conexão. Para serviços stdio, variáveis de ambiente de credenciais são mescladas no ambiente do processo.
Para serviços sensíveis à identidade, defina requiresCredentials: true em services.json. Se não existir credencial de usuário, grupo ou padrão explícito, o daemon rejeita a chamada em vez de usar cabeçalhos base do serviço.
CLI de Credenciais
# Set credentials for an identity on a service
mcp2cli credentials set rico open-brain --header "Authorization: Bearer my-key"
# Set env-based credentials (for stdio services)
mcp2cli credentials set rico n8n --env "N8N_API_KEY=my-n8n-key"
# Set a default credential (used when no user/group match)
mcp2cli credentials set-default proxmox --header "Authorization: PVEAPIToken=shared"
# List all credentials (values are redacted)
mcp2cli credentials list
# Show effective credential source for a user
mcp2cli credentials resolve skippy open-brain
# → {"exists": true, "source": "group"}
# Group management
mcp2cli credentials group add ai_agents skippy bilby nagatha
mcp2cli credentials group add-members ai_agents claude
mcp2cli credentials group remove-members ai_agents bilby
mcp2cli credentials group list
# Remove credentials
mcp2cli credentials remove rico open-brain
mcp2cli credentials remove-default proxmox
mcp2cli credentials group remove ai_agents
# Reload from disk after manual edits
mcp2cli credentials reload
# Populate Open Brain credentials from a Vaultwarden item
mcp2cli credentials bootstrap-open-brain --item "Open Brain - Per-User Tokens"
Exemplo Open Brain
Open Brain (OBv2) é um serviço MCP HTTP onde o token de portador controla a identidade do namespace. Não coloque um cabeçalho Authorization do Open Brain em services.json; armazene-o apenas como credencial por identidade.
services.json — configuração base para um daemon hospedado (sem credenciais, apenas endpoint):
{
"services": {
"open-brain": {
"backend": "http",
"url": "http://open-brain.example.internal:3100/mcp",
"source": "remote",
"requiresCredentials": true,
"preconnect": false
}
}
}
Use source: "remote" quando o CLI estiver roteando por um daemon mcp2cli hospedado. requiresCredentials: true faz credenciais por identidade ausentes falharem de forma segura, e preconnect: false impede que a inicialização do daemon abra uma conexão base não autenticada com o Open Brain.
credentials.json — chaves por identidade:
{
"groups": {
"ai_agents": ["skippy", "bilby", "claude"]
},
"credentials": {
"rico": {
"open-brain": { "headers": { "Authorization": "Bearer ricos-ob-api-key" } }
},
"ai_agents": {
"open-brain": { "headers": { "Authorization": "Bearer agents-shared-ob-key" } }
}
}
}
Agora, quando o rico chama mcp2cli open-brain search_all --params '{"query": "kubernetes"}', a chave pessoal dele é injetada. Quando o skippy chama a mesma ferramenta, a chave compartilhada dos agentes é usada. Cada um recebe sua própria conexão no pool.
Bootstrap Vaultwarden — se o item Open Brain - Per-User Tokens tiver campos personalizados como AUTH_TOKEN_USER_RICO, AUTH_TOKEN_USER_SKIPPY e AUTH_TOKEN_USER_BILBY, execute:
mcp2cli credentials bootstrap-open-brain
O sufixo do campo é convertido para minúsculas e usado como identidade (AUTH_TOKEN_USER_RICO -> rico). Credenciais existentes são ignoradas a menos que --force seja passado. O comando imprime apenas contagens e nomes de identidade; não imprime tokens de portador.
Cabeçalhos de Identidade do Chamador
Valores de cabeçalho e ambiente suportam variáveis de modelo ${caller.id} e ${caller.role}. Elas são substituídas pela identidade do chamador autenticado no momento da chamada.
Em services.json — injete cabeçalhos de identidade para serviços cujo backend confia em metadados do chamador em vez de tokens de portador por usuário:
{
"services": {
"example-service": {
"backend": "http",
"url": "https://example.internal/mcp",
"headers": {
"X-Agent-Id": "${caller.id}",
"X-Role": "${caller.role}"
}
}
}
}
Quando o bilby chama o serviço, os cabeçalhos da solicitação se tornam X-Agent-Id: bilby e X-Role: agent.
Em credentials.json — combine chaves por identidade com cabeçalhos de identidade:
{
"credentials": {
"rico": {
"open-brain": {
"headers": {
"Authorization": "Bearer ricos-ob-key",
"X-Namespace": "${caller.id}"
}
}
}
}
}
Modelos funcionam tanto em cabeçalhos quanto em valores de ambiente. Variáveis desconhecidas (por exemplo, ${caller.email}) são deixadas sem expansão.
Segurança
- Saída de lista redigida --
GET /api/credentialsretornaBear***em vez de valores completos - Proteção IDOR -- agentes só podem resolver suas próprias credenciais, admin necessário para outras
- Permissões de arquivo --
credentials.jsoné escrito com0600(somente leitura/escrita do proprietário) - Validação de entrada -- valores de cabeçalho rejeitam injeção CRLF, cabeçalhos perigosos (Host, Transfer-Encoding) e variáveis de ambiente (PATH, LD_PRELOAD, NODE_OPTIONS) são bloqueados
- Escritas atômicas -- arquivo temporário + renomeação evita escritas parciais em caso de falha
- Invalidação de pool -- alterar credenciais remove conexões obsoletas automaticamente
Recursos Avançados
Cache de Esquema
Os esquemas são armazenados em cache localmente para evitar re-busca a cada invocação. Os esquemas em cache ficam em ~/.cache/mcp2cli/schemas/ com TTL de 24 horas. A derivação do cache é detectada via hash SHA-256 -- se o esquema upstream mudar, o cache é invalidado automaticamente.
# Check cache status (age, TTL, drift)
mcp2cli cache status
# Clear all cached schemas
mcp2cli cache clear
# Clear cache for a specific service
mcp2cli cache clear n8n
# Bypass cache for a single schema lookup
mcp2cli schema n8n.n8n_list_workflows --fresh
Substitua o diretório de cache com MCP2CLI_CACHE_DIR.
Controle de Acesso
Restrinja quais ferramentas são expostas por serviço usando allowTools e blockTools em services.json. Ambos aceitam padrões glob.
{
"services": {
"n8n": {
"description": "n8n workflow automation",
"backend": "stdio",
"command": "npx",
"args": ["-y", "@anthropic/n8n-mcp"],
"allowTools": ["n8n_list_*", "n8n_get_*"],
"blockTools": ["n8n_delete_*"]
}
}
}
Quando ambos estão presentes, allowTools é avaliado primeiro (whitelist), depois blockTools remove correspondências do conjunto permitido.
Pesquisa de Ferramentas entre Serviços
Pesquise ferramentas em todos os serviços usando esquemas em cache:
# Find all tools matching a pattern
mcp2cli grep "workflow"
# Regex patterns work
mcp2cli grep "delete|remove"
Isso pesquisa apenas esquemas em cache -- nenhuma conexão MCP é feita.
Transporte WebSocket
Conecte-se a servidores MCP via WebSocket. Suporta fallback opcional para stdio e controle de acesso, igual ao HTTP.
{
"services": {
"remote-mcp": {
"description": "Remote MCP server via WebSocket",
"backend": "websocket",
"url": "ws://mcp-gateway.local:3000/mcp",
"fallback": {
"command": "npx",
"args": ["-y", "@anthropic/n8n-mcp"]
}
}
}
}
Os serviços WebSocket se beneficiam do mesmo disjuntor e comportamento de fallback que os serviços HTTP.
Chamadas de Ferramentas em Lote
Execute várias chamadas de ferramentas em uma única invocação canalizando NDJSON para mcp2cli batch. Cada linha é um objeto JSON com campos service, tool e params:
# Sequential execution (default)
cat <<EOF | mcp2cli batch
{"service": "n8n", "tool": "n8n_list_workflows", "params": {}}
{"service": "n8n", "tool": "n8n_get_workflow", "params": {"id": "1"}}
EOF
# Parallel execution
cat <<EOF | mcp2cli batch --parallel
{"service": "n8n", "tool": "n8n_list_workflows", "params": {}}
{"service": "n8n", "tool": "n8n_get_workflow", "params": {"id": "1"}}
EOF
A saída é NDJSON -- um resultado por linha com o serviço/ferramenta original para correlação:
{"service":"n8n","tool":"n8n_list_workflows","success":true,"result":{...}}
{"service":"n8n","tool":"n8n_get_workflow","success":true,"result":{...}}
Erros para chamadas individuais são relatados inline sem abortar o lote.
Resiliência de Gateway
Serviços HTTP/SSE podem definir uma configuração stdio fallback. Se o gateway remoto estiver inacessível, o mcp2cli cai transparentemente para um processo de servidor MCP local.
{
"services": {
"n8n": {
"description": "n8n via HTTP gateway with stdio fallback",
"backend": "http",
"url": "http://mcp-gateway:3000/n8n",
"fallback": {
"command": "npx",
"args": ["-y", "@anthropic/n8n-mcp"]
}
}
}
}
Um disjuntor protege contra falhas repetidas: após 5 falhas consecutivas, o circuito abre e roteia diretamente para o fallback por 60 segundos antes de re-testar o primário. O estado do circuito é persistido em ~/.cache/mcp2cli/circuit-breaker/ para sobreviver a reinicializações do processo.
Formatos de Saída
Controle o formato de saída com a flag --format:
mcp2cli n8n n8n_list_workflows --params '{}' --format table
mcp2cli n8n n8n_list_workflows --params '{}' --format yaml
mcp2cli n8n n8n_list_workflows --params '{}' --format csv
mcp2cli n8n n8n_list_workflows --params '{}' --format ndjson
| Formato | Descrição |
|---|---|
json | Padrão. JSON estruturado (inalterado desde v1.0) |
table | Colunas alinhadas -- saída de terminal legível por humanos |
yaml | Saída YAML |
csv | RFC 4180 CSV -- canalize para planilhas ou csvtool |
ndjson | Um objeto JSON por linha -- para pipelines de streaming |
As respostas de erro são sempre JSON, independentemente da flag --format.
Regeneração Automática de Habilidades
Arquivos de habilidade gerados podem ser pré-visualizados e mantidos em sincronia com mudanças de esquema upstream:
# Preview what would change without writing
mcp2cli generate-skills --diff n8n
# Regenerate (preserves manual sections)
mcp2cli generate-skills n8n
Edições manuais dentro dos marcadores MANUAL:START / MANUAL:END são preservadas entre regenerações. Quando a derivação de esquema é detectada (via camada de cache), a regeneração de habilidades pode ser acionada automaticamente.
Para mudanças no Open Brain MCP, use o caminho apoiado por registro em vez de atualizar diretamente um daemon local como prova de lançamento:
# First land any required registry/config/process update in rodaddy/rtech-mcps.
# Then make mcp2cli pull the registry-backed service definition and refresh live schemas.
mcp2cli cache diff open-brain
mcp2cli cache warm open-brain
mcp2cli generate-skills open-brain --conflict=merge
mcp2cli open-brain --help
A validação local deve usar um MCP2CLI_HOME/config/cache temporário isolado para que os testes não possam alterar o estado local real do operador ~/.config/mcp2cli. A verificação final deve ser executada contra o daemon hospedado e provar que as novas ferramentas estão visíveis e chamáveis lá.
Variáveis de Ambiente Adicionais
| Variável | Padrão | Descrição |
|---|---|---|
MCP2CLI_CACHE_DIR | ~/.cache/mcp2cli | Diretório base para cache de esquema e estado do disjuntor |
MCP2CLI_TOKENS_FILE | ~/.config/mcp2cli/tokens.json | Caminho para configuração de token multiusuário |
MCP2CLI_TOKEN_REFRESH_WINDOW_MS | 86400000 | Janela de renovação para tokens expirando (padrão 24h) |
MCP2CLI_TOKEN_TTL_MS | 2592000000 | Tempo de vida para tokens renovados (padrão 30d) |
MCP2CLI_CREDENTIALS_FILE | ~/.config/mcp2cli/credentials.json | Caminho para mapeamentos de credenciais por identidade |
MCP2CLI_IMPORT_TOKEN | (não definido) | Token Bearer usado apenas para importações de configuração importUrl |
MCP2CLI_IMPORT_ALLOWED_HOSTS | (necessário para importUrl) | Lista de permissões separada por vírgulas para hostnames importUrl |
MCP2CLI_IMPORT_ALLOW_DNS | (não definido) | Defina como 1 para permitir hostnames DNS para alvos importUrl não privados |
MCP2CLI_IMPORT_ALLOW_HTTP | (não definido) | Defina como 1 para permitir alvos importUrl não HTTPS |
MCP2CLI_IMPORT_ALLOW_PRIVATE | (não definido) | Defina como 1 para permitir alvos importUrl loopback/privados/link-local |
MCP2CLI_METRICS_INCLUDE_CALLER | (não definido) | Defina como 1 para incluir rótulos brutos do chamador em /metrics público; desabilitado por padrão |
MCP2CLI_VAULTWARDEN_TIMEOUT_MS | 10000 | Tempo limite para consultas ${secret:...} apoiadas por Vaultwarden |
Implantação em Rede
O mcp2cli pode ser executado como um daemon TCP centralizado, permitindo que várias máquinas compartilhem um único conjunto de conexões de servidor MCP. Instale e configure os backends MCP uma vez em um servidor e conecte-se de qualquer máquina usando o cliente CLI ou o wrapper bash (apenas curl + jq -- sem necessidade de Bun).
Início Rápido (Modo TCP)
Servidor -- inicie o daemon com bind TCP:
export MCP2CLI_LISTEN_HOST=0.0.0.0
export MCP2CLI_LISTEN_PORT=9500
export MCP2CLI_AUTH_TOKEN=$(openssl rand -hex 32)
MCP2CLI_DAEMON=1 mcp2cli
Cliente -- aponte qualquer máquina para o daemon remoto:
export MCP2CLI_REMOTE_URL=http://mcp-server.local:9500
export MCP2CLI_AUTH_TOKEN=<same-token-as-server>
mcp2cli n8n n8n_list_workflows --params '{}'
Quando MCP2CLI_REMOTE_URL está definido, o CLI pula completamente a inicialização do daemon local e envia solicitações diretamente via HTTP.
Variáveis de Ambiente de Rede
Além das variáveis de ambiente base, o modo de rede adiciona:
| Variável | Padrão | Descrição |
|---|---|---|
MCP2CLI_LISTEN_HOST | (não definido) | Endereço de bind para modo TCP. Definir isso habilita TCP em vez de socket Unix. Use 0.0.0.0 para escutar em todas as interfaces |
MCP2CLI_LISTEN_PORT | 9500 | Porta TCP quando MCP2CLI_LISTEN_HOST está definido |
MCP2CLI_AUTH_TOKEN | (não definido) | Token Bearer para autenticação TCP. Necessário para implantações em produção. Alias: MCP_TOKEN |
MCP2CLI_REMOTE_URL | (não definido) | URL do daemon mcp2cli remoto (ex.: https://mcp2cli.rodaddy.live). Habilita o modo cliente remoto. Alias: MCP_HOST |
MCP2CLI_CONFIG | ~/.config/mcp2cli/services.json | Caminho para definições de serviço (útil para configuração do lado do servidor em /etc/mcp2cli/) |
MCP2CLI_TOKENS_FILE | ~/.config/mcp2cli/tokens.json | Caminho para configuração de token/RBAC multiusuário |
MCP2CLI_CREDENTIALS_FILE | ~/.config/mcp2cli/credentials.json | Caminho para mapeamentos de credenciais por identidade |
Autenticação
O daemon suporta dois modos de autenticação (veja Autenticação Multiusuário acima):
- RBAC multiusuário via
tokens.json-- cada usuário/agente recebe seu próprio token e papel - Token único legado via variável de ambiente
MCP2CLI_AUTH_TOKEN-- tratado como admin
Todas as comparações de token usam igualdade segura contra timing para prevenir ataques de timing.
Caminhos isentos de autenticação -- estes pulam a autenticação para que balanceadores de carga e monitoramento possam sondar sem credenciais:
GET /health-- verificação de saúde com uptime, memória e contagem de conexões ativasGET /metrics-- endpoint de métricas Prometheus com métricas agregadas de serviço/ferramenta
Métricas Prometheus
O daemon expõe métricas em GET /metrics no formato de exposição de texto Prometheus. Métricas principais:
| Métrica | Tipo | Descrição |
|---|---|---|
mcp2cli_requests_total | contador | Total de solicitações por {service, tool} |
mcp2cli_requests_errors_total | contador | Solicitações com falha por {service, tool} |
mcp2cli_request_duration_ms | histograma | Latência de solicitação com buckets (10ms - 30s) |
mcp2cli_requests_active | gauge | Solicitações atualmente em andamento |
mcp2cli_pool_connections_active | gauge | Tamanho atual do pool de conexões |
mcp2cli_pool_services | gauge | Serviços conectados (rótulo {service}) |
mcp2cli_connection_events_total | contador | Conectar/desconectar/falha de verificação de saúde por {service} |
mcp2cli_auth_failures_total | contador | Total de falhas de autenticação |
mcp2cli_process_uptime_seconds | gauge | Uptime do daemon |
mcp2cli_process_memory_rss_bytes | gauge | Tamanho do conjunto residente |
Rótulos brutos do chamador em /metrics público são desabilitados por padrão para evitar expor IDs de usuário a scrapers não autenticados. Defina MCP2CLI_METRICS_INCLUDE_CALLER=1 apenas em ambientes de monitoramento confiáveis para adicionar séries {service, tool, caller}.
Para uma análise JSON rápida por identidade, chame GET /api/metrics/user/:userId com um token bearer que tenha permissão status. Chamadores não-admin só podem ler suas próprias métricas de usuário; admins podem ler qualquer usuário.
Clientes remotos descobrem o inventário de serviços do daemon através de GET /api/services/discovery autenticado, não da sonda pública /health.
Adicione à sua configuração do Prometheus:
scrape_configs:
- job_name: mcp2cli
static_configs:
- targets: ['mcp-server.local:9500']
Wrapper Bash (clientes apenas com curl)
Para máquinas que só têm curl e jq (sem runtime Bun), use o wrapper bash:
# Install the wrapper
cp scripts/mcp2cli-remote /usr/local/bin/
chmod +x /usr/local/bin/mcp2cli-remote
# Configure
export MCP2CLI_REMOTE_URL=http://mcp-server.local:9500
export MCP2CLI_AUTH_TOKEN=<token>
# Use it like the full CLI
mcp2cli-remote n8n n8n_list_workflows '{}'
Implantação LXC
O diretório deploy/ contém tudo o que é necessário para executar o mcp2cli como um serviço systemd em um contêiner LXC (ou qualquer host Linux):
| Arquivo | Finalidade |
|---|---|
deploy/mcp2cli.service | arquivo de unidade systemd (endurecido com NoNewPrivileges, ProtectSystem=strict) |
deploy/env.example | Modelo de arquivo de ambiente -- copie para /etc/mcp2cli/env |
deploy/services-server.json | Exemplo de configuração de serviço do lado do servidor |
Configuração:
# Copy files into place
cp deploy/mcp2cli.service /etc/systemd/system/
mkdir -p /etc/mcp2cli
cp deploy/env.example /etc/mcp2cli/env
cp deploy/services-server.json /etc/mcp2cli/services.json
# Edit config
vim /etc/mcp2cli/env # set MCP2CLI_AUTH_TOKEN
vim /etc/mcp2cli/services.json # configure your MCP backends
# Enable and start
useradd --system --no-create-home mcp2cli
systemctl daemon-reload
systemctl enable --now mcp2cli
Exemplos com curl
SERVER=http://mcp-server.local:9500
TOKEN=your-token-here
# Health check (no auth required)
curl -s $SERVER/health | jq .
# Prometheus metrics (no auth required)
curl -s $SERVER/metrics
# List tools for a service
curl -s -X POST $SERVER/list-tools \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "n8n"}' | jq .
# Invoke a tool
curl -s -X POST $SERVER/call \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "n8n", "tool": "n8n_list_workflows", "params": {}}' | jq .
# Get a tool schema
curl -s -X POST $SERVER/schema \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "n8n", "tool": "n8n_list_workflows"}' | jq .
Desenvolvimento
bun run dev -- <args> # run without building
bun test # run test suite
bun run build # compile to dist/mcp2cli
Licença
MIT