protect-mcp

Gateway de segurança para servidores MCP — políticas por ferramenta, recibos assinados com Ed25519, portões de aprovação humana e mecanismo de políticas Cedar WASM.

Documentação

protect-mcp

Portão de política Cedar com falha fechada e recibos assinados para chamadas de ferramentas de agentes de IA.

npm version downloads license node

protect-mcp é um portão que fica na frente das chamadas de ferramentas de um agente de IA. Ele avalia cada chamada contra uma política Cedar (a mesma linguagem que a AWS usa para IAM), bloqueia o que viola as regras antes de executar e assina um recibo Ed25519 verificável offline de cada decisão. Ele roda localmente, não envia telemetria das suas decisões para lugar nenhum e é licenciado sob MIT.

Por que é diferente

  • Falha fechada por padrão. Em qualquer erro de política, engine ausente ou falha de avaliação, a decisão é NEGAR. O portão nunca permite silenciosamente. Um modo de observação existe para implantação em sombra, mas mesmo lá uma chamada que seria bloqueada é sinalizada como would_deny: true, então uma falha nunca é silenciosa.
  • Ele prova a própria contenção. serve --enforce e doctor executam um autoteste de inicialização e se recusam a armar o portão a menos que possam mostrar que uma ação conhecidamente proibida é de fato negada. Um portão que não consegue provar que nega não inicia.
  • Cada decisão é um recibo que qualquer um pode verificar. As decisões são assinadas com Ed25519 e verificáveis offline com @veritasacta/verify. Nenhuma confiança em fornecedor é necessária: a matemática não se importa com quem a executa.

Início rápido: da instalação à primeira prova útil

# 1. Generate an Ed25519 keypair, config template, and sample policy.
npx protect-mcp init

# 2. Wrap any MCP server in shadow mode. Nothing is blocked yet; calls are logged.
npx protect-mcp wrap -- node your-mcp-server.js

# 3. Inspect the local-only dashboard: tool inventory, risk, approvals, receipts.
npx protect-mcp dashboard --open

# 4. Draft a reviewable policy from observed calls.
npx protect-mcp recommend --write

# 5. When reviewed, restart the wrapper in enforce mode with that policy.
npx protect-mcp --policy protect-mcp.recommended.json --enforce -- node your-mcp-server.js

Para Claude Desktop, execute um patch de configuração em modo de teste seco primeiro e depois aplique-o:

npx protect-mcp wrap --claude-desktop
npx protect-mcp wrap --claude-desktop --write
npx protect-mcp dashboard --open

O painel vincula-se a 127.0.0.1, lê apenas arquivos locais de log/recibos e não envia nada. Use npx protect-mcp connect somente se você quiser explicitamente um painel hospedado da ScopeBlind.

O portão como servidor MCP

Se você preferir chamar o portão como ferramentas em vez de conectar os hooks do Claude Code, execute-o como um servidor MCP:

npx protect-mcp mcp

Ele fala MCP via stdio e expõe quatro ferramentas somente leitura, o ciclo completo:

  • evaluate_action: decide uma chamada de ferramenta proposta contra uma política Cedar inline, com falha fechada (qualquer erro de política é NEGAR). Retorna { allowed, decision, reason, policy_digest }.
  • sign_decision: transforma uma decisão em um recibo assinado Ed25519 (uma negação assina um gateway_restraint, uma permissão um decision_receipt). Retorna o recibo e sua chave pública; gera uma chave efêmera se você não fornecer uma.
  • verify_receipt: verifica um recibo assinado offline contra uma chave pública. Retorna { valid, error, type, kid, issuer }.
  • self_test: prova, sem entradas. Uma ação conhecidamente proibida é negada, depois um recibo assinado faz o ciclo completo e uma cópia adulterada falha.

Aponte qualquer host MCP para ele, por exemplo Claude Desktop:

{
  "mcpServers": {
    "protect-mcp": { "command": "npx", "args": ["-y", "protect-mcp", "mcp"] }
  }
}

Os recibos são byte-compatíveis com os que o portão assina em tempo de execução, então um recibo cunhado aqui verifica com @veritasacta/verify e o verificador de navegador da mesma forma.

Painel de Ações Local

