@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.3.1

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.
Files changed (281) hide show
  1. package/.env.example +1 -1
  2. package/README.md +11 -2
  3. package/dist/omadaClient/client.d.ts +6 -1
  4. package/dist/omadaClient/client.js +12 -1
  5. package/dist/omadaClient/client.js.map +1 -1
  6. package/dist/omadaClient/diagnose.d.ts +68 -0
  7. package/dist/omadaClient/diagnose.js +164 -0
  8. package/dist/omadaClient/diagnose.js.map +1 -0
  9. package/dist/omadaClient/index.d.ts +6 -0
  10. package/dist/omadaClient/index.js +15 -0
  11. package/dist/omadaClient/index.js.map +1 -1
  12. package/dist/omadaClient/macGroups.d.ts +58 -0
  13. package/dist/omadaClient/macGroups.js +124 -0
  14. package/dist/omadaClient/macGroups.js.map +1 -0
  15. package/dist/tools/infra/actions.d.ts +1 -1
  16. package/dist/tools/infra/actions.js +1 -1
  17. package/dist/tools/omada/index.js +6 -0
  18. package/dist/tools/omada/index.js.map +1 -1
  19. package/dist/tools/omada/macGroups.d.ts +19 -0
  20. package/dist/tools/omada/macGroups.js +77 -0
  21. package/dist/tools/omada/macGroups.js.map +1 -0
  22. package/dist/tools/omada/namespace.js +8 -0
  23. package/dist/tools/omada/namespace.js.map +1 -1
  24. package/dist/version.d.ts +1 -1
  25. package/dist/version.js +1 -1
  26. package/package.json +5 -1
  27. package/.codex/review-rules.md +0 -16
  28. package/.dockerignore +0 -8
  29. package/.gitattributes +0 -30
  30. package/.github/workflows/ci.yml +0 -193
  31. package/AGENTS.md +0 -389
  32. package/Dockerfile +0 -50
  33. package/docker-compose.yml +0 -23
  34. package/docs/CHANGELOG.md +0 -341
  35. package/docs/COVERAGE.md +0 -219
  36. package/docs/QUICK_START.md +0 -240
  37. package/eslint.config.js +0 -33
  38. package/n8n/ai-agent-safety-monitor.json +0 -355
  39. package/openapi.json +0 -1259
  40. package/scripts/check-version-sync.mjs +0 -69
  41. package/scripts/generate-jwt.ts +0 -121
  42. package/src/config.ts +0 -440
  43. package/src/haClient/automations.ts +0 -261
  44. package/src/haClient/calendars.ts +0 -94
  45. package/src/haClient/config.ts +0 -52
  46. package/src/haClient/devices.ts +0 -653
  47. package/src/haClient/entities.ts +0 -128
  48. package/src/haClient/events.ts +0 -689
  49. package/src/haClient/history.ts +0 -73
  50. package/src/haClient/index.ts +0 -336
  51. package/src/haClient/request.ts +0 -142
  52. package/src/haClient/services.ts +0 -45
  53. package/src/haClient/states.ts +0 -60
  54. package/src/haClient/updates.ts +0 -58
  55. package/src/haClient/wsCommand.ts +0 -44
  56. package/src/index.ts +0 -164
  57. package/src/localAI/index.ts +0 -88
  58. package/src/localAI/prompts.ts +0 -50
  59. package/src/localAI/providers/base.ts +0 -120
  60. package/src/localAI/providers/ollama.ts +0 -78
  61. package/src/localAI/providers/openai.ts +0 -86
  62. package/src/localAI/types.ts +0 -67
  63. package/src/omadaClient/auth.ts +0 -178
  64. package/src/omadaClient/client.ts +0 -337
  65. package/src/omadaClient/device.ts +0 -118
  66. package/src/omadaClient/index.ts +0 -310
  67. package/src/omadaClient/network.ts +0 -284
  68. package/src/omadaClient/request.ts +0 -365
  69. package/src/omadaClient/security.ts +0 -51
  70. package/src/omadaClient/site.ts +0 -344
  71. package/src/ownerQuestions/service.ts +0 -536
  72. package/src/permissions/index.ts +0 -143
  73. package/src/resources/index.ts +0 -213
  74. package/src/server/auth.ts +0 -175
  75. package/src/server/chatFace.ts +0 -789
  76. package/src/server/chatSlice.ts +0 -57
  77. package/src/server/common.ts +0 -170
  78. package/src/server/eventSubscription.ts +0 -343
  79. package/src/server/http.ts +0 -626
  80. package/src/server/instructions.ts +0 -97
  81. package/src/server/rateLimiter.ts +0 -227
  82. package/src/server/stdio.ts +0 -41
  83. package/src/server/stream.ts +0 -205
  84. package/src/tools/ai/analyzeSensors.ts +0 -33
  85. package/src/tools/ai/index.ts +0 -20
  86. package/src/tools/common.ts +0 -442
  87. package/src/tools/homeassistant/askOwner.ts +0 -133
  88. package/src/tools/homeassistant/automationControls.ts +0 -66
  89. package/src/tools/homeassistant/calendar.ts +0 -97
  90. package/src/tools/homeassistant/callService.ts +0 -25
  91. package/src/tools/homeassistant/controlClimate.ts +0 -68
  92. package/src/tools/homeassistant/controlCover.ts +0 -48
  93. package/src/tools/homeassistant/controlFan.ts +0 -44
  94. package/src/tools/homeassistant/controlLight.ts +0 -38
  95. package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
  96. package/src/tools/homeassistant/createAutomation.ts +0 -35
  97. package/src/tools/homeassistant/deleteAutomation.ts +0 -24
  98. package/src/tools/homeassistant/entityAction.ts +0 -35
  99. package/src/tools/homeassistant/entityGuard.ts +0 -28
  100. package/src/tools/homeassistant/getAllSensors.ts +0 -46
  101. package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
  102. package/src/tools/homeassistant/getDomainSummary.ts +0 -29
  103. package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
  104. package/src/tools/homeassistant/getHistory.ts +0 -24
  105. package/src/tools/homeassistant/getState.ts +0 -24
  106. package/src/tools/homeassistant/getStates.ts +0 -46
  107. package/src/tools/homeassistant/getVersion.ts +0 -21
  108. package/src/tools/homeassistant/index.ts +0 -121
  109. package/src/tools/homeassistant/listAutomations.ts +0 -35
  110. package/src/tools/homeassistant/listEntities.ts +0 -44
  111. package/src/tools/homeassistant/listPersons.ts +0 -46
  112. package/src/tools/homeassistant/sceneAndScript.ts +0 -53
  113. package/src/tools/homeassistant/searchEntities.ts +0 -58
  114. package/src/tools/homeassistant/sendNotification.ts +0 -179
  115. package/src/tools/homeassistant/systemTools.ts +0 -52
  116. package/src/tools/homeassistant/triggerAutomation.ts +0 -24
  117. package/src/tools/index.ts +0 -78
  118. package/src/tools/infra/actions.ts +0 -95
  119. package/src/tools/infra/index.ts +0 -138
  120. package/src/tools/omada/blockClient.ts +0 -28
  121. package/src/tools/omada/cyclePoePort.ts +0 -32
  122. package/src/tools/omada/deleteClient.ts +0 -27
  123. package/src/tools/omada/disableClientRateLimit.ts +0 -23
  124. package/src/tools/omada/getClient.ts +0 -14
  125. package/src/tools/omada/getDevice.ts +0 -14
  126. package/src/tools/omada/getFirewallSetting.ts +0 -14
  127. package/src/tools/omada/getInternetInfo.ts +0 -14
  128. package/src/tools/omada/getLanNetworkList.ts +0 -14
  129. package/src/tools/omada/getLanProfileList.ts +0 -14
  130. package/src/tools/omada/getPortForwardingStatus.ts +0 -26
  131. package/src/tools/omada/getRateLimitProfiles.ts +0 -14
  132. package/src/tools/omada/getSiteNtpStatus.ts +0 -14
  133. package/src/tools/omada/getSsidDetail.ts +0 -22
  134. package/src/tools/omada/getSsidList.ts +0 -21
  135. package/src/tools/omada/getSwitchStackDetail.ts +0 -14
  136. package/src/tools/omada/getThreatList.ts +0 -42
  137. package/src/tools/omada/getWlanGroupList.ts +0 -14
  138. package/src/tools/omada/graph.ts +0 -187
  139. package/src/tools/omada/index.ts +0 -153
  140. package/src/tools/omada/listBlockedClients.ts +0 -17
  141. package/src/tools/omada/listClients.ts +0 -14
  142. package/src/tools/omada/listClientsActivity.ts +0 -25
  143. package/src/tools/omada/listClientsPastConnections.ts +0 -44
  144. package/src/tools/omada/listDevices.ts +0 -14
  145. package/src/tools/omada/listDevicesStats.ts +0 -41
  146. package/src/tools/omada/listMostActiveClients.ts +0 -14
  147. package/src/tools/omada/listSites.ts +0 -18
  148. package/src/tools/omada/namespace.ts +0 -1164
  149. package/src/tools/omada/searchDevices.ts +0 -20
  150. package/src/tools/omada/setClientRateLimit.ts +0 -26
  151. package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
  152. package/src/tools/omada/setSiteNtpServers.ts +0 -36
  153. package/src/tools/omada/setSsidEnabled.ts +0 -38
  154. package/src/tools/omada/unblockClient.ts +0 -26
  155. package/src/tools/types.ts +0 -11
  156. package/src/tools/utils/pagination-schema.ts +0 -27
  157. package/src/types/ai/index.ts +0 -11
  158. package/src/types/ai/types.ts +0 -67
  159. package/src/types/homeassistant/automations.ts +0 -43
  160. package/src/types/homeassistant/calendars.ts +0 -26
  161. package/src/types/homeassistant/config.ts +0 -14
  162. package/src/types/homeassistant/entities.ts +0 -14
  163. package/src/types/homeassistant/errors.ts +0 -33
  164. package/src/types/homeassistant/haConfig.ts +0 -7
  165. package/src/types/homeassistant/history.ts +0 -13
  166. package/src/types/homeassistant/index.ts +0 -46
  167. package/src/types/homeassistant/request.ts +0 -6
  168. package/src/types/homeassistant/serviceCall.ts +0 -18
  169. package/src/types/homeassistant/states.ts +0 -58
  170. package/src/types/homeassistant/updates.ts +0 -28
  171. package/src/types/index.ts +0 -12
  172. package/src/types/omada/activeClientInfo.ts +0 -17
  173. package/src/types/omada/clientActivity.ts +0 -32
  174. package/src/types/omada/clientBlockStatus.ts +0 -11
  175. package/src/types/omada/clientPastConnection.ts +0 -82
  176. package/src/types/omada/index.ts +0 -14
  177. package/src/types/omada/omadaApiResponse.ts +0 -5
  178. package/src/types/omada/omadaClientInfo.ts +0 -11
  179. package/src/types/omada/omadaDeviceInfo.ts +0 -11
  180. package/src/types/omada/omadaDeviceStats.ts +0 -31
  181. package/src/types/omada/omadaSiteSummary.ts +0 -5
  182. package/src/types/omada/oswStackDetail.ts +0 -11
  183. package/src/types/omada/paginatedResult.ts +0 -6
  184. package/src/types/omada/rateLimitProfile.ts +0 -58
  185. package/src/types/omada/threatInfo.ts +0 -38
  186. package/src/types/omada/tokenResult.ts +0 -6
  187. package/src/types.ts +0 -2
  188. package/src/utils/config-validations.ts +0 -68
  189. package/src/utils/jwt.ts +0 -112
  190. package/src/utils/logger.ts +0 -121
  191. package/src/utils/plainText.ts +0 -48
  192. package/src/utils/redact.ts +0 -59
  193. package/src/utils/sanitizeError.ts +0 -18
  194. package/src/utils/tlsDispatcher.ts +0 -69
  195. package/src/version.ts +0 -5
  196. package/tests/bdd/automation-creation.spec.ts +0 -214
  197. package/tests/bdd/automation-management.spec.ts +0 -267
  198. package/tests/bdd/calendar.spec.ts +0 -190
  199. package/tests/bdd/configuration.spec.ts +0 -283
  200. package/tests/bdd/device-control.spec.ts +0 -344
  201. package/tests/bdd/entity-listing.spec.ts +0 -208
  202. package/tests/bdd/entity-search.spec.ts +0 -183
  203. package/tests/bdd/history-retrieval.spec.ts +0 -195
  204. package/tests/bdd/notifications.spec.ts +0 -238
  205. package/tests/bdd/service-calls.spec.ts +0 -144
  206. package/tests/bdd/state-retrieval.spec.ts +0 -204
  207. package/tests/bench/hotpaths.bench.ts +0 -68
  208. package/tests/config.test.ts +0 -355
  209. package/tests/features/automation-creation.feature +0 -36
  210. package/tests/features/automation-management.feature +0 -54
  211. package/tests/features/calendar.feature +0 -37
  212. package/tests/features/configuration.feature +0 -70
  213. package/tests/features/device-control.feature +0 -100
  214. package/tests/features/entity-listing.feature +0 -51
  215. package/tests/features/entity-search.feature +0 -44
  216. package/tests/features/history-retrieval.feature +0 -38
  217. package/tests/features/notifications.feature +0 -37
  218. package/tests/features/service-calls.feature +0 -35
  219. package/tests/features/state-retrieval.feature +0 -37
  220. package/tests/fixtures/openapi-default-slice.json +0 -290
  221. package/tests/haClient/automationTrace.test.ts +0 -59
  222. package/tests/haClient/automations.test.ts +0 -149
  223. package/tests/haClient/config.test.ts +0 -117
  224. package/tests/haClient/entities.test.ts +0 -188
  225. package/tests/haClient/events.test.ts +0 -455
  226. package/tests/haClient/eventsTls.test.ts +0 -52
  227. package/tests/haClient/history.test.ts +0 -228
  228. package/tests/haClient/index.test.ts +0 -243
  229. package/tests/haClient/request.test.ts +0 -217
  230. package/tests/haClient/services.test.ts +0 -120
  231. package/tests/haClient/states.test.ts +0 -119
  232. package/tests/haClient/updates.test.ts +0 -193
  233. package/tests/index.test.ts +0 -160
  234. package/tests/integration/homeassistant.test.ts +0 -144
  235. package/tests/integration/omada.test.ts +0 -167
  236. package/tests/integration/server.test.ts +0 -151
  237. package/tests/localAI/index.test.ts +0 -177
  238. package/tests/localAI/ollama.test.ts +0 -187
  239. package/tests/localAI/openai.test.ts +0 -257
  240. package/tests/omadaClient/actions.test.ts +0 -161
  241. package/tests/omadaClient/clientBlocks.test.ts +0 -170
  242. package/tests/omadaClient/ntp.test.ts +0 -381
  243. package/tests/omadaClient/site.test.ts +0 -37
  244. package/tests/ownerQuestions/service.test.ts +0 -499
  245. package/tests/ownerQuestions/tools.test.ts +0 -186
  246. package/tests/permissions/index.test.ts +0 -217
  247. package/tests/resources/index.test.ts +0 -288
  248. package/tests/scripts/generateJwt.test.ts +0 -44
  249. package/tests/security/accessControl.test.ts +0 -223
  250. package/tests/security/authentication.test.ts +0 -117
  251. package/tests/security/configuration.test.ts +0 -170
  252. package/tests/security/cryptoTransport.test.ts +0 -172
  253. package/tests/security/dependencies.test.ts +0 -152
  254. package/tests/security/injection.test.ts +0 -117
  255. package/tests/security/insecureDesign.test.ts +0 -121
  256. package/tests/security/logging.test.ts +0 -131
  257. package/tests/security/resourceConsumption.test.ts +0 -142
  258. package/tests/server/auth.test.ts +0 -249
  259. package/tests/server/chatFace.test.ts +0 -320
  260. package/tests/server/common.test.ts +0 -84
  261. package/tests/server/http.test.ts +0 -561
  262. package/tests/server/instructions.test.ts +0 -152
  263. package/tests/server/memoizeJsonSchema.test.ts +0 -71
  264. package/tests/server/stdio.test.ts +0 -99
  265. package/tests/server/stream.test.ts +0 -285
  266. package/tests/server/toolVisibility.http.test.ts +0 -111
  267. package/tests/server/toolVisibility.test.ts +0 -129
  268. package/tests/tools/ai/analyzeSensors.test.ts +0 -227
  269. package/tests/tools/common.test.ts +0 -123
  270. package/tests/tools/homeassistant/handlers.test.ts +0 -872
  271. package/tests/tools/infra/invokeAction.test.ts +0 -280
  272. package/tests/tools/omada/graph.test.ts +0 -385
  273. package/tests/tools/omada/handlers.test.ts +0 -897
  274. package/tests/tools/omada/namespace.test.ts +0 -483
  275. package/tests/tools/registry.test.ts +0 -168
  276. package/tests/utils/config-validations.test.ts +0 -352
  277. package/tests/utils/jwt.test.ts +0 -115
  278. package/tests/utils/logger.test.ts +0 -327
  279. package/tests/utils/redact.test.ts +0 -105
  280. package/tsconfig.json +0 -24
  281. package/vitest.config.ts +0 -38
