Labsco
marcinn2 logo

GREE MCP Server

β˜… 1

from marcinn2

LAN-local MCP server for controlling GREE / EWPE WiFi air conditioners over their native UDP protocol. No cloud. stdio + HTTP transports.

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeAdvanced setup

gree-ac-mcp-server

A Model Context Protocol (MCP) server that controls GREE / EWPE-compatible WiFi air conditioners directly over their native UDP protocol. No Homebridge, no cloud β€” it talks straight to the units on your LAN.

The GREE wire protocol (AES encryption, scan/bind/status/command flow) is implemented from scratch based on eibenp/homebridge-gree-airconditioner and tomikaa87/gree-remote.

  • Two transports: MCP stdio (for Claude Desktop and other local clients) and http (modern Streamable HTTP and legacy HTTP+SSE), with mandatory bearer auth on HTTP.
  • Both encryption schemes: v1 (AES-128-ECB) and v2 (AES-128-GCM), auto-detected per device.
  • Background polling: each device is bound and polled continuously; tool calls fire immediately and the next poll confirms the new state.

CLI flags

FlagDefaultDescription
--transport <stdio|http>stdioTransport mode.
--config <path>$GREE_MCP_CONFIGPath to the config file (required).
--host <host>0.0.0.0HTTP bind host (http mode). Overrides config.
--port <port>8080HTTP bind port (http mode). Overrides config.
--log-level <debug|info|warn|error>infoLog verbosity (JSON lines on stderr).

The config file path may also be supplied via the GREE_MCP_CONFIG environment variable.


MCP tools

Every tool accepts a device selector: mac (canonical) or name (alias, matched against config). Provide one of them. set_* tools fire the UDP command immediately and report "command sent"; the background poll loop confirms the new state shortly after. If a device is offline/unbound, write tools return an error instead of silently succeeding.

ToolInput schemaDescription
list_devices{}All configured devices with online/bound status and last-known mode/temp.
get_device_status{ mac?, name? }Full decoded status of one device.
get_room_temperature{ mac?, name? }Calibrated current temp (Β°C). Flags estimated: true when derived via fakeSensor.
set_power{ mac?, name?, on: boolean }Turn the unit on/off.
set_mode{ mac?, name?, mode: "auto"|"cool"|"dry"|"fan"|"heat" }Set mode (also powers on).
set_target_temperature{ mac?, name?, temperature: number }Set target Β°C. Rejected (not clamped) if out of the device's min/max range.
set_fan_speed{ mac?, name?, speed: "auto"|"quiet"|"low"|"medium-low"|"medium"|"medium-high"|"high"|"turbo" }Set fan speed; quiet/turbo engage dedicated modes; mapped down on 3-speed units.
set_oscillation{ mac?, name?, on: boolean }Apply the configured on/off swing positions.
set_xfan{ mac?, name?, on: boolean }X-Fan / blow. Only usable when xFan: true.
set_light{ mac?, name?, on: boolean }Display light. Only usable when lightControl: true.
set_quiet_mode{ mac?, name?, on: boolean }Quiet mode (turning on disables turbo).
set_turbo_mode{ mac?, name?, on: boolean }Turbo/powerful mode (turning on disables quiet).

Each device is also exposed as a resource at gree://device/<mac> returning its decoded status as JSON.


Using with Claude Desktop (stdio)

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "gree-ac": {
      "command": "node",
      "args": [
        "/absolute/path/to/gree-ac-mcp-server/dist/index.js",
        "--transport", "stdio",
        "--config", "/absolute/path/to/config.json"
      ]
    }
  }
}

No bearer token is needed in stdio mode (the process pipe is the trust boundary).


Docker

The image is multi-stage and runs as the non-root node user, defaulting to HTTP mode reading /config/config.json.

docker build -t gree-ac-mcp-server .
docker run --rm \
  --network host \
  -v "$(pwd)/config.json:/config/config.json:ro" \
  gree-ac-mcp-server

