/**
* Environment-based MCP Client
* Uses environment variables for secure credential management
*/
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { createSmitheryUrl } from "@smithery/sdk";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import dotenv from "dotenv";
// Load environment variables
dotenv.config();
// Validate required environment variables
const requiredEnvVars = [
'HOME_ASSISTANT_TOKEN',
'HOME_ASSISTANT_URL',
'SMITHERY_API_KEY'
];
const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);
if (missingVars.length > 0) {
console.error("โ Missing required environment variables:");
missingVars.forEach(varName => console.error(` - ${varName}`));
console.error("\n๐ก Create a .env file with:");
console.error("HOME_ASSISTANT_TOKEN=your_token_here");
console.error("HOME_ASSISTANT_URL=http://your-hass-ip:8123");
console.error("SMITHERY_API_KEY=your_smithery_key_here");
process.exit(1);
}
// Configuration from environment variables
const config = {
homeAssistantToken: process.env.HOME_ASSISTANT_TOKEN,
homeAssistantUrl: process.env.HOME_ASSISTANT_URL,
debug: process.env.DEBUG === 'true' || false,
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT) || 10000
};
console.log("๐ง Configuration loaded:");
console.log(` - Home Assistant URL: ${config.homeAssistantUrl}`);
console.log(` - Debug mode: ${config.debug}`);
console.log(` - Request timeout: ${config.requestTimeout}ms`);
console.log(` - Token: ${config.homeAssistantToken.substring(0, 10)}...`);
// Create Smithery URL
const serverUrl = createSmitheryUrl(
"https://server.smithery.ai/@gilberth/enhanced-homeassistant-mcp",
{
config,
apiKey: process.env.SMITHERY_API_KEY
}
);
const transport = new StreamableHTTPClientTransport(serverUrl);
// Create MCP client
const client = new Client({
name: "Enhanced Home Assistant Client (Secure)",
version: "1.0.0"
});
async function demonstrateCapabilities() {
try {
console.log("\n๐ Connecting to Enhanced Home Assistant MCP Server...");
await client.connect(transport);
console.log("โ
Connected successfully!");
// Get available tools
const tools = await client.listTools();
console.log(`\n๐ Found ${tools.tools.length} available tools:`);
// Group tools by category
const categories = {
basic: [],
automation: [],
history: [],
devices: [],
system: [],
resources: []
};
tools.tools.forEach(tool => {
if (tool.name.includes('automation')) {
categories.automation.push(tool.name);
} else if (tool.name.includes('history') || tool.name.includes('time') || tool.name.includes('trend')) {
categories.history.push(tool.name);
} else if (tool.name.includes('device') || tool.name.includes('area')) {
categories.devices.push(tool.name);
} else if (tool.name.includes('system') || tool.name.includes('config') || tool.name.includes('log')) {
categories.system.push(tool.name);
} else if (tool.name.includes('resource')) {
categories.resources.push(tool.name);
} else {
categories.basic.push(tool.name);
}
});
Object.entries(categories).forEach(([category, toolNames]) => {
if (toolNames.length > 0) {
console.log(`\n ${category.toUpperCase()}:`);
toolNames.forEach(name => console.log(` - ${name}`));
}
});
// Interactive demonstration
console.log("\n๐ฎ Running capability demonstration...");
// Test connection
console.log("\n1๏ธโฃ Testing Home Assistant API connection...");
const apiResult = await client.callTool({
name: "homeassistant_api",
arguments: {}
});
console.log(` โ
${apiResult.content[0].text}`);
// Get entities overview
console.log("\n2๏ธโฃ Getting entities overview...");
const entitiesResult = await client.callTool({
name: "homeassistant_list_entities",
arguments: { limit: 10 }
});
console.log(` ๐ฑ Retrieved entity list`);
// Search for lights
console.log("\n3๏ธโฃ Searching for light entities...");
try {
const lightsResult = await client.callTool({
name: "homeassistant_search_entities",
arguments: {
query: "light",
limit: 5
}
});
console.log(` ๐ก Found light entities`);
} catch (error) {
console.log(` โ ๏ธ No light entities found or search failed`);
}
// Get system info
console.log("\n4๏ธโฃ Getting system information...");
try {
const systemResult = await client.callTool({
name: "homeassistant_get_system_info",
arguments: {}
});
console.log(` โ๏ธ System information retrieved`);
} catch (error) {
console.log(` โ ๏ธ System info unavailable: ${error.message}`);
}
// Try automations
console.log("\n5๏ธโฃ Checking automations...");
try {
const automationsResult = await client.callTool({
name: "homeassistant_list_automations",
arguments: {}
});
console.log(` ๐ค Automations list retrieved`);
} catch (error) {
console.log(` โ ๏ธ Automations unavailable (normal if none exist)`);
}
console.log("\n๐ Capability demonstration completed!");
console.log("\n๐ก Your Enhanced Home Assistant MCP Server is working correctly!");
console.log(" You can now integrate this with your AI applications.");
} catch (error) {
console.error("\nโ Error during demonstration:", error.message);
if (error.message.includes('unauthorized') || error.message.includes('401')) {
console.error("\n๐ Authentication issue:");
console.error(" - Check your HOME_ASSISTANT_TOKEN");
console.error(" - Ensure the token has proper permissions");
} else if (error.message.includes('connect') || error.message.includes('network')) {
console.error("\n๐ Connection issue:");
console.error(" - Check your HOME_ASSISTANT_URL");
console.error(" - Ensure Home Assistant is accessible from Smithery");
console.error(" - For local HA, you might need to expose it publicly");
} else if (error.message.includes('smithery') || error.message.includes('api key')) {
console.error("\n๐ Smithery issue:");
console.error(" - Check your SMITHERY_API_KEY");
console.error(" - Ensure the server is deployed on Smithery");
}
} finally {
try {
await client.close();
console.log("\n๐ Connection closed gracefully.");
} catch (error) {
console.error("Warning: Error closing connection:", error.message);
}
}
}
// Run the demonstration
demonstrateCapabilities().catch(error => {
console.error("Fatal error:", error);
process.exit(1);
});