protect-mcp dashboard é a visão do operador para passar de visibilidade para aplicação de políticas:

  • Inventário de ferramentas: cada ferramenta observada, contagem de chamadas, risco alto/médio/baixo e se a política ativa tem uma regra exata, um fallback curinga ou nenhuma regra.
  • Cobertura de política: edições locais de política com um clique para Require approval, Block ou Observe. Reinicie o wrapper após revisar as alterações.
  • Fila de aprovação de ação exata: a ferramenta exata, ação, destino, pré-visualização de payload redigida, hash do payload, base da política e motivo capturados antes de um humano aprovar, negar, editar ou assumir o controle.
  • Cadeia de recibos: ids de requisição correlacionados com hashes de recibos assinados, para que um revisor de auditoria possa ver quais decisões têm prova criptográfica.
  • Exportação de auditoria: baixa o pacote de auditoria verificável offline quando recibos assinados existem. Se apenas logs locais não assinados existirem, o painel explica que a assinatura deve ser habilitada primeiro.

Para aprovações de fallback ao vivo no desktop, inicie o painel com o endpoint de aprovação do gateway local e o nonce impressos pelo wrapper:

npx protect-mcp dashboard --open \
  --approval-endpoint http://127.0.0.1:9876 \
  --approval-nonce "$PROTECT_MCP_APPROVAL_NONCE"

Approve encaminha para o gateway local ao vivo quando esses flags estão presentes. Deny, Edit e Take over são registrados localmente como registros de resolução de aprovação; use-os como instrução do operador e reexecute a ferramenta quando necessário.

MVP de Limite Pago: ancoragem de digest, não upload de dados

Recibos locais autoassinados permanecem gratuitos e verificáveis offline. O limite pago é evidência independente de que a ScopeBlind viu um digest de recibo em um momento, sob uma identidade de organização, sem receber o prompt bruto, payload de ferramenta, saída, chave privada ou recibo bruto.

# Create or refresh a local org identity and public-key directory.
npx protect-mcp registry init --org "Meridian Global Macro" --billing-account acct_meridian

# Local preview: writes a digest registry and shareable static verifier page.
npx protect-mcp registry anchor

# Hosted mode: uploads receipt digests only for independent anchoring.
SCOPEBLIND_TOKEN=... npx protect-mcp registry anchor \
  --hosted \
  --endpoint https://api.scopeblind.com \
  --verifier-base https://legate.scopeblind.com

A pré-visualização local é deliberadamente rotulada como local-preview-not-independent. O modo hospedado ancora apenas hashes de recibos, ids de requisição, chaves públicas da organização e metadados de cobrança. Ele não envia recibos brutos ou contexto sensível.

Demonstração Matadora: da sombra à política à prova

protect-mcp killer-demo gera um pacote completo de vendas/demonstração de três minutos:

npx protect-mcp killer-demo --dir ./scopeblind-demo

Ele cria atividade simulada de filesystem, GitHub, e-mail e PMS; mostra chamadas arriscadas em modo sombra; aplica um pacote de políticas; exige aprovação para uma reserva sensível de PMS; executa através do gateway; escreve um recibo assinado; prova que o recibo original verifica; prova que um recibo adulterado falha; e cria um pacote de divulgação seletiva que esconde contexto sensível enquanto mostra a prova mínima.

Abra o DEMO-RUNBOOK.md gerado primeiro. Depois execute o comando do painel impresso para conduzir um cliente pela sequência exata.

Divulgação Seletiva v0

Recibos em modo de compromisso podem carregar um committed_fields_root em vez de expor cada campo em texto claro. Depois, o detentor pode divulgar apenas campos selecionados:

npx protect-mcp verify-disclosure \
  --receipt ./receipts/selective-disclosure.receipt.json \
  --disclosure ./receipts/selective-disclosure.tool-only.json

O verificador verifica o hash do recibo pai, a assinatura Ed25519, a raiz do compromisso e a prova Merkle de cada campo divulgado. Ele então explica quais campos foram divulgados e quais campos comprometidos permanecem ocultos. Isso é divulgação de compromisso com sal, não conhecimento zero completo, mas torna a alegação de privacidade concreta: auditores podem verificar fatos selecionados sem receber o payload completo da ferramenta ou contexto sensível do desk.

Prove uma alegação sobre o registro (atestados cegos à posição)

Você pode provar uma ALEGAÇÃO sobre seu registro sem revelá-lo. Crie um atestado cego à posição, assinado, sobre todo o registro que divulga apenas categorias por decisão (um digest de recibo, o veredito, tags de capacidade), nunca suas entradas, saídas ou dados de ferramenta:

