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.
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 --enforceedoctorexecutam 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 umgateway_restraint, uma permissão umdecision_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,BlockouObserve. 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)
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 regraforbid, o que (sob um portão com falha aberta) deixa umpermitresidual 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
| Command | Description |
|---|---|
serve | Inicia 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. |
init | Gera um par de chaves Ed25519 (keys/gateway.json), um modelo de configuração e uma política de exemplo. |
sample | Semeia 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. |
policy | Veja 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. |
wrap | Imprime 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. |
dashboard | Inicia 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. |
recommend | Elabora 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. |
registry | Cria 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. |
record | Abre 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. |
claim | Cunha 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-record | Cria 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-claim | Verifica 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-demo | Gera um pacote de demonstração completo de modo-sombra para política, aprovação e recibo assinado. |
verify-disclosure | Verifica um pacote scopeblind.selective_disclosure.v0 e explica campos divulgados versus ocultos. |
policy-packs | Lista, inspeciona e instala pacotes de política Cedar iniciais. |
evaluate | Avalia uma chamada de ferramenta contra uma política Cedar (portão PreToolUse). Saída 2 = negar (falha fechada), saída 0 = permitir. |
sign | Assina uma chamada de ferramenta em um recibo (PostToolUse). Melhor esforço: registra uma linha honesta não assinada se não houver chave. |
simulate | Simula uma política contra um log de decisões registrado para ver o que ela teria bloqueado. |
demo | Inicia um servidor de demonstração embutido envolvido com o portão, para ver recibos instantaneamente. |
doctor | Verifica sua configuração (chaves, políticas, mecanismo Cedar, verificador) e executa o autoteste de restrição. |
bundle | Exporta um pacote de auditoria verificável offline de recibos mais a chave pública. |
report | Gera 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
- Protocol (IETF): draft-farley-acta-signed-receipts
- CHANGELOG
- npm
- scopeblind.com
Licenciado sob MIT. Construído por ScopeBlind.
