Local CLI and stdio gateway, file-based policy and tool registry, observe and enforce modes, local exact-request approvals, local SQLite-backed audit receipts, and governed GitHub profile examples.
Boundport puts a policy boundary between AI agents and the systems they touch.
Boundport acts as an agent access gateway between an MCP client and the tools or MCP servers it calls. Each request is evaluated against policy before it reaches the target system, and governed requests leave an audit trail around what was requested, why it was allowed or blocked, and whether approval was required.
Platform, security, or AI infrastructure engineers who need agents to use real systems without granting broad unchecked authority.
An MCP client over stdio, an upstream MCP server launched as a subprocess by Boundport, and the real downstream system behind that server such as GitHub.
Start with policy evaluation before a live proxy session.
The recommended first run is a deterministic policy test. It exercises the governance path without requiring a real upstream server or live credentials.
Prerequisites
- Node.js `>=22.13.0`
- pnpm `10.33.0`
- A local checkout of the Boundport repository
First-run command
pnpm install pnpm run build node apps/cli/dist/index.js policy test \ --config examples/boundport-governed.yaml \ --request examples/policy-request.json
Expected success signal
The command should print a JSON decision payload to stdout. A successful result includes fields such as `effect`, `rule_id`, `reason_code`, `policy_revision`, and `request_digest`.
First live proxy run
node apps/cli/dist/index.js proxy --config ./boundport.yaml
For a live run, `upstream.command` and `upstream.args` must point to a real MCP server. The example config is useful for policy testing, but its upstream path is illustrative and should not be treated as a ready-to-run production profile.
Use the local gateway today. Treat managed control-plane features as planned, not current.
Local development
One local Node.js process runs the Boundport gateway, launches the upstream MCP server as a subprocess, and stores audit plus approval state in local SQLite files.
Self-hosted in customer infrastructure
The open-source gateway can be self-hosted using the same one-process pattern inside customer infrastructure. Today the documented model is a gateway process running close to the protected environment, rather than a separate multi-node or Kubernetes control-plane deployment.
Managed or enterprise direction
Centralized policy distribution, authenticated approvals, searchable hosted audit retention, and gateway fleet control belong to the enterprise product direction rather than the current open-source release.
- MCP client sends JSON-RPC over stdio.
- Boundport normalizes and evaluates the request.
- Boundport records a receipt.
- Allowed calls are forwarded once to the upstream subprocess.
- Approval-gated calls wait for a local operator decision.
- The agent and its arguments are untrusted.
- Upstream tool descriptions and schemas are untrusted until classified.
- Local config and SQLite state are inside the trust boundary only if owned and protected by the operator.
Policies are deterministic, ordered, and bound to exact tool schemas.
Rules are evaluated in order and the first matching rule wins. Supported match conditions today include `server_id`, `tool_name`, `tool_risk`, `environment`, and `principal_id`. Current effects are `allow`, `deny`, and `require_approval`.
Minimal starter policy
schema_version: 1
rules:
- id: allow-reads
match:
tool_risk: read
effect: allow
- id: gate-writes
match:
tool_risk: write
effect: require_approval
approver_groups:
- platform
ttl_seconds: 300
- id: default-deny
match: {}
effect: deny
reason_code: no_matching_rule
A good first policy classifies all known tools, allows low-risk reads, requires approval for writes, and ends with an explicit default deny.
Representative tool registry entry
schema_version: 1
tools:
- server_id: example
tool_name: read_file
schema_digest: sha256:a2c799262a3ce3c19ef5cdd983bf3d12b43ab3c426227091b909dcb7054738c0
risk: read
idempotent: true
secret_fields:
- authorization
`observe` always forwards and records the would-be decision. `enforce` forwards only classified allow decisions and fails closed on unclassified tools.
Argument-level conditions are not currently supported by the implemented matcher, so docs and examples should not imply that Boundport can inspect arbitrary nested arguments in policy rules today.
Approval is exact-request, single-use, and local today.
Approval is triggered only when a matching policy rule uses `effect: require_approval`. The current approval surface is the local CLI against the approvals SQLite database. Approval identity is based on local configuration, not authenticated SSO or hosted RBAC.
node apps/cli/dist/index.js approvals list --config examples/boundport-governed.yaml node apps/cli/dist/index.js approvals approve <approval-id> --config examples/boundport-governed.yaml node apps/cli/dist/index.js approvals reject <approval-id> --config examples/boundport-governed.yaml
- `approval_required` - request is held pending a decision
- `approval_consumed` - approved request is forwarded once
- `approval_rejected` - request is denied and not forwarded
- `approval_expired` - TTL elapsed before approval
- `approval_cancelled` - client cancelled before release
- `duplicate_request_id` - request replay is rejected
Boundport reduces unchecked agent authority by making execution conditional.
Boundport evaluates each request before it reaches the target system. In enforce mode, unclassified tools fail closed, denied decisions are blocked, and approval-gated decisions stay on hold until a valid exact-request approval is consumed.
Registry schema digests tie decisions to exact tool schemas, helping prevent silent drift between what operators reviewed and what tools actually expose at runtime.
Secret handling is conservative: fields marked in `secret_fields` are redacted in receipts and approval summaries, and untrusted upstream stderr is discarded instead of being logged as audit evidence.
- Transport today is stdio inbound and stdio upstream.
- Identity today is configured local operator identity, not enterprise auth.
- Hosted approvals, hosted audit search, and centralized policy are planned, not available in this repo.
- Supported public claims should distinguish between what exists now and what is directional.
Local receipts answer who requested what, which rule decided it, and what happened next.
The local audit store writes receipts to SQLite and exports append-only JSONL. Events include request identity, routing context, decision effect, matched rule, reason code, tool classification, argument summary, and receipt-chain linkage.
Current storage is local by default. Operators can export JSONL and use their own tooling for deeper inspection, while centralized hosted search and retention controls belong to the enterprise direction.
With current receipts, operators should be able to answer which principal invoked which tool, whether the call was allowed, denied, or approval-gated, which policy revision made the decision, and whether the receipt chain still verifies.
Representative receipt fields
schema_version event_id occurred_at request_id request_digest previous_receipt_digest receipt_digest principal client_id gateway_id environment server_id tool_name tool_schema_digest policy_revision decision tool_risk execution argument_summary redaction_profile
GitHub is the concrete governed integration called out in the current public material.
The governed GitHub profile targets `github/github-mcp-server` `v1.7.0` over stdio. Live smoke runs require an inherited `GITHUB_PERSONAL_ACCESS_TOKEN`, and enforce mode fails closed if the schema or tool classification drifts.
Current quickstarts also document configuration examples for Claude Desktop and Claude Code, but those examples are configuration-schema validated rather than backed by published external UAT results.
- Hosted approval delivery
- Slack approvals
- Postgres integration as a supported product integration
- Additional SaaS or cloud provider governed profiles not yet checked in
The minimum governed config includes upstream execution, identity, audit, and approvals.
schema_version: 1
upstream:
command: "node"
args:
- "/absolute/path/to/your-mcp-server.js"
cwd: "."
env:
allow:
- "PATH"
governance:
mode: observe
policy: "./policy.yaml"
registry: "./tool-registry.yaml"
server_id: example
identity:
principal_id: "local:operator"
principal_type: local_profile
client_id: "local-mcp-client"
gateway_id: "local-gateway"
environment: development
audit:
database: "../.boundport/receipts.sqlite"
observe_failure: deny
approvals:
database: "../.boundport/approvals.sqlite"
poll_ms: 100
operator:
id: "operator:local"
groups:
- platform
- `upstream.command` - executable launched as the upstream MCP server
- `upstream.args` - arguments passed to the upstream command
- `upstream.cwd` - working directory for the upstream subprocess
- `upstream.env.allow` - allowlist of inherited environment variable names
- `governance.mode` - `observe` or `enforce`
- `governance.policy` - path to the policy file
- `governance.registry` - path to the tool registry
- `governance.audit.database` - local SQLite audit path
- `governance.approvals.database` - local SQLite approvals path