Bouncer
Carrier integration for GitHub Issues that allows only posting comments to an issue. It uses an isolated process with a hard-coded allowlist for POST /repos/{owner}/{repo}/issues/{issue_number}/comments and rejects non-comment issue modifications.
Read-only integration for reading Notion content, tasks, and comments, plus a constrained carrier integration for inserting human-approved comments only. It is designed to prevent property updates such as owner, due date, or status changes at the credential level.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Bouncer: Permission-Bounded MCP Server & Agent Registry
A permission-bounded Model Context Protocol (MCP) server and agent registry where the forbidden write has no code path, proven by automated credential audits and prompt-injection red-team tests.
1. Core Security Thesis & Objective
Build agent governance that is enforced by structure, not by instructions in a prompt.
The Rule: An agent may read and report, may carry a human-authored update into a system of record after a human consents, but may never autonomously write a commitment (an owner, a due date, a status) into a shared work system.
Bouncer makes that last part impossible: The tool does not exist, and the credential behind it cannot do it either.
"Prompt injection cannot produce a forbidden write, because no tool and no credential in the agent's grant can perform it. I can show you the audit that proves it."Related MCP server: project-bridge
2. Architecture Overview
flowchart TD
subgraph Untrusted_Zone ["Untrusted LLM Agent"]
Agent["Agent (LLM Loop)\n- Susceptible to Prompt Injection\n- Per-Agent Bearer Token"]
end
subgraph Human_Zone ["Human Review Gate"]
Human["Human Reviewer\nCLI: bouncer issue-consent"]
Token["Signed Consent Token\nsha256(text) + target + nonce + 10m TTL"]
Human -->|Issues| Token
end
subgraph Bouncer_Core ["Bouncer Governance MCP Server"]
Gate["1. Identify Agent from Bearer Token\n(Constant-Time SHA-256 API Key Matching)"]
Filter["2. list_tools(): Dynamic Tool Surface\n(Only granted tools returned; forbidden tools hidden)"]
Authz["3. authorize(agent, tool, args)\nEnforces Tier Policy & Fail-Closed Logging"]
Audit["4. Append-Only Decision Audit Log\n(SQL Triggers + Hash Chained prev_hash + WAL Locking)"]
Gate --> Filter --> Authz --> Audit
end
subgraph Execution_Boundary ["Structural Execution Boundary"]
ReadTool["Read Tools (read_tasks, read_task, read_comments)"]
CarryTool["Carry Tool (post_human_authored_comment)\n- Verifies sha256(text)\n- Verifies Agent & Target Match\n- Atomically Consumes Persistent Nonce\n- Zero params for owner/date/status"]
end
subgraph Work_Systems ["System of Record"]
NotionRO["Notion Read-Only Integration\n(Capability: Read Content ONLY -> Proven 403 on update)"]
NotionCarrier["Notion Carrier Integration\n(Capability: Insert Comments ONLY)"]
GitHubCarrier["GitHub Issues Carrier Client\n(Allowlist: POST /issues/{id}/comments ONLY)"]
end
Agent -->|Invokes MCP| Gate
Token -.->|Supplied by Agent| CarryTool
Authz -->|Allowed Read| ReadTool
Authz -->|Allowed Carry| CarryTool
ReadTool -->|Read Credential| NotionRO
CarryTool -->|Carrier Secret| NotionCarrier
CarryTool -->|Allowlisted Transport| GitHubCarrier3. Risk Tiers Enforced by Bouncer
Every agent in the registry must be explicitly categorized into one of four risk tiers. Incomplete entries fail validation immediately:
Tier | Meaning | Allowed Tools | Review & Human Evidence Required |
| Read-Only Internal |
| Registered owner; eval suite recommended; zero write tools |
| Draft Producer | Read tools + | Eval suite with safety test cases required |
| Carries Human Update | Read tools + | Cryptographic consent token on every write; eval gate green |
| External Output | Read tools, carry tool, | Human approves each action; budget limits; strict eval gate |
Hard Invariant Rule: No tier may ever include a tool from the forbidden write set (
set_owner,set_due_date,set_status,update_property,update_any_property,assign,delete_page,delete_issue). The registry validator strictly fails CI on the mere presence of such a name in any grant.
4. Threat Matrix & Structural Controls
Full details are documented in docs/threat-model.md.
# | Forbidden Outcome | Attack Path | Structural Control | Verification Proof |
1 | Agent sets owner, due date, or status | Prompt injection in task text, model error, tool misuse | No such tool exists; credential has no update capability; audit proves 403 | Automated credential audit ( |
2 | Agent posts text a human never approved | Model edits text after human approval | Consent token cryptographically binds |
|
3 | Consent token reused (Replay attack) | Replay of intercepted token | Single-use nonce atomically stored in SQLite database, 10-minute short expiry |
|
4 | Agent uses another agent's powers | Stolen or guessed token | Cryptographic SHA-256 API key matching ( |
|
5 | Unregistered agent runs | Unreviewed agent launched informally | Server strictly refuses unknown identities; CI fails on incomplete registry entries |
|
6 | Silent policy change | Edit permissions without review | Registry stored in YAML under version control, |
|
7 | Audit log tampering | Rogue agent or operator deletes rows | Append-only database triggers (prohibiting UPDATE/DELETE), cryptographic hash chaining ( |
|
8 | Audit failure blind spot | Disk full or DB locked during execution | Authorizer strictly fails closed ( |
|
9 | Cross-tenant connection bleed | Shared server in multi-agent deployment |
|
|
5. Security Engineering & Hardening
Bouncer undergoes continuous rigorous hardening against production failure modes:
Cryptographic Agent Authentication: Bearer tokens are resolved via constant-time SHA-256 digests (
secrets.compare_digest) against pre-registered hashes inregistry/agents.yaml, eliminating timing attacks and token guessing.Persistent SQLite Nonce Storage (
SqliteNonceStore): Consent token nonces are committed immediately to disk using SQLitePRIMARY KEYuniqueness constraints, ensuring replay attacks fail even across server reboots, container redeployments, and horizontal processes.Fail-Closed Audit Pipeline: If the audit subsystem fails to record a decision (e.g., disk exhaustion, database lock timeout), the authorization engine intercepts the failure and fails closed (
AUDIT_FAILURE_FAIL_CLOSED). Unaudited tool execution is impossible.Concurrency Locking & Block Chain Integrity: Audit entries are serialized with thread locks and SQLite
BEGIN IMMEDIATEtransactions in WAL mode, guaranteeing zero forks in the cryptographic hash chain (prev_hash).Canonical JSON Digesting: Hash chaining serializes block payloads using canonical JSON (
separators=(",", ":"), sorted keys), eliminating delimiter collision and injection vulnerabilities.Multi-Tenant ASGI Middleware (
BouncerAuthMiddleware): Isolates caller identities per HTTP/SSE connection via PythonContextVar, preventing tenant credential bleed in shared deployments.Production Fail-Closed Secrets: The consent signing key
BOUNCER_CONSENT_SECRETstrictly requires explicit configuration in production mode (ENV=production), immediately terminating startup if unconfigured.
6. Automated Credential Audit Results
To prove that governance is enforced at the credential layer, Bouncer runs an automated credential audit script (scripts/audit_credentials.py) that attempts every forbidden operation across every registered agent:
======================================================================
BOUNCER CREDENTIAL AUDIT ENGINE: TESTING STRUCTURAL RESTRICTIONS
======================================================================
Total Registered Agents Audited: 4
Forbidden Operations Tested per Agent: 5
Total Forbidden Attempts: 20
Total Blocked at Work System API: 20
Protection Rate: 100.0% (Structurally Impossible)
======================================================================Agent ID | Tier | Credential Ref | Forbidden Operations Tested | Blocked | Enforced Result |
| T0 |
| 5 | 5 | PASS (100% Blocked - 403) |
| T1 |
| 5 | 5 | PASS (100% Blocked - 403) |
| T2 |
| 5 | 5 | PASS (100% Blocked - 403) |
| T3 |
| 5 | 5 | PASS (100% Blocked - 403) |
Full report committed at audit/credential-audit.md.
7. Notion vs. GitHub Carrier Pattern Comparison
A critical design consideration when building Bouncer was the disparity in permission models between work systems:
Notion (Credential-Level Restriction):
Notion separates Read content, Insert comments, and Update content into discrete integration capabilities. A Notion token granted Read + Comment capabilities structurally receives a403 RestrictedObjectErrorwhenever attempting a property update.GitHub Issues (Code-Level Carrier Wrapper):
GitHub's fine-grained permission needed to comment on an issue (Issues: write) also permits changing assignees, milestones, labels, and state. Because GitHub does not offer a comment-only credential, Bouncer places that credential strictly inside an Isolated Carrier Process whose HTTP transport is bounded by a hard-coded regex allowlist:POST /repos/{owner}/{repo}/issues/{issue_number}/comments
Any non-comment request (e.g.PATCH /repos/.../issues/...) is intercepted and rejected withCarrierAllowlistViolationErrorbefore touching the network.
See docs/adr/0001-why-notion-primary.md and docs/adr/0002-carrier-pattern-for-github.md.
8. Quickstart & CLI Commands
1. Installation
git clone https://github.com/Harsh-karn/Bouncer-permission-bounded-MCP-server-and-agent-registry-.git
cd Bouncer-permission-bounded-MCP-server-and-agent-registry-
uv venv
source .venv/bin/activate # Or on Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"2. Validate Agent Registry
Validate agent definitions against tier rules and ensure no forbidden tools are granted:
bouncer validate --path registry/agents.yaml3. Human Review Gate: Issue Consent Token
Interactively inspect proposed text, calculate its cryptographic hash, and sign a single-use token:
bouncer issue-consent --agent status-reporter --target task-101 --text "Deployment verified on production."4. Query Append-Only Decision Audit Log
Inspect decisions and verify cryptographic hash chain integrity:
bouncer audit --agent weekly-digest --since 7d --verify5. Run Full Test Suite & Red-Team Attacks
# Run all 82 unit, architecture, and invariant tests
pytest -v
# Run the 12-payload adversarial prompt-injection suite
pytest -v tests/redteam/test_injection.py
# Run live credential audit script
python scripts/audit_credentials.py9. Architecture Decision Records (ADRs)
10. Interview Talking Points & Resume Bullets
Resume Bullets
Authored an MCP governance server with risk-tiered, least-privilege tool grants, ensuring AI agents cannot write commitments (owners, due dates, statuses); verified by automated credential audits and 12 prompt-injection red-team payloads with zero successful writes.
Designed a cryptographic human review gate using signed, single-use tokens bound to a SHA-256 hash of the exact human-approved text, preventing post-approval text tampering, target confusion, and replay attacks across server restarts.
Built an agent registry and validator enforcing owner, risk tier, tool grant, and human gate for every agent, backed by an append-only decision audit log with cryptographic hash chaining (
prev_hash) queryable per agent.Architected fail-closed execution barriers and concurrency-safe block chaining, ensuring tool requests without auditable records are blocked, and multi-tenant ASGI requests remain isolated via asynchronous context propagation.
Key Questions & Answers
Q: Why is a prompt instruction not enough?
A: Prompt instructions fail against jailbreaks, direct injection, and indirect data poisoning. In Bouncer, governance is structural: the forbidden write tool does not exist on the protocol surface, and the agent's credentials lack write capabilities at the API layer.Q: What stops the carrier from being abused if the agent is compromised?
A: The carrier only accepts calls accompanied by an unexpired, cryptographically signed token issued by a human reviewer. The token bindssha256(text)and target ID, and its single-use nonce is atomically consumed upon first execution in persistent SQLite storage, preventing modification or replay.Q: How does Bouncer handle work systems without fine-grained scopes?
A: For coarse APIs like GitHub (Issues: write), Bouncer encapsulates the credential within an isolated Carrier client whose HTTP transport is constrained by a strict regex allowlist admitting onlyPOST .../issues/{id}/comments.
License
This project is licensed under the MIT License.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only finance and operations controls for AI agents with evidence and safe next actions.
Governed memory and workspace for any AI: tasks, calendar, mail and pages, with per-action consent.
Give your agents your team's real data — read the shared graph, propose actions your team approves.
Preventive human-approval write-gate for AI agents: writes commit only after a human approves.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables controlled AI-agent access to enterprise-shaped tools with a deny-by-default gated write path, human approval, dry-run execution, and append-only audit logging.1-
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to read structured project context and propose task changes that require explicit human approval, with scoped permissions, idempotency, and a full audit trail.MIT
- AlicenseBqualityCmaintenanceEnables AI agents to act on live business objects under enforceable per-call identity, per-tool grants, and mandatory human approval for irreversible actions, with connectors isolated from core logic.8MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to read local business data and request database mutations, while requiring human approval before updates or deletions are executed. It provides read-only tools, approval workflows, and audit logging to prevent autonomous destructive changes.-