Metadata-Version: 2.4
Name: fortigate-mcp
Version: 0.2.0
Summary: Local read-only MCP server for Fortigate administration over SSH
Author: Alberto Diaz
License-Expression: MIT
Project-URL: Homepage, https://github.com/Picaresco/MCP-Fortigate
Project-URL: Issues, https://github.com/Picaresco/MCP-Fortigate/issues
Keywords: mcp,fortigate,fortinet,ssh,readonly,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.6.0
Requires-Dist: paramiko>=3.4.0
Requires-Dist: pydantic>=2.7.0
Dynamic: license-file

![Fortigate MCP banner](assets/banner.png)

# Fortigate MCP

Servidor MCP local para consultar Fortigate por SSH en modo solo lectura.

Pensado para FortiOS 7.4+ y para usarse desde Codex y Claude Desktop mediante transporte `stdio`.

Tambien puede usarse desde cualquier cliente compatible con MCP local por `stdio`, como Cursor, VS Code con GitHub Copilot, Visual Studio con GitHub Copilot Agent Mode, Claude Code y otros clientes MCP.

## Seguridad

Este MCP no ejecuta comandos libres. Todas las herramientas son read-only y el comando manual `fortigate_run_readonly_command` valida una allowlist estricta.

Bloquea tokens como `config`, `edit`, `set`, `unset`, `delete`, `purge`, `reboot`, `shutdown`, `restore`, `factoryreset`, `format` y `debug`.

El token `execute` tambien esta bloqueado por defecto, salvo una excepcion estricta para comandos de lectura de logs (`execute log filter ...` y `execute log display`). Aun asi, un perfil read-only del propio Fortigate puede rechazar esos comandos; en ese caso la herramienta de resumen de ataques indicara que los logs no son accesibles.

Las busquedas de logs estan limitadas a filtros acotados y a un maximo de 500 lineas para reducir impacto. No se permiten acciones de borrado, backup, flush o cambios de configuracion.

La captura de paquetes (`fortigate_sniff_packets`) requiere filtro obligatorio, limita la captura a 20 paquetes y no activa `debug flow`.

La seguridad real debe reforzarse tambien en el Fortigate usando un usuario con perfil de solo lectura.

## Instalacion

Uso recomendado para clientes MCP:

```powershell
uvx fortigate-mcp@latest
```

`uvx` ejecuta el servidor en un entorno aislado gestionado por uv y permite usar la ultima version publicada sin crear una venv manual.

Para fijar una version concreta en entornos donde quieras reproducibilidad:

```powershell
uvx fortigate-mcp@0.2.0
```

Instalacion local para desarrollo desde el repositorio:

```powershell
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
Copy-Item fortigate.config.example.json fortigate.config.json
```

Tambien se puede instalar de forma persistente con pip:

```powershell
python -m pip install --upgrade fortigate-mcp
```

Edita `fortigate.config.json`:

```json
{
  "fortigate": {
    "host": "192.168.1.1",
    "port": 22,
    "username": "admin",
    "password": "change-me",
    "timeout": 15,
    "banner_timeout": 15,
    "auth_timeout": 15,
    "look_for_keys": false,
    "allow_agent": false,
    "disabled_algorithms": {}
  }
}
```

`fortigate.config.json` esta ignorado por Git.

## Herramientas MCP

