initial commit

This commit is contained in:
Martin 2026-02-10 13:24:32 -05:00
commit 66bce7b869
8 changed files with 639 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# Testing
.pytest_cache/
.coverage
htmlcov/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db

231
README.md Normal file
View File

@ -0,0 +1,231 @@
# MCP Bridge - Home Assistant Integration
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs)
Bridge integration between Home Assistant and MCP (Model Context Protocol) servers, enabling AI agents to control your smart home.
## Features
- 🎯 **Selective Entity Exposure**: Only expose entities you explicitly mark via Voice Assistant settings
- 🔒 **Secure Script Access**: Control which scripts AI can execute using labels
- 📊 **Rich Metadata**: Provides complete entity information including area, device class, and capabilities
- 🔌 **Zero Configuration**: Works out of the box after installation
- 🤖 **AI-Ready**: Designed for MCP servers and AI agent integration
## What is MCP?
MCP (Model Context Protocol) is Anthropic's protocol for connecting AI agents to external tools and data sources. This integration makes your Home Assistant instance accessible to AI agents via MCP servers.
## Installation
### Via HACS (Recommended)
1. **Add Custom Repository**
- Open HACS in Home Assistant
- Click the three dots (⋮) in top right
- Select "Custom repositories"
- Repository: `http://your-gitea-server/username/homeassistant-mcp-bridge`
- Category: **Integration**
- Click "Add"
2. **Install**
- HACS → Integrations
- Click "+ Explore & Download Repositories"
- Search for "MCP Bridge"
- Click "Download"
- Restart Home Assistant
### Manual Installation
1. Copy `custom_components/mcp_bridge` to your Home Assistant config directory
2. Restart Home Assistant
See [INSTALLATION_GUIDE.md](INSTALLATION_GUIDE.md) for detailed instructions.
## Quick Start
### 1. Expose Entities
Go to **Settings → Voice Assistants → Expose** and toggle the entities you want the AI to control.
### 2. Mark Scripts as Accessible
For custom scripts:
1. Go to **Settings → Automations & Scenes → Scripts**
2. Click your script → Settings icon (⚙️)
3. Add label: `mcp_accessible`
4. Save
### 3. Test the Services
**Developer Tools → Services:**
```yaml
service: mcp_bridge.get_exposed_entities
```
```yaml
service: mcp_bridge.get_exposed_scripts
```
## Services
### `mcp_bridge.get_exposed_entities`
Returns all entities exposed to voice assistants with complete metadata.
**Example Response:**
```json
{
"entities": [
{
"entity_id": "light.living_room",
"state": "on",
"friendly_name": "Living Room Light",
"area": "Living Room",
"domain": "light",
"supported_features": 43,
"attributes": {...}
}
],
"count": 1
}
```
### `mcp_bridge.get_exposed_scripts`
Returns scripts marked with `mcp_accessible` label, including their parameters.
**Example Response:**
```json
{
"scripts": [
{
"entity_id": "script.set_fan_speed",
"friendly_name": "Set Fan Speed",
"description": "Control bedroom fan",
"fields": {
"speed": {
"name": "Speed",
"description": "0=off, 1=low, 2=medium, 3=high",
"required": true,
"selector": {"number": {"min": 0, "max": 3}}
}
}
}
],
"count": 1
}
```
### `mcp_bridge.get_entity_metadata`
Get detailed metadata for a specific entity.
**Parameters:**
- `entity_id`: The entity to query
## Architecture
```
AI Agent (Claude/n8n)
MCP Server
mcp_bridge Services
Home Assistant
```
The integration provides three services that MCP servers can call to:
1. Discover available entities
2. Discover available scripts
3. Query entity states and metadata
## Use Cases
- **Voice Control**: "Turn on the living room lights"
- **Automated Scenes**: AI suggests and executes scenes based on context
- **Smart Responses**: "What's the temperature in the bedroom?"
- **Custom Automations**: Execute complex scripts via natural language
## Configuration
No configuration required! The integration automatically loads on Home Assistant restart.
**Optional:** Control which entities/scripts are exposed using:
- Voice Assistant exposure settings (for entities)
- `mcp_accessible` label (for scripts)
## Compatibility
- **Home Assistant**: 2024.1.0 or newer
- **HACS**: Any version
- **Python**: 3.11+
## Documentation
- [Installation Guide](INSTALLATION_GUIDE.md) - Detailed setup instructions
- [Integration README](custom_components/mcp_bridge/README.md) - Technical details
- [Gitea Setup Guide](GITEA_SETUP_GUIDE.md) - For hosting on your own Gitea
## Development
### Running Tests
```bash
pytest custom_components/mcp_bridge/test_init.py
```
### Project Structure
```
homeassistant-mcp-bridge/
├── custom_components/
│ └── mcp_bridge/
│ ├── __init__.py # Core integration logic
│ ├── manifest.json # Integration metadata
│ ├── services.yaml # Service definitions
│ └── README.md # Integration docs
├── hacs.json # HACS configuration
├── info.md # HACS UI description
└── README.md # This file
```
## Contributing
This is a personal project for homelab use, but suggestions and improvements are welcome!
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test thoroughly
5. Submit a pull request
## Roadmap
- [x] Basic entity exposure
- [x] Script discovery with labels
- [x] Complete metadata support
- [ ] Real-time state updates via WebSocket
- [ ] Custom entity tags beyond voice assistant exposure
- [ ] Integration config flow (UI-based setup)
- [ ] Service call history/logging
## License
MIT License - Use freely in your homelab!
## Support
- **Issues**: [Gitea Issues](http://your-gitea-server/username/homeassistant-mcp-bridge/issues)
- **Logs**: Settings → System → Logs (filter by "mcp_bridge")
## Acknowledgments
- Built for use with [Anthropic's MCP](https://modelcontextprotocol.io/)
- Designed to work with n8n workflows
---
**Made with ❤️ for home automation enthusiasts**

View File

@ -0,0 +1,143 @@
# MCP Bridge - Home Assistant Custom Integration
This integration provides services to expose filtered entities and custom scripts to MCP (Model Context Protocol) servers, enabling AI agents to control your Home Assistant instance.
## Installation
### Via HACS (Recommended)
1. **Install HACS** (if not already installed): https://hacs.xyz/docs/setup/download
2. **Add this repository as a custom repository:**
- Open HACS in Home Assistant
- Click the three dots in the top right
- Select "Custom repositories"
- Add your Gitea URL: `http://your-gitea-server/username/homeassistant-mcp-bridge`
- Category: Integration
- Click "Add"
3. **Install the integration:**
- Go to HACS → Integrations
- Click "+ Explore & Download Repositories"
- Search for "MCP Bridge"
- Click "Download"
- Restart Home Assistant
### Manual Installation
1. Copy the `mcp_bridge` folder to your Home Assistant `custom_components` directory:
```
/config/custom_components/mcp_bridge/
```
2. Restart Home Assistant
3. The integration will be automatically loaded (no configuration needed)
## Services
### `mcp_bridge.get_exposed_entities`
Returns all entities that are exposed to voice assistants.
**Returns:**
```json
{
"entities": [...],
"count": 42
}
```
### `mcp_bridge.get_exposed_scripts`
Returns all custom scripts marked with the `mcp_accessible` label.
**Returns:**
```json
{
"scripts": [...],
"count": 1
}
```
### `mcp_bridge.get_entity_metadata`
Get detailed metadata for a specific entity.
**Parameters:**
- `entity_id` (required): The entity to query
**Returns:**
```json
{
"entity_id": "light.living_room",
"state": "on",
...
}
```
## Usage
### Exposing Entities to AI Agent
1. Go to Settings → Voice Assistants → Expose
2. Toggle entities you want the AI agent to control
3. These entities will be returned by `mcp_bridge.get_exposed_entities`
### Exposing Scripts to AI Agent
1. Create your custom script in HA
2. Add the label `mcp_accessible` to the script:
- Go to Settings → Automations & Scenes → Scripts
- Click on your script
- Click the settings icon (top right)
- Under "Labels", add `mcp_accessible`
3. The script will now be returned by `mcp_bridge.get_exposed_scripts`
## Example: Marking a Script as MCP-Accessible
```yaml
# In your scripts.yaml or via UI
set_master_bedroom_fan_speed:
alias: "Set Master Bedroom Fan Speed"
description: "[MCP] Set the speed of the master bedroom fan."
# Add label via UI: Settings → Scripts → (your script) → Labels → mcp_accessible
fields:
fan_state:
name: Fan speed
description: "0=off, 1=low, 2=medium, 3=high"
required: true
selector:
number:
min: 0
max: 3
step: 1
sequence:
# Your script actions here
```
## Testing
You can test the services in Home Assistant's Developer Tools → Services:
1. Select `mcp_bridge.get_exposed_entities`
2. Click "Call Service"
3. View the response in the "Response" tab
## Troubleshooting
**No entities returned:**
- Make sure you've exposed entities via Settings → Voice Assistants → Expose
**No scripts returned:**
- Ensure your scripts have the `mcp_accessible` label
- Check Home Assistant logs for errors: Settings → System → Logs
**Integration not loading:**
- Check the logs for errors
- Ensure the folder structure is correct
- Restart Home Assistant
## Version
0.1.0 - Initial release

View File

@ -0,0 +1,171 @@
"""MCP Bridge integration for Home Assistant.
This integration provides services to expose filtered entities and scripts
to MCP (Model Context Protocol) servers for AI agent control.
"""
import logging
from typing import Any
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.typing import ConfigType
from homeassistant.const import CONF_ENTITY_ID
_LOGGER = logging.getLogger(__name__)
DOMAIN = "mcp_bridge"
# Label to mark scripts as MCP-accessible
MCP_ACCESSIBLE_LABEL = "mcp_accessible"
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the MCP Bridge integration."""
_LOGGER.info("Setting up MCP Bridge integration")
async def get_exposed_entities(call: ServiceCall) -> dict[str, Any]:
"""Get all entities exposed to voice assistants."""
entity_reg = er.async_get(hass)
exposed_entities = []
# Iterate through all entities
for entity_id, state in hass.states.async_all():
entity_entry = entity_reg.async_get(entity_id)
# Check if entity is exposed to conversation (voice assistant)
if entity_entry and entity_entry.options.get("conversation", {}).get("should_expose", False):
# Get area name if available
area_name = None
if entity_entry.area_id:
area_reg = hass.helpers.area_registry.async_get(hass)
area = area_reg.async_get_area(entity_entry.area_id)
if area:
area_name = area.name
# Build entity data
entity_data = {
"entity_id": entity_id,
"state": state.state,
"friendly_name": state.attributes.get("friendly_name", entity_id),
"area": area_name,
"domain": entity_id.split(".")[0],
"device_class": state.attributes.get("device_class"),
"supported_features": state.attributes.get("supported_features", 0),
"last_changed": state.last_changed.isoformat(),
"last_updated": state.last_updated.isoformat(),
"attributes": dict(state.attributes)
}
exposed_entities.append(entity_data)
_LOGGER.debug(f"Found {len(exposed_entities)} exposed entities")
return {
"entities": exposed_entities,
"count": len(exposed_entities)
}
async def get_exposed_scripts(call: ServiceCall) -> dict[str, Any]:
"""Get all scripts marked as MCP-accessible."""
entity_reg = er.async_get(hass)
exposed_scripts = []
# Get all script entities
for entity_id in hass.states.async_entity_ids("script"):
entity_entry = entity_reg.async_get(entity_id)
# Check if script has the mcp_accessible label
if entity_entry and MCP_ACCESSIBLE_LABEL in entity_entry.labels:
state = hass.states.get(entity_id)
if not state:
continue
# Get script attributes
script_data = {
"entity_id": entity_id,
"friendly_name": state.attributes.get("friendly_name", entity_id),
"description": state.attributes.get("description", ""),
"fields": state.attributes.get("fields", {}),
}
exposed_scripts.append(script_data)
_LOGGER.debug(f"Found {len(exposed_scripts)} exposed scripts")
return {
"scripts": exposed_scripts,
"count": len(exposed_scripts)
}
async def get_entity_metadata(call: ServiceCall) -> dict[str, Any]:
"""Get detailed metadata for a specific entity."""
entity_id = call.data.get(CONF_ENTITY_ID)
if not entity_id:
_LOGGER.error("entity_id not provided")
return {"error": "entity_id required"}
entity_reg = er.async_get(hass)
entity_entry = entity_reg.async_get(entity_id)
state = hass.states.get(entity_id)
if not state:
_LOGGER.error(f"Entity {entity_id} not found")
return {"error": f"Entity {entity_id} not found"}
# Get area name if available
area_name = None
if entity_entry and entity_entry.area_id:
area_reg = hass.helpers.area_registry.async_get(hass)
area = area_reg.async_get_area(entity_entry.area_id)
if area:
area_name = area.name
metadata = {
"entity_id": entity_id,
"state": state.state,
"friendly_name": state.attributes.get("friendly_name", entity_id),
"area": area_name,
"domain": entity_id.split(".")[0],
"device_class": state.attributes.get("device_class"),
"supported_features": state.attributes.get("supported_features", 0),
"last_changed": state.last_changed.isoformat(),
"last_updated": state.last_updated.isoformat(),
"attributes": dict(state.attributes)
}
if entity_entry:
metadata["labels"] = list(entity_entry.labels)
metadata["is_exposed_to_conversation"] = entity_entry.options.get(
"conversation", {}
).get("should_expose", False)
return metadata
# Register services
hass.services.async_register(
DOMAIN,
"get_exposed_entities",
get_exposed_entities,
schema=None
)
hass.services.async_register(
DOMAIN,
"get_exposed_scripts",
get_exposed_scripts,
schema=None
)
hass.services.async_register(
DOMAIN,
"get_entity_metadata",
get_entity_metadata,
schema=None
)
_LOGGER.info("MCP Bridge services registered successfully")
return True

View File

@ -0,0 +1,11 @@
{
"domain": "mcp_bridge",
"name": "MCP Bridge",
"documentation": "https://www.git.quarantinedstudio.com/mvezina/homeassistant-mcp-bridge",
"issue_tracker": "https://www.git.quarantinedstudio.com/mvezina/homeassistant-mcp-bridge/issues",
"requirements": [],
"codeowners": [],
"version": "0.1.0",
"iot_class": "local_polling",
"config_flow": false
}

View File

@ -0,0 +1,21 @@
get_exposed_entities:
name: Get Exposed Entities
description: Returns all entities exposed to voice assistants with full metadata.
fields: {}
get_exposed_scripts:
name: Get Exposed Scripts
description: Returns all custom scripts marked as MCP-accessible (with mcp_accessible label).
fields: {}
get_entity_metadata:
name: Get Entity Metadata
description: Get detailed metadata for a specific entity.
fields:
entity_id:
name: Entity ID
description: The entity ID to get metadata for
required: true
example: "light.living_room"
selector:
entity:

6
hacs.json Normal file
View File

@ -0,0 +1,6 @@
{
"name": "MCP Bridge",
"content_in_root": false,
"render_readme": true,
"homeassistant": "2024.1.0"
}

35
info.md Normal file
View File

@ -0,0 +1,35 @@
# MCP Bridge
Bridge integration between Home Assistant and MCP (Model Context Protocol) servers for AI agent control.
## Features
- ✅ Expose entities to AI agents via voice assistant settings
- ✅ Control which scripts are accessible using labels
- ✅ Complete entity metadata including area, device class, and attributes
- ✅ Secure: Only exposes what you explicitly mark
## Services
- `mcp_bridge.get_exposed_entities` - Get all exposed entities
- `mcp_bridge.get_exposed_scripts` - Get MCP-accessible scripts
- `mcp_bridge.get_entity_metadata` - Get detailed entity info
## Configuration
No configuration needed! The integration auto-loads after installation.
### Exposing Entities
Go to: **Settings → Voice Assistants → Expose**
Toggle the entities you want the AI agent to control.
### Exposing Scripts
1. Create or edit a script
2. Click the settings icon ⚙️
3. Add the label: `mcp_accessible`
4. Save
That's it! The script is now accessible to AI agents.