Content
# Govee Smart Light MCP Server
An MCP server that controls Govee smart bulbs (H6008 and compatible) over the LAN UDP protocol. Designed for use with a Discord bot so Claude can set room lighting based on conversation — moods, time of day, whatever feels right.
- **Local only** — no cloud API, no internet required, no rate limits
- **Windows-friendly** — works around the `govee-led-wez` multicast bug (WinError 10022)
- **Multi-bulb** — supports 1–N bulbs, each given a friendly name
- **Stable IDs** — device IDs are pinned per IP in a cache file so they never drift across restarts
- **Flexible lookup** — tools accept device ID, IP address, *or* configured name as the bulb reference
- **Color effects** — smooth RGB cycling as a built-in effect
## Prerequisites
- Python 3.11+
- Govee H6008 (or compatible) bulbs on the same WiFi network as your PC
- LAN Control enabled on each bulb (see below)
## Enable LAN Control on Your Bulbs
This is required **for each bulb** before the server can discover or control it:
1. Open the **Govee Home** app on your phone
2. Tap on the device (e.g., "H6008")
3. Tap the **gear icon** (⚙️) in the top-right corner
4. Scroll down and toggle **LAN Control** to ON
If you don't see the LAN Control option, make sure:
- Your phone and bulb are on the same WiFi network
- The bulb firmware is up to date (check for updates in the app)
- The bulb model supports LAN control (H6008 does)
## Installation
```bash
cd "L:\claude code projects\claude smart light"
pip install -r requirements.txt
```
## Configuration
Copy the example config to your own:
```bash
cp config.example.json config.json
```
Then edit `config.json` to match your network. `config.json` is gitignored, so your personal setup never gets committed.
```json
{
"interface": "10.0.0.31",
"known_devices": [
{"ip": "10.0.0.80", "name": "Bedroom Left"},
{"ip": "10.0.0.249", "name": "Bedroom Center"},
{"ip": "10.0.0.123", "name": "Bedroom Right"}
],
"discovery_timeout": 3.0,
"log_level": "INFO",
"log_to_file": false
}
```
| Field | Description |
|-------|-------------|
| `interface` | IP of the network interface to bind to. Set this to your **WiFi adapter's IP** if your PC has multiple network interfaces (wired + wireless). Leave empty `""` for auto-detect. |
| `known_devices` | List of bulbs. Each entry needs `ip`; `name` is optional (if omitted, the bulb is labelled `Light 1`, `Light 2`, etc. by position). Used for unicast fallback when multicast discovery fails (common on Windows with dual NICs). |
| `discovery_timeout` | Seconds to wait for bulb discovery responses. Increase to 5.0 if bulbs are slow to respond. |
| `log_level` | `INFO` (default) or `DEBUG`. DEBUG logs every UDP packet sent and received — useful for troubleshooting, noisy otherwise. |
| `log_to_file` | `false` (default) or `true`. When true, `server.py` writes to `server.log` and `keepalive.py` writes to `keepalive.log` next to the scripts. Stderr logging is always on regardless. |
### Finding your bulb's IP
Check your router's DHCP client list, or look in the Govee Home app under the device's WiFi settings. **Set a DHCP reservation (static IP) for each bulb** in your router — the Govee LAN protocol doesn't handle IP changes gracefully, and a reservation is the cleanest fix.
### Stable device IDs (`device_cache.json`)
The Govee firmware returns different device IDs depending on whether the bulb received a multicast or unicast scan. To keep IDs stable for MCP clients (so Claude doesn't have to relearn them every session), the first ID seen at each IP is pinned in `device_cache.json` and reused forever. The cache is created automatically on first discovery — you shouldn't need to touch it.
If a bulb is ever replaced with new hardware at the same IP, delete that line from `device_cache.json` and restart the server to re-pin.
## Testing
Before plugging the server into your bot, run the discovery test to verify basic connectivity:
```bash
python test_discovery.py
```
This will discover bulbs, print device info, query state, and run a color cycle (red → green → blue → warm white). If you don't see the bulb change color, see [Troubleshooting](#troubleshooting).
## Running the MCP Server
### Standalone (for testing)
```bash
python server.py
```
The server communicates via stdio (JSON-RPC over stdin/stdout). It will start, discover devices, then wait for MCP tool calls.
### Registering with your Discord bot (llmcord)
Add this under the `mcp.servers` block in your bot's `config.yaml`:
```yaml
mcp:
enabled: true
servers:
govee-lights:
command: python
args: ["L:/claude code projects/claude smart light/server.py"]
```
If you already have other MCP servers configured (e.g. a memory system), just add the `govee-lights` entry alongside them — each server is a sibling key under `servers`.
### Recommended system prompt snippet
Near the tool descriptions, add an anti-hallucination instruction. Without this, some models will narrate light changes ("Your room is now blue!") without actually calling the tool:
```
**IMPORTANT — LIGHT CONTROL HALLUCINATION PREVENTION:**
When changing lights, you MUST call the actual Govee tool BEFORE writing any confirmation.
Never narrate a light change ("There you go!", "Done!", "Your room is now blue!") without having made a real tool call in the same response.
If you're unsure whether you actually called the tool, call it again. A duplicate call is better than a hallucinated one.
Do NOT describe your intent to change the light before calling the tool — call the tool FIRST, then describe what happened after.
```
## Keeping Bulbs Awake (`keepalive.py`)
Govee H6008 bulbs go idle on the LAN if no app or controller talks to them for a while — after idling, the first few commands from the MCP server can get dropped while the bulb wakes back up. The included `keepalive.py` script sends a lightweight status ping to every configured bulb every 45 seconds to prevent this.
Run it manually:
```bash
python keepalive.py
```
Or autostart on Windows login:
1. Press `Win+R`, type `shell:startup`, press Enter
2. Right-click → New → Shortcut
3. Target: `pythonw "L:\claude code projects\claude smart light\keepalive.py"` (using `pythonw` hides the console window)
4. Name it "Govee Keepalive"
Logs go to `keepalive.log` next to the script. The keepalive reuses `config.json` — no separate setup needed. It's safe to run alongside `server.py`; if port 4002 is already held, it still sends the pings (which is all the bulb needs), it just can't verify responses.
## Available Tools
| Tool | Description |
|------|-------------|
| `list_lights(rescan?)` | List all discovered bulbs with IDs, names, IPs, and online status. Pass `rescan=true` to re-run discovery. |
| `get_light_state(light_id)` | Get current on/off, brightness, RGB color, color temperature, and any active effect. |
| `turn_on(light_id)` | Turn a bulb on. |
| `turn_off(light_id)` | Turn a bulb off. |
| `set_brightness(light_id, brightness)` | Set brightness 1–100. Turns the bulb on. |
| `set_color(light_id, r, g, b)` | Set RGB color (each 0–255). Turns the bulb on. |
| `set_color_temperature(light_id, kelvin)` | Set color temperature 2000K–9000K. Turns the bulb on. |
| `start_color_cycle(light_id, speed?, saturation?, brightness?)` | Start a smooth RGB rainbow cycle on a bulb. `speed` 0.1–5.0 (1.0 = ~30s/cycle), `saturation` 0.0–1.0, `brightness` 1–100. Runs until stopped. |
| `stop_effect(light_id)` | Stop any running effect and reset the bulb to 2700K warm white. |
`light_id` accepts any of: the Govee device ID (e.g. `AA:BB:CC:DD:EE:FF:GG:HH`), the bulb's IP address, or the `name` from `config.json`. Use whichever is most convenient.
## Troubleshooting
### No devices discovered
1. **LAN Control not enabled** — This is the #1 cause. Open the Govee Home app → device → gear icon → toggle LAN Control ON. You must do this for **each bulb**.
2. **Wrong network interface** — If your PC has both wired (Ethernet) and wireless (WiFi) connections, set `"interface"` in `config.json` to your WiFi adapter's IP (e.g., `"10.0.0.31"`). Run `ipconfig` to find it.
3. **Firewall blocking UDP** — Windows Firewall must allow UDP on ports 4001, 4002, and 4003. Add inbound rules:
```
netsh advfirewall firewall add rule name="Govee LAN 4001" dir=in action=allow protocol=UDP localport=4001
netsh advfirewall firewall add rule name="Govee LAN 4002" dir=in action=allow protocol=UDP localport=4002
netsh advfirewall firewall add rule name="Govee LAN 4003" dir=in action=allow protocol=UDP localport=4003
```
4. **Multicast issues on Windows** — If multicast discovery fails (common with dual NICs), add your bulb IPs to `known_devices` in `config.json`. The server will send unicast scan packets directly to those IPs as a fallback.
5. **Bulb not powered on** — The bulb must have physical power (wall switch on). The Govee "off" state means the LED is off, but the WiFi radio is still active.
6. **Different subnet** — The bulb and PC must be on the same subnet (same WiFi network, same IP range like 10.0.0.x).
### Commands sent but bulb doesn't respond
- The Govee LAN protocol is fire-and-forget UDP — there's no acknowledgment. If a command doesn't take effect, the packet may have been lost or the bulb may have gone idle on the LAN.
- Run `keepalive.py` in the background to prevent bulbs from idling out.
- Check that `interface` in `config.json` matches your WiFi adapter IP.
- Set `"log_level": "DEBUG"` in `config.json` and restart the server to see every packet it sends.
### Bulb's IP changed
Set a DHCP reservation in your router so the bulb always gets the same IP. Then update `config.json` (and delete the old line from `device_cache.json` if the hardware also changed). Restart the server.
### Claude hallucinates light changes
Some models will write "Your room is now blue!" without actually calling the tool. Add the anti-hallucination snippet from [Recommended system prompt snippet](#recommended-system-prompt-snippet) to your bot's system prompt, placed near the tool descriptions for maximum salience.
### Port 4002 already in use
Another instance of the server (or another Govee controller like Home Assistant) may be using port 4002. Only one listener can bind to this port at a time. Stop the other process first. `keepalive.py` is safe to run alongside the server — it degrades to fire-and-forget mode automatically when it can't bind.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
markitdown
Python tool for converting files and office documents to Markdown.
OpenAI Whisper
OpenAI Whisper MCP Server - 基于本地 Whisper CLI 的离线语音识别与翻译,无需 API Key,支持...
oh-my-opencode
Background agents · Curated agents like oracle, librarians, frontend...
claude-flow
Claude-Flow v2.7.0 is an enterprise AI orchestration platform.
ai-engineering-from-scratch
Learn it. Build it. Ship it for others. The most comprehensive open-source...
chatbox
User-friendly Desktop Client App for AI Models/LLMs (GPT, Claude, Gemini, Ollama...)