- `fortigate_list_allowed_commands`
- `fortigate_get_system_status`
- `fortigate_get_interfaces`
- `fortigate_get_routes`
- `fortigate_lookup_route_for_ip`
- `fortigate_get_policy_routes`
- `fortigate_get_firewall_policies`
- `fortigate_get_local_in_policy`
- `fortigate_get_ipsec_vpns`
- `fortigate_get_ssl_vpn_users`
- `fortigate_get_ssl_vpn_lan_connections`
- `fortigate_trace_session`
- `fortigate_search_logs`
- `fortigate_search_traffic_logs`
- `fortigate_sniff_packets`
- `fortigate_get_recent_errors`
- `fortigate_get_auth_attack_summary`
- `fortigate_run_audit_readonly`
- `fortigate_get_public_exposure`
- `fortigate_get_nat_overview`
- `fortigate_get_proxy_policy_overview`
- `fortigate_find_policy_by_ip`
- `fortigate_find_policy_for_flow`
- `fortigate_explain_flow`
- `fortigate_get_policy_risk_summary`
- `fortigate_get_security_profiles_overview`
- `fortigate_get_traffic_controls`
- `fortigate_get_admin_access_surface`
- `fortigate_get_interface_health`
- `fortigate_get_vpn_overview`
- `fortigate_get_vpn_error_summary`
- `fortigate_get_sdwan_status`
- `fortigate_get_dynamic_routing_status`
- `fortigate_get_external_attack_surface`
- `fortigate_export_readonly_snapshot`
- `fortigate_compare_snapshots`
- `fortigate_run_readonly_command`

## Ejemplos de uso

Los siguientes ejemplos son ficticios y solo muestran el tipo de preguntas que puedes hacer desde un agente compatible con MCP.

### Diagnostico general

**Peticion**

```text
Hazme un diagnostico basico del Fortigate.
```

**Respuesta de ejemplo**

```text
Fortigate FG-80F / FortiOS 7.4.x

Estado general:
- Uptime: 128 dias
- CPU: 4%
- Memoria: 58%
- Sesiones activas: 8.421
- Modo: NAT

Observaciones:
- Rendimiento estable.
- No se observan interfaces fisicas con errores relevantes.
- Hay 2 tuneles IPsec caidos que conviene revisar.
```

### Tuneles IPsec

**Peticion**

```text
Listame las conexiones IPsec con entidades externas y dime cuales estan caidas.
```

**Respuesta de ejemplo**

```text
Tuneles IPsec:

| Nombre              | Peer publico    | Estado | Observacion                  |
|---------------------|-----------------|--------|------------------------------|
| vpn-acme-main       | 203.0.113.10    | UP     | Trafico reciente             |
| vpn-partner-backup  | 198.51.100.25   | DOWN   | Sin fase 2 activa            |
| vpn-datacenter      | 203.0.113.80    | UP     | Estable                      |

Resumen: 2 tuneles activos, 1 tunel caido.
```

### Usuarios SSL-VPN

**Peticion**

```text
Que usuarios estan conectados ahora por VPN y a que equipos internos acceden?
```

**Respuesta de ejemplo**

```text
Usuarios SSL-VPN conectados:

| Usuario       | IP VPN        | Origen publico | Destinos LAN observados       |
|---------------|---------------|----------------|-------------------------------|
| ana.garcia    | 10.212.10.14  | 198.51.100.44  | 10.10.20.15:3389              |
| soporte.n1    | 10.212.10.18  | 203.0.113.52   | 10.10.30.20:443, 10.10.30.5:22 |

Nota: la vista se basa en sesiones activas observadas en el Fortigate.
```

### Exposicion publica

**Peticion**

```text
Muestrame que servicios internos estan publicados hacia Internet.
```

**Respuesta de ejemplo**

```text
Exposicion publica detectada:

| VIP              | IP publica     | Destino interno | Servicio |
|------------------|----------------|-----------------|----------|
| vip-portal       | 203.0.113.120  | 10.10.40.10     | HTTPS    |
| vip-rdp-soporte  | 203.0.113.121  | 10.10.50.25     | RDP      |

Recomendacion:
- Revisar si RDP debe seguir expuesto publicamente.
- Aplicar restricciones por origen si el servicio es necesario.
```

### Ataques de usuario y contrasena

**Peticion**

```text
Tenemos ataques de usuario y contrasena contra el Fortigate?
```

**Respuesta de ejemplo**

