Skip to content

Repository files navigation

AgentGate

MCP-native least-agency gateway for tool-using AI agents.

This MVP implements the customer-support account recovery demo from docs/:

  • Scan an MCP-shaped tool manifest.
  • Run a deterministic unsafe baseline agent — or a live/scripted agent loop where every tool call is mediated by the gateway.
  • Route the same workflow through AgentGate policy enforcement: allow, allow_with_transform (redaction/limit/arg-narrowing), require_approval, deny, and quarantine.
  • Approve/deny gated calls and resume the original tool call when approved.
  • Log runtime decisions and audit events; export them as OpenTelemetry (OTLP/JSON) traces.
  • Run baseline/protected eval suites against final world state (security failures are distinguished by scenario tag).
  • Export blocked incidents as regression YAML and re-run them through the eval runner (Story 6.4 round-trip).
  • Edit or upload the active policy from the dashboard or API.
  • Drive everything from a CLI and gate CI with the protected eval.

Run

pnpm install
pnpm db:seed
pnpm upstream:local
pnpm dev

Open http://localhost:3000.

Run pnpm upstream:local in a second terminal. It starts the local upstream executor that the Live Gateway defaults call at http://127.0.0.1:4000/tool and http://127.0.0.1:4000/mcp.

The first screen is Live Gateway. It is the real execution surface:

  • Enter a tool executor URL.
  • Select a registered tool.
  • Edit the JSON arguments.
  • Set identity and approval state for high-risk calls.
  • Click Send Real Tool Call.
  • Inspect whether AgentGate allowed the call and whether the upstream was called.
  • Resolve pending runtime approvals in the Approval Queue.

The Demo Lab tab is only for the seeded hackathon scenario and eval loop.

For the verified production preview:

pnpm build
pnpm start

Demo Commands

pnpm scan:tools
pnpm demo:baseline
pnpm demo:protected
pnpm eval:run --mode=baseline
pnpm eval:run --mode=protected
pnpm regression:export --decision=dec_001

The protected path should show:

  • auth.reset_password returns require_approval.
  • email.send_external returns deny.
  • password_reset_performed remains false.
  • External outbox stays empty.
  • A pending approval is created.

API

The app exposes both Next API routes and canonical rewrites:

  • POST /v1/tools/scan
  • POST /v1/policy/evaluate
  • GET /v1/policy · POST /v1/policy (upload/edit the active policy YAML)
  • POST /v1/tool-call
  • POST /v1/mcp
  • POST /v1/approvals (approve/deny and resume the original call)
  • POST /v1/evals/run
  • POST /v1/regressions/export
  • POST /v1/regressions/run (re-run exported regression YAML — Story 6.4)
  • GET /v1/telemetry (OTLP/JSON trace export of every decision)
  • GET /v1/state

All request bodies are validated with zod; malformed input returns a 400 with structured issues. Mutating endpoints serialize their read-modify-write through an in-process lock with atomic file replacement. Set AGENTGATE_API_TOKEN to require Authorization: Bearer <token> (or x-agentgate-token) on mutating routes; unset leaves the demo open.

Real Tool Execution

Demo mode calls the local fake world inside AgentGate. External mode calls a separate upstream process. For local verification, start the included executor:

pnpm upstream:local

Then call AgentGate with execution_mode: "external".

curl -s http://localhost:3000/v1/tool-call \
  -H 'Content-Type: application/json' \
  -d '{
    "execution_mode": "external",
    "upstream_url": "http://localhost:4000/tool",
    "tool_call": {
      "name": "crm.lookup_customer",
      "args": {"email": "real_customer@example.com"}
    },
    "input_email_trust_level": "untrusted"
  }'

AgentGate evaluates policy first. Only allow and allow_with_transform calls are forwarded. Denied, pending approval-gated, and quarantined calls do not reach the upstream. High-risk calls such as password reset can forward after the required runtime state is present, for example identity_verification_status: "verified" and approval_status: "approved".

The upstream receives:

{
  "tool": "crm.lookup_customer",
  "args": {"email": "real_customer@example.com"},
  "decision": {
    "decision_id": "dec_001",
    "matched_policy_ids": ["support.allow_customer_lookup_for_active_ticket"],
    "risk_score": 25,
    "reason": "Customer lookup is allowed for active support tickets."
  }
}

Allowed upstream origins default to common localhost ports. For non-local upstreams:

AGENTGATE_ALLOWED_UPSTREAM_ORIGINS=https://tools.example.com pnpm start

You can also set a default tool executor:

AGENTGATE_UPSTREAM_TOOL_URL=http://localhost:4000/tool pnpm start

MCP Proxy Mode

Point an MCP Streamable HTTP client at:

http://localhost:3000/v1/mcp

AgentGate handles initialize, tools/list, and tools/call.

To forward allowed tools/call requests to a real MCP server:

AGENTGATE_MCP_UPSTREAM_URL=http://localhost:4000/mcp pnpm start

Blocked MCP tool calls return a JSON-RPC error with the AgentGate decision in error.data.

CLI

A single CLI wraps the gateway for scripts and CI:

pnpm agentgate scan                       # risk-scan the tool manifest
pnpm agentgate eval --mode protected      # run the eval suite
pnpm agentgate regression:export          # export the latest blocked incident
pnpm agentgate regression:run             # re-run exported regression YAML (Story 6.4)
pnpm agentgate policy:validate policy.yaml
pnpm agentgate agent --injection          # drive an agent loop through the gateway
pnpm agentgate telemetry                  # print OTLP/JSON traces
pnpm agentgate ci-gate --mode protected   # exit non-zero if the release is BLOCKED

scripts/agentgate-cli.ts is also exposed as the agentgate bin.

Agent mode

runAgent() lets a real or scripted agent propose tool calls; each one is mediated by the gateway and the decision is fed back as an observation, so the model cannot take an action the policy forbids. The default client is deterministic (ScriptedLlmClient). Set ANTHROPIC_API_KEY and pass --live to use the Claude Messages API (AnthropicLlmClient, with prompt caching).

CI gate / GitHub Action

.github/workflows/agentgate.yml runs typecheck, tests, build, and the AgentGate release gate. The repo also ships a reusable composite action (action.yml) that fails a job when the protected eval recommends block:

- uses: your-org/agentgate@v1
  with:
    mode: protected

Persistence

The hackathon demo uses a local file-backed runtime store at .agentgate/runtime.json (override the directory with AGENTGATE_RUNTIME_DIR). Writes are atomic (temp file + rename) and serialized through an in-process lock. It preserves the documented entities for the local loop: tools, policy, scans, decisions, audit events, eval runs/results, world state, approvals, quarantine status, regression exports, and regression runs.

About

Least-agency gateway for AI agent tool calls — policy-enforced allow/transform/approval/deny/quarantine, eval + regression loop, and a dark/light console dashboard.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages