Compare commits

..

1 Commits

Author SHA1 Message Date
jango-blockchained
ce4e92502a Enhance terminal output with descriptive logging and formatting 2024-12-17 15:29:39 +01:00
7 changed files with 168 additions and 297 deletions

View File

@@ -1,6 +1,3 @@
NODE_ENV=development
HASS_HOST=http://homeassistant.local:8123
NODE_ENV=production
HASS_HOST=your_home_assistant_url
HASS_TOKEN=your_home_assistant_token
PORT=3000
HASS_SOCKET_URL=ws://homeassistant.local:8123/api/websocket
LOG_LEVEL=debug

109
README.md
View File

@@ -1,31 +1,7 @@
# Model Context Protocol Server for Home Assistant
*Forked from [tevonsb/homeassistant-mcp](https://github.com/tevonsb/homeassistant-mcp)*
A powerful bridge between your Home Assistant instance and Language Learning Models (LLMs), enabling natural language control and monitoring of your smart home devices through the Model Context Protocol (MCP).
![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Node.js](https://img.shields.io/badge/node-%3E%3D20.10.0-green.svg)
![Docker Compose](https://img.shields.io/badge/docker-compose-%3E%3D1.27.0-blue.svg)
![NPM](https://img.shields.io/badge/npm-%3E%3D7.0.0-orange.svg)
## Table of Contents
- [Key Features](#key-features)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Basic Setup](#basic-setup)
- [Docker Setup (Recommended)](#docker-setup-recommended)
- [Configuration](#configuration)
- [Development](#development)
- [Supported Commands](#supported-commands)
- [Natural Language Integration](#natural-language-integration)
- [Troubleshooting](#troubleshooting)
- [Project Status](#project-status)
- [Contributing](#contributing)
- [Resources](#resources)
- [License](#license)
## Key Features
- **Smart Device Control** 🎮
@@ -45,10 +21,9 @@ A powerful bridge between your Home Assistant instance and Language Learning Mod
## Prerequisites
- **Node.js** 20.10.0 or higher
- **NPM** package manager
- **Docker Compose** for containerization
- Running **Home Assistant** instance
- Node.js 20.10.0 or higher
- NPM package manager
- Running Home Assistant instance
- Home Assistant long-lived access token ([How to get token](https://community.home-assistant.io/t/how-to-get-long-lived-access-token/162159))
## Installation
@@ -67,42 +42,34 @@ npm install
npm run build
```
### Docker Setup
### Docker Setup (Recommended)
> Note: This setup is currently in progress. You can use the `docker` branch to get the latest changes.
1. Clone and prepare:
```bash
git clone https://github.com/jango-blockchained/homeassistant-mcp.git
cd homeassistant-mcp
```
1. **Clone and prepare:**
```bash
git clone -b docker https://github.com/jango-blockchained/homeassistant-mcp.git
cd homeassistant-mcp
cp .env.example .env
```
2. Configure environment:
```env
NODE_ENV=production
HASS_HOST=your_home_assistant_url
HASS_TOKEN=your_home_assistant_token
```
2. **Configure environment `.env` file:**
```env
...
HASS_TOKEN=your_home_assistant_token
...
```
3. **Launch with Docker Compose:**
```bash
docker-compose up -d
```
3. Launch with Docker Compose:
```bash
docker-compose up -d
```
## Configuration
Copy `.env.example` to `.env`.
Create a `.env` file with:
```bash
cp .env.example .env
```
Configure environment `.env` file:
```env
...
HASS_TOKEN=your_home_assistant_token
...
HASS_HOST=your_home_assistant_url # e.g., http://homeassistant.local:8123
PORT=3000 # Optional, defaults to 3000
```
## Development
@@ -111,7 +78,7 @@ HASS_TOKEN=your_home_assistant_token
npm run dev # Development mode
npm run build # Build project
npm run start # Production mode
npx jest --config=jest.config.cjs # Run tests
npx jest --config=jest.config.js # Run tests
```
## Supported Commands
@@ -253,14 +220,14 @@ npx jest --config=jest.config.cjs # Run tests
## Troubleshooting
### Common Issues
1. **Node.js Version (`toSorted is not a function`)**
- **Solution:** Update to Node.js 20.10.0+
2. **Connection Issues**
1. Node.js Version (`toSorted is not a function`)
- Solution: Update to Node.js 20.10.0+
2. Connection Issues
- Verify Home Assistant is running
- Check `HASS_HOST` accessibility
- Check HASS_HOST accessibility
- Validate token permissions
3. **Entity Control Issues**
- Verify `entity_id` exists
3. Entity Control Issues
- Verify entity_id exists
- Check entity domain matches command
- Ensure parameter values are valid
@@ -271,27 +238,11 @@ npx jest --config=jest.config.cjs # Run tests
- Device control (Lights, Climate, Covers, Switches, Contacts)
- Basic state management
- Error handling and validation
- Docker containerization and configuration
- Jest testing setup and TypeScript integration
- Environment variable management
- Home Assistant API integration
- Project documentation and README organization
🚧 **In Progress**
- Custom prompt testing and optimization
- Custom prompt testing
- Resource context integration
- Tool organization optimization
- Enhanced macOS integration
- Type safety improvements
- Testing coverage expansion
🔜 **Planned**
- Multi-platform desktop integration
- Advanced error recovery mechanisms
- Performance optimization
- WebSocket implementation for real-time updates
- Enhanced security features
- API documentation generation
## Contributing

View File

@@ -1,152 +0,0 @@
#!/bin/bash
# macos-setup.sh
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
echo -e "${BLUE}Setting up MCP Integration for Claude Desktop${NC}"
# Function to compare version numbers
version_greater_equal() {
printf '%s\n' "$2" "$1" | sort -V -C
}
# Check if Homebrew is installed
if ! command -v brew &> /dev/null; then
echo -e "${RED}Homebrew is not installed. Installing Homebrew...${NC}"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# Check if Node.js is installed
if ! command -v node &> /dev/null; then
echo -e "${RED}Node.js is not installed. Installing via Homebrew...${NC}"
brew install node@20
brew link node@20
else
NODE_VERSION=$(node -v)
if ! version_greater_equal "${NODE_VERSION//v/}" "20.10.0"; then
echo -e "${RED}Node.js version must be 20.10.0 or higher. Current version: $NODE_VERSION${NC}"
echo -e "${BLUE}Installing Node.js 20 via Homebrew...${NC}"
brew install node@20
brew link node@20
fi
fi
# Check if npm is installed
if ! command -v npm &> /dev/null; then
echo -e "${RED}npm is not installed. Please install npm and try again.${NC}"
exit 1
fi
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo -e "${RED}jq is not installed. Installing via Homebrew...${NC}"
brew install jq
fi
# Create MCP directory if it doesn't exist
MCP_DIR="$HOME/.mcp"
mkdir -p "$MCP_DIR"
# Clone the Home Assistant MCP repository
echo -e "${BLUE}Cloning Home Assistant MCP repository...${NC}"
git clone https://github.com/jango-blockchained/homeassistant-mcp.git "$MCP_DIR/homeassistant-mcp"
cd "$MCP_DIR/homeassistant-mcp"
# Install dependencies and build
echo -e "${BLUE}Installing dependencies and building...${NC}"
npm install
npm run build
# Create Claude Desktop config directory (macOS specific path)
CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude"
mkdir -p "$CLAUDE_CONFIG_DIR"
# Prompt for configurations
echo -e "${BLUE}Please enter your configurations:${NC}"
read -p "Home Assistant URL (e.g., http://homeassistant.local:8123): " HASS_HOST
read -p "Home Assistant Long-lived access token: " HASS_TOKEN
# Create .env file for Home Assistant
cat > "$MCP_DIR/homeassistant-mcp/.env" << EOL
NODE_ENV=production
HASS_HOST=$HASS_HOST
HASS_TOKEN=$HASS_TOKEN
PORT=3000
EOL
# Create base configuration for Home Assistant
CONFIG_JSON='{
"mcpServers": {
"homeassistant": {
"command": "node",
"args": [
"'$MCP_DIR'/homeassistant-mcp/dist/index.js"
],
"env": {
"HASS_TOKEN": "'$HASS_TOKEN'",
"HASS_HOST": "'$HASS_HOST'",
"NODE_ENV": "production",
"PORT": "3000"
}
}
}
}'
# Prompt for enabling Brave Search
read -p "Do you want to enable Brave Search integration? (y/n): " ENABLE_BRAVE_SEARCH
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
# Install Brave Search MCP globally only if enabled
echo -e "${BLUE}Installing Brave Search MCP...${NC}"
npm install -g @modelcontextprotocol/server-brave-search
read -p "Brave Search API Key: " BRAVE_API_KEY
# Add Brave Search to the configuration
CONFIG_JSON=$(echo $CONFIG_JSON | jq '.mcpServers += {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "'$BRAVE_API_KEY'"
}
}
}')
fi
# Write the final configuration to file
echo $CONFIG_JSON | jq '.' > "$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
# Set proper permissions
chmod 600 "$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
chmod 600 "$MCP_DIR/homeassistant-mcp/.env"
echo -e "${GREEN}Installation complete!${NC}"
echo -e "${BLUE}Configuration files created at:${NC}"
echo " - $CLAUDE_CONFIG_DIR/claude_desktop_config.json"
echo " - $MCP_DIR/homeassistant-mcp/.env"
echo -e "${BLUE}To use the integration:${NC}"
echo "1. Make sure Claude Desktop is installed from https://claude.ai/download"
echo "2. Restart Claude Desktop"
echo "3. Home Assistant MCP integration is now available"
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
echo "4. Brave Search MCP integration is also available"
fi
echo -e "${RED}Note: Keep your access tokens and API keys secure and never share them with others${NC}"
# Optional: Test the installations
read -p "Would you like to test the installations? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Testing Home Assistant MCP connection...${NC}"
node "$MCP_DIR/homeassistant-mcp/dist/index.js" test
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Testing Brave Search MCP...${NC}"
npx @modelcontextprotocol/server-brave-search test
fi
fi

118
claude_desktop_setup.sh Normal file
View File

@@ -0,0 +1,118 @@
#!/bin/bash
# mcp-setup.sh
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
echo -e "${BLUE}Setting up MCP Integration for Claude Desktop${NC}"
# Check if Node.js is installed
if ! command -v node &> /dev/null; then
echo -e "${RED}Node.js is not installed. Installing via nvm...${NC}"
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Load nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# Install Node.js 20.10.0
nvm install 20.10.0
nvm use 20.10.0
else
NODE_VERSION=$(node -v)
if [[ ${NODE_VERSION//v/} < "20.10.0" ]]; then
echo -e "${RED}Node.js version must be 20.10.0 or higher. Current version: $NODE_VERSION${NC}"
exit 1
fi
fi
# Install Brave Search MCP globally
echo -e "${BLUE}Installing Brave Search MCP...${NC}"
npm install -g @modelcontextprotocol/server-brave-search
# Create MCP directory if it doesn't exist
MCP_DIR="$HOME/.mcp"
mkdir -p "$MCP_DIR"
# Clone the Home Assistant MCP repository
echo -e "${BLUE}Cloning Home Assistant MCP repository...${NC}"
git clone https://github.com/jango-blockchained/homeassistant-mcp.git "$MCP_DIR/homeassistant-mcp"
cd "$MCP_DIR/homeassistant-mcp"
# Install dependencies and build
npm install
npm run build
# Prompt for configurations
echo -e "${BLUE}Please enter your configurations:${NC}"
read -p "Home Assistant URL (e.g., http://homeassistant.local:8123): " HASS_HOST
read -p "Home Assistant Long-lived access token: " HASS_TOKEN
read -p "Brave Search API Key: " BRAVE_API_KEY
# Create .env file for Home Assistant
cat > "$MCP_DIR/homeassistant-mcp/.env" << EOL
NODE_ENV=production
HASS_HOST=$HASS_HOST
HASS_TOKEN=$HASS_TOKEN
EOL
# Create Claude Desktop config directory
CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude"
mkdir -p "$CLAUDE_CONFIG_DIR"
# Create combined configuration file
cat > "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" << EOL
{
"mcpServers": {
"homeassistant": {
"command": "node",
"args": [
"$MCP_DIR/homeassistant-mcp/dist/index.js"
],
"env": {
"HASS_TOKEN": "$HASS_TOKEN",
"HASS_HOST": "$HASS_HOST"
}
},
"brave-search": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-brave-search"
],
"env": {
"BRAVE_API_KEY": "$BRAVE_API_KEY"
}
}
}
}
EOL
# Set proper permissions
chmod 600 "$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
chmod 600 "$MCP_DIR/homeassistant-mcp/.env"
echo -e "${GREEN}Installation complete!${NC}"
echo -e "${BLUE}Configuration file created at:${NC} $CLAUDE_CONFIG_DIR/claude_desktop_config.json"
echo -e "${BLUE}To use the integration:${NC}"
echo "1. Make sure Claude Desktop is installed from https://claude.ai/download"
echo "2. Restart Claude Desktop"
echo "3. Both Home Assistant and Brave Search MCP integrations should now be available"
echo -e "${RED}Note: Keep your access tokens and API keys secure and never share them with others${NC}"
# Optional: Test the installations
read -p "Would you like to test the installations? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
echo -e "${BLUE}Testing Home Assistant MCP connection...${NC}"
node "$MCP_DIR/homeassistant-mcp/dist/index.js" test
echo -e "${BLUE}Testing Brave Search MCP...${NC}"
npx @modelcontextprotocol/server-brave-search test
fi

View File

@@ -1,43 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'^@src/(.*)$': '<rootDir>/src/$1',
'^@tests/(.*)$': '<rootDir>/__tests__/$1',
'^(\\.{1,2}/.*)\\.js$': '$1'
},
roots: [
'<rootDir>/src',
'<rootDir>/__tests__'
],
transform: {
'^.+\\.tsx?$': ['ts-jest', {
useESM: true,
tsconfig: './tsconfig.json'
}]
},
extensionsToTreatAsEsm: ['.ts', '.tsx'],
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
resolver: '<rootDir>/jest-resolver.cjs',
transformIgnorePatterns: [
'node_modules/(?!(@digital-alchemy|litemcp|semver|zod)/)'
],
modulePathIgnorePatterns: [
'<rootDir>/dist/'
],
testEnvironmentOptions: {
experimentalVmModules: true
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
globals: {
'ts-jest': {
useESM: true,
tsconfig: {
allowJs: true,
esModuleInterop: true
}
}
}
};

View File

@@ -30,7 +30,7 @@
"semver": "^6.3.1",
"ts-jest": "^28.0.8",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
"typescript": "^4.9.5"
},
"author": "Jango Blockchained",
"license": "MIT"

View File

@@ -33,19 +33,6 @@ const commonCommands = ['turn_on', 'turn_off', 'toggle'] as const;
const coverCommands = [...commonCommands, 'open', 'close', 'stop', 'set_position', 'set_tilt_position'] as const;
const climateCommands = [...commonCommands, 'set_temperature', 'set_hvac_mode', 'set_fan_mode', 'set_humidity'] as const;
interface HassEntity {
entity_id: string;
state: string;
attributes: Record<string, any>;
last_changed?: string;
last_updated?: string;
context?: {
id: string;
parent_id?: string;
user_id?: string;
};
}
async function main() {
const hass = await get_hass();
@@ -70,8 +57,8 @@ async function main() {
throw new Error(`Failed to fetch devices: ${response.statusText}`);
}
const states = await response.json() as HassEntity[];
const devices = states.reduce((acc: Record<string, HassEntity[]>, state: HassEntity) => {
const states = await response.json();
const devices = states.reduce((acc: any, state: any) => {
const domain = state.entity_id.split('.')[0];
if (!acc[domain]) {
acc[domain] = [];
@@ -234,7 +221,20 @@ async function main() {
// Start the server
await server.start();
console.log('MCP Server started');
console.log('MCP Server started successfully and is ready to accept commands.');
// Add more detailed logging for server actions
server.on('toolAdded', (tool) => {
console.log(`Tool added: ${tool.name} - ${tool.description}`);
});
server.on('toolExecuted', (tool, result) => {
console.log(`Tool executed: ${tool.name} - Result: ${result.success ? 'Success' : 'Failure'}`);
if (!result.success) {
console.error(`Error: ${result.message}`);
}
});
console.log('Listening for incoming connections...');
}
main().catch(console.error);