Skip to main content
Glama
bhargavlukka

SecureAgentServer

by bhargavlukka

Безопасная система агентов MCP

Сервер и клиент MCP для тикетов поддержки и клиентских аккаунтов, созданные и защищённые сквозным образом: аутентификация по подписанным токенам, два независимых рубежа защиты от prompt-инъекций и подмены инструментов, документированная модель угроз и обязательный контроль человеком для единственного разрушительного вызова инструмента. Разработано для лабораторной работы «Secure an MCP-Based Agent System».

Архитектура

flowchart TD
    HOST["Host application"] --> CLIENT["client.py\n(fastmcp.Client + elicitation_handler)"]
    CLIENT <-->|"Streamable HTTP\nAuthorization: Bearer <signed JWT>"| SERVER

    subgraph Server["server.py — FastMCP('SecureAgentServer')"]
        AUTH["JWTVerifier (HS256)\nissuer + audience + signature checked"]
        G1["Guardrail 1: sanitize_untrusted_text()\napplied to ticket body/subject"]
        G2["Guardrail 2: verify_tool_manifest()\nchecked at startup, refuses to start on mismatch"]
        TOOLS["Tools: search_tickets, lookup_customer_account,\nclose_ticket (elicitation-gated)"]
        AUTH --> TOOLS
        TOOLS --> G1
    end
    G2 -.->|startup check| SERVER

    TOOLS --> TICKETS[("data/tickets.json\n(untrusted customer text)")]
    TOOLS --> CUSTOMERS[("data/customers.json\n('internal API')")]

Related MCP server: enterprise-agent-lab

Настройка

pip install -r requirements.txt

# 1. Set the JWT signing secret (never commit the real value; see .env.example)
export MCP_JWT_SECRET="a-long-random-secret-at-least-32-characters"

# 2. Generate the pinned tool-integrity manifest (a deliberate, manual step —
#    see docs/threat-model.md Risk #2)
python generate_manifest.py

# 3. Run the server
python server.py

# 4. In another terminal (same MCP_JWT_SECRET exported)
python client.py --auto-confirm   # non-interactive demo
python client.py                  # interactive: real yes/no confirmation prompts

Воспроизведение мер безопасности

Мера безопасности

Как её проверить

Аутентификация на основе подписанных JWT

Два последних демонстрационных примера в client.py: токен с областью только на чтение отклоняется в close_ticket, а подделанный / неподписанный токен отклоняется с кодом 401 ещё до запуска любых инструментов — оба случая зафиксированы в demo/session_log.txt

Рубеж 1: санитизация prompt-инъекций

Запустите клиент и посмотрите результат search_tickets для TICKET-2002 (в его содержимом внедрена фраза-триггер «IGNORE ALL PREVIOUS INSTRUCTIONS...») — возвращаемый текст обёрнут, а триггерная фраза отредактирована. На stdout сервера при срабатывании появляется строка [SECURITY].

Рубеж 2: обнаружение подмены инструментов

python demo/verify_tampering_detection.py — изменяет описание close_ticket в памяти и показывает, что verify_tool_manifest() обнаруживает расхождение; результаты запуска см. в demo/tampering_detection_log.txt

Обязательный контроль человека над разрушительными действиями

в демонстрационном журнале close_ticket завершается только после [ELICITATION] ... -> accepting; запустите client.py без --auto-confirm, чтобы увидеть реальное интерактивное окно подтверждения

Разграничение по принципу наименьших привилегий

add_ticket_note / close_ticket явно проверяют область write:tickets через get_access_token() (server.py::_require_scope), а не только требование на уровне подключения — это демонстрируется отклонением токена с областью только на чтение выше

Модель угроз

Полное описание, включающее 5 выявленных рисков с мерами смягчения и явно указанными замечаниями об остаточных рисках, а не замолчаянных: docs/threat-model.md.

Что намеренно вынесено за рамки, сказано прямо

  • mint_token.py заменяет реального провайдера удостоверений OAuth 2.1 — в продакшене нужно настоящее выпуск/перевыпуск/отзыв токенов, а не локальный скрипт.

  • Нет ограничения скорости или усиления на сетевом уровне (завершение TLS, WAF) — это демонстрация безопасности на прикладном уровне, а не полное руководство по защите развёртывания.

  • Основанная на regex-часть рубежа 1 явно вспомогательная, работающая по принципу best-effort — см. риск № 1 в docs/threat-model.md о том, почему именно обёртка разделителем является основной действующей мерой.

Без секретов в репозитории

MCP_JWT_SECRET считывается из окружения (см. .env.example) и никогда не захардкожен и не коммитится. tool_manifest.json намеренно находится в коммите — это зафиксированный хэш-манифест (вроде lockfile), а не секрет.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables 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
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enforces authenticated identity on every tool call and SSE frame, rotates vaulted credentials in place, and restricts tools via allowlists.
    71 npm
    MIT