Skip to main content
Glama
bhargavlukka

SecureAgentServer

by bhargavlukka

Sicheres MCP-basiertes Agent-System

Ein MCP-Server und -Client für Support-Tickets und Kundenkonten, durchgängig entwickelt und abgesichert: signierte Token-Authentifizierung, zwei unabhängige Schutzmechanismen gegen Prompt Injection und Tool Poisoning, ein dokumentiertes Bedrohungsmodell sowie eine Human-in-the-Loop-Sperre für den einzigen destruktiven Tool-Aufruf. Entwickelt für das Lab „Secure an MCP-Based Agent System“.

Architektur

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

Einrichtung

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

Nachvollziehen der Sicherheitsmaßnahmen

Sicherheitsmaßnahme

So verifizieren Sie sie

Signierte-JWT-Authentifizierung

Die letzten beiden Demos von client.py: Ein Nur-Lese-Token wird beim Aufruf von close_ticket abgelehnt, und ein gefälschtes/unsigniertes Token wird mit 401 abgelehnt, bevor überhaupt ein Tool ausgeführt wird – beides festgehalten in demo/session_log.txt.

Schutzmechanismus 1: Prompt-Injection-Bereinigung

Führen Sie den Client aus und prüfen Sie die search_tickets-Ausgabe für TICKET-2002 (deren Inhalt einen eingeschleusten „IGNORE ALL PREVIOUS INSTRUCTIONS...“-Payload enthält) – der zurückgegebene Text wird umschlossen und die Auslösephrase geschwärzt. Der Server protokolliert bei diesem Ereignis in seiner eigenen stdout-Erzeugung eine [SECURITY]-Zeile.

Schutzmechanismus 2: Tool-Poisoning-Erkennung

python demo/verify_tampering_detection.py – verändert die Beschreibung von close_ticket im Speicher und zeigt, wie verify_tool_manifest() die Abweichung erkannt; einen dokumentierten Lauf finden Sie in demo/tampering_detection_log.txt.

Human-in-the-Loop bei destruktiven Aktionen

close_ticket wird im Demo-Log erst nach [ELICITATION] ... -> accepting abgeschlossen; führen Sie client.py ohne --auto-confirm aus, um eine echte interaktive Bestätigungsaufforderung zu sehen.

Least-Privilege-Scoping

add_ticket_note/close_ticket prüfen explizit write:tickets über get_access_token() (server.py::_require_scope), nicht nur eine Anforderung auf Verbindungsebene – demonstriert durch die obige Ablehnung des Nur-Lese-Tokens.

Bedrohungsmodell

Vollständige Ausarbeitung einschließlich 5 identifizierter Risiken mit Gegenmaßnahmen und Restrisiko-Hinweisen, die explizit benannt statt beschönigt werden: docs/threat-model.md.

Was bewusst außerhalb des Umfangs liegt, klar benannt

  • mint_token.py steht stellvertretend für einen echten OAuth-2.1-Identitätsanbieter – eine Produktionsbereitstellung benötigt echte Token-Ausstellung, -Rotation und -Widerruf, kein lokales Skript zum Prägen von Token.

  • Kein Rate-Limiting oder Härtung auf Netzwerkebene (TLS-Terminierung, WAF) – dies ist eine Sicherheitsdemo auf Anwendungsebene und kein vollständiger Leitfaden zur Härtung von Bereitstellungen.

  • Die regex-basierte Hälfte von Schutzmechanismus 1 ist ausdrücklich eine sekundäre, Best-Effort-Ebene – siehe Risiko Nr. 1 in docs/threat-model.md, warum das Umschließen mit Begrenzern (delimiter-wrapping) die Maßnahme ist, auf die sich tatsächlich verlassen wird.

Keine Geheimnisse im Repository

MCP_JWT_SECRET wird aus der Umgebung gelesen (siehe .env.example) und ist nie hartkodiert oder eingecheckt. tool_manifest.json ist bewusst eingecheckt – es ist ein festgeschriebenes Hash-Manifest (wie eine Lockfile), kein Geheimnis.

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