Skip to main content
Glama

f5xc-waap-mcp

Serveur MCP (Model Context Protocol) pour F5 Distributed Cloud WAAP. Il couvre les load balancers, le WAF, les policies, le bot defense, la sécurité des API, les security events et les logs. Il est sécurisé par conception :

  • lecture seule par défaut ;

  • les écritures passent par un plan (diff exhaustif calculé côté serveur), puis une confirmation humaine qui affiche ce diff complet et le hash du corps envoyé (MCP elicitation), puis l'application ;

  • aucune suppression, aucun remplacement générique et aucun outil de requête générique ;

  • l'identité est nominative : chaque token est résolu en utilisateur XC (whoami) avant tout appel.

Les endpoints viennent de la référence API officielle (data/catalog.json, généré par scripts/generate_catalog.py à partir des spécifications OpenAPI publiées sur docs.cloud.f5.com).

Sujets : n'activer que ce dont on a besoin

Les outils et les types d'objets sont regroupés par sujet. Chaque sujet s'active individuellement avec F5XC_MCP_TOPICS (défaut : all). Un outil dont le sujet est désactivé n'est pas enregistré : il n'existe pas pour le modèle, ce qui réduit la liste d'outils (donc les tokens) et la surface d'attaque.

Sujet

Outils

Types d'objets lisibles

core (toujours actif)

list_supported_kinds, list_namespaces, list_objects, get_object, plan_create_object

—

load_balancing

get_lb_dns_info, get_lb_performance, list_certificate_expiry

LB HTTP/TCP/CDN, origin pools, health checks, certificats, chaînes, CA, BIG-IP, IP publiques

waf

get_waf_signatures_version, get_waf_rule_hits, suggest_waf_exclusion_rule, plan_set_lb_waf, plan_set_waf_mode, plan_add_waf_exclusion_rule

App Firewall, WAF exclusion policies

policies

get_active_service_policies, plan_update_ip_prefix_set

service policies, rate limiters, IP prefix sets, forward proxy, policers

ddos

get_lb_dos_mitigation_rules

—

bot_and_users

—

bot defense, malicious users, app settings, app types

api_security

—

API definitions, groupes, discovery, sensitive data

network_security

—

network firewalls, Fast ACL

dns

—

zones, DNS LB, pools, health checks, geo sets

observability

list_alerts, query_alerts_history

alert policies, receivers, log receivers

events_logs

query_security_events, aggregate_security_events, query_security_incidents, query_suspicious_users, query_access_logs, aggregate_access_logs, query_audit_logs

—

posture

get_lb_security_posture, audit_namespace_security

—

F5XC_MCP_TOPICS=all                       # tout (défaut)
F5XC_MCP_TOPICS=waf,posture,events_logs   # seulement ceux-là (+ core)
F5XC_MCP_TOPICS=all,-dns,-bot_and_users   # tout sauf ceux-là
  • Un nom inconnu empêche le démarrage (la liste valide est affichée).

  • Les types d'objets d'un sujet désactivé sont refusés par list_objects, get_object et plan_create_object (topic_disabled) ; list_supported_kinds ne montre que les sujets actifs.

  • Un sujet n'accorde jamais l'écriture : les outils plan_* d'un sujet n'existent que si F5XC_MCP_MODE=write et F5XC_MCP_ENABLE_WRITES=true. apply_plan et plan_revert n'existent que si au moins un outil d'écriture existe.

  • Les outils de posture et d'audit lisent en interne les LB et les WAF même si load_balancing ou waf sont désactivés : ce sont des lectures internes de l'outil, pas des outils exposés.

Related MCP server: ewm-ops-mcp

Outils

Lecture (toujours disponibles)

Outil

Rôle

list_supported_kinds

Les 40 types d'objets couverts, par famille, avec le lien vers la doc

list_namespaces

Namespaces autorisés

list_objects(kind, namespace)

Liste d'un type d'objet (LB, origin pools, WAF, service policies, rate limiters, API definitions, zones DNS...)

get_object(kind, namespace, name, view)

