Loading...
Loading...
Control Home Assistant smart home devices through AI assistants using the Model Context Protocol
npx skill4agent add aradotso/mcp-skills homeassistant-mcp-serverSkill by ara.so — MCP Skills collection
{
"mcpServers": {
"homeassistant": {
"command": "uvx",
"args": ["homeassistant-mcp"],
"env": {
"HASS_HOST": "http://homeassistant.local:8123",
"HASS_TOKEN": "your_long_lived_access_token_here"
}
}
}
}pip install homeassistant-mcpexport HASS_HOST="http://homeassistant.local:8123"
export HASS_TOKEN="your_token_here"
homeassistant-mcpgit clone https://github.com/robbrad/homeassistant-mcp.git
cd homeassistant-mcp
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev]"
homeassistant-mcp| Variable | Description | Example |
|---|---|---|
| Home Assistant URL | |
| Long-lived access token | Generate from HA profile page |
| Variable | Default | Description |
|---|---|---|
| | Cache TTL for bulk state queries (seconds) |
| | Cache TTL for individual entity queries (seconds) |
| | Logging level (DEBUG, INFO, WARNING, ERROR) |
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"homeassistant": {
"command": "uvx",
"args": ["homeassistant-mcp"],
"env": {
"HASS_HOST": "http://homeassistant.local:8123",
"HASS_TOKEN": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
}
}
}.cursor/mcp.json{
"mcpServers": {
"homeassistant": {
"command": "uvx",
"args": ["homeassistant-mcp"],
"env": {
"HASS_HOST": "${HASS_HOST}",
"HASS_TOKEN": "${HASS_TOKEN}"
}
}
}
}# 1. Discover all available tools
discover_tools()
# Returns: Full catalog of 40 tools organized by category
# 2. Search for specific tools by description
search_tools(query="lights brightness")
# Returns: BM25-ranked tool schemas matching query
# 3. Call a discovered tool by name
call_tool(tool_name="lights_control", arguments={...})
# Executes the specified tool with given arguments# Step 1: Discover what tools are available
tools = discover_tools()
# Returns categories: Device Control, Automation & Scenes, Input Helpers, etc.
# Step 2: Search for specific functionality
results = search_tools(query="control lights and brightness")
# Returns: lights_control schema with full parameters
# Step 3: Use the tool directly
lights_control(
action="turn_on",
entity_id="light.living_room",
brightness=80,
color_temp=370
)# Turn on lights with brightness and color
lights_control(
action="turn_on",
entity_id="light.bedroom",
brightness=100, # 0-100
rgb_color=[255, 0, 0] # Red
)
# Set color temperature
lights_control(
action="turn_on",
entity_id="light.kitchen",
color_temp=370 # Warm white (153-500 mireds)
)
# Turn off
lights_control(action="turn_off", entity_id="light.bedroom")
# Bulk operations
lights_control(
action="turn_on",
entity_id="light.all_lights",
brightness=50
)# Set temperature and mode
climate_control(
action="set_temperature",
entity_id="climate.living_room",
temperature=22, # Celsius
hvac_mode="heat" # Options: heat, cool, auto, off, heat_cool
)
# Set fan mode
climate_control(
action="set_fan_mode",
entity_id="climate.bedroom",
fan_mode="auto" # Options: auto, low, medium, high
)
# Get current state
climate_control(action="get", entity_id="climate.living_room")# Set position
cover_control(
action="set_position",
entity_id="cover.garage_door",
position=50 # 0-100 (0=closed, 100=open)
)
# Open/close
cover_control(action="open", entity_id="cover.living_room_blinds")
cover_control(action="close", entity_id="cover.bedroom_blinds")
# Set tilt
cover_control(
action="set_tilt",
entity_id="cover.venetian_blinds",
tilt=45
)# Lock/unlock
lock_control(action="lock", entity_id="lock.front_door")
lock_control(action="unlock", entity_id="lock.back_door", code="1234")
# Get state
lock_control(action="get", entity_id="lock.front_door")# Play/pause/stop
media_player_control(action="play", entity_id="media_player.living_room_tv")
media_player_control(action="pause", entity_id="media_player.spotify")
# Volume control
media_player_control(
action="volume_set",
entity_id="media_player.speakers",
volume=0.5 # 0.0-1.0
)
# Select source
media_player_control(
action="select_source",
entity_id="media_player.receiver",
source="HDMI 1"
)# Start cleaning
vacuum_control(action="start", entity_id="vacuum.roborock")
# Return to dock
vacuum_control(action="dock", entity_id="vacuum.roborock")
# Set fan speed
vacuum_control(
action="set_fan_speed",
entity_id="vacuum.roborock",
fan_speed="turbo"
)# List all entities
states_control(action="list")
# List entities by domain
states_control(action="list", domain="light")
# Get specific entity
states_control(action="get", entity_id="sensor.temperature")
# Set entity state
states_control(
action="set",
entity_id="sensor.custom_sensor",
state="active",
attributes={"battery": 95}
)
# Delete entity state
states_control(action="delete", entity_id="sensor.old_sensor")# List all devices
list_devices()
# Filter by domain
list_devices(domain="light")
# Filter by area
list_devices(area="living_room")
# Filter by floor
list_devices(floor="ground_floor")
# Combine filters
list_devices(domain="switch", area="bedroom")# Call any Home Assistant service directly
call_service(
domain="light",
service="turn_on",
service_data={
"entity_id": "light.bedroom",
"brightness": 80,
"rgb_color": [255, 120, 0]
}
)
# Notify service
call_service(
domain="notify",
service="mobile_app_phone",
service_data={
"message": "Motion detected in garage",
"title": "Security Alert"
}
)
# TTS service
call_service(
domain="tts",
service="google_translate_say",
service_data={
"entity_id": "media_player.kitchen_speaker",
"message": "Dinner is ready"
}
)# List all automations
automation_control(action="list")
# Trigger automation
automation_control(action="trigger", automation_id="automation.morning_routine")
# Enable/disable
automation_control(action="enable", automation_id="automation.night_mode")
automation_control(action="disable", automation_id="automation.away_mode")
# Reload automations
automation_control(action="reload")# List scenes
scene_control(action="list")
# Activate scene
scene_control(action="activate", scene_id="scene.movie_time")# List scripts
script_control(action="list")
# Execute script with variables
script_control(
action="execute",
script_id="script.notification_routine",
variables={"message": "Door left open", "priority": "high"}
)
# Reload scripts
script_control(action="reload")# Render Jinja2 templates
template_render(
template="{{ states('sensor.temperature') | float + 5 }}"
)
# Complex template with entity states
template_render(
template="""
{% set lights = states.light | selectattr('state', 'eq', 'on') | list %}
{{ lights | length }} lights are currently on
"""
)# Get entity history (last N hours)
history_query(
entity_id="sensor.temperature",
hours=24
)
# Get logbook entries
logbook_query(
entity_id="binary_sensor.front_door",
hours=12
)
# Get error log summary (parsed and deduplicated)
error_log_get()# List all calendars
calendar_access(action="list")
# Get events for date range
calendar_access(
action="get_events",
calendar_id="calendar.family",
start_date="2024-05-01",
end_date="2024-05-31"
)# Get camera snapshot
camera_proxy_get(
entity_id="camera.front_door",
width=640,
height=480
)
# Enable motion detection
camera_control(
action="enable_motion_detection",
entity_id="camera.garage"
)
# Take snapshot
camera_control(
action="snapshot",
entity_id="camera.backyard",
filename="/config/www/snapshots/backyard.jpg"
)# Access entity state and attributes
# URI: hass://entity/{entity_id}
hass://entity/light.living_room
# Returns: {"state": "on", "attributes": {"brightness": 100, ...}}# Get all entities in an area (compact summaries)
# URI: hass://area/{area_id}
hass://area/living_room
# Returns: List of entities with state and key attributes# Get all entities for a device (compact summaries)
# URI: hass://device/{device_id}
hass://device/abc123def456
# Returns: Device entities with states# Get all available services organized by domain
# URI: hass://services
hass://services
# Returns: All service definitions with parameters# Get entity history with pagination
# URI: hass://entity/{entity_id}/history?hours=24&limit=100
hass://entity/sensor.temperature/history?hours=24
# Returns: Paginated history with state changes# 1. Discover automation tools
tools = discover_tools()
# 2. Create morning scene
scene_control(action="activate", scene_id="scene.morning")
# 3. Set climate
climate_control(
action="set_temperature",
entity_id="climate.bedroom",
temperature=21,
hvac_mode="heat"
)
# 4. Open blinds
cover_control(action="open", entity_id="cover.bedroom_blinds")
# 5. Turn on lights gradually
lights_control(
action="turn_on",
entity_id="light.bedroom",
brightness=30,
transition=60 # Seconds
)# Check all locks
locks = list_devices(domain="lock")
for lock in locks:
state = lock_control(action="get", entity_id=lock["entity_id"])
if state["state"] == "unlocked":
send_notification(
message=f"{lock['name']} is unlocked!",
title="Security Alert"
)
# Check door sensors
doors = list_devices(domain="binary_sensor", area="entry")
for door in doors:
if "door" in door["entity_id"]:
state = states_control(action="get", entity_id=door["entity_id"])
# Process door states# Turn off unused devices
lights = states_control(action="list", domain="light")
for light in lights:
if light["state"] == "on":
# Check if anyone home using presence sensors
presence = states_control(action="get", entity_id="binary_sensor.occupancy")
if presence["state"] == "off":
lights_control(action="turn_off", entity_id=light["entity_id"])
# Optimize climate
climate_control(
action="set_temperature",
entity_id="climate.all",
temperature=19, # Lower when away
hvac_mode="heat"
)# Dim lights
lights_control(
action="turn_on",
entity_id="light.media_room",
brightness=10,
rgb_color=[255, 100, 0]
)
# Close blinds
cover_control(action="close", entity_id="cover.media_room_blinds")
# Start media player
media_player_control(
action="select_source",
entity_id="media_player.tv",
source="Netflix"
)
media_player_control(action="play", entity_id="media_player.tv")# Only turn on if temperature is low
temp_state = states_control(action="get", entity_id="sensor.temperature")
current_temp = float(temp_state["state"])
if current_temp < 18:
climate_control(
action="set_temperature",
entity_id="climate.living_room",
temperature=22,
hvac_mode="heat"
)
# Turn on lights only if dark
lux_state = states_control(action="get", entity_id="sensor.illuminance")
if float(lux_state["state"]) < 50:
lights_control(action="turn_on", entity_id="light.all_lights")# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=src --cov-report=html# Format code
black src/ tests/
# Lint
ruff check src/ tests/
# Type checking
mypy src/# Clone and setup
git clone https://github.com/robbrad/homeassistant-mcp.git
cd homeassistant-mcp
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
# Create .env file
cat > .env << EOF
HASS_HOST=http://homeassistant.local:8123
HASS_TOKEN=your_token_here
LOG_LEVEL=DEBUG
EOF
# Run server
homeassistant-mcpfrom fastmcp import FastMCP
mcp = FastMCP("homeassistant")
@mcp.tool(
description="Control custom device",
tags=["device", "custom"],
timeout=30.0
)
async def custom_device_control(
action: str,
entity_id: str,
value: int = 0
) -> dict:
"""
Control custom device
Args:
action: Action to perform (on, off, set)
entity_id: Entity ID
value: Optional value parameter
"""
client = get_hass_client()
return await client.call_service(
domain="custom_domain",
service=action,
service_data={"entity_id": entity_id, "value": value}
)# Check API info
api_info()
# Returns HA version, loaded components, and connection status
# Verify host and token
# Ensure HASS_HOST includes protocol (http:// or https://)
# Verify token has not expired# List all entities to find correct entity_id
all_entities = states_control(action="list")
# Search by domain
lights = states_control(action="list", domain="light")
# List devices in area
devices = list_devices(area="bedroom")# List available services
services = services_control(action="list", domain="light")
# Check service schema
schema = services_control(action="get", domain="light", service="turn_on")
# Validate configuration
config_check()# Discover all tools
all_tools = discover_tools()
# Search for specific functionality
matching_tools = search_tools(query="your search query")
# Call tool by name if not directly available
call_tool(tool_name="tool_name", arguments={...})# Adjust cache TTL for more frequent updates
export CACHE_TTL_STATES=5 # 5 seconds instead of default 30
export CACHE_TTL_ENTITY=2 # 2 seconds instead of default 10
# Enable debug logging to see cache hits/misses
export LOG_LEVEL=DEBUG# Get parsed error log with deduplication
errors = error_log_get()
# Returns: Deduplicated errors with component counts and timestampsHASS_TOKENCACHE_TTL_STATESCACHE_TTL_ENTITY