ha-ai-mcp-server 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/addon/addon.adapter.d.ts +22 -0
- package/dist/adapters/addon/addon.adapter.d.ts.map +1 -0
- package/dist/adapters/addon/addon.adapter.js +92 -0
- package/dist/adapters/addon/addon.adapter.js.map +1 -0
- package/dist/adapters/browser/playwright.adapter.d.ts +27 -0
- package/dist/adapters/browser/playwright.adapter.d.ts.map +1 -0
- package/dist/adapters/browser/playwright.adapter.js +156 -0
- package/dist/adapters/browser/playwright.adapter.js.map +1 -0
- package/dist/adapters/ha/ha-rest.adapter.d.ts +19 -0
- package/dist/adapters/ha/ha-rest.adapter.d.ts.map +1 -0
- package/dist/adapters/ha/ha-rest.adapter.js +70 -0
- package/dist/adapters/ha/ha-rest.adapter.js.map +1 -0
- package/dist/adapters/ha/ha-ws.adapter.d.ts +29 -0
- package/dist/adapters/ha/ha-ws.adapter.d.ts.map +1 -0
- package/dist/adapters/ha/ha-ws.adapter.js +178 -0
- package/dist/adapters/ha/ha-ws.adapter.js.map +1 -0
- package/dist/browser/renderer.d.ts +3 -0
- package/dist/browser/renderer.d.ts.map +1 -0
- package/dist/browser/renderer.js +3 -0
- package/dist/browser/renderer.js.map +1 -0
- package/dist/clients/addon-client.d.ts +3 -0
- package/dist/clients/addon-client.d.ts.map +1 -0
- package/dist/clients/addon-client.js +3 -0
- package/dist/clients/addon-client.js.map +1 -0
- package/dist/clients/ha-rest.d.ts +3 -0
- package/dist/clients/ha-rest.d.ts.map +1 -0
- package/dist/clients/ha-rest.js +3 -0
- package/dist/clients/ha-rest.js.map +1 -0
- package/dist/clients/ha-ws.d.ts +3 -0
- package/dist/clients/ha-ws.d.ts.map +1 -0
- package/dist/clients/ha-ws.js +3 -0
- package/dist/clients/ha-ws.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -0
- package/dist/core/config.d.ts +30 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +27 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +29 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/logger.d.ts +13 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +25 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/domain/models/automation.d.ts +19 -0
- package/dist/domain/models/automation.d.ts.map +1 -0
- package/dist/domain/models/automation.js +2 -0
- package/dist/domain/models/automation.js.map +1 -0
- package/dist/domain/models/dashboard.d.ts +21 -0
- package/dist/domain/models/dashboard.d.ts.map +1 -0
- package/dist/domain/models/dashboard.js +2 -0
- package/dist/domain/models/dashboard.js.map +1 -0
- package/dist/domain/models/entity.d.ts +13 -0
- package/dist/domain/models/entity.d.ts.map +1 -0
- package/dist/domain/models/entity.js +2 -0
- package/dist/domain/models/entity.js.map +1 -0
- package/dist/domain/models/system.d.ts +35 -0
- package/dist/domain/models/system.d.ts.map +1 -0
- package/dist/domain/models/system.js +2 -0
- package/dist/domain/models/system.js.map +1 -0
- package/dist/domain/ports/addon-client.port.d.ts +31 -0
- package/dist/domain/ports/addon-client.port.d.ts.map +1 -0
- package/dist/domain/ports/addon-client.port.js +2 -0
- package/dist/domain/ports/addon-client.port.js.map +1 -0
- package/dist/domain/ports/ha-client.port.d.ts +17 -0
- package/dist/domain/ports/ha-client.port.d.ts.map +1 -0
- package/dist/domain/ports/ha-client.port.js +2 -0
- package/dist/domain/ports/ha-client.port.js.map +1 -0
- package/dist/domain/ports/renderer.port.d.ts +7 -0
- package/dist/domain/ports/renderer.port.d.ts.map +1 -0
- package/dist/domain/ports/renderer.port.js +2 -0
- package/dist/domain/ports/renderer.port.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/services/automation.service.d.ts +20 -0
- package/dist/services/automation.service.d.ts.map +1 -0
- package/dist/services/automation.service.js +118 -0
- package/dist/services/automation.service.js.map +1 -0
- package/dist/services/dashboard.service.d.ts +22 -0
- package/dist/services/dashboard.service.d.ts.map +1 -0
- package/dist/services/dashboard.service.js +72 -0
- package/dist/services/dashboard.service.js.map +1 -0
- package/dist/services/system.service.d.ts +19 -0
- package/dist/services/system.service.d.ts.map +1 -0
- package/dist/services/system.service.js +83 -0
- package/dist/services/system.service.js.map +1 -0
- package/dist/tools/automation.d.ts +33 -0
- package/dist/tools/automation.d.ts.map +1 -0
- package/dist/tools/automation.js +246 -0
- package/dist/tools/automation.js.map +1 -0
- package/dist/tools/dashboard.d.ts +33 -0
- package/dist/tools/dashboard.d.ts.map +1 -0
- package/dist/tools/dashboard.js +166 -0
- package/dist/tools/dashboard.js.map +1 -0
- package/dist/tools/system.d.ts +44 -0
- package/dist/tools/system.d.ts.map +1 -0
- package/dist/tools/system.js +306 -0
- package/dist/tools/system.js.map +1 -0
- package/dist/tools/types.d.ts +26 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +39 -0
- package/src/adapters/addon/addon.adapter.ts +113 -0
- package/src/adapters/browser/playwright.adapter.ts +186 -0
- package/src/adapters/ha/ha-rest.adapter.ts +82 -0
- package/src/adapters/ha/ha-ws.adapter.ts +212 -0
- package/src/browser/renderer.ts +7 -0
- package/src/clients/addon-client.ts +2 -0
- package/src/clients/ha-rest.ts +2 -0
- package/src/clients/ha-ws.ts +2 -0
- package/src/config.ts +1 -0
- package/src/core/config.ts +39 -0
- package/src/core/errors.ts +28 -0
- package/src/core/logger.ts +27 -0
- package/src/domain/models/automation.ts +19 -0
- package/src/domain/models/dashboard.ts +23 -0
- package/src/domain/models/entity.ts +13 -0
- package/src/domain/models/system.ts +37 -0
- package/src/domain/ports/addon-client.port.ts +35 -0
- package/src/domain/ports/ha-client.port.ts +16 -0
- package/src/domain/ports/renderer.port.ts +7 -0
- package/src/index.ts +103 -0
- package/src/services/automation.service.ts +142 -0
- package/src/services/dashboard.service.ts +83 -0
- package/src/services/system.service.ts +94 -0
- package/src/tools/automation.ts +300 -0
- package/src/tools/dashboard.ts +206 -0
- package/src/tools/system.ts +368 -0
- package/src/tools/types.ts +30 -0
- package/tests/clients.test.ts +522 -0
- package/tests/e2e-smoke.test.ts +620 -0
- package/tests/renderer.test.ts +286 -0
- package/tests/skills.test.ts +189 -0
- package/tests/tools.test.ts +530 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { ToolClients, McpToolResult } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export const listEntitiesSchema = {
|
|
6
|
+
domain_filter: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Filter by domain prefix (e.g. 'light', 'sensor', 'switch', 'binary_sensor')"),
|
|
10
|
+
search_query: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Search query to filter entity_id or friendly_name"),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getLogsSchema = {
|
|
17
|
+
lines_count: z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.positive()
|
|
21
|
+
.optional()
|
|
22
|
+
.default(100)
|
|
23
|
+
.describe("Number of log lines to retrieve from Home Assistant log (default: 100)"),
|
|
24
|
+
source: z
|
|
25
|
+
.enum(["core", "supervisor", "all"])
|
|
26
|
+
.optional()
|
|
27
|
+
.default("all")
|
|
28
|
+
.describe("Log source to query ('core' for HA Core events, 'supervisor' for Docker/App lifecycle, 'all' for combined)"),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const createBackupSchema = {
|
|
32
|
+
label: z
|
|
33
|
+
.string()
|
|
34
|
+
.describe("Description or label for the manual backup snapshot"),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const restoreBackupSchema = {
|
|
38
|
+
snapshot_id: z
|
|
39
|
+
.string()
|
|
40
|
+
.describe("Snapshot ID to restore (e.g. 'snap_20260831_120000_configuration_yaml')"),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const callServiceSchema = {
|
|
44
|
+
domain: z
|
|
45
|
+
.string()
|
|
46
|
+
.describe("Service domain (e.g. 'light', 'switch', 'automation', 'climate', 'homeassistant')"),
|
|
47
|
+
service: z
|
|
48
|
+
.string()
|
|
49
|
+
.describe("Service name to invoke (e.g. 'turn_on', 'turn_off', 'toggle', 'reload', 'trigger')"),
|
|
50
|
+
service_data: z
|
|
51
|
+
.record(z.any())
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Service payload parameters (e.g. { entity_id: 'light.office_light' })"),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export async function handleSystemHealth(clients: ToolClients): Promise<McpToolResult> {
|
|
57
|
+
try {
|
|
58
|
+
const [haApi, addonHealth] = await Promise.allSettled([
|
|
59
|
+
clients.restClient.checkApi(),
|
|
60
|
+
clients.addonClient.checkHealth(),
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const isHaOk = haApi.status === "fulfilled";
|
|
64
|
+
const isAddonOk = addonHealth.status === "fulfilled";
|
|
65
|
+
|
|
66
|
+
const report = {
|
|
67
|
+
status: isHaOk && isAddonOk ? "ok" : "degraded",
|
|
68
|
+
timestamp: new Date().toISOString(),
|
|
69
|
+
homeassistant: {
|
|
70
|
+
api: isHaOk ? "ok" : "unreachable",
|
|
71
|
+
url: (clients.restClient as any).haUrl || (clients.restClient as any).client?.defaults?.baseURL,
|
|
72
|
+
details: isHaOk ? (haApi as PromiseFulfilledResult<any>).value : { error: (haApi as PromiseRejectedResult).reason?.message },
|
|
73
|
+
},
|
|
74
|
+
addon: isAddonOk
|
|
75
|
+
? (addonHealth as PromiseFulfilledResult<any>).value
|
|
76
|
+
: { status: "unreachable", error: (addonHealth as PromiseRejectedResult).reason?.message },
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: "text",
|
|
83
|
+
text: JSON.stringify(report, null, 2),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
} catch (error: any) {
|
|
88
|
+
return {
|
|
89
|
+
isError: true,
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: "text",
|
|
93
|
+
text: `Failed to retrieve system health: ${error.message || String(error)}`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function handleSystemListEntities(
|
|
101
|
+
clients: ToolClients,
|
|
102
|
+
args: { domain_filter?: string; search_query?: string }
|
|
103
|
+
): Promise<McpToolResult> {
|
|
104
|
+
try {
|
|
105
|
+
const states = await clients.restClient.getStates();
|
|
106
|
+
const domainFilter = args.domain_filter?.toLowerCase().trim();
|
|
107
|
+
const searchQuery = args.search_query?.toLowerCase().trim();
|
|
108
|
+
|
|
109
|
+
const filtered = states
|
|
110
|
+
.filter((s) => {
|
|
111
|
+
if (domainFilter && !s.entity_id.toLowerCase().startsWith(`${domainFilter}.`)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (searchQuery) {
|
|
115
|
+
const entityMatch = s.entity_id.toLowerCase().includes(searchQuery);
|
|
116
|
+
const nameMatch =
|
|
117
|
+
s.attributes?.friendly_name &&
|
|
118
|
+
String(s.attributes.friendly_name).toLowerCase().includes(searchQuery);
|
|
119
|
+
if (!entityMatch && !nameMatch) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
})
|
|
125
|
+
.map((s) => ({
|
|
126
|
+
entity_id: s.entity_id,
|
|
127
|
+
state: s.state,
|
|
128
|
+
friendly_name: s.attributes?.friendly_name || s.entity_id,
|
|
129
|
+
last_changed: s.last_changed,
|
|
130
|
+
last_updated: s.last_updated,
|
|
131
|
+
attributes: s.attributes,
|
|
132
|
+
}));
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: "text",
|
|
138
|
+
text: JSON.stringify(filtered, null, 2),
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
} catch (error: any) {
|
|
143
|
+
return {
|
|
144
|
+
isError: true,
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: `Failed to list entities: ${error.message || String(error)}`,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function handleSystemGetLogs(
|
|
156
|
+
clients: ToolClients,
|
|
157
|
+
args: { lines_count?: number; source?: "core" | "supervisor" | "all" }
|
|
158
|
+
): Promise<McpToolResult> {
|
|
159
|
+
try {
|
|
160
|
+
const linesCount = args.lines_count ?? 100;
|
|
161
|
+
const source = args.source ?? "all";
|
|
162
|
+
|
|
163
|
+
const logSections: string[] = [];
|
|
164
|
+
const errors: string[] = [];
|
|
165
|
+
|
|
166
|
+
if (source === "core" || source === "all") {
|
|
167
|
+
try {
|
|
168
|
+
const coreLogs = await clients.addonClient.getLogs(linesCount);
|
|
169
|
+
if (coreLogs.lines.length > 0) {
|
|
170
|
+
logSections.push(`=== Home Assistant Core Logs ===\n${coreLogs.lines.join("\n")}`);
|
|
171
|
+
}
|
|
172
|
+
} catch (err: any) {
|
|
173
|
+
errors.push(`Core logs error: ${err.message}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (source === "supervisor" || source === "all") {
|
|
178
|
+
try {
|
|
179
|
+
const supLogs = await clients.restClient.getSupervisorLogs(linesCount);
|
|
180
|
+
if (supLogs.length > 0) {
|
|
181
|
+
logSections.push(`=== Home Assistant Supervisor Logs ===\n${supLogs.join("\n")}`);
|
|
182
|
+
}
|
|
183
|
+
} catch (err: any) {
|
|
184
|
+
errors.push(`Supervisor logs error: ${err.message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (logSections.length === 0 && errors.length > 0) {
|
|
189
|
+
return {
|
|
190
|
+
isError: true,
|
|
191
|
+
content: [
|
|
192
|
+
{
|
|
193
|
+
type: "text",
|
|
194
|
+
text: `Failed to retrieve logs: ${errors.join(", ")}`,
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
content: [
|
|
202
|
+
{
|
|
203
|
+
type: "text",
|
|
204
|
+
text: logSections.join("\n\n") || "(No log output available from requested sources)",
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
} catch (error: any) {
|
|
209
|
+
return {
|
|
210
|
+
isError: true,
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: `Failed to retrieve logs: ${error.message || String(error)}`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function handleSystemCreateBackup(
|
|
222
|
+
clients: ToolClients,
|
|
223
|
+
args: { label: string }
|
|
224
|
+
): Promise<McpToolResult> {
|
|
225
|
+
try {
|
|
226
|
+
let currentContent = "default_config:\n";
|
|
227
|
+
try {
|
|
228
|
+
const file = await clients.addonClient.readFile("configuration.yaml");
|
|
229
|
+
currentContent = file.content;
|
|
230
|
+
} catch {
|
|
231
|
+
// default skeleton
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const writeRes = await clients.addonClient.writeFile("configuration.yaml", currentContent, {
|
|
235
|
+
validateYaml: false,
|
|
236
|
+
label: args.label,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
content: [
|
|
241
|
+
{
|
|
242
|
+
type: "text",
|
|
243
|
+
text: `Backup created successfully with label "${args.label}". Snapshot ID: ${writeRes.snapshot_id} for file "${writeRes.path}".`,
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
};
|
|
247
|
+
} catch (error: any) {
|
|
248
|
+
return {
|
|
249
|
+
isError: true,
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: `Failed to create backup snapshot: ${error.message || String(error)}`,
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export async function handleSystemRestoreBackup(
|
|
261
|
+
clients: ToolClients,
|
|
262
|
+
args: { snapshot_id: string }
|
|
263
|
+
): Promise<McpToolResult> {
|
|
264
|
+
try {
|
|
265
|
+
const res = await clients.addonClient.restoreSnapshot(args.snapshot_id);
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: "text",
|
|
271
|
+
text: `Successfully restored backup from snapshot "${args.snapshot_id}". Restored file: ${res.restored_file} (Source backup: ${res.restored_from}, Safety backup: ${res.safety_backup}).`,
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
} catch (error: any) {
|
|
276
|
+
return {
|
|
277
|
+
isError: true,
|
|
278
|
+
content: [
|
|
279
|
+
{
|
|
280
|
+
type: "text",
|
|
281
|
+
text: `Failed to restore backup snapshot: ${error.message || String(error)}`,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export async function handleSystemCallService(
|
|
289
|
+
clients: ToolClients,
|
|
290
|
+
args: { domain: string; service: string; service_data?: Record<string, any> }
|
|
291
|
+
): Promise<McpToolResult> {
|
|
292
|
+
try {
|
|
293
|
+
const res = await clients.restClient.callService(args.domain, args.service, args.service_data);
|
|
294
|
+
return {
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: "text",
|
|
298
|
+
text: `Service ${args.domain}.${args.service} executed successfully.${res ? " Response: " + JSON.stringify(res) : ""}`,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
} catch (error: any) {
|
|
303
|
+
return {
|
|
304
|
+
isError: true,
|
|
305
|
+
content: [
|
|
306
|
+
{
|
|
307
|
+
type: "text",
|
|
308
|
+
text: `Failed to call service ${args.domain}.${args.service}: ${error.message || String(error)}`,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function registerSystemTools(server: McpServer, clients: ToolClients): void {
|
|
316
|
+
server.registerTool(
|
|
317
|
+
"ha_system_health",
|
|
318
|
+
{
|
|
319
|
+
description: "Check the health, connectivity, and status of Home Assistant and the AI Addon.",
|
|
320
|
+
},
|
|
321
|
+
async () => handleSystemHealth(clients)
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
server.registerTool(
|
|
325
|
+
"ha_system_list_entities",
|
|
326
|
+
{
|
|
327
|
+
description: "List and filter Home Assistant entities by domain and search query with full state attributes.",
|
|
328
|
+
inputSchema: listEntitiesSchema,
|
|
329
|
+
},
|
|
330
|
+
async (args) => handleSystemListEntities(clients, args)
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
server.registerTool(
|
|
334
|
+
"ha_system_call_service",
|
|
335
|
+
{
|
|
336
|
+
description: "Call any Home Assistant service (e.g. 'light.turn_on', 'switch.toggle', 'climate.set_temperature').",
|
|
337
|
+
inputSchema: callServiceSchema,
|
|
338
|
+
},
|
|
339
|
+
async (args) => handleSystemCallService(clients, args)
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
server.registerTool(
|
|
343
|
+
"ha_system_get_logs",
|
|
344
|
+
{
|
|
345
|
+
description: "Fetch sanitized, tail-formatted Home Assistant core logs.",
|
|
346
|
+
inputSchema: getLogsSchema,
|
|
347
|
+
},
|
|
348
|
+
async (args) => handleSystemGetLogs(clients, args)
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
server.registerTool(
|
|
352
|
+
"ha_system_create_backup",
|
|
353
|
+
{
|
|
354
|
+
description: "Create an instant snapshot backup with a custom label.",
|
|
355
|
+
inputSchema: createBackupSchema,
|
|
356
|
+
},
|
|
357
|
+
async (args) => handleSystemCreateBackup(clients, args)
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
server.registerTool(
|
|
361
|
+
"ha_system_restore_backup",
|
|
362
|
+
{
|
|
363
|
+
description: "Restore a configuration or automation file from a previous snapshot backup.",
|
|
364
|
+
inputSchema: restoreBackupSchema,
|
|
365
|
+
},
|
|
366
|
+
async (args) => handleSystemRestoreBackup(clients, args)
|
|
367
|
+
);
|
|
368
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HARestAdapter } from "../adapters/ha/ha-rest.adapter.js";
|
|
2
|
+
import type { HAWsAdapter } from "../adapters/ha/ha-ws.adapter.js";
|
|
3
|
+
import type { AddonAdapter } from "../adapters/addon/addon.adapter.js";
|
|
4
|
+
import type { PlaywrightDashboardAdapter } from "../adapters/browser/playwright.adapter.js";
|
|
5
|
+
|
|
6
|
+
export interface ToolClients {
|
|
7
|
+
restClient: HARestAdapter;
|
|
8
|
+
wsClient: HAWsAdapter;
|
|
9
|
+
addonClient: AddonAdapter;
|
|
10
|
+
renderer: PlaywrightDashboardAdapter;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface McpToolTextContent {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface McpToolImageContent {
|
|
19
|
+
type: "image";
|
|
20
|
+
data: string;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type McpToolContent = McpToolTextContent | McpToolImageContent;
|
|
25
|
+
|
|
26
|
+
export interface McpToolResult {
|
|
27
|
+
[x: string]: unknown;
|
|
28
|
+
content: McpToolContent[];
|
|
29
|
+
isError?: boolean;
|
|
30
|
+
}
|