# "No action reached the network across the record":
npx protect-mcp claim --no net.egress

# other predicates:
#   --only fs.read,fs.write     all actions were confined to these capabilities
#   --no-verdict blocked        no action was blocked
#   --count blocked             how many were blocked

Qualquer um verifica offline, vendo apenas as categorias, nunca o conteúdo:

npx protect-mcp verify-claim claim-<id>.json

O verificador recalcula uma raiz Merkle sobre o conjunto divulgado e recalcula o predicado independentemente, então o emissor não pode mentir sobre a alegação dada a divulgação. Adicione --anchor para registrar o digest da alegação no log de transparência público e somente anexação da ScopeBlind, para que uma contraparte que não confie em você possa confirmar que o conjunto divulgado está completo e não foi silenciosamente recortado (apenas o hash é enviado; o registro permanece local):

npx protect-mcp claim --no net.egress --anchor

Isso é um atestado responsável e cego à posição, não conhecimento zero completo: ele revela a forma, não o conteúdo.

Experimente em 60 segundos (sem agente necessário)

Watch the two-minute demo film

Assista ao filme de dois minutos em legate.scopeblind.com/record e depois reproduza-o na sua própria cópia:

npx protect-mcp sample     # seed a labeled sample record (8 decisions: 1 blocked, 2 payments)
npx protect-mcp record     # open it: signatures verified in your browser

npx protect-mcp claim --payment-under 100 --anchor --output payments-under-100.json
npx protect-mcp verify-claim payments-under-100.json
npx protect-mcp anchor-record

Solte o demo-tampered.jsonl gerado na página de registro para ver uma edição pós-assinatura ser detectada. sample se recusa a tocar em um registro existente, então execute-o em uma pasta vazia. Quando estiver pronto para a coisa real, conecte o portão abaixo e os mesmos comandos rodarão contra o registro do seu próprio agente.

Início rápido de hook do Claude Code

# Generate hook config and a sample Cedar policy.
npx protect-mcp init-hooks

# Serve the Claude Code hook gate in enforce mode. It runs a restraint self-test
# first and refuses to start if it cannot prove it denies a forbidden vector.
npx protect-mcp serve --enforce --cedar ./cedar

Avaliação única, do jeito que um hook PreToolUse a chama. Código de saída 2 significa negar (a ferramenta é bloqueada); código de saída 0 significa permitir:

npx protect-mcp evaluate --cedar ./cedar --tool Bash --input '{"command":"rm"}'
echo $?   # 2  -> denied, fail-closed

npx protect-mcp evaluate --cedar ./cedar --tool Read --input '{"path":"README.md"}'
echo $?   # 0  -> allowed

Uma política ausente ou não carregável nega (código de saída 2) a menos que você passe explicitamente --fail-on-missing-policy false.

Hooks do Claude Code

protect-mcp init-hooks escreve um .claude/settings.json para você. Para conectar o portão manualmente, os dois verbos que você precisa são evaluate (PreToolUse, bloqueia no código de saída 2) e sign (PostToolUse, registra um recibo). Fixe a versão para que uma sessão do Claude Code sempre execute o portão que você testou:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "npx protect-mcp@0.9.1 evaluate --cedar ./cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\""
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "npx protect-mcp@0.9.1 sign --tool \"$TOOL_NAME\" --receipts ./receipts --key ./keys/gateway.json"
          }
        ]
      }
    ]
  }
}

evaluate sai com código 2 ao negar para que o Claude Code bloqueie a chamada de ferramenta, e 0 ao permitir. sign é de melhor esforço: ele anexa um recibo assinado Ed25519 quando uma chave está configurada, e se nenhum assinante estiver disponível ele registra uma linha não assinada honesta ("signed": false) em vez de falhar a ferramenta.

Use em outros agentes (Codex, Cursor, Gemini, Hermes)

O mesmo portão com falha fechada roda como hook de ferramenta em qualquer agente que os suporte. Adicione --format <host> para que o verbo leia o payload do hook desse host do stdin e negue no contrato dele:

