Skip to main content
Glama
kcsoukup

ASUS Merlin Router MCP Server

by kcsoukup
README.md
# ASUS Merlin Router MCP Server

Model Context Protocol (MCP) server for managing ASUS routers running Asuswrt-Merlin firmware via SSH/SCP.

![Docker Pulls](https://img.shields.io/docker/pulls/kcsoukup/asus-merlin-mcp)
![Docker Image Version](https://img.shields.io/docker/v/kcsoukup/asus-merlin-mcp?sort=semver)
![Docker Image Size](https://img.shields.io/docker/image-size/kcsoukup/asus-merlin-mcp)

---

## 🚨 BREAKING CHANGE - v3.x Security Update

**Docker containers now run as rootless (non-root user `mcpuser`) for enhanced security.**

**If upgrading from v1.0.0 to v3.x, you MUST update your MCP configuration with TWO changes:**

| Component | v1.0.0 (Deprecated) | v3.x (Current) |
|-----------|---------------------|----------------|
| Container User | `root` | `mcpuser` (UID 1000) |
| Volume Mount | `~/.ssh:/root/.ssh:ro` | `~/.ssh:/home/mcpuser/.ssh:ro` |
| SSH Key Path | `/root/.ssh/id_rsa` | `/home/mcpuser/.ssh/id_rsa` |

**Required Changes:**

1. **Update Volume Mount** in Docker args:
   ```json
   "-v", "~/.ssh:/home/mcpuser/.ssh:ro"  // Changed from /root/.ssh
   ```

2. **Update Environment Variable**:
   ```json
   "ROUTER_KEY_FILE": "/home/mcpuser/.ssh/id_rsa"  // Changed from /root/.ssh/id_rsa
   ```

**Complete MCP Configuration Example:**
```json
{
  "mcpServers": {
    "asus-router": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/home/yourusername/.ssh:/home/mcpuser/.ssh:ro",
        "-e", "ROUTER_HOST=192.168.1.1",
        "-e", "ROUTER_USER=admin",
        "-e", "ROUTER_KEY_FILE=/home/mcpuser/.ssh/id_rsa",
        "kcsoukup/asus-merlin-mcp:latest"
      ]
    }
  }
}
```

**Security Benefits:**
- ✅ Follows Docker security best practices (rootless containers)
- ✅ Reduces attack surface by running as non-privileged user
- ✅ Prevents privilege escalation vulnerabilities

---

## Features

This MCP server provides **47 tools** across 8 categories for comprehensive router management:

- **System Information** (14 tools): Router info, device lists, WiFi status, services, NVRAM, file operations, processes
- **Firewall Management** (2 tools): Configure firewall settings and VPN passthrough
- **URL/Keyword Filtering** (9 tools): Global URL/keyword content filtering
- **Network Service Filtering** (6 tools): Block/allow services by IP/port/protocol with scheduling (NEW in v3.0)
- **MAC Filtering** (3 tools): Add/remove/list WiFi access control rules
- **DHCP Management** (3 tools): Add/remove/list static IP reservations
- **Internet Access Control** (2 tools): Block/unblock devices (parental controls)
- **VPN Routing Policy** (3 tools): Route devices through VPN clients (Asuswrt-Merlin only)
- **VPN Server Monitoring** (2 tools): Monitor VPN server status and users

For detailed example prompts for each tool, see **[TOOLS_PROMPTS.md](TOOLS_PROMPTS.md)**

## Prerequisites

### Router Setup
1. Enable SSH on your router:
   - Login to router web interface
   - Go to **Administration > System**
   - Set **Enable SSH** to **LAN only** (or LAN & WAN if needed)
   - Click **Apply**

2. (Recommended) Set up SSH key authentication:
   ```bash
   # On your Debian workstation
   ssh-keygen -t rsa -b 4096

   # Copy your public key to router
   ssh-copy-id admin@192.168.1.1

   # Or manually via web interface:
   # Administration > System > SSH Authentication Key
   ```

### Debian Workstation Setup
```bash
# Install Python 3.11+ if not already installed
sudo apt update
sudo apt install python3 python3-pip python3-venv

# Optional: Install Docker for containerized deployment
sudo apt install docker.io docker-compose
```

## Installation

### Option 1: Local Installation (Recommended for Development)

1. **Clone or create project directory:**
   ```bash
   mkdir asus-merlin-mcp
   cd asus-merlin-mcp
   ```

2. **Save the MCP server code as `asus_merlin_mcp.py`**

3. **Create virtual environment and install dependencies:**
   ```bash
   python3 -m venv venv
   source venv/bin/activate
   pip install -r requirements.txt
   ```

4. **Configure router connection:**
   ```bash
   cp .env.example .env
   nano .env  # Edit with your router details
   ```

5. **Test the connection:**
   ```bash
   # Export environment variables
   export $(cat .env | xargs)

   # Run the server (it will connect via stdio)
   python asus_merlin_mcp.py
   ```

### Option 2: Docker Installation

#### Quick Start - Pull from Docker Hub:
```bash
# Pull the pre-built image (use :latest for current version or specific version tag)
docker pull kcsoukup/asus-merlin-mcp:latest
```

**Available versions:** `v1.0.0`, `v3.0`, `latest`

#### Build from Source (Alternative):

1. **Build the Docker image:**
   ```bash
   docker build -t asus-merlin-mcp .
   ```

2. **Edit docker-compose.yml with your router credentials**
   ```bash
   # Optional -- The credentials are passed to the container via the MCP configurations in Claude or other chatbots.
   ```

3. **Run with Docker Compose:**
   ```bash
   docker-compose up -d
   ```

## Claude Configuration

The configuration location depends on which Claude installation you're using:

### Claude Code (Native Installation)

MCP servers are automatically configured in `~/.claude.json` under your project path:

**Config file:** `~/.claude.json`

#### For Local Installation:
```json
{
  "installMethod": "native",
  "projects": {
    "/path/to/asus-merlin-mcp": {
      "mcpServers": {
        "asus-router": {
          "command": "/path/to/asus-merlin-mcp/venv/bin/python",
          "args": ["/path/to/asus-merlin-mcp/asus_merlin_mcp.py"],
          "env": {
            "ROUTER_HOST": "192.168.1.1",
            "ROUTER_PORT": "22",
            "ROUTER_USER": "admin",
            "ROUTER_KEY_FILE": "/home/yourusername/.ssh/id_rsa"
          }
        }
      }
    }
  }
}
```

#### For Docker Installation:
```json
{
  "installMethod": "native",
  "projects": {
    "/path/to/asus-merlin-mcp": {
      "mcpServers": {
        "asus-router": {
          "command": "docker",
          "args": [
            "run", "-i", "--rm",
            "-v", "/home/yourusername/.ssh:/home/mcpuser/.ssh:ro",
            "-e", "ROUTER_HOST=192.168.1.1",
            "-e", "ROUTER_PORT=22",
            "-e", "ROUTER_USER=admin",
            "-e", "ROUTER_KEY_FILE=/home/mcpuser/.ssh/id_rsa",
            "kcsoukup/asus-merlin-mcp:latest"
          ]
        }
      }
    }
  }
}
```

---

### Claude Code (NPM Installation)

**Config file:** `~/.claude/settings.json`

#### For Local Installation:
```json
{
  "mcpServers": {
    "asus-router": {
      "command": "/path/to/asus-merlin-mcp/venv/bin/python",
      "args": ["/path/to/asus-merlin-mcp/asus_merlin_mcp.py"],
      "env": {
        "ROUTER_HOST": "192.168.1.1",
        "ROUTER_PORT": "22",
        "ROUTER_USER": "admin",
        "ROUTER_KEY_FILE": "/home/yourusername/.ssh/id_rsa"
      }
    }
  }
}
```

#### For Docker Installation:
```json
{
  "mcpServers": {
    "asus-router": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/home/yourusername/.ssh:/home/mcpuser/.ssh:ro",
        "-e", "ROUTER_HOST=192.168.1.1",
        "-e", "ROUTER_PORT=22",
        "-e", "ROUTER_USER=admin",
        "-e", "ROUTER_KEY_FILE=/home/mcpuser/.ssh/id_rsa",
        "kcsoukup/asus-merlin-mcp:latest"
      ]
    }
  }
}
```

---

### Claude Desktop

**Config file locations:**
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`

#### For Local Installation:
```json
{
  "mcpServers": {
    "asus-router": {
      "command": "/path/to/asus-merlin-mcp/venv/bin/python",
      "args": ["/path/to/asus-merlin-mcp/asus_merlin_mcp.py"],
      "env": {
        "ROUTER_HOST": "192.168.1.1",
        "ROUTER_PORT": "22",
        "ROUTER_USER": "admin",
        "ROUTER_KEY_FILE": "/home/yourusername/.ssh/id_rsa"
      }
    }
  }
}
```

#### For Docker Installation:
```json
{
  "mcpServers": {
    "asus-router": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/home/yourusername/.ssh:/home/mcpuser/.ssh:ro",
        "-e", "ROUTER_HOST=192.168.1.1",
        "-e", "ROUTER_PORT=22",
        "-e", "ROUTER_USER=admin",
        "-e", "ROUTER_KEY_FILE=/home/mcpuser/.ssh/id_rsa",
        "kcsoukup/asus-merlin-mcp:latest"
      ]
    }
  }
}
```

**Important Notes:**
- Replace `/home/yourusername` with your actual home directory path (e.g., `/home/triskull`)
- Do NOT use `${HOME}` or `~` in JSON configuration files - they will not expand
- After updating the configuration file, restart Claude Code or Claude Desktop for the changes to take effect

## Usage Examples

Once configured in Claude Desktop, you can interact with your router:

**Example prompts:**
- "What's the current status of my router?"
- "List all connected devices"
- "Restart the wireless service"
- "Show me the WiFi configuration"
- "Get the value of wan_ipaddr from NVRAM"
- "Upload this backup script to /jffs/scripts/"
- "Check if VPN is running"
- "Show me the router's system log"

## Available Tools

For detailed example prompts, see **[TOOLS_PROMPTS.md](TOOLS_PROMPTS.md)**

### System Information Tools (14)
| Tool | Description |
|------|-------------|
| `get_router_info` | System info (uptime, memory, firmware) |
| `get_connected_devices` | List DHCP clients |
| `get_all_network_devices` | Comprehensive device list (DHCP + static + ARP) |
| `get_wifi_status` | WiFi status for all radios |
| `restart_service` | Restart specific service |
| `reboot_router` | Reboot router (requires confirmation) |
| `get_vpn_status` | Check VPN client/server status |
| `list_processes` | Show running processes |
| `get_nvram_variable` | Read NVRAM variable |
| `set_nvram_variable` | Write NVRAM variable |
| `execute_command` | Run custom SSH command |
| `read_file` | Read file from router |
| `upload_file` | Upload file (MD5 verified) |
| `download_file` | Download file (MD5 verified) |

### MAC Filtering Tools (3)
| Tool | Description |
|------|-------------|
| `add_mac_filter` | Add device to MAC filter (whitelist/blacklist) |
| `remove_mac_filter` | Remove device from MAC filter |
| `list_mac_filters` | Show current MAC filters |

### DHCP Management Tools (3)
| Tool | Description |
|------|-------------|
| `add_dhcp_reservation` | Reserve IP for MAC address (static lease) |
| `remove_dhcp_reservation` | Remove DHCP reservation |
| `list_dhcp_reservations` | Show all DHCP reservations |

### Internet Access Control Tools (2)
| Tool | Description |
|------|-------------|
| `block_device_internet` | Block/unblock device internet (parental controls) |
| `list_blocked_devices` | Show blocked devices |

### VPN Routing Policy Tools (3)
| Tool | Description |
|------|-------------|
| `add_vpn_routing_policy` | Route device through VPN client |
| `remove_vpn_routing_policy` | Remove device from VPN routing |
| `list_vpn_policies` | Show all VPN routing policies |

### VPN Server Monitoring Tools (2)
| Tool | Description |
|------|-------------|
| `get_vpn_server_status` | VPN server status and connected clients |
| `get_vpn_server_users` | List authorized VPN server users |

## Common Services to Restart

- `wireless` - WiFi services
- `wan` - WAN connection
- `httpd` - Web interface
- `vpnclient1` - VPN client 1
- `vpnclient2` - VPN client 2
- `dnsmasq` - DNS/DHCP server

## Security Notes

1. **Use SSH keys instead of passwords** for better security
2. **Enable SSH on LAN only** unless you need WAN access
3. **Be careful with NVRAM operations** - incorrect values can break your router
4. **Test commands manually first** before automating
5. **Keep backups** of your router configuration

## Troubleshooting

### Connection Issues
```bash
# Test SSH connection manually
ssh admin@192.168.1.1

# Check if SSH is enabled on router
# Via web interface: Administration > System > Enable SSH
```

### Permission Denied
```bash
# Ensure SSH keys are readable
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub

# Verify key is added to router
ssh admin@192.168.1.1 "cat /tmp/home/root/.ssh/authorized_keys"
```

### Import Errors
```bash
# Ensure virtual environment is activated
source venv/bin/activate

# Reinstall dependencies
pip install -r requirements.txt --force-reinstall
```

### Volume Mount Errors (Docker)
If you see an error like:
```
Error: error creating named volume "${HOME}/.keys":
error running volume create option: names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument
```

**Cause:** JSON configuration files do not expand shell variables like `${HOME}` or `~`.

**Solution:** Replace `${HOME}` with your actual home directory path in the configuration:
```json
// Wrong - will not work:
"-v", "${HOME}/.ssh:/home/mcpuser/.ssh:ro"

// Correct - use absolute path:
"-v", "/home/triskull/.ssh:/home/mcpuser/.ssh:ro"
```

To find your home directory:
```bash
echo $HOME
# Output: /home/triskull
```

## How-To Guide: Common Administrative Tasks

This section provides practical examples for common router administration tasks using the MCP tools.

### Managing the Hosts File

The router's custom hosts file (`/jffs/configs/hosts.add`) allows you to add static DNS entries that persist across reboots.

#### View Current Hosts File
**Via Claude:**
```
"Show me the contents of /jffs/configs/hosts.add"
```

**MCP Tool Used:** `read_file`

#### Add a New Host Entry

**Option 1: Download, Edit, Upload (Recommended)**

1. Download the file:
   ```
   "Download /jffs/configs/hosts.add from the router to ./hosts.add"
   ```
   *Uses: `download_file` tool*
   *Note: Downloads are MD5 checksum verified for integrity*

2. Edit the file locally with your text editor:
   ```bash
   nano hosts.add
   # Add line like:
   # 192.168.0.100    newserver.damage.inc    newserver
   ```

3. Upload back to router:
   ```
   "Upload ./hosts.add to /jffs/configs/hosts.add on the router"
   ```
   *Uses: `upload_file` tool*
   *Note: Uploads are MD5 checksum verified to ensure file integrity*

4. Apply changes:
   ```
   "Restart the dnsmasq service"
   ```
   *Uses: `restart_service` with `service_name: dnsmasq`*

**⚠️ WARNING:** Do NOT use `execute_command` with echo/heredoc for file operations. Always use the download → edit → upload workflow shown above for file safety and MD5 verification.

#### Update an Existing Host Entry

1. Download the hosts file
2. Edit locally to change the desired line
3. Upload back to router
4. Restart dnsmasq

#### Remove a Host Entry

Via Claude:
```
"Execute this command: sed -i '/hostname-to-remove/d' /jffs/configs/hosts.add"
"Restart the dnsmasq service"
```

*Replace `hostname-to-remove` with the actual hostname or IP*

### Managing NVRAM Variables

NVRAM stores persistent router configuration. **Warning:** Incorrect values can break your router!

#### Get a Single NVRAM Variable
```
"Get the NVRAM variable wan_ipaddr"
```
*Uses: `get_nvram_variable`*

#### Set an NVRAM Variable (Without Commit)
```
"Set NVRAM variable custom_setting to value123 but don't commit"
```
*Uses: `set_nvram_variable` with `commit: false`*

This sets the variable in RAM but won't persist across reboots.

#### Set and Commit NVRAM Variable
```
"Set NVRAM variable custom_setting to value123 and commit it"
```
*Uses: `set_nvram_variable` with `commit: true`*

**⚠️ Warning:** Committed changes persist across reboots. Double-check values before committing!

#### Backup NVRAM to File
```
"Execute this command: nvram show > /jffs/nvram_backup_$(date +%Y%m%d).txt"
"Download /jffs/nvram_backup_20250101.txt to ./nvram_backup.txt"
```

### Managing Custom Scripts

Scripts in `/jffs/scripts/` persist across reboots and can run at various router events.

#### Common Script Hooks
- `init-start` - First script run during boot
- `services-start` - Runs after router services start
- `wan-start` - Runs when WAN interface comes up
- `firewall-start` - Runs when firewall starts

#### Upload a Custom Script
```
"Upload ./my-custom-script.sh to /jffs/scripts/services-start on the router"
```
*MD5 checksum automatically verified to ensure script integrity*

Then make it executable:
```
"Execute this command: chmod +x /jffs/scripts/services-start"
```

#### View Existing Scripts
```
"Execute this command: ls -la /jffs/scripts/"
```

#### Read a Script's Contents
```
"Read the file /jffs/scripts/firewall-start"
```

### Monitoring and Diagnostics

#### Check System Resources
```
"What's my router's current status?"
```
*Uses: `get_router_info` - Shows uptime, memory, firmware*

#### List All Connected Devices
```
"List all connected devices on my network"
```
*Uses: `get_connected_devices` - Shows DHCP leases*

#### Find a Specific Device
```
"Show connected devices and look for hostname 'rpiserver'"
"Execute this command: cat /var/lib/misc/dnsmasq.leases | grep rpiserver"
```

#### Check WiFi Status
```
"What's my WiFi status?"
```
*Uses: `get_wifi_status` - Shows radio status and SSIDs*

#### View System Logs
```
"Read the file /jffs/syslog.log with max 50 lines"
```
*Uses: `read_file` with `max_lines: 50`*

#### Monitor Running Processes
```
"List all running processes"
"List processes filtered by 'vpn'"
```
*Uses: `list_processes` with optional filter*

### VPN Management

#### Check VPN Status
```
"What's my VPN status?"
```
*Uses: `get_vpn_status` - Shows client/server states*

#### View VPN Configuration
```
"Execute this command: nvram show | grep vpn_client1"
```

#### Restart VPN Client
```
"Restart the vpnclient1 service"
```
*Uses: `restart_service` with `service_name: vpnclient1`*

### Service Management

#### Restart Wireless Service
```
"Restart the wireless service"
```
*Useful after changing WiFi settings*

#### Restart WAN Connection
```
"Restart the wan service"
```
*Forces WAN reconnection*

#### Restart Web Interface
```
"Restart the httpd service"
```
*Restarts the router's web UI*

### File Management

**Note:** All file uploads and downloads are cryptographically verified using MD5 checksums to ensure data integrity. This is especially important for binary files, scripts, and executables.

#### Download Router Files
```
"Download /jffs/configs/dnsmasq.conf.add to ./dnsmasq.conf.add"
```
*Checksum verified for integrity*

#### Upload Configuration Files
```
"Upload ./firewall-rules.txt to /jffs/scripts/firewall-start"
```
*Checksum verified to prevent corruption*

#### Check File Permissions
```
"Execute this command: ls -la /jffs/scripts/"
```

#### Make Script Executable
```
"Execute this command: chmod +x /jffs/scripts/script-name"
```

### Advanced Router Operations

#### Backup Entire JFFS Partition
```
"Execute this command: tar -czf /tmp/jffs_backup_$(date +%Y%m%d).tar.gz /jffs/"
"Download /tmp/jffs_backup_20250101.tar.gz to ./router_backup.tar.gz"
```

#### View Network Connections
```
"Execute this command: netstat -an | grep ESTABLISHED"
```

#### Check Router Temperature (if supported)
```
"Execute this command: wl -i eth1 phy_tempsense"
```

#### Reboot Router
```
"Reboot the router"
```
*Requires confirmation - **⚠️ This will disconnect all clients!***

### Tips and Best Practices

1. **Always test commands manually first** before automating them
2. **Keep backups** of configuration files before making changes
3. **Use descriptive hostnames** in hosts.add for easier management
4. **Document your custom scripts** with comments
5. **Restart services after configuration changes** to apply them
6. **Use SSH keys** instead of passwords for better security
7. **Be cautious with NVRAM commits** - test without commit first
8. **Monitor logs** after making changes to catch issues early

## Advanced Usage

### Backup Router Configuration
```bash
# Via Claude: "Download the router's NVRAM backup"
# This will use the download_file tool to get /jffs/nvram/nvram.txt
```

### Upload Custom Scripts
```bash
# Upload a script to run on router boot
# Files in /jffs/scripts/ persist across reboots
```

### Monitor Router Health
```bash
# Set up periodic checks via cron jobs on the router
# Use the execute_command tool to create cron entries
```

## Contributing

Feel free to extend this MCP server with additional tools for:
- Traffic monitoring
- Firewall rule management
- Bandwidth statistics
- Port forwarding configuration
- Guest network management

## Resources

- [Asuswrt-Merlin Wiki](https://github.com/RMerl/asuswrt-merlin.ng/wiki)
- [MCP Documentation](https://modelcontextprotocol.io/)
- [Paramiko Documentation](https://www.paramiko.org/)

## License

MIT License - Use at your own risk. Always maintain backups of your router configuration.