Skip to main content
Glama
mirukullacode

IntentGate

IntentGate

Your agent said it would read the README. It tried to read your SSH key.IntentGate blocked it.

Intent enforcement for any MCP client and ElevenLabs voice agents, powered by ArmorIQ. One command. Zero code changes. A live Flight Recorder of what your agent planned vs. what it tried.

Live playground · Website · How it works · Architecture · DX notes on ArmorIQ

ci npm


npx intentgate-mcp agent        # a real Claude agent attacks a poisoned workspace through IntentGate
npx intentgate-mcp init         # protect Claude Desktop (or --client cursor)

Try it in 30 seconds

Open the live playground and press Run with IntentGate. A real Claude agent is asked to summarize a README that hides an instruction to read an SSH key and post it to an attacker. You watch, live:

  1. the agent declares its plan and ArmorIQ signs it,

  2. the README read is allowed by ArmorIQ's server under the org policy,

  3. anything off-plan is blocked, and the attacker's inbox stays empty.

Run without IntentGate runs the same agent with no gateway at all, so the comparison is honest. Nothing real is touched: the key is fake and the attacker is a local port.

Related MCP server: AgentGuard MCP Server

Why

Agents act on text they read, and attackers write some of that text. A hidden line in a README, a web page, a support ticket or a caller on the phone can steer an agent into actions nobody asked for.

ArmorIQ fixes this with intent verification: the agent commits to a plan, ArmorIQ signs it, and every action is checked against it. But that needs SDK code, and Claude Desktop, Cursor and ElevenLabs agents can't run your code.

IntentGate is an MCP server that sits in front of your MCP servers and does the ArmorIQ work for any client:

  1. The agent calls declare_plan. ArmorIQ signs it and issues an intent token.

  2. Every tool call is decided by ArmorIQ's backend (tool in plan, org policy) plus argument binding (the arguments match what was declared).

  3. Anything off-plan is blocked. Policy holds and plan changes go to a human, with a spoken alert via ElevenLabs.

  4. Everything streams to the Flight Recorder at localhost:4747.

Proof

One real session, plan signed by ArmorIQ, three decisions:

Call

Result

Decided by

read_file README.md

allowed, enforcement_passed

ArmorIQ server

read_file .ssh/id_rsa

blocked, path differs from plan

IntentGate argument binding

http_post to the attacker

blocked, tool not in plan

ArmorIQ

Flight Recorder showing the allowed README read and the two blocked calls

The same scripted agent on the live playground, without the gateway and with it:

Without IntentGate: the key leaks in 3 seconds

With IntentGate: two blocks, nothing leaks

Playground, no gateway, key leaked

Playground, with IntentGate, two blocked

The voice agent session, an ElevenLabs agent over the hosted gateway, lookup allowed and two plan changes held for a human:

Flight Recorder showing the voice session with an allowed lookup and two holds

Run the call yourself. On the playground, Run a support call drives a real ElevenLabs agent through the gateway with a scripted social-engineering caller. You are the supervisor: when the agent asks to change its plan, Approve or Deny it from the Flight Recorder tab while the call is live. The gateway answers the agent within five seconds either way, so the voice platform never times out, and records your decision when it lands.

Playground voice run: caller, agent, tool calls, with the visitor as supervisor

The agent intentgate, the MCP servers workspace and web, and the policy that allows read_file, list_files, fetch_url and blocks write_file, http_post are registered on platform.armoriq.ai. ArmorIQ's own policy page counts the decisions.

A finding worth stating plainly. Current Claude models (Opus 5.5, Opus 4.8, Haiku 5.5) read the poisoned README, recognise the injection and refuse it on their own. We did not tune the attack to beat them. IntentGate's job is to make the outcome not depend on the model: the same gateway blocks a weaker model, a scripted agent, or a future jailbreak the same way. scripts/simulate.ts drives a scripted hijacked agent through the real engine, which is where the screenshot above comes from.

The finding behind argument binding

