Skip to main content
Glama
Anshv784
by Anshv784

AgentGate

Управляемый шлюз вызовов инструментов для ИИ-агентов, построенный на ADK от Terminal 3.

Дайте LLM-агенту API-ключ — и он сможет вызвать что угодно, потратить что угодно и слить что угодно, а вы узнаете об этом только потом, из логов, которые он сам о себе написал.

AgentGate помещает аппаратно-изолированный анклав между агентом и внешним миром. Агент называет endpoint, а не URL. Он никогда не хранит учётные данные. Он никогда не видит личные данные пользователя. И каждая его попытка — разрешённая или отклонённая — попадает в реестр, который он не может редактировать.

Он поставляется как MCP-сервер, поэтому любой MCP-клиент (Claude Code, Claude Desktop, Cursor, SDK-агент) получает управляемые вызовы инструментов, добавив одну запись в конфигурацию. Никаких фреймворков, никакого переписывания.

  MCP client (Claude / Cursor / your agent)
    │  call_endpoint { endpoint: "resend", path: "/emails",
    │                  body: { to: ["{{profile.verified_contacts.email.value}}"] } }
    ▼
  AgentGate MCP server            ← holds the T3N session; the model holds nothing
    │
    ▼
┌─ z:<tid>:agentgate — TEE contract (Rust → WASM, Intel TDX) ───────────────┐
│  1. every {{…}} marker must be profile.* AND on this endpoint's allowlist │
│  2. path must be one the tenant enumerated — exact match, no globs        │
│  3. credential read from the sealed z:<tid>:secrets map                   │
│  4. host substitutes real PII inside the enclave (contract never sees it) │
│  5. upstream response projected to declared fields only                   │
│  6. ledger entry appended — for ALLOWED and DENIED alike                  │
└───────────────────────────────────────────────────────────────────────────┘
    ▼
  api.resend.com   ← reached only if the data owner's grant permits this host

Это работает. Вот подтверждение

npm run demo против тестнета T3N — каждый вызов ниже выполнен агентом, выпущенным организацией:

🛑 DENIED   profile field outside the endpoint's allowlist  ({{profile.ssn}})
            marker rejected: 'ssn' is not in this endpoint's allowed_placeholders
🛑 DENIED   marker reaching for another namespace  ({{secret.resend_api_key}})
            marker rejected: 'secret.resend_api_key' is not a profile marker
🛑 DENIED   path the tenant never enumerated  (/domains)
            path rejected: '/domains' is not in this endpoint's allowed_paths
🛑 DENIED   endpoint that does not exist  (stripe)
            unknown endpoint

── policy is per-ENDPOINT, not per-host ──────────────────────────────
   'resend' and 'resend-notify' share a host AND a credential.
   The same marker is allowed on one and refused on the other.

✅ ALLOWED  {{profile.first_name}} via 'resend'        (allowlisted there)
            {"data":{"id":"d7299ce6-668f-47f2-8e22-8f3f96c0f255"},"status":200}
🛑 DENIED   {{profile.first_name}} via 'resend-notify' (allowlist is empty)
            marker rejected: 'first_name' is not in this endpoint's allowed_placeholders
✅ ALLOWED  no markers via 'resend-notify'             (allowed, returns nothing)
            {"data":{},"status":200}

Реальные письма были доставлены. Адрес и имя получателя были определены внутри анклава из профиля владельца данных — они не появляются ни во входных данных агента, ни в MCP-транспорте, ни в памяти контракта, ни в реестре.

Последняя строка — это проекция ответа по умолчанию «запрещено»: resend-notify не объявляет response_fields, поэтому успешный вызов возвращает код состояния и пустой объект. Даже идентификатор сообщения вышестоящей системы скрыт.

Реестр после этого:

denied     0  resend/emails         markers=["profile.ssn", …]        'ssn' not allowed here
denied     0  resend/emails         markers=["secret.resend_api_key"] not a profile marker
denied     0  resend/domains        markers=[]                        path not enumerated
denied     0  stripe/emails         markers=[]                        unknown endpoint
ok       200  resend/emails         markers=["first_name","last_name","verified_contacts.email.value"]
denied     0  resend-notify/emails  markers=["profile.first_name", …] 'first_name' not allowed here
ok       200  resend-notify/emails  markers=[]

Записываются имена маркеров. Значения маркеров никогда не были доступны для записи.

Related MCP server: MCP Warden

Быстрый старт

npm install
cp .env.example .env          # add your T3N_API_KEY from terminal3.io/claim-page
npm run test                  # 9 native policy tests, no network, no credits
npm run build                 # Rust → wasm32-wasip2
npm run deploy                # idempotent — safe to re-run
npm run doctor                # pre-flight a deployment you didn't just create
npm run demo                  # the run shown above

