list-devices.tool.ts•3.56 kB
/**
* List Devices Tool for Home Assistant
*
* This tool lists all available devices in Home Assistant,
* with optional filtering by domain, area, or floor.
*/
import { z } from "zod";
import { logger } from "../../utils/logger.js";
import { BaseTool } from "../base-tool.js";
import { MCPContext } from "../../mcp/types.js";
import { get_hass } from "../../hass/index.js";
// Define the schema for our tool parameters
const listDevicesSchema = z.object({
domain: z.enum([
"light",
"climate",
"alarm_control_panel",
"cover",
"switch",
"contact",
"media_player",
"fan",
"lock",
"vacuum",
"scene",
"script",
"camera",
]).optional().describe("Filter devices by domain"),
area: z.string().optional().describe("Filter devices by area"),
floor: z.string().optional().describe("Filter devices by floor"),
});
// Infer the type from the schema
type ListDevicesParams = z.infer<typeof listDevicesSchema>;
/**
* ListDevicesTool class extending BaseTool
*/
export class ListDevicesTool extends BaseTool {
constructor() {
super({
name: "list_devices",
description: "List all available Home Assistant devices with optional filtering",
parameters: listDevicesSchema,
metadata: {
category: "home_assistant",
version: "1.0.0",
tags: ["devices", "home_assistant", "list"],
}
});
}
/**
* Execute method for the BaseTool class
*/
public async execute(params: ListDevicesParams, _context: MCPContext): Promise<Record<string, unknown>> {
logger.debug(`Executing ListDevicesTool with params: ${JSON.stringify(params)}`);
try {
const hass = await get_hass();
const states = await hass.getStates();
let filteredStates = states;
// Apply filters
if (params.domain) {
filteredStates = filteredStates.filter(state =>
state.entity_id.startsWith(`${params.domain}.`)
);
}
if (params.area) {
filteredStates = filteredStates.filter(state =>
state.attributes?.area_id === params.area
);
}
if (params.floor) {
filteredStates = filteredStates.filter(state =>
state.attributes?.floor_id === params.floor
);
}
// Format the response
const devices = filteredStates.map(state => ({
entity_id: state.entity_id,
state: state.state,
attributes: {
friendly_name: state.attributes?.friendly_name,
area_id: state.attributes?.area_id,
floor_id: state.attributes?.floor_id,
...state.attributes
}
}));
logger.debug(`Found ${devices.length} devices matching criteria`);
return {
devices,
total_count: devices.length,
filters_applied: {
domain: params.domain,
area: params.area,
floor: params.floor
}
};
} catch (error) {
logger.error(`Error in ListDevicesTool: ${error instanceof Error ? error.message : String(error)}`);
throw error;
}
}
}