summary (options configurées et références), spec (secrets masqués) ou referrers (qui utilise l'objet)

get_active_service_policies

Service policies actives au niveau du namespace

get_lb_security_posture

Protections actives d'un LB HTTP (WAF et son mode, bot, API discovery, IP reputation, rate limit, DDoS, TLS...) avec des constats classés par sévérité

audit_namespace_security

La même posture pour tous les LB HTTP d'un namespace

query_security_events / aggregate_security_events

Security events filtrés, top signatures / IP / pays / LB

query_security_incidents, query_suspicious_users

Incidents, utilisateurs suspects

query_access_logs / aggregate_access_logs

Access logs et agrégations (codes de réponse, chemins...)

query_audit_logs

Qui a modifié quoi dans le namespace

suggest_waf_exclusion_rule

Règle d'exclusion proposée par XC pour un faux positif

get_lb_dos_mitigation_rules, get_lb_dns_info, get_waf_signatures_version

DDoS auto-mitigation, infos DNS du LB, version des signatures

get_waf_rule_hits

Nombre de déclenchements par règle WAF (et par LB, sévérité, tag…), trié : les candidats faux positifs

get_lb_performance

Équivalent de Overview > Performance : débit, erreurs 4xx/5xx, latences, RTT et scores de santé par LB

list_alerts, query_alerts_history

Alertes actives et historique, pour contextualiser une analyse

list_certificate_expiry

Certificats TLS triés par expiration : CN, SAN, émetteur, jours restants, LB utilisateurs ; inclut les certificats automatiques des LB ; la clé privée n'est jamais lue

Écriture (seulement avec F5XC_MCP_MODE=write et F5XC_MCP_ENABLE_WRITES=true)

Outil

Rôle

plan_set_lb_waf

Attacher (ou retirer) un App Firewall sur un LB

plan_set_waf_mode

Passer un WAF en blocking ou en monitoring

plan_update_ip_prefix_set

Ajouter ou retirer des IP d'une liste (blocage, allowlist)

plan_add_waf_exclusion_rule

Ajouter une exclusion WAF (faux positif). Les règles qui désactivent tout le WAF sont refusées

plan_create_object

Créer un objet sans effet tant qu'il n'est pas référencé : App Firewall, service policy, ip_prefix_set, rate limiter, WAF exclusion policy, health check

apply_plan(plan_id)

Applique un plan après confirmation humaine

plan_revert(plan_id)

Prépare le retour à l'état d'avant un replace appliqué (si F5XC_MCP_ROLLBACK_DIR est défini) ; plan revu comme les autres, avec l'auteur d'origine ; HIGH RISK si ce n'est pas vous. Les secrets ne sont jamais écrits dans le fichier : ils sont repris de l'objet actuel

Ce que voit la personne qui confirme

Le message d'élicitation est construit par le serveur, pas par le modèle. Il contient :

  • un bandeau !!! HIGH RISK !!! avec les raisons quand le changement baisse la protection : WAF désactivé ou passé en monitoring, WAF attaché en monitoring, bot / IP reputation / rate limit désactivés, trusted clients modifiés, modification d'un ip_prefix_set (qui peut servir d'allowlist), création d'un objet déjà référencé (il devient actif immédiatement) ou dont la recherche de références est incomplète ;

  • pour les exclusions WAF, chaque règle nouvelle ou modifiée est évaluée. Elle n'est « standard » que si elle exclut des signatures précises sur un domaine et un chemin précis. Sinon elle est HIGH RISK : any_domain, any_path, domaine ou chemin absent, path_regex, exclusion de types d'attaque, de violations ou de bots, signature_id 0, ou waf_skip_processing ;

  • la cible, la requête (PUT /api/config/...) et le SHA-256 du corps envoyé ;

  • le diff complet, feuille par feuille. Les règles nommées sont appariées par nom et un changement d'ordre est signalé. Les valeurs sont échappées en JSON (caractères de contrôle ou invisibles visibles), jamais tronquées.

Pour confirmer, il faut retaper le nom de l'objet. En cas de HIGH RISK, il faut aussi retaper les 8 premiers caractères du hash.

