# Tplink Omada Mcp

> MCP server for TP-Link Omada Controller. Use your prefered AI agent to see all the information on your TP-Link Omada Controller.

- **Type:** MCP server
- **Install:** `agentstack add mcp-migueltvms-tplink-omada-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [MiguelTVMS](https://agentstack.voostack.com/s/migueltvms)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [MiguelTVMS](https://github.com/MiguelTVMS)
- **Source:** https://github.com/MiguelTVMS/tplink-omada-mcp
- **Website:** https://hub.docker.com/r/jmtvms/tplink-omada-mcp

## Install

```sh
agentstack add mcp-migueltvms-tplink-omada-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# TP-Link Omada MCP server

> ## 🤖 AI-Developed Repository
>
> Since **March 2, 2026**, this repository contains no human-written code.
>
> All planning, development, and code review is performed by AI agents. Humans remain in the loop for direction, decisions, and final approval — but every line of code, every test, every commit, and every PR is the work of AI.
>
> This is not an experiment. This is how it works now. [Know more](https://miguel.ms)

---

A Model Context Protocol (MCP) server implemented in TypeScript that exposes the TP-Link Omada controller APIs to AI copilots and automation workflows. The server authenticates against a controller, lists sites, devices, and connected clients, and offers a generic tool to invoke arbitrary Omada API endpoints.

> **Compatibility:** Tested with Omada Controller versions 5.x and 6.x

## Quick Start

### Using with Claude Desktop (stdio)

1. **Pull the Docker image** (or build it locally with `npm run docker:build`):

   ```bash
   docker pull jmtvms/tplink-omada-mcp:latest
   ```

2. **Add the MCP server to Claude Desktop configuration**. Edit your Claude Desktop config file:
   - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

3. **Add the following configuration**:

   ```json
   {
     "mcpServers": {
       "tplink-omada": {
         "command": "docker",
         "args": [
           "run",
           "-i",
           "--rm",
           "-e", "OMADA_BASE_URL=https://your-omada-controller.local",
           "-e", "OMADA_CLIENT_ID=your-client-id",
           "-e", "OMADA_CLIENT_SECRET=your-client-secret",
           "-e", "OMADA_OMADAC_ID=your-omadac-id",
           "-e", "OMADA_SITE_ID=your-site-id",
           "-e", "OMADA_STRICT_SSL=false",
           "jmtvms/tplink-omada-mcp:latest"
         ]
       }
     }
   }
   ```

   Replace the environment variable values with your actual Omada controller credentials.

4. **Restart Claude Desktop** to load the new MCP server configuration.

5. **Verify the connection** by asking Claude to list your Omada sites or devices.

### Using Docker Containers

#### CLI/stdio Container

```bash
docker run -it --rm \
  --env-file .env \
  jmtvms/tplink-omada-mcp:latest
```

#### HTTP Server Container

```bash
docker run -d \
  --env-file .env \
  -e MCP_SERVER_USE_HTTP=true \
  -e MCP_HTTP_BIND_ADDR=0.0.0.0 \
  -p 3000:3000 \
  jmtvms/tplink-omada-mcp:latest
```

The HTTP server will be available at `http://localhost:3000/mcp`.

## Features

- OAuth client-credentials authentication with automatic token refresh
- Tools for retrieving sites, network devices, and connected clients
- Generic Omada API invoker for advanced automation scenarios
- Environment-driven configuration
- Per-tag Omada OpenAPI references stored under `docs/openapi`
- Ready-to-use devcontainer with a companion Omada controller service

## Getting started

### Prerequisites

- Docker (for running pre-built containers) or Node.js 24+ (for local development)
- Access to a TP-Link Omada controller (for example using the `mbentley/omada-controller` Docker image)

### Configuration

The MCP server reads its configuration from environment variables. See `.env.example` for a complete reference.

#### Tool Category Filtering

| Variable                  | Required | Default                                                      | Description                                          |
| ------------------------- | -------- | ------------------------------------------------------------ | ---------------------------------------------------- |
| `OMADA_TOOL_CATEGORIES` | No       | `dashboard:r,client-insights:r,clients:r,devices-all:r` | Comma-separated categories to enable at startup |
Each token is `[:]`. Permission suffixes:

| Suffix | Effect               |
| ------ | -------------------- |
| `:r` | Read tools only |
| `:w` | Write tools only |
| `:rw` | Read and write tools |
| _(none)_ | Same as `:rw`      |

##### Category Reference

Categories marked with `*` are reserved for upcoming phases and have no tool implementations yet. Specifying them will produce a startup warning and they will be skipped. Write tools are currently limited to the `clients` category.

| Group                   | Categories                                                                    |
| ----------------------- | ----------------------------------------------------------------------------- |
| Dashboard & Insights    | `dashboard`, `client-insights`, `insights`*                                   |
| Clients                 | `clients`                                                                     |
| Devices                 | `devices-general`, `devices-ap`, `devices-switch`, `devices-gateway`          |
| Wireless                | `wireless-ssid`, `wireless-radio`, `wireless-auth`                            |
| Network                 | `network-wan`, `network-sim-lte`*, `network-lan`, `network-routing`, `network-nat`, `network-services` |
| Firewall & Security     | `firewall-acl`, `firewall-traffic`, `firewall-ids`, `security-threat`, `security-wids` |
| VPN                     | `vpn`                                                                         |
| Profiles & Schedules    | `profiles`, `schedules`, `auth-profiles`                                     |
| Logs                    | `logs`                                                                        |
| Controller & Org        | `controller`, `sites`, `maintenance`, `account-users`, `account-sso`*, `account-cloud` |
| Hotspot                 | `hotspot-portal`*, `hotspot-vouchers`*, `hotspot-users`*                      |
| Niche                   | `site-templates`*, `voip`*, `olt`*, `msp`*                                    |

Group aliases expand to all categories in their group:

| Alias          | Expands to                                                                                    |
| -------------- | --------------------------------------------------------------------------------------------- |
| `all` | Every category |
| `devices-all` | `devices-general`, `devices-ap`, `devices-switch`, `devices-gateway` |
| `wireless-all` | `wireless-ssid`, `wireless-radio`, `wireless-auth`                                            |
| `network-all` | `network-wan`, `network-lan`, `network-routing`, `network-nat`, `network-services` |
| `firewall-all` | `firewall-acl`, `firewall-traffic`, `firewall-ids`                                            |
| `security-all` | `security-threat`, `security-wids`                                                            |

Examples:

```bash
# Read-only access to everything
OMADA_TOOL_CATEGORIES=all:r

# Default safe subset (read only)
OMADA_TOOL_CATEGORIES=dashboard:r,client-insights:r,clients:r,devices-all:r

# Full access including write operations
OMADA_TOOL_CATEGORIES=all:rw

# Network read + client write operations
OMADA_TOOL_CATEGORIES=network-all:r,clients:rw
```

#### Omada Client Configuration

| Variable              | Required | Default | Description                                                                 |
| --------------------- | -------- | ------- | --------------------------------------------------------------------------- |
| `OMADA_BASE_URL` | Yes      | -       | Base URL of the Omada controller (e.g., `https://omada-controller.local`) |
| `OMADA_CLIENT_ID` | Yes      | -       | OAuth client ID generated under Omada Platform Integration |
| `OMADA_CLIENT_SECRET` | Yes      | -       | OAuth client secret associated with the client ID                           |
| `OMADA_OMADAC_ID` | Yes      | -       | Omada controller ID (omadacId) to target |
| `OMADA_SITE_ID` | No       | -       | Optional default site ID; if omitted, each MCP call must pass a siteId |
| `OMADA_STRICT_SSL` | No       | `true`  | Enforce strict SSL certificate validation (set to `false` for self-signed) |
| `OMADA_TIMEOUT` | No       | `30000` | HTTP request timeout in milliseconds |
#### MCP Generic Server Configuration

| Variable                 | Required | Default | Description                                                                 |
| ------------------------ | -------- | ------- | --------------------------------------------------------------------------- |
| `MCP_SERVER_LOG_LEVEL` | No       | `info`  | Logging verbosity (`debug`, `info`, `warn`, `error`, `silent`) |
| `MCP_SERVER_LOG_FORMAT` | No       | `plain` | Log output format (`plain`, `json`, or `gcp-json`) |
| `MCP_SERVER_USE_HTTP` | No       | `false` | Start HTTP server instead of stdio |
> **Session IDs and authentication:** When `OMADA_CLIENT_ID`, `OMADA_CLIENT_SECRET`, and `OMADA_OMADAC_ID` are provided (the default client-credentials mode), the server runs statelessly and treats the `Mcp-Session-Id` header as optional. A future OAuth-based user authentication mode will require this header again.

#### MCP Server HTTP Configuration

These variables are only used when `MCP_SERVER_USE_HTTP=true`:

| Variable                       | Required | Default                         | Description                                                                 |
| ------------------------------ | -------- | ------------------------------- | --------------------------------------------------------------------------- |
| `MCP_HTTP_PORT` | No       | `3000`                          | Port for the HTTP server |
| `MCP_HTTP_BIND_ADDR` | No       | `127.0.0.1`                     | Bind address (IPv4/IPv6). Use atapter IP address to expose to the network. |
| `MCP_HTTP_PATH` | No       | `/mcp`                          | Base path for MCP endpoints |
| `MCP_HTTP_ENABLE_HEALTHCHECK` | No       | `true`                          | Enable a healthcheck endpoint |
| `MCP_HTTP_HEALTHCHECK_PATH` | No       | `/healthz`                      | Path for the healthcheck endpoint |
| `MCP_HTTP_ALLOW_CORS` | No       | `true`                          | Enable CORS for the HTTP server |
| `MCP_HTTP_ALLOWED_ORIGINS` | No       | `127.0.0.1, localhost`          | Comma-separated list of allowed origins. Use `*` to allow all (dev only) |
| `MCP_HTTP_NGROK_ENABLED` | No       | `false`                         | Use ngrok to expose the HTTP server publicly |
| `MCP_HTTP_NGROK_AUTH_TOKEN` | No       | -                               | Ngrok auth token (required if `MCP_HTTP_NGROK_ENABLED=true`) |
Create a `.env` file (ignored by git) or export the variables before launching the server.

### Development

```bash
npm run dev
```

The dev mode keeps the TypeScript server running with live reload support via `tsx`.

### Building

```bash
npm run build
```

### Linting

```bash
npm run check
```

### Testing

#### Unit tests

```bash
npm test               # run all unit tests
npm run test:watch     # watch mode
npm run test:coverage  # with coverage report
```

Coverage thresholds:

| Level | Metric | Threshold |
|-------|--------|-----------|
| Per-file | Lines, Statements, Functions | 90% |
| Global | Branches | 70% |

#### Integration tests (Docker)

> Not implemented yet — this section documents the **planned** integration test strategy tracked in **#57** and **#58**.

Integration tests will run against a real Omada Software Controller in a Docker container. They are **not** planned to run on every PR — they serve as a milestone release gate and a test harness for write tools.

Planned layout:
- `test/docker/` (compose + snapshot/seed tooling)
- `tests/integration/`
- `npm run test:integration`

> ⚠️ **Phase 2 write tools must only be tested against the Docker controller — never against a production controller.**

### Running the MCP server

```bash
npm start
```

The MCP server communicates over standard input and output. Integrate it with MCP-compatible clients by referencing the `npm start` command and providing the required environment variables.

### Docker image

A container image is provided for running the MCP server:

```bash
npm run docker:build  # Build the Docker image (tag: jmtvms/tplink-omada-mcp:latest)
npm run docker:run    # Launch the container with your .env file
npm run docker:push   # Push the image to Docker Hub
```

You can also pull the pre-built image directly from Docker Hub:

```bash
docker pull jmtvms/tplink-omada-mcp:latest
```

The same image supports both stdio and HTTP transports - configure the desired mode using environment variables (e.g., set `MCP_SERVER_USE_HTTP=true` for HTTP mode).

### Debugging with MCP Inspector

Use the MCP Inspector to interactively test tools, resources, and prompts without leaving your browser. The inspector automatically adapts to your `.env` configuration:

- **`npm run inspector`** — Launches the inspector based on your `.env` settings:
  - If `MCP_SERVER_USE_HTTP=false` (or unset): Runs the server in stdio mode with `tsx src/index.ts` for live reload debugging
  - If `MCP_SERVER_USE_HTTP=true`: Connects to an already-running HTTP server at the configured port/transport (start the server first with `npm run dev`)
  
- **`npm run inspector:build`** — Compiles the project first, then launches the inspector against the production build (`dist/index.js`) to verify release parity. Also adapts to stdio or HTTP mode based on `.env`.

**Requirements:** The inspector requires a `.env` file at the repository root. It will load both `.env` and `.env.local` (if present) to determine the server mode, port, transport, and path.

The MCP Inspector tool automatically binds to localhost and generates a session token for authentication (printed to the console and auto-filled in the browser URL).

### Transport Protocols

The MCP server uses the **Streamable HTTP** transport, which implements the [MCP protocol version 2025-03-26](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#http-with-sse).

```bash
export MCP_SERVER_USE_HTTP=true
npm run dev
```

Features:

- Single endpoint for all operations (GET, POST, DELETE)
- Server-Sent Events for streaming responses
- Built-in session management with cryptographic session IDs (the server currently operates statelessly when using client credentials)

The endpoint defaults to `/mcp` and handles:

- `GET /mcp` - Establish SSE stream and initialize session
- `POST /mcp` - Send JSON-RPC messages
- `DELETE /mcp` - Terminate session

#### Security Considerations

DNS rebinding protection is enabled by default:

- **Origin Validation**: The server validates the `Origin` header on all incoming connections. Configure allowed origins with `MCP_HTTP_ALLOWED_ORIGINS` (default: `127.0.0.1, localhost`). Use `*` to allow all origins (development only, not recommended for production).
- **Network Binding**: The server binds to `127.0.0.1` by default, restricting access to localhost only. Set `MCP_HTTP_BIND_ADDR=0.0.0.0` to expose the server to your network (not recommended for production without additional security measures).

For more information on the MCP protocol and transports, see the [Model Context Protocol documentation](https://modelcontextprotocol.io/).

### HTTP transport usage

Start the HTTP transport with:

```bash
# Start with HTTP enabled
export MCP_SERVER_USE_HTTP=true
npm run dev    # live reload during development
npm run start  # run the compiled output
```

By default, the server listens on `127.0.0.1:3000` and exposes the MCP endpoint at `/mcp` with a health check on `/healthz`. Configure the bind address, port, and path using the optional `MCP_HTTP_*` environment variables documented in `.env.example`. The `npm run docker:run:http` helper wraps the HTTP image and publishes the port automatically.

#### Using ngrok

To share the local server with remote tooling, you can use ngrok to expose the HTTP server publicly.

##### Option 1: Built-in ngrok support (recommended)

Set the following environment variables:

```bash
export MCP_HTTP_NGROK_ENABLED=true
export MCP_HTTP_NGROK_AUTH_TOKEN=your

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [MiguelTVMS](https://github.com/MiguelTVMS)
- **Source:** [MiguelTVMS/tplink-omada-mcp](https://github.com/MiguelTVMS/tplink-omada-mcp)
- **License:** MIT
- **Homepage:** https://hub.docker.com/r/jmtvms/tplink-omada-mcp

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-migueltvms-tplink-omada-mcp
- Seller: https://agentstack.voostack.com/s/migueltvms
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