```text
Resumen de autenticacion reciente:

- SSL-VPN: 37 fallos de login en la ultima hora.
- Administracion HTTPS/SSH: sin fallos relevantes.
- IPs con mas intentos:
  - 198.51.100.200: 22 intentos
  - 203.0.113.77: 9 intentos

Posible fuerza bruta contra SSL-VPN.
```

### Busqueda de logs

**Peticion**

```text
Busca eventos recientes de VPN con status failure.
```

**Respuesta de ejemplo**

```text
Log Search

- Category: event
- Filter: status=failure
- Events parsed: 14

| Date       | Time     | Type  | Subtype | Action | Src          | Status  | Description |
|------------|----------|-------|---------|--------|--------------|---------|-------------|
| 2026-05-01 | 11:42:10 | event | vpn     | tunnel | 203.0.113.10 | failure | IPsec phase 1 negotiation failed |
```

### Seguimiento de sesiones

**Peticion**

```text
Mira si hay sesiones desde 10.212.10.14 hacia 10.10.20.15 por RDP.
```

**Respuesta de ejemplo**

```text
Session Trace

- Filters: {"src_ip": "10.212.10.14", "dst_ip": "10.10.20.15", "dst_port": 3389, "protocol": 6}
- Sessions found: 2
- Policy IDs: 42

Evidence:
- session info: proto=6 ...
- 10.212.10.14:55122->10.10.20.15:3389 ...
- policy_id=42 ...
```

### Logs de trafico

**Peticion**

```text
Busca logs de trafico recientes hacia 79.148.246.79.
```

**Respuesta de ejemplo**

```text
Log Search

- Category: traffic
- Filter: dstip=79.148.246.79
- Events parsed: 5

| Date       | Time     | Action | Src        | Dst          | Description       |
|------------|----------|--------|------------|--------------|-------------------|
| 2026-05-01 | 21:47:09 | close  | 10.0.0.106 | 79.148.246.79|                   |
```

### Captura acotada

**Peticion**

```text
Haz una captura de 5 paquetes para host 10.0.0.57 y puerto 22.
```

**Respuesta de ejemplo**

```text
Fortigate Command Result

- Command: diagnose sniffer packet any 'host 10.0.0.57 and port 22' 4 5 a

2026-05-01 19:47:30 ssl.root in 10.212.134.100.22467 -> 10.0.0.57.22
```

### Lookup de ruta

**Peticion**

```text
Por donde saldria el Fortigate para llegar a 10.20.30.40?
```

**Respuesta de ejemplo**

```text
Route Lookup

| Network       | Interface | Gateway     | Code | Distance | Metric |
|---------------|-----------|-------------|------|----------|--------|
| 10.20.30.0/24 | ipsec-acme| -           | S    | 10       | 0      |
```

### Policy routes y NAT

**Peticion**

```text
Revisa si hay policy routes o NAT que puedan afectar al trafico.
```

**Respuesta de ejemplo**

```text
Policy routes:
- config router policy / end

NAT Overview:
- VIP objects: 73
- NAT policies: 67
- Central SNAT: sin entradas
```

### Proxy, UTM y controles de trafico

**Peticion**

```text
Comprueba si proxy, perfiles de seguridad, DoS o shapers pueden afectar al trafico.
```

**Respuesta de ejemplo**

```text
Proxy Policy Overview:
- proxy-policy ZTNA_ALLOW
- access-proxy RDP

Security Profiles Overview:
- Politicas con AV/IPS/WebFilter/AppCtrl/SSL inspection

Traffic Controls:
- DoS-policy
- traffic-shaper
- per-ip-shaper
```

### Errores recientes

**Peticion**

```text
Dime que errores recientes ves en el Fortigate.
```

**Respuesta de ejemplo**