Добавьте в любой MCP-клиент:

{ "mcpServers": {
    "agentgate": { "command": "npx", "args": ["tsx", "/path/to/agentgate/mcp/server.ts"] } } }

Добавление endpoint

Один файл. Никакого Rust, никакого повторного развёртывания контракта.

// agentgate.config.json
"endpoints": {
  "stripe": {
    "base": "https://api.stripe.com",
    "secret_key": "stripe_api_key",        // key in z:<tid>:secrets
    "auth_header": "Authorization",
    "auth_prefix": "Bearer ",
    "allowed_paths": ["/v1/customers"],    // exact match only
    "allowed_placeholders": ["first_name", "verified_contacts.email.value"],
    "response_fields": ["id"]              // everything else is dropped
  }
}

Затем npm run deploy. Он пропускает регистрацию контракта, если wasm не изменился, поэтому добавление endpoint стоит ~160 кредитов вместо ~1 850.

Почему дизайн устроен именно так

Три решения появились из измерений платформы, а не из чтения о ней:

  • Отказы возвращают Ok, а не Err. Записи контракта откатываются при ошибке, поэтому возврат Err при отказе политики откатил бы запись аудита, фиксирующую этот отказ — агент мог бы многократно нарушать политику и не оставлять следов.

  • Ответы проецируются, а не передаются напрямую. http-with-placeholders защищает только исходящий канал. Ответ вышестоящей системы возвращается в WASM полностью, поэтому endpoint, который эхо-возвращает запрос, отдаёт обратно PII, которую скрывали маркеры. Продемонстрировано в docs/BUGS.md.

  • Контракт не задаёт Content-Type. Хост добавляет свой собственный, а не заменяет ваш, что даёт application/json,application/json, и строгие вышестоящие системы отклоняют это — молча, с HTTP 200 и пустым телом. См. docs/BUGS.md#1.

Структура репозитория

Путь

Что это

contract/

TEE-контракт — policy.rs чистый и тестируется нативно, gateway.rs общается с хостом

mcp/server.ts

MCP-сервер — 3 инструмента

scripts/deploy.ts

идемпотентный деплой; владеет реестром contract_id

scripts/doctor.ts

предварительная проверка здоровья

scripts/demo.ts

запуск, показанный выше

agentgate.config.json

каждый endpoint и разрешение, декларативно (2 endpoint, контрастные политики)

deployments.json

зафиксированный реестр всех когда-либо выпущенных contract_id

docs/BUGS.md

13 находок по платформе

docs/ARCHITECTURE.md

почему граница анклава проходит именно там

docs/HANDOVER.md

инструкция для того, кто будет эксплуатировать это дальше

contract-probe/

одноразовая диагностика для картографирования поверхности плейсхолдеров — не поставляется

Статус

Собрано и проверено end-to-end против тестнета T3N с @terminal3/t3n-sdk@5.2.0, с полным потоком из трёх субъектов:

Субъект

Владеет

Роль в показанном выше запуске

Арендатор

eth-ключ, финансируется

владеет контрактом, запечатывает учётные данные, перечисляет политику

Владелец данных

собственный DID + профиль

предоставляет доступ агенту; маркеры разрешаются по его профилю

Агент

непрозрачный bearer-токен, ничего больше

выполняет все вызовы, показанные выше

Подписывающий ключ агента был создан внутри TEE и никогда его не покидал. Он не хранит ни API-ключей, ни URL, ни личных данных и не может обратиться к основному контракту, чтобы проверить собственные разрешения — тем не менее он доставляет персонализированное письмо в реальный почтовый ящик.

Чтобы это заработало, Terminal 3 пришлось вручную профинансировать DID агента: выпущенный агент начинает с нуля, и один вызов резервирует 10 000 токенов, без самостоятельного пополнения (docs/BUGS.md#10). Каждый разработчик столкнётся с этим на своём первом агенте.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to make authenticated API calls and run commands with secrets injected, while keeping credentials completely hidden from the model, with policy enforcement, grants, and audit logging.
    6
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to reach upstream MCP tool servers through a central policy gateway that authenticates each agent, enforces least-privilege and default-deny rules, and applies response obligations such as redaction, inference stripping, PII masking, and truncation. It also records every decision in a tamper-evident, hash-chained audit log that can be verified later.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to securely reach enterprise tools and other agents through a governed gateway with pinned tool definitions, delegated authorization, content inspection, human approval, and signed audit trails.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to call backend tools under per-agent policy, deciding which tools each agent can see, what arguments it may pass, how often it may call, and which writes wait for human approval. It also redacts secrets and PII from tool results, fences untrusted output against injection, and records every call in a hash-chained audit log.
    25 npm
    MIT