Skip to main content
Glama
README.md
# DrayTek Vigor 167 MCP Server

MCP-Server für DSL-Diagnose und CLI-Zugriff am **DrayTek Vigor 167** (Firmware 5.2.8) über interaktive SSH-Shell.

Befehle werden **nicht geraten**: Discovery läuft live gegen das Gerät (`?` / `help`) und wird unter `cache/command_tree.json` gecacht. Convenience-Tools und Parser basieren auf **verifiziertem** CLI-Output.

## Status

| Komponente | Status |
|------------|--------|
| Python venv (`.venv`) | `mcp[cli]` + `paramiko` installiert |
| Cursor MCP (`~/.cursor/mcp.json`) | **Noch nicht eingetragen** — siehe Abschnitt [Cursor einbinden](#cursor-einbinden) |
| `.env` mit Modem-Credentials | Lokal vorhanden, nicht im Git |

## Voraussetzungen

- Python 3.11+
- Netzwerkzugang zum Modem (Standard: `192.168.167.1:22`)
- Cursor oder anderer MCP-Client
- DrayTek Vigor 167 mit eingeschränkter Bridge-CLI (kein voller DrayOS-Befehlssatz)

## Schnellstart

```bash
cd ~/Workspaces/draytek-vigor-mcp
python -m venv .venv
source .venv/bin/activate
pip install "mcp[cli]" paramiko
```

`.env` anlegen (Format siehe unten), dann Discovery testen:

```bash
.venv/bin/python discover.py 2 --refresh
.venv/bin/python -c "from vigor_ssh import run_command; print(run_command('exec dslinfo'))"
```

Server manuell starten (stdio-MCP):

```bash
.venv/bin/python server.py
```

## Credentials (`.env`)

Nicht committen (steht in `.gitignore`). **Kein Standard-dotenv** — Parsing: erstes `:` trennt Schlüssel und Wert, umschließende `"` am Wert werden entfernt.

```env
mcp:"geheim"
VIGOR_HOST:"192.168.167.1"
VIGOR_PORT:"22"
```

Optional:

```env
VIGOR_PROMPT:"vigor>\\s*$"
VIGOR_IDLE_SEC:"0.8"
```

Die erste Zeile ohne reservierten Schlüssel (`VIGOR_*`) ist der **CLI-Benutzername**; der Wert ist das CLI-Passwort.

## SSH- und CLI-Ablauf (Vigor 167)

Am 167 unterscheidet sich der Ablauf von klassischen DrayTek-Routern:

1. **SSH-Transport**: `auth_none` (kein SSH-Passwort/Key nötig)
2. **Interaktive Shell**: `invoke_shell` + PTY — `exec_command` liefert oft leere Ausgabe
3. **CLI-Login**: Gerät fragt `Username:` / `Password:` (Credentials aus `.env`)
4. **Prompt**: `vigor>`
5. **Neue Session pro Aufruf**: Das Modem beendet idle SSH-Sessions

`enable` ist in der CLI vorhanden, aber am Vigor 167 **ohne konfigurierbares Passwort nutzlos** (*Access denied*). DSL-Diagnose funktioniert ohne privilegierten Modus.

## Cursor einbinden

Eintrag in `~/.cursor/mcp.json` unter `mcpServers` ergänzen:

```json
{
  "mcpServers": {
    "draytek-vigor": {
      "command": "/home/ladwein/Workspaces/draytek-vigor-mcp/.venv/bin/python",
      "args": ["/home/ladwein/Workspaces/draytek-vigor-mcp/server.py"],
      "cwd": "/home/ladwein/Workspaces/draytek-vigor-mcp"
    }
  }
}
```

Danach Cursor neu laden oder MCP-Server in den Einstellungen aktivieren.

## MCP-Tools

| Tool | CLI-Befehl | Beschreibung |
|------|------------|--------------|
| `discover_commands` | `?`, `exec ?`, `config ?`, `help` | Befehlsbaum vom Gerät (gecacht) |
| `run_command` | beliebig | Einzelbefehl ausführen |
| `run_commands` | beliebig | Mehrere Befehle in einer SSH-Session |
| `get_dsl_info` | `exec dslinfo` | Sync-Status, Profil, Raten, SNR |
| `get_system_info` | `exec sysinfo` | Modell, Firmware, Build-Infos |
| `get_device_time` | `exec date` | Gerätezeit |
| `get_services` | `exec services` | Offene Dienste/Ports |
| `get_config_status` | `exec cfg status` | Config-Profil-Status |
| `get_command_tree_summary` | — | Gecachter Discovery-Baum |

`run_command` / `run_commands` decken per Definition alle vom Gerät akzeptierten Befehle ab. Ungültige Befehle liefern die Geräte-Fehlermeldung im Ergebnis, keine Exception nach außen.

### Beispiel `get_dsl_info` (FW 5.2.8, verifiziert)

```
Status : Showtime
Mode : VDSL2
Profile : 17a
Annex : ANNEX B
DSL Version : 5.12.31.0_B_A60901
Line Uptime : …
Downstream Line Rate : … kbps
Upstream Line Rate : … kbps
SNR Downstream : … dB
SNR Upstream : … dB
```

**Nicht verfügbar** in `exec dslinfo` auf 5.2.8: Attenuation, CRC/FEC/ES/SES — dafür gibt es bewusst kein Convenience-Tool.

## Verifizierter Befehlsbaum (Kurzüberblick)

### Top-Level (`?`)

`help`, `quit`, `logout`, `history`, `enable`, `exit`, `config`, `exec`

### Exec (`exec ?`)

`date`, `ping`, `reboot_system`, `operation_mode`, `lan_mtu`, `wan_mtu`, `dot3ah_oam`, `y1731`, `dsl_dbg`, `dsl_35b_enhance`, `dsl_35b_target`, `process_dbg`, `tr069`, `coredump`, `sysinfo`, `telnet`, `cfg`, `services`, `dslinfo`, `nat_prio`

### Config (`help`, Auszug)

```
config Configuration Physical_Interface
config Configuration WAN WAN_Connections
config Monitoring DSL_Status Monitoring_DSL_General
config Monitoring DSL_Status Monitoring_DSL_Tone
config System_Maintenance Device_Settings Time
config System_Maintenance Management Access_Control
…
```

Config-Zweige nutzen Web-Form-CLI (`show` / `edit`); ohne `enable` kaum schreibbar.

Vollständiger Baum: `cache/command_tree.json` oder `discover.py 2 --refresh`.

## Discovery manuell

```bash
.venv/bin/python discover.py 2 --refresh
```

Parameter: Tiefe (Standard `2`), `--refresh` erzwingt Neuerkennung.

## Projektstruktur

```
server.py       MCP-Server (FastMCP)
vigor_ssh.py    SSH auth_none, CLI-Login, Prompt-Handling
discover.py     Befehls-Discovery via ?
parsers.py      Regex-Parser für verifizierte Ausgaben
pyproject.toml  Abhängigkeiten
cache/          command_tree.json (generiert, nicht committen)
.env            Credentials (lokal, nicht committen)
```

## Hinweise und Grenzen

- **Bridge-Modem**: Absichtlich eingeschränkte CLI — kein voip/qos/etc. wie bei großen DrayOS-Routern.
- **Kein `enable`**: Privilegierte Config-Befehle über CLI nicht erreichbar.
- **Timing**: `VIGOR_IDLE_SEC` erhöhen (z. B. `1.0`), falls Ausgaben abgeschnitten werden.
- **Credentials**: Niemals in Code, Logs oder Commits — nur in `.env`.
- **Parser**: Nur für tatsächlich gelieferte Felder; bei Firmware-Änderungen Discovery und Parser neu verifizieren.

## Fehlerbehebung

| Symptom | Ursache / Lösung |
|---------|------------------|
| Leere SSH-Ausgabe | Kein PTY / `exec_command` — dieser Server nutzt `invoke_shell` |
| `Access denied` bei `enable` | Erwartet; am 167 kein Enable-Passwort |
| `Authentication failed` (Paramiko) | Am 167 `auth_none` + CLI-Login — `vigor_ssh.py` nutzt Transport, nicht Passwort-SSH |
| Abgeschnittene CLI-Ausgabe | `VIGOR_IDLE_SEC` in `.env` erhöhen |
| MCP-Tools fehlen in Cursor | Eintrag in `~/.cursor/mcp.json` fehlt — siehe oben |

## Lizenz / Gerät

Getestet gegen DrayTek Vigor 167, Firmware **5.2.8**, Host `192.168.167.1`.

TDQS

A3.6/5.0

Scored across 9 tools

Disambiguation5/5

Each tool has a clearly distinct purpose. For example, discover_commands and get_command_tree_summary are related but serve different stages (discovery vs. cached retrieval), while run_command and run_commands differ in the number of commands executed. No two tools could be easily confused.

Naming Consistency5/5

All tools use snake_case with a consistent pattern: get_ prefix for status retrieval, discover_ for discovery, and run_ for command execution. The naming is uniform and predictable.

Tool Count5/5

9 tools is well-scoped for a network device management server. It covers discovery, common status queries, and arbitrary CLI execution without being too many or too few.

Completeness4/5

The tool set covers discovery, status checks, and command execution. While it lacks dedicated tools for some operations (e.g., interface stats, reboot), these can be achieved via run_command. Minor gaps exist but do not severely hinder common use cases.

Maintenance

ActivityInactive
ResponsivenessNo issues