Un diff qui ne peut pas être montré en entier est refusé au moment du plan : plus de 80 champs, une valeur de plus de 300 caractères ou plus de 8 000 caractères au total. Il faut alors découper le changement. Un changement qui touche un champ secret (clé privée, mot de passe, token...) est refusé.

Un plan est à usage unique, lié à l'utilisateur XC qui l'a créé, et expire après 5 minutes.

Il est refusé si l'objet a changé entre le plan et l'application. Le contrôle couvre la spec, les métadonnées réécrites par le PUT (labels, annotations, description, disable) et l'uid, ce qui détecte un objet supprimé puis recréé.

L'API XC publiée n'offre pas de précondition de version sur le PUT. Il reste donc une fenêtre courte entre la relecture de contrôle et le PUT ; voir le modèle de menaces.

Les namespaces system et shared ne sont jamais modifiés.

Installation

python -m venv .venv && . .venv/bin/activate
pip install --require-hashes -r requirements-dev.lock
pip install --require-hashes -r requirements-build.lock
pip install --no-deps --no-build-isolation .
pytest                                              # tests + propriétés Hypothesis
python -I scripts/mutate_guards.py . mutation.json  # chaque garde-fou doit être tué par les tests

Configuration

Variable

Défaut

Rôle

F5XC_TENANT

(obligatoire)

Identifiant court du tenant : https://<tenant>.console.ves.volterra.io

F5XC_ALLOWED_NAMESPACES

(obligatoire)

Liste séparée par des virgules ; tout autre namespace est refusé

F5XC_API_TOKEN

—

stdio uniquement : ton token API personnel. Interdit en mode HTTP

F5XC_MCP_TOPICS

all

Sujets activés : all, waf,posture, all,-dns (voir « Sujets »)

F5XC_MCP_MODE

read

read ou write

F5XC_MCP_ENABLE_WRITES

false

Doit aussi valoir true pour activer l'écriture

F5XC_MCP_TRANSPORT

stdio

stdio ou streamable-http

F5XC_MCP_BIND_HOST / _PORT

127.0.0.1 / 8765

Loopback par défaut (reverse proxy TLS devant)

F5XC_MCP_ALLOW_NON_LOOPBACK_BIND

false

Autorise un bind hors loopback (conteneur). Exige le mode HTTP et F5XC_MCP_ALLOWED_HOSTS

F5XC_MCP_ALLOWED_HOSTS / _ORIGINS

localhost

Valeurs Host et Origin acceptées (anti DNS rebinding)

F5XC_MCP_CA_BUNDLE

—

