MCP server for controlling a Philips Hue bridge via the local CLIP v2 API
HueMCP demonstrates solid tool design with clear naming (verb_noun pattern), comprehensive descriptions (avg 180 chars), and well-structured JSON schemas. All 8 tools have input schemas with typed parameters and descriptions. However, output schemas are not formally documented, responses are inferred from code summaries. Error handling is basic (try/except wrapper returning {ok: false, error: str(e)}), lacking recovery guidance. No tool annotations (readOnlyHint/destructiveHint) despite clear read/write distinction. Parameter descriptions are strong but could benefit from explicit constraints (e.g., brightness 0-100 is stated in description but not as JSON Schema minmax). Overall: production-ready for a smart-home domain tool, but lacks polish for enterprise use.
Activate a scene in a group (room or zone). Use `list_scenes(group_id)` to discover scenes for a given group.
Generic escape hatch — fetch a Hue resource by type, optionally by id. `rtype` is a CLIP v2 resource type, e.g. `light`, `room`, `zone`, `scene`, `grouped_light`, `device`, `bridge`, `motion`, `temperature`, `button`, `behavior_instance`, `smart_scene`. Returns the raw bridge payload — useful when you need fields the higher-level tools don't expose.
List every light on the bridge with on/off state, brightness, colour, and owner. `owner.rid` points to the parent device — useful when one device exposes multiple light services. To find which room a light belongs to, cross-reference the device id against `list_rooms()` `children`.
List rooms with their `grouped_light_id` (use with `set_group`) and member devices.
List scenes. If `group_id` is given (a room or zone id), only scenes targeting that group are returned. Use the returned `id` with `activate_scene`.
Output schemas not formally documented. Code infers response structure (e.g., {lights: [...], rooms: [...]}), but no JSON Schema definitions provided for LLM to understand return types. Agents cannot reliably extract fields for downstream calls.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). set_light, set_group, activate_scene are write operations but lack destructiveHint. Read-only tools lack readOnlyHint. Agents cannot distinguish safe from risky calls without reading descriptions.
Error handling is minimal. All errors return {ok: false, error: str(e)}, which is opaque to LLMs. No recovery guidance (e.g., 'Light not found. Call list_lights() to discover valid IDs'). No error categorization (retryable vs user-fixable).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 65 | 2026-07-28+ | v2 |
List zones with their `grouped_light_id` (use with `set_group`) and member lights. Zones differ from rooms: a light belongs to exactly one room but can be in many zones (e.g. a "Downstairs" zone spanning Kitchen + Living room).
Update a group (room or zone). Pass only the attributes you want to change. Use `list_rooms()` or `list_zones()` to get group ids. The `grouped_light_id` from those tools is what you pass here.
Update one light. Pass only the attributes you want to change. Use `list_lights()` to discover what each light supports — it returns `effects.available`, `timed_effects.available`, and (for gradient strips) a `gradient` block with `points_capable` and `mode_values`. - `brightness` is 0–100 (percent). Setting brightness on an off light does NOT turn it on; pass `on=True` as well. - `color_temp_mirek` is the CIE mired value; the per-light valid range is reported by `list_lights()` as `color_temp_range_mirek` (commonly 153–500, i.e. ~6500K–2000K). Setting this clears any active colour. - `color_xy` is a 2-element list `[x, y]` in CIE 1931 colour space, clamped to the light's gamut. Setting this clears any active colour temperature. - `effect` is one of the values from `effects.available` (e.g. `no_effect`, `candle`, `fire`, `prism`, `sparkle`, `opal`, `glisten`). Pass `no_effect` to stop a running effect. - `gradient_points` is a list of `[x, y]` CIE 1931 points (typically 2–5, capped by the light's `gradient.points_capable`). Only meaningful for gradient-capable strips like the Hue Play Gradient lightstrip. - `gradient_mode` is one of the light's `gradient.mode_values` — `interpolated_palette` (default smooth blend), `interpolated_palette_mirrored`, `random_pixelated`, or `segmented_palette`. - `timed_effect` is `sunrise`, `sunset`, or `no_effect`. Use `timed_effect_duration_ms` to set how long the effect runs.
Parameter constraints stated in descriptions but not enforced in JSON Schema. E.g., brightness '0-100 (percent)' is text, not minmax. color_xy is array but no length constraint (should be exactly 2). Agents cannot validate before calling.
get_resource is a generic escape hatch with free-form rtype parameter. No enum constraint on valid resource types. Description lists examples (light, room, zone, ...) but LLM could hallucinate invalid types. Should be enum: [light, room, zone, scene, grouped_light, device, bridge, motion, temperature, button, behavior_instance, smart_scene].