domotz-mcp
Version:
MCP server for Domotz API and BMS (Building Management System) integration with IoT device monitoring
100 lines (99 loc) • 4.03 kB
JavaScript
import axios from "axios";
import { z } from "zod";
import { MCPTool } from "mcp-framework";
export default class HomeAssistantDiscoveryTool extends MCPTool {
name = "ha_discover";
description = "Discover entities and devices in Home Assistant";
schema = {
ha_url: {
type: z.string(),
description: "Home Assistant URL (e.g., http://homeassistant.local:8123)"
},
access_token: {
type: z.string(),
description: "Long-lived access token from Home Assistant"
},
entity_type: {
type: z.string().optional(),
description: "Filter by entity type (e.g., light, switch, sensor, climate)"
}
};
async execute(params) {
try {
const { ha_url, access_token, entity_type } = params;
// Remove trailing slash from URL
const baseUrl = ha_url.replace(/\/$/, "");
// Get all states (entities)
const statesResponse = await axios.get(`${baseUrl}/api/states`, {
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": "application/json"
}
});
let entities = statesResponse.data;
// Filter by entity type if specified
if (entity_type) {
entities = entities.filter((entity) => entity.entity_id.startsWith(`${entity_type}.`));
}
// Get devices
const devicesResponse = await axios.get(`${baseUrl}/api/config/device_registry/list`, {
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": "application/json"
}
});
// Get areas
const areasResponse = await axios.get(`${baseUrl}/api/config/area_registry/list`, {
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": "application/json"
}
});
// Process entities to extract useful information
const processedEntities = entities.map((entity) => ({
entity_id: entity.entity_id,
name: entity.attributes.friendly_name || entity.entity_id,
state: entity.state,
type: entity.entity_id.split('.')[0],
attributes: entity.attributes,
last_changed: entity.last_changed,
last_updated: entity.last_updated
}));
// Group entities by type
const entitiesByType = {};
processedEntities.forEach((entity) => {
if (!entitiesByType[entity.type]) {
entitiesByType[entity.type] = [];
}
entitiesByType[entity.type].push(entity);
});
return {
success: true,
summary: {
total_entities: processedEntities.length,
total_devices: devicesResponse.data.length,
total_areas: areasResponse.data.length,
entity_types: Object.keys(entitiesByType).map(type => ({
type,
count: entitiesByType[type].length
}))
},
entities: processedEntities,
devices: devicesResponse.data.slice(0, 10), // Limit to first 10 devices
areas: areasResponse.data
};
}
catch (error) {
if (error.response?.status === 401) {
return {
success: false,
error: "Invalid access token. Please check your Home Assistant long-lived access token."
};
}
return {
success: false,
error: error.message || "Failed to discover Home Assistant entities"
};
}
}
}