# the PreToolUse / before-tool command for each host
npx -y protect-mcp@latest evaluate --format codex  --cedar ./cedar   # OpenAI Codex
npx -y protect-mcp@latest evaluate --format gemini --cedar ./cedar   # Gemini CLI BeforeTool
npx -y protect-mcp@latest evaluate --format cursor --cedar ./cedar   # Cursor beforeShellExecution
npx -y protect-mcp@latest evaluate --format hermes --cedar ./cedar   # Hermes pre_tool_call

Emparelhe cada um com sign --format <host> no evento pós-ferramenta para recibos. O caso importante é Hermes, que ignora códigos de saída de hook e lê o veredito do stdout, então --format hermes nega via {"decision":"block"} em vez de código de saída 2 (um código de saída 2 bruto falharia silenciosamente aberto lá). Sem --format, os verbos leem os flags --tool/--input exatamente como na seção do Claude Code acima.

Escreva uma política

As políticas Cedar vivem em um diretório que você aponta com --cedar. Uma regra forbid nega, uma regra permit permite. Para corresponder a um valor na entrada da ferramenta, use o idioma .contains():

// Allow read-only tools.
permit(
  principal,
  action == Action::"MCP::Tool::call",
  resource == Tool::"Read"
);

// Deny dangerous shell commands by matching the command against a list.
forbid(
  principal,
  action == Action::"MCP::Tool::call",
  resource == Tool::"Bash"
) when {
  ["rm", "dd", "mkfs"].contains(context.command)
};

// Block destructive tools outright.
forbid(
  principal,
  action == Action::"MCP::Tool::call",
  resource == Tool::"delete_file"
);

Perigo: NÃO escreva context.command in ["rm", "dd"] para corresponder a uma string contra uma lista. in é para hierarquias de entidades, não associação de strings. Cedar trata a expressão como um erro de tipo e descarta silenciosamente toda a regra forbid, o que (sob um portão com falha aberta) deixa um permit residual em pé. Este é exatamente o defeito por trás do aviso abaixo. Use [...].contains(context.command) em vez disso. A partir de 0.7.0 o portão nega nesse erro em vez de permitir, e um teste de alarme de CI falha o build se o padrão for reintroduzido em uma política enviada. Veja GHSA-hm46-7j72-rpv9.

Pacotes de política iniciais

A maioria das equipes não deveria escrever Cedar do zero no primeiro dia. Instale um pacote inicial, rode em modo sombra, inspecione recibos e depois aperte ou aplique:

npx protect-mcp policy-packs list
npx protect-mcp policy-packs show secrets-safe
npx protect-mcp policy-packs install filesystem-safe --dir ./cedar
npx protect-mcp policy-packs install all --dir ./cedar
npx protect-mcp serve --cedar ./cedar

Pacotes integrados:

  • filesystem-safe: ações destrutivas de arquivo e leituras de caminhos semelhantes a segredos.
  • git-safe: force pushes, hard resets, limpeza destrutiva, exclusão de repositório.
  • email-safe: permite rascunho, bloqueia envios não supervisionados.
  • database-safe: postura de banco de dados orientada a leitura, bloqueia SQL de escrita/admin.
  • cloud-spend-safe: criação óbvia de gastos em nuvem e destruição de infraestrutura.
  • secrets-safe: exfiltração comum de segredos de arquivo, env, shell e nuvem.
  • finance-mandate-safe: violações de lista restrita e concentração em fluxos de reserva.

Verifique um recibo

Recibos são assinados e verificáveis offline por qualquer pessoa com a chave pública. Sem rede, sem fornecedor, sem confiança na ScopeBlind:

npx @veritasacta/verify ./receipts/receipts.jsonl --format jsonl
# Exit 0 = valid, non-zero = tampered or malformed

npx protect-mcp bundle --output audit.json exporta um pacote de auditoria autocontido e verificável offline dos seus recibos mais a chave pública de assinatura.

Segurança

protect-mcp 0.7.0 falha fechado por design. Em qualquer erro de avaliação de política, um engine ausente ou uma política que errou na avaliação, a decisão é NEGAR, não permitir. serve --enforce e doctor executam um autoteste de inicialização que prova que o portão nega um vetor conhecidamente proibido antes de ser confiável, e se recusa a armar se não conseguir.

Versões afetadas: 0.5.x e 0.6.x. Essas linhas falham abertas (retornam PERMITIR em erro de avaliação) e não avaliam Cedar corretamente contra o engine fixado, então uma regra forbid poderia falhar em bloquear. Atualize para >= 0.7.0.