ArmorIQ's plan check is tool-level: if read_file(README.md) is in the plan, read_file(.ssh/id_rsa) is the same tool, so it passes. IntentGate adds argument binding with path normalization and globs, so the plan means exactly what it says. Details in How it works and in the DX notes, which collect eleven concrete findings from a week on the SDK and platform.

Install

npx intentgate-mcp init                 # wraps the servers already in Claude Desktop
npx intentgate-mcp init --client cursor
npx intentgate-mcp agent                # run the attack demo with a real Claude agent
npx intentgate-mcp agent --passthrough  # the same agent with no enforcement at all
npx intentgate-mcp playground           # host the demo page + Flight Recorder (what the live URL runs)
npx intentgate-mcp serve --token <secret>   # Streamable HTTP for ElevenLabs agents
npx intentgate-mcp doctor               # checks keys, servers, ports, and asks ArmorIQ what it will do for each tool
npx intentgate-mcp uninstall            # restores your original config

Needs Node 20+. Set ARMORIQ_API_KEY (get one). The built-in agent and playground also need ANTHROPIC_API_KEY. Optional ELEVENLABS_API_KEY for voice alerts. No ArmorIQ key? Add --offline to try everything unsigned.

How a call is decided

client ──tools/call──▶ IntentGate ──▶ 1. plan declared?        (gateway)
                                      2. ArmorIQ decision      (their server, sdk mode)
                                      3. argument binding      (IntentGate)
                                      4. hold → human approval (recorder, voice)
                                      5. forward · report · record

ArmorIQ runs in sdk mode: every decision is made on their backend, so it appears in their trace by construction. Local mode is not usable yet because the backend does not publish its verification key; the spike notes have the measurements.

Deploy your own playground

The repo ships a Dockerfile and railway.json. On Railway: Deploy from GitHub repo, set ARMORIQ_API_KEY, ANTHROPIC_API_KEY, HOST=0.0.0.0, PORT=4747, generate a domain on port 4747. One run at a time, a fresh sandbox per run, an eight-second cooldown.

Docs

Takeaways in three lines

  • The model is not the safety layer. Three current Claude models refused our injection on their own; the gateway makes the outcome independent of which model you run.

  • Tool-level plans have an argument-shaped hole. Argument binding closes it, and belongs in the platform.

  • Next: upstream binding as an SDK option, a "protect any MCP server" cookbook entry, and holds through ArmorIQ's own delegation flow. Full list in docs/takeaways.md.

Develop

npm install && npm --prefix ui install
npm test                      # unit, gateway, HTTP and end-to-end stdio tests
npm run build                 # CLI + Flight Recorder UI
npx tsx scripts/simulate.ts   # scripted hijacked agents through the real engine (add --offline without a key)

Honest limitations

  • An injection that reaches the model before it declares its plan can shape that plan. Every tool is blocked until a plan exists, which closes the common path, but not a malicious initial prompt.

  • Loose plans give loose protection: http_post { url: "*" } allows any URL.

  • Local verification mode depends on ArmorIQ publishing its IAP public key, which it does not yet.

  • Built in one week for the ArmorIQ Flow State hackathon. Tested on Windows and Linux (Railway) with the MCP TypeScript SDK; feedback welcome.

License

MIT · Built by Manjunath Irukulla for the ArmorIQ × ElevenLabs Flow State hackathon.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Wraps your existing MCP servers and checks each tool call against policy and live state before it runs. Allow, block, or require a refresh, with a reason the agent can act on.
    5
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Provides a secure MCP boundary for AI agents, intercepting and validating tool calls, redacting secrets, and requiring human approval for sensitive actions with a tamper-evident audit trail.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a governed execution boundary for AI agents, enforcing deterministic policy, one-shot human approvals, and signed receipts for MCP tool effects.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a governance layer for MCP servers, enforcing policy-based allow/deny/approval rules, requiring human approval for risky calls, and recording an auditable trail of every AI agent tool call.
    MIT