```text
Recent Errors

- Events scanned: 50
- Error-like events: 10

| Date       | Time     | Subtype | Level   | Status          | Src/Peer    | Message             |
|------------|----------|---------|---------|-----------------|-------------|---------------------|
| 2026-05-01 | 21:34:07 | vpn     | error   | negotiate_error | 80.58.157.1 | IPsec phase 1 error |
| 2026-05-01 | 21:34:02 | endpoint| warning |                 |             | EMS certificate error |
```

### Politica candidata para un flujo

**Peticion**

```text
Que politicas podrian permitir 10.212.10.14 hacia 10.0.0.57 por SSH?
```

**Respuesta de ejemplo**

```text
Policy Lookup For Flow

- Flow: 10.212.10.14 -> 10.0.0.57 protocol 6 dst_port 22
- Best route interface: internal
- Candidate policies: 2

| ID | Name      | Src Intf | Dst Intf | Src Match          | Dst Match   | Service |
|----|-----------|----------|----------|--------------------|-------------|---------|
| 2  | VPN->LAN  | ssl.root | internal | SSLVPN_TUNNEL_ADDR | 10.0.0.0/24 | ALL     |
```

### Explicacion completa de un flujo

**Peticion**

```text
Explica el flujo 10.212.134.100 hacia 10.0.0.57 por TCP/22.
```

**Respuesta de ejemplo**

```text
Flow Explanation

- Destination route: 10.0.0.0/24 via internal
- Candidate policies: 2
- Active sessions: 1
- Traffic log matches: 0

Candidate Policies:
- policy 63 VPN-NUNSYS --> LAN
- policy 2 VPN --> LAN

Active Session Evidence:
- policy_id=2
- 10.212.134.100:32889 -> 10.0.0.57:22
```

### Superficie administrativa

**Peticion**

```text
Audita como se administra el Fortigate y si hay accesos peligrosos.
```

**Respuesta de ejemplo**

```text
Admin Access Surface

| Interface | IP             | Allowaccess | WAN-like | Risky |
|-----------|----------------|-------------|----------|-------|
| wan1      | 192.0.2.10/24  | ping, fgfm  | yes      | -     |

| Admin  | Profile     | No Trusthost | 2FA |
|--------|-------------|--------------|-----|
| claude | SoloLectura | yes          | -   |
```

### Superficie externa

**Peticion**

```text
Resume todo lo expuesto hacia fuera en el Fortigate.
```

**Respuesta de ejemplo**

```text
External Attack Surface

- WAN-like interfaces con allowaccess
- VIPs/DNAT publicados y politicas asociadas
- SSL-VPN: puerto, interfaces, origenes y pools
- IPsec peers y remote gateways
- Proxy/ZTNA publicado
- Local-in policy
```

### Riesgo de politicas

**Peticion**

```text
Resume las politicas amplias o con logging mejorable.
```

**Respuesta de ejemplo**

```text
Policy Risk Summary

- Policies parsed: 143
- Policies with findings: 126

| ID | Name      | Src Addr | Dst Addr | Service | Issues                         |
|----|-----------|----------|----------|---------|--------------------------------|
| 4  | LAN->WAN  | all      | all      | ALL     | srcaddr all; dstaddr all; service ALL |
```

### SD-WAN

**Peticion**

```text
Revisa el estado de SD-WAN y sus SLA.
```

**Respuesta de ejemplo**

```text
SD-WAN Status

- Health-checks: alive/dead, packet-loss, latency, jitter y SLA map.
- Services: miembros seleccionados por regla SD-WAN.
- Configuracion: miembros, gateways, health-checks y servicios.
```

### Comparacion de snapshots

**Peticion**

```text
Compara el snapshot inicial con el ultimo y dime que ha cambiado.
```

**Respuesta de ejemplo**

```text
Snapshot Comparison

- Changed sections: 4

| Section              | Added | Removed |
|----------------------|-------|---------|
| ipsec_tunnel_summary | 3     | 3       |
| ssl_vpn_monitor      | 2     | 6       |
```

### Auditoria read-only