Detalhes e remediação: GHSA-hm46-7j72-rpv9. Para relatar uma vulnerabilidade, veja SECURITY.md.

Comandos

CommandDescription
serveInicia o servidor de hook HTTP para Claude Code (porta 9377). --enforce executa o autoteste de restrição primeiro; --cedar <dir> e --policy <path> selecionam a política.
initGera um par de chaves Ed25519 (keys/gateway.json), um modelo de configuração e uma política de exemplo.
sampleSemeia um registro de exemplo claramente rotulado (8 decisões: uma chamada bloqueada, dois pagamentos; kid sample-demo) além de uma cópia adulterada, para que record, claim, verify-claim e anchor-record sejam reproduzíveis do zero antes de conectar um agente. Recusa-se a tocar em um registro existente; --force substitui.
policyVeja e altere a política Cedar a partir do terminal: policy list (permitir / proibir / negar por padrão por ferramenta, com a frequência com que o portão permitiu ou negou), policy show, policy allow <tool>, policy deny <tool>, policy path. Um serve em execução recarrega automaticamente na alteração.
wrapImprime um comando MCP protegido ou aplica patch nos servidores MCP do Claude Desktop. Simulação por padrão; use --write para atualizar a configuração do Claude Desktop.
dashboardInicia um painel somente local em 127.0.0.1 mostrando inventário de ferramentas, risco, cobertura de política, aprovações de ação exata, cadeias de recibos e exportação de auditoria.
recommendElabora uma política JSON revisável a partir de chamadas locais observadas. Simulação por padrão; use --write para criar protect-mcp.recommended.json.
registryCria uma identidade de organização, ancora resumos de recibos e escreve uma página de verificação estática. O modo hospedado envia apenas resumos.
recordAbre um visualizador local e pesquisável sobre seus recibos (--live transmite enquanto o agente executa): assinaturas Ed25519 verificadas no seu navegador contra sua chave de gateway, tags de capacidade, uma árvore de proveniência e exportação assinada com um clique. Tudo local, nada enviado.
claimCunha uma atestação assinada e cega à posição de um predicado sobre o registro (--no <cap> incl. --no payment, --only <c1,c2>, --no-verdict <verdict>, --count <verdict>, --payment-under <cap>), divulgando apenas categorias de decisão. Adicione --anchor para registrar o resumo da reivindicação no log de transparência público; chaves inscritas ancoram como uma organização nomeada.
anchor-recordCria um ponto de verificação da raiz Merkle + contagem + intervalo de tempo do registro no log público (amigável a heartbeat: pula quando inalterado). Uma reivindicação posterior cujo compromisso corresponda a um ponto de verificação ancorado é comprovadamente sobre o registro completo a partir desse ponto de verificação.
verify-claimVerifica um pacote de reivindicação offline: assinatura, raiz Merkle recalculada, predicado recalculado independentemente e o sidecar de ancoragem quando presente (vincula o envelope ancorado a esta reivindicação exata e confirma que o log público o contém). --check-anchor exige a âncora; --offline pula a etapa do log.
killer-demoGera um pacote de demonstração completo de modo-sombra para política, aprovação e recibo assinado.
verify-disclosureVerifica um pacote scopeblind.selective_disclosure.v0 e explica campos divulgados versus ocultos.
policy-packsLista, inspeciona e instala pacotes de política Cedar iniciais.
evaluateAvalia uma chamada de ferramenta contra uma política Cedar (portão PreToolUse). Saída 2 = negar (falha fechada), saída 0 = permitir.
signAssina uma chamada de ferramenta em um recibo (PostToolUse). Melhor esforço: registra uma linha honesta não assinada se não houver chave.
simulateSimula uma política contra um log de decisões registrado para ver o que ela teria bloqueado.
demoInicia um servidor de demonstração embutido envolvido com o portão, para ver recibos instantaneamente.
doctorVerifica sua configuração (chaves, políticas, mecanismo Cedar, verificador) e executa o autoteste de restrição.
bundleExporta um pacote de auditoria verificável offline de recibos mais a chave pública.
reportGera um relatório de conformidade (Markdown ou JSON) a partir do log de decisões e recibos.

Execute npx protect-mcp --help para a referência completa de flags.

Links

Licenciado sob MIT. Construído por ScopeBlind.