UDP discovery/broadcast needs L2 access to the AC's subnet. --network host is the simplest way to give the container that on Linux; otherwise set each device's address explicitly and ensure UDP/7000 routing to the units works from the container network.

The container EXPOSEs 8080. Override the entrypoint args to change transport/port, e.g. docker run ... gree-ac-mcp-server --transport http --config /config/config.json --port 9000.


Logging & security

  • Logs are JSON lines on stderr (stdout is reserved for the MCP channel in stdio mode), including device mac, action, and outcome.
  • The bearer token and all AES/device keys are never logged.
  • Logs contain device identifiers (mac, IP address). When running as a long-lived service (systemd, Docker, etc.), cap retention with normal log rotation so these don't accumulate indefinitely. Keep the default --log-level info; debug logs more identifiers.
  • HTTP mode uses plaintext bearer auth. Run it only on a trusted home LAN, or put a TLS-terminating reverse proxy (Caddy, nginx, …) in front of it β€” otherwise the token and request data are exposed in transit. stdio mode has no network exposure.

This is a self-hosted, personal/household tool with no analytics, no third-party services, and no on-disk data persistence (device state is kept in memory only). Configuration β€” including your bearerToken and device MACs β€” lives in your local config.json, which .gitignore already excludes from version control.

Testing

npm test

Covers the protocol crypto (v1/v2 encrypt-decrypt round-trips and a known-answer vector, plus envelope pack/unpack) and config-schema validation (defaults, MAC normalization, interval inheritance, duplicate-MAC and bad-value rejection).

Project layout

src/
  index.ts            entrypoint: CLI args, config load, lifecycle
  config.ts           zod schema, validation, defaults
  logger.ts           JSON-lines logger (stderr)
  gree/
    protocol.ts       AES v1/v2 + pack envelope
    commands.ts       field codes, value maps, swing maps
    device.ts         GreeDevice: scan/bind/poll/command state machine
    manager.ts        DeviceManager: registry, resolve, health summary
    types.ts          shared types
  mcp/
    server.ts         McpServer construction
    tools.ts          tool handlers
    resources.ts      per-device resources
  transport/
    stdio.ts          stdio transport
    http.ts           Streamable HTTP + legacy SSE + /healthz
  auth/
    bearer.ts         bearer-token middleware

Out of scope

  • No GCloud-bridged / sub-device (bridge) topology. The reference plugin supports devices behind a bridge (mac@bridgemac); this server intentionally targets directly-addressable WiFi units only. TODO: add bridge/sub-device discovery and the subDev/sublist handshake if needed.
  • No web UI.

Disclaimer

This is an independent, unofficial project. It is not affiliated with, endorsed by, or supported by GREE Electric Appliances Inc. or any of its subsidiaries. "GREE" and any related trademarks belong to their respective owners and are used here only to describe compatibility.

I built this in my free time and maintain it as a personal hobby project. It is provided as-is, without any warranty; use it at your own risk. It controls real heating/cooling hardware, so test carefully in your own environment.

GDPR / data protection

This is a self-hosted, personal/household tool. It runs entirely on your own machine/LAN, has no analytics or third-party services, makes no external network calls, and persists nothing to disk (device state is kept in memory; your bearerToken and device MACs live only in your local config.json). The only personal-data-adjacent values it handles are device identifiers (MAC and LAN IP addresses), which may appear in logs.

Used for your own home, this typically falls under the GDPR "purely personal or household activity" exemption (Art. 2(2)(c), Recital 18), meaning the GDPR generally does not apply. If you instead deploy it in a context where you process other people's data (e.g. a workplace, rental property, or any commercial setting), you are the data controller and are solely responsible for your own GDPR compliance, including transport security, log retention, transparency, and any required legal basis.

Any compliance commentary, scan, or assessment associated with this project is a preliminary, informational aid only β€” it is not legal advice and is not a substitute for a qualified legal audit. The authors accept no liability for how the software is deployed or used.