@@ -1,24 +0,0 @@
1
- /**
2
- * getHistory tool - Get historical data for an entity
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { historySchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
- import type { z } from 'zod';
9
-
10
- type HistoryArgs = z.infer<typeof historySchema>;
11
-
12
- export function registerGetHistoryTool(server: McpServer, client: HaClient): void {
13
- server.registerTool(
14
- 'getHistory',
15
- {
16
- description: 'Get historical data for an entity.',
17
- inputSchema: historySchema,
18
- },
19
- wrapToolHandler('getHistory', async ({ entity_id, hours = 24 }: HistoryArgs) => {
20
- const history = await client.getHistory(entity_id, hours);
21
- return toToolResult(history);
22
- }, Permission.QUERY)
23
- );
24
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * getState tool - Get state of a specific entity
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { entityIdSchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
-
9
- export function registerGetStateTool(server: McpServer, client: HaClient): void {
10
- server.registerTool(
11
- 'getState',
12
- {
13
- description: 'Get the state of a specific entity by entity_id.',
14
- inputSchema: entityIdSchema,
15
- },
16
- wrapToolHandler('getState', async ({ entity_id }: { entity_id: string }) => {
17
- const state = await client.getState(entity_id);
18
- if (!state) {
19
- return toToolResult({ error: 'Entity not found', entity_id, hint: 'Use the searchEntities tool with a keyword to find the correct entity_id' }, true);
20
- }
21
- return toToolResult(state);
22
- }, Permission.QUERY)
23
- );
24
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * getStates tool - Get all entity states from Home Assistant
3
- * Returns paginated, lightweight entities by default to reduce response size.
4
- */
5
-
6
- import type { McpServer } from '@modelcontextprotocol/server';
7
- import type { HaClient } from '../../haClient/index.js';
8
- import { toLightweight } from '../../types/index.js';
9
- import { haPaginationSchema, toToolResult, wrapToolHandler, Permission, paginateArray } from '../common.js';
10
-
11
- export function registerGetStatesTool(server: McpServer, client: HaClient): void {
12
- server.registerTool(
13
- 'getStates',
14
- {
15
- description: 'Get all entity states from Home Assistant. Returns paginated lightweight entities by default (50 per page). Use includeAttributes=true for full entity data.',
16
- inputSchema: haPaginationSchema,
17
- },
18
- wrapToolHandler('getStates', async (args) => {
19
- const { page, pageSize, includeAttributes } = args;
20
- const states = await client.getStates();
21
-
22
- if (includeAttributes) {
23
- // Return full entities with all attributes
24
- const result = paginateArray(states, page, pageSize);
25
- return toToolResult({
26
- page: result.page,
27
- pageSize: result.pageSize,
28
- totalCount: result.totalCount,
29
- totalPages: result.totalPages,
30
- entities: result.items,
31
- });
32
- }
33
-
34
- // Default: return lightweight entities
35
- const lightweight = states.map(toLightweight);
36
- const result = paginateArray(lightweight, page, pageSize);
37
- return toToolResult({
38
- page: result.page,
39
- pageSize: result.pageSize,
40
- totalCount: result.totalCount,
41
- totalPages: result.totalPages,
42
- entities: result.items,
43
- });
44
- }, Permission.QUERY)
45
- );
46
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * getVersion tool - Get Home Assistant version info
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { emptySchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
-
9
- export function registerGetVersionTool(server: McpServer, client: HaClient): void {
10
- server.registerTool(
11
- 'getVersion',
12
- {
13
- description: 'Get Home Assistant version and configuration information.',
14
- inputSchema: emptySchema,
15
- },
16
- wrapToolHandler('getVersion', async () => {
17
- const version = await client.getVersion();
18
- return toToolResult(version);
19
- }, Permission.QUERY)
20
- );
21
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * Home Assistant tools index - registers all HA MCP tools
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { logger } from '../../utils/logger.js';
8
-
9
- // State & Entity Tools
10
- import { registerGetStatesTool } from './getStates.js';
11
- import { registerGetStateTool } from './getState.js';
12
- import { registerGetEntitiesByDomainTool } from './getEntitiesByDomain.js';
13
- import { registerSearchEntitiesTool } from './searchEntities.js';
14
- import { registerGetAllSensorsTool } from './getAllSensors.js';
15
- import { registerListEntitiesTool } from './listEntities.js';
16
- import { registerGetDomainSummaryTool } from './getDomainSummary.js';
17
- import { registerGetHistoryTool } from './getHistory.js';
18
-
19
- // Service & Control Tools
20
- import { registerCallServiceTool } from './callService.js';
21
- import { registerEntityActionTool } from './entityAction.js';
22
-
23
- // Device Control Tools
24
- import { registerControlLightTool } from './controlLight.js';
25
- import { registerControlClimateTool } from './controlClimate.js';
26
- import { registerControlMediaPlayerTool } from './controlMediaPlayer.js';
27
- import { registerControlCoverTool } from './controlCover.js';
28
- import { registerControlFanTool } from './controlFan.js';
29
- import { registerActivateSceneTool, registerRunScriptTool } from './sceneAndScript.js';
30
- import { registerSendNotificationTool, registerListNotificationTargetsTool } from './sendNotification.js';
31
-
32
- // Automation Tools
33
- import { registerListAutomationsTool } from './listAutomations.js';
34
- import { registerTriggerAutomationTool } from './triggerAutomation.js';
35
- import {
36
- registerEnableAutomationTool,
37
- registerDisableAutomationTool,
38
- registerToggleAutomationTool,
39
- registerReloadAutomationsTool,
40
- } from './automationControls.js';
41
- import { registerCreateAutomationTool } from './createAutomation.js';
42
- import { registerDeleteAutomationTool } from './deleteAutomation.js';
43
- import { registerGetAutomationTraceTool } from './getAutomationTrace.js';
44
-
45
- // System Tools
46
- import { registerGetVersionTool } from './getVersion.js';
47
- import {
48
- registerRestartHomeAssistantTool,
49
- registerGetSystemLogTool,
50
- registerCheckUpdatesTool,
51
- } from './systemTools.js';
52
-
53
- // Calendar Tools
54
- import { registerListCalendarsTool, registerGetCalendarEventsTool } from './calendar.js';
55
-
56
- // Person Tools
57
- import { registerListPersonsTool } from './listPersons.js';
58
-
59
- export function registerHomeAssistantTools(server: McpServer, client: HaClient): number {
60
- logger.debug('Registering Home Assistant tools');
61
- let toolCount = 0;
62
-
63
- // State & Entity Tools
64
- registerGetStatesTool(server, client);
65
- registerGetStateTool(server, client);
66
- registerGetEntitiesByDomainTool(server, client);
67
- registerSearchEntitiesTool(server, client);
68
- registerGetAllSensorsTool(server, client);
69
- registerListEntitiesTool(server, client);
70
- registerGetDomainSummaryTool(server, client);
71
- registerGetHistoryTool(server, client);
72
- toolCount += 8;
73
-
74
- // Service & Control Tools
75
- registerCallServiceTool(server, client);
76
- registerEntityActionTool(server, client);
77
- toolCount += 2;
78
-
79
- // Device Control Tools
80
- registerControlLightTool(server, client);
81
- registerControlClimateTool(server, client);
82
- registerControlMediaPlayerTool(server, client);
83
- registerControlCoverTool(server, client);
84
- registerControlFanTool(server, client);
85
- registerActivateSceneTool(server, client);
86
- registerRunScriptTool(server, client);
87
- registerSendNotificationTool(server, client);
88
- registerListNotificationTargetsTool(server, client);
89
- toolCount += 9;
90
-
91
- // Automation Tools
92
- registerListAutomationsTool(server, client);
93
- registerTriggerAutomationTool(server, client);
94
- registerEnableAutomationTool(server, client);
95
- registerDisableAutomationTool(server, client);
96
- registerToggleAutomationTool(server, client);
97
- registerReloadAutomationsTool(server, client);
98
- registerCreateAutomationTool(server, client);
99
- registerDeleteAutomationTool(server, client);
100
- registerGetAutomationTraceTool(server, client);
101
- toolCount += 9;
102
-
103
- // System Tools
104
- registerGetVersionTool(server, client);
105
- registerRestartHomeAssistantTool(server, client);
106
- registerGetSystemLogTool(server, client);
107
- registerCheckUpdatesTool(server, client);
108
- toolCount += 4;
109
-
110
- // Calendar Tools
111
- registerListCalendarsTool(server, client);
112
- registerGetCalendarEventsTool(server, client);
113
- toolCount += 2;
114
-
115
- // Person Tools
116
- registerListPersonsTool(server, client);
117
- toolCount += 1;
118
-
119
- logger.info('Home Assistant tools registered', { toolCount });
120
- return toolCount;
121
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * listAutomations tool - List all automations
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { automationFilterSchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
- import type { z } from 'zod';
9
-
10
- type ListAutomationsArgs = z.infer<typeof automationFilterSchema>;
11
-
12
- /**
13
- * Shared handler — used by the MCP registration below AND the chat face
14
- * (`POST /api/tools/listAutomations`) so both doors behave identically.
15
- */
16
- export function createListAutomationsHandler(client: HaClient) {
17
- return wrapToolHandler('listAutomations', async ({ state }: ListAutomationsArgs) => {
18
- let automations = await client.getAutomations();
19
- if (state) {
20
- automations = automations.filter(a => a.state === state);
21
- }
22
- return toToolResult({ count: automations.length, filter: state ? { state } : null, automations });
23
- }, Permission.QUERY);
24
- }
25
-
26
- export function registerListAutomationsTool(server: McpServer, client: HaClient): void {
27
- server.registerTool(
28
- 'listAutomations',
29
- {
30
- description: 'List all Home Assistant automations with their status and last triggered time.',
31
- inputSchema: automationFilterSchema,
32
- },
33
- createListAutomationsHandler(client)
34
- );
35
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * listEntities tool - List entities with optional filtering
3
- * Returns lightweight entities by default to reduce response size.
4
- */
5
-
6
- import { z } from 'zod';
7
- import type { McpServer } from '@modelcontextprotocol/server';
8
- import type { HaClient } from '../../haClient/index.js';
9
- import { toLightweight } from '../../types/index.js';
10
- import { toToolResult, wrapToolHandler, Permission } from '../common.js';
11
-
12
- const listEntitiesSchema = z.object({
13
- domain: z.string().optional().describe('Filter by domain (e.g., "light", "switch", "sensor")'),
14
- search: z.string().optional().describe('Search query to filter by entity_id or friendly_name'),
15
- state: z.string().optional().describe('Filter by state (e.g., "on", "off", "unavailable")'),
16
- limit: z.number().int().min(1).max(200).default(50).describe('Maximum number of entities to return (1-200, default 50)'),
17
- includeAttributes: z.boolean().default(false).describe('Include full attributes (increases response size significantly)'),
18
- });
19
-
20
- type ListEntitiesArgs = z.infer<typeof listEntitiesSchema>;
21
-
22
- export function registerListEntitiesTool(server: McpServer, client: HaClient): void {
23
- server.registerTool(
24
- 'listEntities',
25
- {
26
- description: 'List entities with optional filtering by domain, state, or search query. Returns lightweight entities by default (limit 50). Use includeAttributes=true for full entity data.',
27
- inputSchema: listEntitiesSchema,
28
- },
29
- wrapToolHandler('listEntities', async (args: ListEntitiesArgs) => {
30
- const { includeAttributes, ...filterArgs } = args;
31
- const allEntities = await client.listEntities(filterArgs);
32
-
33
- // Convert to lightweight entities unless full attributes requested
34
- const entities = includeAttributes ? allEntities : allEntities.map(toLightweight);
35
-
36
- return toToolResult({
37
- count: entities.length,
38
- limit: args.limit,
39
- filters: { domain: args.domain, search: args.search, state: args.state },
40
- entities,
41
- });
42
- }, Permission.QUERY)
43
- );
44
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * listPersons tool - List all person entities (household members)
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { emptySchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
-
9
- export function registerListPersonsTool(server: McpServer, client: HaClient): void {
10
- server.registerTool(
11
- 'listPersons',
12
- {
13
- description: `List all household members (person entities) in Home Assistant.
14
-
15
- Returns each person's name, location state (home/away/unknown), and linked device trackers.
16
-
17
- Use this tool when the user asks:
18
- - "Who's home?"
19
- - "Where is everyone?"
20
- - "List family members"
21
- - "Is anyone home?"
22
- - "Where is Dad/Mom/etc?"`,
23
- inputSchema: emptySchema,
24
- },
25
- wrapToolHandler('listPersons', async () => {
26
- const entities = await client.getEntitiesByDomain('person');
27
-
28
- const persons = entities.map(entity => ({
29
- entity_id: entity.entity_id,
30
- name: entity.attributes.friendly_name || entity.entity_id.replace('person.', ''),
31
- state: entity.state, // home, not_home, unknown
32
- device_trackers: entity.attributes.source ? [entity.attributes.source] : [],
33
- }));
34
-
35
- const onsiteCount = persons.filter(p => p.state === 'home').length;
36
- const awayCount = persons.filter(p => p.state === 'not_home').length;
37
-
38
- return toToolResult({
39
- count: persons.length,
40
- onsite: onsiteCount,
41
- away: awayCount,
42
- persons,
43
- });
44
- }, Permission.QUERY)
45
- );
46
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * Scene and Script tools - Activate scenes and run scripts
3
- */
4
-
5
- import type { McpServer } from '@modelcontextprotocol/server';
6
- import type { HaClient } from '../../haClient/index.js';
7
- import { entityIdSchema, runScriptSchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
8
- import { entityNotFoundResult } from './entityGuard.js';
9
- import type { z } from 'zod';
10
-
11
- type EntityIdArgs = z.infer<typeof entityIdSchema>;
12
- type RunScriptArgs = z.infer<typeof runScriptSchema>;
13
-
14
- export function registerActivateSceneTool(server: McpServer, client: HaClient): void {
15
- server.registerTool(
16
- 'activateScene',
17
- {
18
- description: 'Activate a Home Assistant scene.',
19
- inputSchema: entityIdSchema,
20
- },
21
- wrapToolHandler('activateScene', async ({ entity_id }: EntityIdArgs) => {
22
- const missing = await entityNotFoundResult(client, entity_id);
23
- if (missing) return missing;
24
- const result = await client.callService({
25
- domain: 'scene',
26
- service: 'turn_on',
27
- target: { entity_id },
28
- });
29
- return toToolResult({ success: true, entity_id, action: 'activated', context: result.context });
30
- }, Permission.CONTROL)
31
- );
32
- }
33
-
34
- export function registerRunScriptTool(server: McpServer, client: HaClient): void {
35
- server.registerTool(
36
- 'runScript',
37
- {
38
- description: 'Run a Home Assistant script with optional variables.',
39
- inputSchema: runScriptSchema,
40
- },
41
- wrapToolHandler('runScript', async ({ entity_id, variables }: RunScriptArgs) => {
42
- const missing = await entityNotFoundResult(client, entity_id);
43
- if (missing) return missing;
44
- const result = await client.callService({
45
- domain: 'script',
46
- service: 'turn_on',
47
- target: { entity_id },
48
- service_data: variables as Record<string, unknown> | undefined,
49
- });
50
- return toToolResult({ success: true, entity_id, action: 'executed', context: result.context });
51
- }, Permission.CONTROL)
52
- );
53
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * searchEntities tool - Search for entities by name or entity_id
3
- * Returns paginated, lightweight entities by default to reduce response size.
4
- */
5
-
6
- import { z } from 'zod';
7
- import type { McpServer } from '@modelcontextprotocol/server';
8
- import type { HaClient } from '../../haClient/index.js';
9
- import { toLightweight } from '../../types/index.js';
10
- import { toToolResult, wrapToolHandler, Permission, paginateArray } from '../common.js';
11
-
12
- const searchEntitiesSchema = z.object({
13
- query: z.string().describe('Search query (searches in entity_id and friendly_name)'),
14
- page: z.number().int().min(1).default(1).describe('Page number (starts at 1)'),
15
- pageSize: z.number().int().min(1).max(200).default(50).describe('Entities per page (1-200, default 50)'),
16
- includeAttributes: z.boolean().default(false).describe('Include full attributes (increases response size significantly)'),
17
- });
18
-
19
- export function registerSearchEntitiesTool(server: McpServer, client: HaClient): void {
20
- server.registerTool(
21
- 'searchEntities',
22
- {
23
- description: `Search for entities by name or entity_id. Returns paginated lightweight entities by default (50 per page). Use includeAttributes=true for full entity data.
24
-
25
- Note: For queries about people, family members, or "who's home?", use the listPersons tool instead.`,
26
- inputSchema: searchEntitiesSchema,
27
- },
28
- wrapToolHandler('searchEntities', async (args) => {
29
- const { query, page, pageSize, includeAttributes } = args;
30
- const allEntities = await client.searchEntities(query);
31
-
32
- if (includeAttributes) {
33
- // Return full entities with all attributes
34
- const result = paginateArray(allEntities, page, pageSize);
35
- return toToolResult({
36
- query,
37
- page: result.page,
38
- pageSize: result.pageSize,
39
- totalCount: result.totalCount,
40
- totalPages: result.totalPages,
41
- entities: result.items,
42
- });
43
- }
44
-
45
- // Default: return lightweight entities
46
- const lightweight = allEntities.map(toLightweight);
47
- const result = paginateArray(lightweight, page, pageSize);
48
- return toToolResult({
49
- query,
50
- page: result.page,
51
- pageSize: result.pageSize,
52
- totalCount: result.totalCount,
53
- totalPages: result.totalPages,
54
- entities: result.items,
55
- });
56
- }, Permission.QUERY)
57
- );
58
- }
@@ -1,179 +0,0 @@
1
- /**
2
- * sendNotification tool - Send notifications through Home Assistant
3
- * Supports HA Mobile App notifications with actions, images, sounds, and more
4
- */
5
-
6
- import type { McpServer } from '@modelcontextprotocol/server';
7
- import type { HaClient } from '../../haClient/index.js';
8
- import { sendNotificationSchema, listNotificationTargetsSchema, toToolResult, wrapToolHandler, Permission } from '../common.js';
9
- import type { z } from 'zod';
10
-
11
- type SendNotificationArgs = z.infer<typeof sendNotificationSchema>;
12
-
13
- /**
14
- * Build notification data object for mobile app
15
- */
16
- function buildNotificationData(args: SendNotificationArgs): Record<string, unknown> {
17
- const data: Record<string, unknown> = {};
18
-
19
- // Tag and grouping
20
- if (args.tag) data.tag = args.tag;
21
- if (args.group) data.group = args.group;
22
-
23
- // Priority and importance (Android)
24
- if (args.priority) data.priority = args.priority;
25
- if (args.importance) data.importance = args.importance;
26
- if (args.ttl) data.ttl = args.ttl;
27
-
28
- // Actions - format for mobile app
29
- if (args.actions && args.actions.length > 0) {
30
- data.actions = args.actions.map(action => ({
31
- action: action.action,
32
- title: action.title,
33
- ...(action.uri && { uri: action.uri }),
34
- }));
35
- }
36
-
37
- // Media
38
- if (args.image) data.image = args.image;
39
- if (args.video) data.video = args.video;
40
- if (args.icon_url) data.icon_url = args.icon_url;
41
-
42
- // Behavior
43
- if (args.sticky !== undefined) data.sticky = args.sticky;
44
- if (args.persistent !== undefined) data.persistent = args.persistent;
45
- if (args.clickAction) data.clickAction = args.clickAction;
46
-
47
- // Sound and vibration (Android)
48
- if (args.channel) data.channel = args.channel;
49
- if (args.vibrationPattern) data.vibrationPattern = args.vibrationPattern;
50
- if (args.ledColor) data.ledColor = args.ledColor;
51
-
52
- // iOS specific
53
- if (args.sound) data.sound = args.sound;
54
- if (args.badge !== undefined) data.badge = args.badge;
55
- if (args.interruptionLevel) data['push'] = { 'interruption-level': args.interruptionLevel };
56
-
57
- // Merge any raw data passed through
58
- if (args.data) {
59
- Object.assign(data, args.data);
60
- }
61
-
62
- return data;
63
- }
64
-
65
- export function registerSendNotificationTool(server: McpServer, client: HaClient): void {
66
- server.registerTool(
67
- 'sendNotification',
68
- {
69
- description: `Send a notification through Home Assistant Mobile App or persistent notifications.
70
-
71
- Features for mobile app notifications:
72
- - Actionable notifications with up to 3 buttons
73
- - Images and videos
74
- - Custom sounds and vibration patterns
75
- - Notification grouping and replacement (via tag)
76
- - Priority and importance settings
77
- - Sticky/persistent notifications
78
- - iOS interruption levels (passive, active, time-sensitive, critical)
79
-
80
- To clear a notification, send message "clear_notification" with the same tag.
81
-
82
- Examples:
83
- - Simple: { message: "Hello!", target: "mobile_app_phone" }
84
- - With actions: { message: "Doorbell", target: "mobile_app_phone", actions: [{ action: "OPEN", title: "Open Door" }] }
85
- - With image: { message: "Camera alert", target: "mobile_app_phone", image: "/api/camera_proxy/camera.front" }`,
86
- inputSchema: sendNotificationSchema,
87
- },
88
- wrapToolHandler('sendNotification', async (args: SendNotificationArgs) => {
89
- const serviceData: Record<string, unknown> = { message: args.message };
90
-
91
- if (args.title) serviceData.title = args.title;
92
-
93
- // Build mobile app data if any mobile-specific options provided
94
- const notificationData = buildNotificationData(args);
95
- if (Object.keys(notificationData).length > 0) {
96
- serviceData.data = notificationData;
97
- }
98
-
99
- const service = args.target || 'persistent_notification';
100
- const result = await client.callService({
101
- domain: 'notify',
102
- service,
103
- service_data: serviceData,
104
- });
105
-
106
- return toToolResult({
107
- success: true,
108
- service: `notify.${service}`,
109
- message: args.message,
110
- title: args.title,
111
- tag: args.tag,
112
- hasActions: args.actions && args.actions.length > 0,
113
- context: result.context,
114
- });
115
- }, Permission.NOTIFY)
116
- );
117
- }
118
-
119
- export function registerListNotificationTargetsTool(server: McpServer, client: HaClient): void {
120
- server.registerTool(
121
- 'listNotificationTargets',
122
- {
123
- description: 'List available notification targets (mobile apps and other notify services). Use this to discover which devices can receive notifications.',
124
- inputSchema: listNotificationTargetsSchema,
125
- },
126
- wrapToolHandler('listNotificationTargets', async () => {
127
- // Get all entities and find mobile_app device trackers to infer notify services
128
- const states = await client.getStates();
129
-
130
- // Find mobile app related entities
131
- const mobileApps: Array<{ target: string; friendly_name?: string; type: string }> = [];
132
-
133
- for (const entity of states) {
134
- // Look for device_tracker.mobile_app_* entities which indicate mobile app presence
135
- if (entity.entity_id.startsWith('device_tracker.') &&
136
- entity.attributes.source_type === 'gps') {
137
- // This might be a mobile app - extract the device name
138
- const match = entity.entity_id.match(/device_tracker\.(.+)/);
139
- if (match) {
140
- const deviceName = match[1];
141
- // Mobile app notify services are typically notify.mobile_app_<device>
142
- mobileApps.push({
143
- target: `mobile_app_${deviceName}`,
144
- friendly_name: entity.attributes.friendly_name as string,
145
- type: 'mobile_app',
146
- });
147
- }
148
- }
149
-
150
- // Also check for notify.* entities directly if available
151
- if (entity.entity_id.startsWith('notify.')) {
152
- const serviceName = entity.entity_id.replace('notify.', '');
153
- mobileApps.push({
154
- target: serviceName,
155
- friendly_name: entity.attributes.friendly_name as string,
156
- type: 'notify_service',
157
- });
158
- }
159
- }
160
-
161
- // Always include persistent_notification as it's always available
162
- const targets = [
163
- { target: 'persistent_notification', friendly_name: 'Persistent Notification (Web UI)', type: 'built_in' },
164
- ...mobileApps,
165
- ];
166
-
167
- // Remove duplicates
168
- const uniqueTargets = targets.filter((t, i, arr) =>
169
- arr.findIndex(x => x.target === t.target) === i
170
- );
171
-
172
- return toToolResult({
173
- count: uniqueTargets.length,
174
- targets: uniqueTargets,
175
- note: 'Mobile app targets are typically named "mobile_app_<device_name>". Use the target value in sendNotification.',
176
- });
177
- }, Permission.QUERY)
178
- );
179
- }