
scopeblind-gateway v0.13.1
Reçus signés Ed25519 + politiques Cedar pour les agents IA. Finance mandate gate (Legate), packs de preuves, 3 Internet-Drafts IETF. npx protect-mcp
protect-mcp
Portail de politique Cedar à échec fermé (fail-closed) plus reçus signés pour les appels d'outils d'agents IA.
protect-mcp est un portail qui se place devant les appels d'outils d'un agent IA. Il évalue
chaque appel par rapport à une politique Cedar (le même langage
qu'AWS utilise pour IAM), bloque ce qui enfreint les règles avant son exécution, et signe un
reçu Ed25519 vérifiable hors ligne de chaque décision. Il s'exécute localement, n'envoie aucune
télémétrie de vos décisions où que ce soit, et est sous licence MIT.
Ce qui le rend différent
- Échec fermé par défaut. En cas d'erreur de politique, de moteur manquant ou d'échec
d'évaluation, la décision est DENY. Le portail n'autorise jamais silencieusement. Un
mode observation existe pour un déploiement en ombre, mais même là, un appel qui serait
bloqué est signalé
would_deny: true, de sorte qu'un échec n'est jamais silencieux. - Il prouve sa propre retenue.
serve --enforceetdoctorexécutent un auto-test au démarrage et refusent d'armer le portail à moins de pouvoir démontrer qu'une action connue comme interdite est effectivement refusée. Un portail qui ne peut pas prouver qu'il refuse ne démarre pas. - Chaque décision est un reçu que n'importe qui peut vérifier. Les décisions sont signées
en Ed25519 et vérifiables hors ligne avec
@veritasacta/verify. Aucune confiance envers un fournisseur requise : les mathématiques ne se soucient pas de qui les exécute.
Démarrage rapide : de l'installation à la première preuve utile```bash
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
Pour Claude Desktop, exécutez d'abord un patch de configuration en dry-run, puis appliquez-le :```bash
npx protect-mcp wrap --claude-desktop
npx protect-mcp wrap --claude-desktop --write
npx protect-mcp dashboard --open
Le tableau de bord se lie à 127.0.0.1, ne lit que les fichiers de journaux/reçus locaux et ne téléverse rien. N'utilisez npx protect-mcp connect que si vous souhaitez explicitement un tableau de bord ScopeBlind hébergé.
La passerelle en tant que serveur MCP
Si vous préférez appeler la passerelle comme des outils plutôt que de câbler les hooks Claude Code, exécutez-la en tant que serveur MCP :```bash npx protect-mcp mcp
Il parle MCP via stdio et expose quatre outils en lecture seule, toute la boucle :
- **`evaluate_action`** : décide d'un appel d'outil proposé selon une politique Cedar inline, en échec fermé (toute erreur de politique est DENY). Retourne `{ allowed, decision, reason, policy_digest }`.
- **`sign_decision`** : transforme une décision en reçu signé Ed25519 (un refus signe un `gateway_restraint`, une autorisation un `decision_receipt`). Retourne le reçu et sa clé publique ; génère une clé éphémère si vous n'en fournissez pas.
- **`verify_receipt`** : vérifie un reçu signé hors ligne par rapport à une clé publique. Retourne `{ valid, error, type, kid, issuer }`.
- **`self_test`** : le prouve, sans entrées. Une action connue comme interdite est refusée, puis un reçu signé fait un aller-retour et une copie falsifiée échoue.
Pointez n'importe quel hôte MCP vers lui, par exemple Claude Desktop :```json
{
"mcpServers": {
"protect-mcp": { "command": "npx", "args": ["-y", "protect-mcp", "mcp"] }
}
}
Les reçus sont compatibles octet pour octet avec ceux que la passerelle signe à l'exécution, donc un reçu généré ici se vérifie avec @veritasacta/verify et le vérificateur navigateur de la même manière.
Tableau de bord des actions locales
protect-mcp dashboard est la vue opérateur pour passer de la visibilité à l'application des règles :
- Inventaire des outils : chaque outil observé, nombre d'appels, risque élevé/moyen/faible, et si la politique active dispose d'une règle exacte, d'un repli par joker, ou d'aucune règle.
- Couverture des politiques : modifications locales de la politique en un clic pour
Require approval,Block, ouObserve. Redémarrez le wrapper après avoir examiné les modifications. - File d'attente d'approbation des actions exactes : l'outil exact, l'action, la destination, l'aperçu de la charge utile expurgée, le hachage de la charge utile, la base de la politique et la capture de la raison avant qu'un humain approuve, refuse, modifie ou prenne le relais.
- Chaîne de reçus : identifiants de requête corrélés avec les hachages de reçus signés, afin qu'un auditeur puisse voir quelles décisions disposent d'une preuve cryptographique.
- Export d'audit : télécharge le paquet d'audit vérifiable hors ligne lorsque des reçus signés existent. Si seuls des journaux locaux non signés existent, le tableau de bord explique que la signature doit d'abord être activée.
Pour les approbations de repli sur bureau en direct, démarrez le tableau de bord avec le point de terminaison d'approbation de la passerelle locale et le nonce affichés par le wrapper :```bash
npx protect-mcp dashboard --open
--approval-endpoint http://127.0.0.1:9876
--approval-nonce "$PROTECT_MCP_APPROVAL_NONCE"
`Approve` est transmis à la passerelle locale active lorsque ces indicateurs sont présents.
`Deny`, `Edit` et `Take over` sont enregistrés localement en tant qu'enregistrements
de résolution d'approbation ; utilisez-les comme instruction de l'opérateur et relancez l'outil si nécessaire.
### MVP de la frontière payante : ancrage de digest, pas de téléversement de données
Les reçus auto-signés locaux restent gratuits et vérifiables hors ligne. La frontière payante est
une preuve indépendante que ScopeBlind a vu un digest de reçu à un moment donné, sous une identité
d'organisation, sans recevoir le prompt brut, la charge utile de l'outil, la sortie, la clé privée ou
le reçu brut.```bash
# 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
L'aperçu local est délibérément étiqueté local-preview-not-independent.
Le mode hébergé n'ancre que les hachages de reçus, les identifiants de requête, les clés publiques d'organisation et
les métadonnées de facturation. Il ne téléverse pas les reçus bruts ni le contexte sensible.
Démo percutante : de l'ombre à la politique à la preuve
protect-mcp killer-demo génère un pack de vente/démo complet de trois minutes :```bash
npx protect-mcp killer-demo --dir ./scopeblind-demo
Il crée un système de fichiers simulé, une activité GitHub, e-mail et PMS ; affiche les appels risqués en
mode shadow ; applique un pack de politiques ; exige une approbation pour une réservation PMS sensible ;
exécute via la passerelle ; écrit un reçu signé ; prouve que le reçu
original est vérifié ; prouve qu'un reçu falsifié échoue ; et crée un package de divulgation
sélective qui masque le contexte sensible tout en montrant la preuve minimale.
Ouvrez d'abord le `DEMO-RUNBOOK.md` généré. Exécutez ensuite la commande de tableau de bord
affichée pour guider un client à travers la séquence exacte.
### Selective Disclosure v0
Les reçus en mode engagement peuvent porter un `committed_fields_root` au lieu d'exposer
chaque champ en clair. Plus tard, le détenteur peut divulguer uniquement les champs sélectionnés :```bash
npx protect-mcp verify-disclosure \
--receipt ./receipts/selective-disclosure.receipt.json \
--disclosure ./receipts/selective-disclosure.tool-only.json
Le vérificateur contrôle le hash du reçu parent, la signature Ed25519, la racine d'engagement, et la preuve de Merkle de chaque champ divulgué. Il explique ensuite quels champs ont été divulgués et quels champs engagés restent cachés. Il s'agit d'une divulgation par engagement salé, et non d'une connaissance nulle complète, mais cela rend la revendication de confidentialité concrète : les auditeurs peuvent vérifier des faits sélectionnés sans recevoir la charge utile complète de l'outil ni le contexte sensible du bureau.
Prouver une affirmation sur l'enregistrement (attestations à position aveugle)
Vous pouvez prouver une AFFIRMATION sur votre enregistrement sans le révéler. Émettez une attestation signée, à position aveugle, sur l'ensemble de l'enregistrement qui ne divulgue que les catégories par décision (un digest de reçu, le verdict, les étiquettes de capacité), jamais vos entrées d'outil, sorties ou données :```bash
"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
N'importe qui peut le vérifier hors ligne, ne voyant que les catégories, jamais le contenu :```bash
npx protect-mcp verify-claim claim-<id>.json
Le vérificateur recalcule une racine de Merkle sur l'ensemble divulgué et recalcule le prédicat de manière indépendante, de sorte que l'émetteur ne peut pas mentir sur l'affirmation compte tenu de la divulgation. Ajoutez --anchor pour enregistrer le condensé de l'affirmation dans le journal de transparence public en ajout seul ScopeBlind, afin qu'une contrepartie qui ne vous fait pas confiance puisse confirmer que l'ensemble divulgué est complet et n'a pas été discrètement retaillé (seul le hachage est envoyé ; l'enregistrement reste local) :```bash
npx protect-mcp claim --no net.egress --anchor
Il s'agit d'une attestation responsable et aveugle à la position, et non d'une connaissance nulle complète : elle
révèle la forme, pas le contenu.
## Essayez en 60 secondes (aucun agent requis)
[](https://legate.scopeblind.com/record)
Regardez le film de deux minutes sur [legate.scopeblind.com/record](https://legate.scopeblind.com/record), puis rejouez-le sur votre propre copie :```bash
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
Déposez le fichier demo-tampered.jsonl généré dans la page d'enregistrement pour voir une modification post-signature se faire détecter. sample refuse de toucher un enregistrement existant, donc exécutez-le dans un dossier vide. Lorsque vous êtes prêt pour le vrai test, connectez la barrière ci-dessous et les mêmes commandes s'exécutent contre l'enregistrement de votre propre agent.
Démarrage rapide du hook Claude Code```bash
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
Évaluation en un seul passage, telle qu'un hook PreToolUse l'appelle. Le code de sortie 2 signifie refuser (l'outil est bloqué) ; le code de sortie 0 signifie autoriser :```bash
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
Une politique manquante ou non chargeable refuse (exit 2) sauf si vous passez explicitement
--fail-on-missing-policy false.
Hooks de Claude Code
protect-mcp init-hooks écrit un .claude/settings.json pour vous. Pour câbler la
barrière manuellement, les deux verbes dont vous avez besoin sont evaluate (PreToolUse, bloque sur exit 2)
et sign (PostToolUse, enregistre un reçu). Épinglez la version afin qu'une session Claude Code
exécute toujours la barrière que vous avez testée :```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "npx [email protected] evaluate --cedar ./cedar --tool "$TOOL_NAME" --input "$TOOL_INPUT""
}
]
}
],
"PostToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "npx [email protected] sign --tool "$TOOL_NAME" --receipts ./receipts --key ./keys/gateway.json"
}
]
}
]
}
}
### Signer la décision de politique elle-même
À partir de la version 0.13.0, `sign` peut évaluer la politique et enregistrer la décision réelle dans le reçu au lieu d'une autorisation inconditionnelle. Passez le répertoire de politique ainsi que les mêmes entrée et contexte que le hook transmettrait à `evaluate` :```bash
npx [email protected] sign --cedar ./cedar --tool Bash \
--input '{"command":"rm -rf /"}' --context '{"command_pattern":"rm -rf"}' \
--receipts ./receipts --key ./keys/gateway.json
Le payload de reçu porte ensuite decision (allow ou deny), reason
(cedar_allow ou cedar_deny), et policy_digest (le digest
acta-policy-digest-v1 de l'ensemble de politiques), et cite
draft-farley-acta-signed-receipts-03. La commande affiche la décision et le
digest sur stdout. Un deny est quand même signé : le reçu est l'enregistrement
de la décision, pas une autorisation de poursuivre.
Deux modèles d'action Cedar sont pris en charge. Le runtime gate évalue
Action::"MCP::Tool::call" avec l'outil comme ressource, ce que les
politiques dans cedar/ attendent et ce que sign --cedar utilise par défaut.
Les politiques qui nomment l'outil comme action (action == Action::"Bash"),
telles que la politique de conformité publiée dans
agent-governance-testvectors, nécessitent --action-model tool. evaluate
accepte le même flag.
evaluate se termine avec le code 2 en cas de deny afin que Claude Code
bloque l'appel d'outil, et 0 en cas d'allow. sign est best-effort : il
ajoute un reçu signé Ed25519 lorsqu'une clé est configurée, et si aucun
signataire n'est disponible, il enregistre une ligne non signée honnête
("signed": false) plutôt que de faire échouer l'outil.
L'utiliser dans d'autres agents (Codex, Cursor, Gemini, Hermes)
Le même gate fail-closed s'exécute comme hook d'outil dans tout agent qui les
prend en charge. Ajoutez --format <host> pour que le verbe lise le payload
de hook de cet hôte depuis stdin et refuse selon son contrat :```bash
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
Associez chacun à `sign --format <host>` sur l'événement post-tool pour obtenir des reçus. Le cas important est **Hermes**, qui ignore les codes de sortie des hooks et lit le verdict depuis stdout, donc `--format hermes` refuse via `{"decision":"block"}` plutôt que par exit 2 (un exit-2 brut échouerait silencieusement en mode ouvert dans ce cas). Sans `--format`, les verbes lisent les flags `--tool`/`--input` exactement comme dans la section Claude Code ci-dessus.
## Écrire une politique
Les politiques Cedar résident dans un répertoire que vous indiquez avec `--cedar`. Une règle `forbid` refuse, une règle `permit` autorise. Pour faire correspondre une valeur dans l'entrée de l'outil, utilisez l'idiome `.contains()` :```cedar
// 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"
);
Danger : n'écrivez PAS
context.command in ["rm", "dd"]pour faire correspondre une chaîne à une liste.inest destiné aux hiérarchies d'entités, pas à l'appartenance à une chaîne. Cedar traite l'expression comme une erreur de type et ignore silencieusement toute la règleforbid, ce qui (sous une porte à échec ouvert) laisse subsister unpermitrésiduel. C'est exactement le défaut à l'origine de l'avis ci-dessous. Utilisez plutôt[...].contains(context.command). À partir de la version 0.7.0, la porte refuse en cas de cette erreur au lieu de permettre, et un test de déclenchement CI fait échouer la compilation si le motif est réintroduit dans une politique livrée. Voir GHSA-hm46-7j72-rpv9.
Packs de politiques de démarrage
La plupart des équipes ne devraient pas écrire du Cedar à partir de zéro dès le premier jour. Installez un pack de démarrage, exécutez-le en mode fantôme, inspectez les reçus, puis resserrez ou appliquez :```bash 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
Packs intégrés :
- `filesystem-safe` : actions destructrices sur les fichiers et lectures de chemins de type secret.
- `git-safe` : force pushes, hard resets, nettoyages destructeurs, suppression de dépôt.
- `email-safe` : autoriser la rédaction, bloquer les envois non supervisés.
- `database-safe` : posture DB orientée lecture, bloquer les SQL d'écriture/administration.
- `cloud-spend-safe` : création évidente de dépenses cloud et destruction d'infrastructure.
- `secrets-safe` : exfiltration courante de secrets via fichiers, env, shell et cloud.
- `finance-mandate-safe` : violations de listes restreintes et de concentration dans les flux de réservation.
## Vérifier un reçu
Les reçus sont signés et vérifiables hors ligne par quiconque possède la clé publique. Pas de
réseau, pas de fournisseur, aucune confiance en ScopeBlind :```bash
npx @veritasacta/verify ./receipts/receipts.jsonl --format jsonl
# Exit 0 = valid, non-zero = tampered or malformed
npx protect-mcp bundle --output audit.json exporte un bundle d'audit autonome et vérifiable hors ligne de vos reçus, accompagné de la clé de signature publique.
Sécurité
protect-mcp 0.7.0 échoue en mode fermé par conception. En cas d'erreur d'évaluation de politique, d'absence de moteur, ou de politique ayant échoué à l'évaluation, la décision est DENY, et non allow. serve --enforce et doctor exécutent un auto-test au démarrage qui prouve que le portail refuse un vecteur connu comme interdit avant d'être approuvé, et refusent de s'armer s'il ne le peut pas.
Versions affectées : 0.5.x et 0.6.x. Ces branches échouent en mode ouvert (elles renvoient ALLOW en cas d'erreur d'évaluation) et n'évaluent pas correctement Cedar face au moteur épinglé, de sorte qu'une règle forbid pouvait ne pas bloquer. Mettez à niveau vers >= 0.7.0.
Détails et remédiation : GHSA-hm46-7j72-rpv9. Pour signaler une vulnérabilité, voir SECURITY.md.
Commandes
| Commande | Description |
|---|---|
serve | Démarre le serveur de hook HTTP pour Claude Code (port 9377). --enforce exécute d'abord l'auto-test de retenue ; --cedar <dir> et --policy <path> sélectionnent la politique. |
init | Génère une paire de clés Ed25519 (keys/gateway.json), un modèle de configuration et une politique d'exemple. |
sample | Initialise un enregistrement d'exemple clairement étiqueté (8 décisions : un appel bloqué, deux paiements ; kid sample-demo) ainsi qu'une copie falsifiée, afin que record, claim, verify-claim et anchor-record soient rejouables de zéro avant de connecter un agent. Refuse de toucher à un enregistrement existant ; --force force l'opération. |
policy | Consultez et modifiez la politique Cedar depuis le terminal : policy list (permit / forbid / default-deny par outil, avec la fréquence à laquelle le portail l'a autorisé ou refusé), policy show, policy allow <tool>, policy deny <tool>, policy path. Un serve en cours recharge à chaud lors du changement. |
wrap | Affiche une commande MCP protégée ou modifie les serveurs MCP de Claude Desktop. Dry-run par défaut ; utilisez --write pour mettre à jour la configuration de Claude Desktop. |
dashboard | Démarre un tableau de bord local uniquement sur 127.0.0.1 affichant l'inventaire des outils, le risque, la couverture des politiques, les approbations d'actions exactes, les chaînes de reçus et l'export d'audit. |
recommend | Rédige une politique JSON révisable à partir des appels locaux observés. Dry-run par défaut ; utilisez --write pour créer protect-mcp.recommended.json. |
registry | Crée une identité d'organisation, ancre les empreintes de reçus et écrit une page de vérification statique. Le mode hébergé ne téléverse que les empreintes. |
record | Ouvre une visionneuse locale et consultable de vos reçus (--live diffuse en continu pendant l'exécution de l'agent) : signatures Ed25519 vérifiées dans votre navigateur contre votre clé de portail, étiquettes de capacités, arbre de provenance et export signé en un clic. Tout est local, rien n'est téléversé. |
claim | Émet une attestation signée et aveugle à la position d'un prédicat sur l'enregistrement (--no <cap> incl. --no payment, --only <c1,c2>, --no-verdict <verdict>, --count <verdict>, --payment-under <cap>), ne divulguant que les catégories de décisions. Ajoutez --anchor pour enregistrer l'empreinte de la revendication dans le journal de transparence public ; les clés inscrites s'ancrent en tant qu'organisation nommée. |
anchor-record | Enregistre la racine de Merkle + le nombre + la plage temporelle de l'enregistrement dans le journal public (compatible heartbeat : ignore si inchangé). Une revendication ultérieure dont l'engagement correspond à un point de contrôle ancré est prouvablement établie sur l'enregistrement complet à ce point de contrôle. |
verify-claim | Vérifie un pack de revendication hors ligne : signature, racine de Merkle recalculée, prédicat recalculé indépendamment, et le sidecar d'ancrage lorsqu'il est présent (lie l'enveloppe ancrée à cette revendication exacte, puis confirme que le journal public la détient). --check-anchor exige l'ancre ; --offline saute le saut vers le journal. |
killer-demo | Génère un pack de démonstration complet allant du mode shadow à la politique, à l'approbation, puis au reçu signé. |
verify-disclosure | Vérifie un paquet scopeblind.selective_disclosure.v0 et explique les champs divulgués par rapport aux champs masqués. |
policy-packs | Liste, inspecte et installe des packs de politiques Cedar de démarrage. |
evaluate | Évalue un appel d'outil contre une politique Cedar (portail PreToolUse). Code de sortie 2 = deny (fail-closed), code de sortie 0 = allow. |
sign | Signe un appel d'outil dans un reçu (PostToolUse). Au mieux : enregistre une ligne non signée honnête en l'absence de clé. |
simulate | Exécute une politique en dry-run contre un journal de décisions enregistré pour voir ce qu'elle aurait bloqué. |
demo | Démarre un serveur de démonstration intégré enveloppé avec le portail, pour voir les reçus instantanément. |
doctor | Vérifie votre configuration (clés, politiques, moteur Cedar, vérificateur) et exécute l'auto-test de retenue. |
bundle | Exporte un bundle d'audit vérifiable hors ligne des reçus plus la clé publique. |
report | Génère un rapport de conformité (Markdown ou JSON) à partir du journal de décisions et des reçus. |
Exécutez npx protect-mcp --help pour la référence complète des options.
Liens
- Protocole (IETF) : draft-farley-acta-signed-receipts
- CHANGELOG
- npm
- scopeblind.com
Sous licence MIT. Développé par ScopeBlind.