**Peticion**

```text
Haz una auditoria de seguridad del Fortigate y prioriza los hallazgos.
```

**Respuesta de ejemplo**

```text
Hallazgos prioritarios:

1. Firmware pendiente de revision
   - Version observada: FortiOS 7.4.x
   - Accion: comparar con el ultimo release recomendado por Fortinet.

2. Servicios publicados hacia Internet
   - Detectados VIPs con HTTPS y RDP.
   - Accion: validar necesidad, origenes permitidos y logging.

3. Tuneles VPN caidos
   - 1 tunel IPsec sin fase 2 activa.
   - Accion: revisar propuestas y conectividad con el peer.

4. SSL-VPN
   - Usuarios conectados y sesiones LAN activas.
   - Accion: revisar MFA, grupos permitidos y politicas asociadas.
```

## Configuracion para Claude Desktop

Anade este servidor en el JSON de Claude Desktop:

```json
{
  "mcpServers": {
    "fortigate": {
      "command": "uvx",
      "args": [
        "fortigate-mcp@latest"
      ],
      "env": {
        "FORTIGATE_MCP_CONFIG": "C:\\ruta\\segura\\fortigate.config.json"
      }
    }
  }
}
```

Si prefieres ejecutar el `server.py` del repo para desarrollo, usa la venv local:

```json
{
  "mcpServers": {
    "fortigate": {
      "command": "C:\\ruta\\al\\proyecto\\.venv\\Scripts\\python.exe",
      "args": [
        "C:\\ruta\\al\\proyecto\\server.py"
      ],
      "env": {
        "FORTIGATE_MCP_CONFIG": "C:\\ruta\\segura\\fortigate.config.json"
      }
    }
  }
}
```

## Configuracion para Codex

Anade este bloque a `%USERPROFILE%\.codex\config.toml`:

```toml
[mcp_servers.fortigate]
command = 'uvx'
args = ['fortigate-mcp@latest']

[mcp_servers.fortigate.env]
FORTIGATE_MCP_CONFIG = 'C:\ruta\segura\fortigate.config.json'
```

## Configuracion para Cursor

Cursor puede cargar servidores MCP desde `.cursor/mcp.json` en el proyecto o desde la configuracion global del usuario.

```json
{
  "mcpServers": {
    "fortigate": {
      "command": "uvx",
      "args": [
        "fortigate-mcp@latest"
      ],
      "env": {
        "FORTIGATE_MCP_CONFIG": "C:\\ruta\\segura\\fortigate.config.json"
      }
    }
  }
}
```

## Configuracion para VS Code

VS Code usa `mcp.json`. Puedes configurarlo a nivel de workspace en `.vscode/mcp.json` o desde la configuracion de usuario.

```json
{
  "servers": {
    "fortigate": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "fortigate-mcp@latest"
      ],
      "env": {
        "FORTIGATE_MCP_CONFIG": "C:\\ruta\\segura\\fortigate.config.json"
      }
    }
  }
}
```

## Configuracion para Visual Studio

Visual Studio 2022 17.14+ y Visual Studio 2026 pueden detectar configuraciones MCP en `%USERPROFILE%\\.mcp.json`, en `<SOLUTIONDIR>\\.mcp.json`, en `.vscode/mcp.json` o en `.cursor/mcp.json`.

Ejemplo de `%USERPROFILE%\\.mcp.json`:

```json
{
  "servers": {
    "fortigate": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "fortigate-mcp@latest"
      ],
      "env": {
        "FORTIGATE_MCP_CONFIG": "C:\\ruta\\segura\\fortigate.config.json"
      }
    }
  }
}
```

## Prueba rapida

Validar sintaxis:

```powershell
.\.venv\Scripts\python.exe -m py_compile server.py
```

Verificar con MCP Inspector:

```powershell
npx @modelcontextprotocol/inspector uvx fortigate-mcp@latest
```