CA supplémentaire (proxy d'entreprise) ; la vérification TLS ne peut pas être désactivée

F5XC_MCP_HTTPS_PROXY

—

Proxy sortant vers XC (http(s)://hôte:port, sans identifiants). HTTPS_PROXY n'est pas lu

F5XC_MCP_WRITE_KILL_SWITCH

—

Chemin d'un fichier : tant qu'il existe, toute écriture est refusée, y compris un apply_plan déjà en cours de confirmation (sans redémarrage)

F5XC_MCP_ROLLBACK_DIR

—

Répertoire (0700) où l'état « avant » de chaque replace appliqué est gardé (0600) pour plan_revert

F5XC_MCP_RATE_PER_MINUTE / _GLOBAL_RATE_PER_MINUTE

60 / 300

Limites de débit

F5XC_MCP_MAX_EVENTS, _MAX_ITEMS, _MAX_QUERY_WINDOW_H

100, 200, 168

Bornes des réponses

F5XC_MCP_PLAN_TTL_S

300

Durée de vie d'un plan

F5XC_MCP_MIN_IPV4_PREFIX_LEN

16

Préfixe minimum accepté dans un ip_prefix_set (/0, /8... refusés)

F5XC_MCP_IDENTITY_CACHE_TTL_S

300

Cache de la résolution token → utilisateur

F5XC_MCP_AUTH_RATE_PER_MINUTE

30

Validations de tokens inconnus par minute (tous clients confondus)

F5XC_MCP_ALLOW_SERVICE_CREDENTIALS

false

Accepte les service credentials (comptes non nominatifs)

F5XC_MCP_AUDIT_LOG

stderr

Fichier du journal d'audit JSON (créé en 0600, compatible logrotate)

Premier test sur un tenant : f5xc-waap-mcp check

À lancer avant toute mise en service, avec le token personnel d'un utilisateur qui a le rôle prévu pour le serveur :

F5XC_TENANT=acme-corp F5XC_ALLOWED_NAMESPACES=prod,staging F5XC_API_TOKEN=... f5xc-waap-mcp check

La commande appelle whoami et indique quels champs sont remplis (name, email, user_uuid, type) et l'identité retenue. Puis, pour chaque namespace autorisé, elle indique si le rôle peut lister les LB HTTP et lire les service policies actives. Elle n'écrit rien et n'affiche jamais le token. Code de sortie 1 si l'identité ne peut pas être résolue : dans ce cas, le serveur refusera tous les appels.

Objets partagés (namespace shared)

Si les App Firewalls, IP prefix sets ou service policies sont dans shared, ajoutez shared à F5XC_ALLOWED_NAMESPACES pour pouvoir les lire. Sinon, la posture d'un LB affiche « unknown (namespace 'shared' not allow-listed) » pour son WAF. L'écriture dans shared (comme dans system) reste refusée en dur, quelle que soit la configuration.

Token, identité et droits

Crée un token API personnel dans la console XC (Account > Credentials). Le serveur le résout en utilisateur avec GET /api/web/custom/namespaces/system/whoami avant tout autre appel :

  • l'audit et les quotas utilisent le nom, l'e-mail et l'UUID XC, pas le token ;

  • une rotation de token ne change donc pas l'identité ;

  • un token refusé par XC (401) est mis en cache négatif 60 s et ne consomme aucun quota. Un 403 sur whoami (rôle qui ne peut pas lire le namespace system) donne l'erreur identity_unavailable, sans cache négatif : une correction du rôle s'applique tout de suite ;

  • les validations de tokens inconnus sont limitées globalement ;

  • les service credentials sont refusées par défaut.

Les droits du serveur sont ceux de ton rôle XC : commence avec un rôle en lecture sur les namespaces concernés, et ne passe à un rôle d'écriture que pour le mode write. Le journal d'audit XC (query_audit_logs) reste le contrôle compensatoire, côté F5.

Claude Code (stdio)

.mcp.json. Le token est lu depuis ton environnement, jamais écrit dans le fichier :

{
  "mcpServers": {
    "f5xc-waap": {
      "command": "f5xc-waap-mcp",
      "env": {
        "F5XC_TENANT": "acme-corp",
        "F5XC_ALLOWED_NAMESPACES": "prod,staging",
        "F5XC_API_TOKEN": "${F5XC_API_TOKEN}"
      }
    }
  }
}

Mode HTTP (multi-utilisateur)

F5XC_TENANT=acme-corp F5XC_ALLOWED_NAMESPACES=prod F5XC_MCP_TRANSPORT=streamable-http \
F5XC_MCP_ALLOWED_HOSTS=mcp.example.com F5XC_MCP_ALLOWED_ORIGINS=https://mcp.example.com \
f5xc-waap-mcp

Chaque client envoie son propre token dans l'en-tête X-F5XC-API-Token. Le serveur n'a pas de token à lui. Termine le TLS sur un reverse proxy devant 127.0.0.1:8765, et limite le débit par IP sur ce proxy : le serveur limite les validations de tokens inconnus, mais il ne voit que l'IP du proxy.

Conteneur

L'image est construite à partir d'une base Debian 13 (trixie) épinglée par digest. Les dépendances sont vérifiées par hash, elle tourne en utilisateur non-root (UID 65532), sans outil de build ni pip. La CI la scanne avec Trivy et échoue sur toute vulnérabilité HIGH/CRITICAL corrigeable.

docker build -t f5xc-waap-mcp .

Deux façons de l'exposer :

  • proxy dans le même namespace réseau (sidecar dans un pod, ou --network container:<proxy>) : le serveur reste en 127.0.0.1, sans configuration de plus ;

  • bind explicite, quand le proxy est ailleurs :

docker run --read-only --cap-drop=ALL --security-opt no-new-privileges \
  -p 127.0.0.1:8765:8765 \
  -e F5XC_TENANT=acme-corp -e F5XC_ALLOWED_NAMESPACES=prod \
  -e F5XC_MCP_BIND_HOST=0.0.0.0 -e F5XC_MCP_ALLOW_NON_LOOPBACK_BIND=true \
  -e F5XC_MCP_ALLOWED_HOSTS=mcp.example.com \
  f5xc-waap-mcp

Journal d'audit et Splunk

Événements tool_call, plan_created, plan_confirmation et plan_applied, reliés par plan_id et request_id, avec l'utilisateur XC nominatif. Pour Splunk :

  • sur un hôte, F5XC_MCP_AUDIT_LOG=/var/log/f5xc-waap-mcp/audit.jsonl et un Universal Forwarder ([monitor:///var/log/f5xc-waap-mcp/audit.jsonl], sourcetype = _json). Le fichier est créé en 0600 et rouvert après une rotation logrotate ;

  • en conteneur, garder stderr et utiliser le logging driver splunk (ou le collecteur de logs du cluster).

Dépendances et chaîne d'approvisionnement

  • Verrous : requirements*.lock épinglent chaque paquet, transitifs compris, avec leurs hashes. Ils sont régénérés par scripts/lock.sh avec un délai de 14 jours sur les nouvelles versions ; les exceptions de sécurité sont listées dans le script.

  • CI : actions épinglées par SHA, installations --require-hashes, ruff, bandit, pip-audit sur les trois verrous (et une fois par semaine), SBOM CycloneDX en artefact, construction et test de l'image (non-root, système de fichiers en lecture seule).

Mettre à jour le catalogue

python scripts/generate_catalog.py

Le script échoue si un chemin utilisé n'existe plus dans la documentation.

Seules les variables F5XC_* comptent

Le serveur ne lit que les variables préfixées F5XC_ (et F5XC_MCP_). Des variables génériques comme MODE, API_TOKEN ou HTTPS_PROXY n'ont aucun effet ; un test et une règle Semgrep l'imposent (audit F-15).

Preuves de sécurité

Réponse à l'audit, preuves et commandes de rejeu : docs/AUDIT_RESPONSE.md.

Outil

Ce qu'il prouve

Propriétés Hypothesis (tests/test_diff_reconstruction.py, tests/test_audit_properties.py)

Le diff se rejoue exactement ; aucune ligne forgeable ; aucun caractère invisible ne passe

scripts/mutate_guards.py

Chaque garde-fou retiré fait échouer au moins un test

fuzz/fuzz_parsers.py (atheris)

Requêtes de logs, chemins, sanitisation et diff tiennent leurs invariants sur entrées arbitraires

.semgrep/rules.yml

Pas de fuite de token vers log/erreur/réponse ; pas de chemin XC hors catalogue ; fullmatch imposé

scripts/openapi_facts.py

Faits tirés de la spec OpenAPI brute (pas de précondition de version, champs d'exclusion WAF, whoami)

Licence

MIT, voir LICENSE. Le fichier embarqué src/f5xc_waap_mcp/data/public_suffix_list.dat est la Public Suffix List, sous licence MPL-2.0 (en-tête conservé), rafraîchie par scripts/update_psl.py.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables read-only inspection of Google Ads accounts through MCP, including account inventory, reporting, metadata, change history, and safe GAQL queries.
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables warehouse operations agents to inspect tasks, deliveries, stock, and KPIs, and to attempt write operations in shadow mode with human approval and segregation of duties enforced as code.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables read-only querying of Twilio Segment workspaces to audit which destinations receive which events, trace event routing and governance, identify stale or ungoverned sources, and check destination delivery health, with permanent safeguards against data deletion.
    24 PyPI
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables investigation of devices, model breaches and analyst incidents from an MCP host through a bounded set of read-only tools, with operator-controlled profiles and a fixed operation inventory. Writes, PCAP export, email and HTTP transport are excluded, and responses are minimized and escaped before entering model context.
    17 npm
    2
    Apache 2.0