@coffeerunhobby/mcp-ha-connect 0.5.0

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 (294) hide show
  1. package/.dockerignore +8 -0
  2. package/.env.example +149 -0
  3. package/.gitattributes +30 -0
  4. package/Dockerfile +33 -0
  5. package/LICENSE +21 -0
  6. package/README.md +394 -0
  7. package/dist/config.d.ts +33 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +183 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/haClient/automations.d.ts +67 -0
  12. package/dist/haClient/automations.d.ts.map +1 -0
  13. package/dist/haClient/automations.js +181 -0
  14. package/dist/haClient/automations.js.map +1 -0
  15. package/dist/haClient/config.d.ts +28 -0
  16. package/dist/haClient/config.d.ts.map +1 -0
  17. package/dist/haClient/config.js +38 -0
  18. package/dist/haClient/config.js.map +1 -0
  19. package/dist/haClient/devices.d.ts +219 -0
  20. package/dist/haClient/devices.d.ts.map +1 -0
  21. package/dist/haClient/devices.js +506 -0
  22. package/dist/haClient/devices.js.map +1 -0
  23. package/dist/haClient/entities.d.ts +35 -0
  24. package/dist/haClient/entities.d.ts.map +1 -0
  25. package/dist/haClient/entities.js +97 -0
  26. package/dist/haClient/entities.js.map +1 -0
  27. package/dist/haClient/events.d.ts +138 -0
  28. package/dist/haClient/events.d.ts.map +1 -0
  29. package/dist/haClient/events.js +344 -0
  30. package/dist/haClient/events.js.map +1 -0
  31. package/dist/haClient/history.d.ts +26 -0
  32. package/dist/haClient/history.d.ts.map +1 -0
  33. package/dist/haClient/history.js +54 -0
  34. package/dist/haClient/history.js.map +1 -0
  35. package/dist/haClient/index.d.ts +153 -0
  36. package/dist/haClient/index.d.ts.map +1 -0
  37. package/dist/haClient/index.js +223 -0
  38. package/dist/haClient/index.js.map +1 -0
  39. package/dist/haClient/request.d.ts +34 -0
  40. package/dist/haClient/request.d.ts.map +1 -0
  41. package/dist/haClient/request.js +93 -0
  42. package/dist/haClient/request.js.map +1 -0
  43. package/dist/haClient/services.d.ts +22 -0
  44. package/dist/haClient/services.d.ts.map +1 -0
  45. package/dist/haClient/services.js +39 -0
  46. package/dist/haClient/services.js.map +1 -0
  47. package/dist/haClient/states.d.ts +26 -0
  48. package/dist/haClient/states.d.ts.map +1 -0
  49. package/dist/haClient/states.js +53 -0
  50. package/dist/haClient/states.js.map +1 -0
  51. package/dist/haClient/updates.d.ts +22 -0
  52. package/dist/haClient/updates.d.ts.map +1 -0
  53. package/dist/haClient/updates.js +48 -0
  54. package/dist/haClient/updates.js.map +1 -0
  55. package/dist/haClient.d.ts +97 -0
  56. package/dist/haClient.d.ts.map +1 -0
  57. package/dist/haClient.js +344 -0
  58. package/dist/haClient.js.map +1 -0
  59. package/dist/index.d.ts +8 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +92 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/localAI/index.d.ts +37 -0
  64. package/dist/localAI/index.d.ts.map +1 -0
  65. package/dist/localAI/index.js +73 -0
  66. package/dist/localAI/index.js.map +1 -0
  67. package/dist/localAI/prompts.d.ts +20 -0
  68. package/dist/localAI/prompts.d.ts.map +1 -0
  69. package/dist/localAI/prompts.js +48 -0
  70. package/dist/localAI/prompts.js.map +1 -0
  71. package/dist/localAI/providers/base.d.ts +51 -0
  72. package/dist/localAI/providers/base.d.ts.map +1 -0
  73. package/dist/localAI/providers/base.js +80 -0
  74. package/dist/localAI/providers/base.js.map +1 -0
  75. package/dist/localAI/providers/ollama.d.ts +22 -0
  76. package/dist/localAI/providers/ollama.d.ts.map +1 -0
  77. package/dist/localAI/providers/ollama.js +63 -0
  78. package/dist/localAI/providers/ollama.js.map +1 -0
  79. package/dist/localAI/providers/openai.d.ts +23 -0
  80. package/dist/localAI/providers/openai.d.ts.map +1 -0
  81. package/dist/localAI/providers/openai.js +63 -0
  82. package/dist/localAI/providers/openai.js.map +1 -0
  83. package/dist/localAI/types.d.ts +61 -0
  84. package/dist/localAI/types.d.ts.map +1 -0
  85. package/dist/localAI/types.js +6 -0
  86. package/dist/localAI/types.js.map +1 -0
  87. package/dist/ollamaClient.d.ts +37 -0
  88. package/dist/ollamaClient.d.ts.map +1 -0
  89. package/dist/ollamaClient.js +110 -0
  90. package/dist/ollamaClient.js.map +1 -0
  91. package/dist/resources/index.d.ts +11 -0
  92. package/dist/resources/index.d.ts.map +1 -0
  93. package/dist/resources/index.js +238 -0
  94. package/dist/resources/index.js.map +1 -0
  95. package/dist/server/common.d.ts +9 -0
  96. package/dist/server/common.d.ts.map +1 -0
  97. package/dist/server/common.js +27 -0
  98. package/dist/server/common.js.map +1 -0
  99. package/dist/server/eventSubscription.d.ts +53 -0
  100. package/dist/server/eventSubscription.d.ts.map +1 -0
  101. package/dist/server/eventSubscription.js +257 -0
  102. package/dist/server/eventSubscription.js.map +1 -0
  103. package/dist/server/http.d.ts +12 -0
  104. package/dist/server/http.d.ts.map +1 -0
  105. package/dist/server/http.js +491 -0
  106. package/dist/server/http.js.map +1 -0
  107. package/dist/server/rateLimiter.d.ts +70 -0
  108. package/dist/server/rateLimiter.d.ts.map +1 -0
  109. package/dist/server/rateLimiter.js +156 -0
  110. package/dist/server/rateLimiter.js.map +1 -0
  111. package/dist/server/sse.d.ts +32 -0
  112. package/dist/server/sse.d.ts.map +1 -0
  113. package/dist/server/sse.js +76 -0
  114. package/dist/server/sse.js.map +1 -0
  115. package/dist/server/stdio.d.ts +8 -0
  116. package/dist/server/stdio.d.ts.map +1 -0
  117. package/dist/server/stdio.js +16 -0
  118. package/dist/server/stdio.js.map +1 -0
  119. package/dist/server/stream.d.ts +26 -0
  120. package/dist/server/stream.d.ts.map +1 -0
  121. package/dist/server/stream.js +81 -0
  122. package/dist/server/stream.js.map +1 -0
  123. package/dist/server.d.ts +8 -0
  124. package/dist/server.d.ts.map +1 -0
  125. package/dist/server.js +30 -0
  126. package/dist/server.js.map +1 -0
  127. package/dist/tools/callService.d.ts +8 -0
  128. package/dist/tools/callService.d.ts.map +1 -0
  129. package/dist/tools/callService.js +100 -0
  130. package/dist/tools/callService.js.map +1 -0
  131. package/dist/tools/getClient.d.ts +8 -0
  132. package/dist/tools/getClient.d.ts.map +1 -0
  133. package/dist/tools/getClient.js +94 -0
  134. package/dist/tools/getClient.js.map +1 -0
  135. package/dist/tools/getDevice.d.ts +8 -0
  136. package/dist/tools/getDevice.d.ts.map +1 -0
  137. package/dist/tools/getDevice.js +94 -0
  138. package/dist/tools/getDevice.js.map +1 -0
  139. package/dist/tools/getEntitiesByDomain.d.ts +8 -0
  140. package/dist/tools/getEntitiesByDomain.d.ts.map +1 -0
  141. package/dist/tools/getEntitiesByDomain.js +80 -0
  142. package/dist/tools/getEntitiesByDomain.js.map +1 -0
  143. package/dist/tools/getState.d.ts +8 -0
  144. package/dist/tools/getState.d.ts.map +1 -0
  145. package/dist/tools/getState.js +90 -0
  146. package/dist/tools/getState.js.map +1 -0
  147. package/dist/tools/getStates.d.ts +8 -0
  148. package/dist/tools/getStates.d.ts.map +1 -0
  149. package/dist/tools/getStates.js +70 -0
  150. package/dist/tools/getStates.js.map +1 -0
  151. package/dist/tools/index.d.ts +9 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +9 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/listClients.d.ts +8 -0
  156. package/dist/tools/listClients.d.ts.map +1 -0
  157. package/dist/tools/listClients.js +73 -0
  158. package/dist/tools/listClients.js.map +1 -0
  159. package/dist/tools/listDevices.d.ts +8 -0
  160. package/dist/tools/listDevices.d.ts.map +1 -0
  161. package/dist/tools/listDevices.js +73 -0
  162. package/dist/tools/listDevices.js.map +1 -0
  163. package/dist/tools/listSites.d.ts +8 -0
  164. package/dist/tools/listSites.d.ts.map +1 -0
  165. package/dist/tools/listSites.js +67 -0
  166. package/dist/tools/listSites.js.map +1 -0
  167. package/dist/tools/registry.d.ts +9 -0
  168. package/dist/tools/registry.d.ts.map +1 -0
  169. package/dist/tools/registry.js +1382 -0
  170. package/dist/tools/registry.js.map +1 -0
  171. package/dist/tools/searchDevices.d.ts +8 -0
  172. package/dist/tools/searchDevices.d.ts.map +1 -0
  173. package/dist/tools/searchDevices.js +84 -0
  174. package/dist/tools/searchDevices.js.map +1 -0
  175. package/dist/tools/searchEntities.d.ts +8 -0
  176. package/dist/tools/searchEntities.d.ts.map +1 -0
  177. package/dist/tools/searchEntities.js +80 -0
  178. package/dist/tools/searchEntities.js.map +1 -0
  179. package/dist/types/entity.d.ts +98 -0
  180. package/dist/types/entity.d.ts.map +1 -0
  181. package/dist/types/entity.js +2 -0
  182. package/dist/types/entity.js.map +1 -0
  183. package/dist/types/errors.d.ts +16 -0
  184. package/dist/types/errors.d.ts.map +1 -0
  185. package/dist/types/errors.js +32 -0
  186. package/dist/types/errors.js.map +1 -0
  187. package/dist/types/haConfig.d.ts +8 -0
  188. package/dist/types/haConfig.d.ts.map +1 -0
  189. package/dist/types/haConfig.js +2 -0
  190. package/dist/types/haConfig.js.map +1 -0
  191. package/dist/types/index.d.ts +6 -0
  192. package/dist/types/index.d.ts.map +1 -0
  193. package/dist/types/index.js +2 -0
  194. package/dist/types/index.js.map +1 -0
  195. package/dist/types/request.d.ts +7 -0
  196. package/dist/types/request.d.ts.map +1 -0
  197. package/dist/types/request.js +2 -0
  198. package/dist/types/request.js.map +1 -0
  199. package/dist/types/serviceCall.d.ts +18 -0
  200. package/dist/types/serviceCall.d.ts.map +1 -0
  201. package/dist/types/serviceCall.js +2 -0
  202. package/dist/types/serviceCall.js.map +1 -0
  203. package/dist/types.d.ts +2 -0
  204. package/dist/types.d.ts.map +1 -0
  205. package/dist/types.js +3 -0
  206. package/dist/types.js.map +1 -0
  207. package/dist/utils/config-validations.d.ts +12 -0
  208. package/dist/utils/config-validations.d.ts.map +1 -0
  209. package/dist/utils/config-validations.js +43 -0
  210. package/dist/utils/config-validations.js.map +1 -0
  211. package/dist/utils/logger.d.ts +24 -0
  212. package/dist/utils/logger.d.ts.map +1 -0
  213. package/dist/utils/logger.js +94 -0
  214. package/dist/utils/logger.js.map +1 -0
  215. package/dist/wrapper.d.ts +8 -0
  216. package/dist/wrapper.d.ts.map +1 -0
  217. package/dist/wrapper.js +301 -0
  218. package/dist/wrapper.js.map +1 -0
  219. package/docker-compose.yml +17 -0
  220. package/docs/CHANGELOG.md +86 -0
  221. package/docs/LOCAL_CLIENT.md +268 -0
  222. package/docs/SSE_API.md +341 -0
  223. package/eslint.config.js +33 -0
  224. package/n8n/ai-agent-safety-monitor.json +355 -0
  225. package/openapi.json +166 -0
  226. package/package.json +51 -0
  227. package/src/config.ts +260 -0
  228. package/src/haClient/automations.ts +217 -0
  229. package/src/haClient/config.ts +41 -0
  230. package/src/haClient/devices.ts +653 -0
  231. package/src/haClient/entities.ts +128 -0
  232. package/src/haClient/events.ts +456 -0
  233. package/src/haClient/history.ts +68 -0
  234. package/src/haClient/index.ts +287 -0
  235. package/src/haClient/request.ts +127 -0
  236. package/src/haClient/services.ts +45 -0
  237. package/src/haClient/states.ts +60 -0
  238. package/src/haClient/updates.ts +58 -0
  239. package/src/index.ts +99 -0
  240. package/src/localAI/index.ts +88 -0
  241. package/src/localAI/prompts.ts +50 -0
  242. package/src/localAI/providers/base.ts +120 -0
  243. package/src/localAI/providers/ollama.ts +78 -0
  244. package/src/localAI/providers/openai.ts +86 -0
  245. package/src/localAI/types.ts +67 -0
  246. package/src/resources/index.ts +266 -0
  247. package/src/server/common.ts +38 -0
  248. package/src/server/eventSubscription.ts +318 -0
  249. package/src/server/http.ts +546 -0
  250. package/src/server/rateLimiter.ts +195 -0
  251. package/src/server/sse.ts +120 -0
  252. package/src/server/stdio.ts +22 -0
  253. package/src/server/stream.ts +113 -0
  254. package/src/tools/callService.ts +114 -0
  255. package/src/tools/getEntitiesByDomain.ts +92 -0
  256. package/src/tools/getState.ts +103 -0
  257. package/src/tools/getStates.ts +80 -0
  258. package/src/tools/index.ts +9 -0
  259. package/src/tools/registry.ts +1521 -0
  260. package/src/tools/searchEntities.ts +92 -0
  261. package/src/types/entity.ts +110 -0
  262. package/src/types/errors.ts +33 -0
  263. package/src/types/haConfig.ts +7 -0
  264. package/src/types/index.ts +5 -0
  265. package/src/types/request.ts +6 -0
  266. package/src/types/serviceCall.ts +18 -0
  267. package/src/types.ts +2 -0
  268. package/src/utils/config-validations.ts +46 -0
  269. package/src/utils/logger.ts +114 -0
  270. package/src/wrapper.ts +340 -0
  271. package/tests/config.test.ts +332 -0
  272. package/tests/haClient/automations.test.ts +133 -0
  273. package/tests/haClient/config.test.ts +96 -0
  274. package/tests/haClient/entities.test.ts +188 -0
  275. package/tests/haClient/history.test.ts +170 -0
  276. package/tests/haClient/index.test.ts +221 -0
  277. package/tests/haClient/request.test.ts +217 -0
  278. package/tests/haClient/services.test.ts +120 -0
  279. package/tests/haClient/states.test.ts +119 -0
  280. package/tests/haClient/updates.test.ts +193 -0
  281. package/tests/index.test.ts +164 -0
  282. package/tests/localAI/index.test.ts +168 -0
  283. package/tests/localAI/ollama.test.ts +187 -0
  284. package/tests/localAI/openai.test.ts +257 -0
  285. package/tests/server/common.test.ts +64 -0
  286. package/tests/server/http.test.ts +326 -0
  287. package/tests/server/sse.test.ts +240 -0
  288. package/tests/server/stdio.test.ts +102 -0
  289. package/tests/server/stream.test.ts +287 -0
  290. package/tests/tools/registry.test.ts +355 -0
  291. package/tests/utils/config-validations.test.ts +289 -0
  292. package/tests/utils/logger.test.ts +327 -0
  293. package/tsconfig.json +25 -0
  294. package/vitest.config.ts +26 -0
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Local AI Client Types
3
+ * Shared interfaces for AI provider implementations
4
+ */
5
+ /**
6
+ * Supported AI provider types
7
+ * Use 'none' to explicitly disable AI features
8
+ */
9
+ export type AIProviderType = 'ollama' | 'openai' | 'none';
10
+ /**
11
+ * Sensor data input for analysis
12
+ */
13
+ export interface SensorData {
14
+ [entity_id: string]: {
15
+ state: string;
16
+ unit?: string;
17
+ attributes?: Record<string, unknown>;
18
+ };
19
+ }
20
+ /**
21
+ * AI analysis result
22
+ */
23
+ export interface AnalysisResult {
24
+ severity: 'critical' | 'high' | 'medium' | 'low';
25
+ issue: string;
26
+ reasoning: string;
27
+ recommended_actions: string[];
28
+ ssh_diagnostics: string[];
29
+ confidence: number;
30
+ model: string;
31
+ provider: string;
32
+ response_time: number;
33
+ }
34
+ /**
35
+ * AI provider configuration
36
+ */
37
+ export interface AIProviderConfig {
38
+ provider: AIProviderType;
39
+ baseUrl: string;
40
+ model: string;
41
+ timeout: number;
42
+ apiKey?: string;
43
+ }
44
+ /**
45
+ * AI provider interface - all providers must implement this
46
+ */
47
+ export interface AIProviderInterface {
48
+ /**
49
+ * Analyze sensor data using AI
50
+ */
51
+ analyzeSensors(sensors: SensorData): Promise<AnalysisResult>;
52
+ /**
53
+ * Check if the AI provider is available
54
+ */
55
+ checkHealth(): Promise<boolean>;
56
+ /**
57
+ * Get the provider name
58
+ */
59
+ getProviderName(): string;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/localAI/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,SAAS,EAAE,MAAM,GAAG;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAE7D;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhC;;OAEG;IACH,eAAe,IAAI,MAAM,CAAC;CAC3B"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Local AI Client Types
3
+ * Shared interfaces for AI provider implementations
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/localAI/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Ollama AI Client
3
+ * Handles AI analysis requests to Ollama
4
+ */
5
+ import type { EnvironmentConfig } from './config.js';
6
+ export interface SensorData {
7
+ [entity_id: string]: {
8
+ state: string;
9
+ unit?: string;
10
+ attributes?: Record<string, unknown>;
11
+ };
12
+ }
13
+ export interface AnalysisResult {
14
+ severity: 'critical' | 'high' | 'medium' | 'low';
15
+ issue: string;
16
+ reasoning: string;
17
+ recommended_actions: string[];
18
+ ssh_diagnostics: string[];
19
+ confidence: number;
20
+ model: string;
21
+ response_time: number;
22
+ }
23
+ export declare class OllamaClient {
24
+ private baseUrl;
25
+ private model;
26
+ private timeout;
27
+ constructor(config: EnvironmentConfig);
28
+ /**
29
+ * Analyze sensors using Ollama AI
30
+ */
31
+ analyzeSensors(sensors: SensorData): Promise<AnalysisResult>;
32
+ /**
33
+ * Check if Ollama is available
34
+ */
35
+ checkHealth(): Promise<boolean>;
36
+ }
37
+ //# sourceMappingURL=ollamaClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaClient.d.ts","sourceRoot":"","sources":["../src/ollamaClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAwBrD,MAAM,WAAW,UAAU;IACzB,CAAC,SAAS,EAAE,MAAM,GAAG;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB;AAOD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,iBAAiB;IAMrC;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAmElE;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAUtC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Ollama AI Client
3
+ * Handles AI analysis requests to Ollama
4
+ */
5
+ import { logger } from './utils/logger.js';
6
+ // AI System prompt for sensor analysis (from original implementation)
7
+ const AI_SYSTEM_PROMPT = `You are a home automation AI analyzing Home Assistant sensors.
8
+
9
+ SEVERITY RULES:
10
+ - critical: Gas/smoke/CO detected, fire, temp>40°C indoors, power spike>500%, door open>2h with alarm
11
+ - high: Battery<10%, power spike>300%, door open>30min with alarm, temp>35°C
12
+ - medium: Battery<20%, connectivity issues, minor anomalies
13
+ - low: Informational warnings
14
+
15
+ OUTPUT FORMAT (JSON only, no markdown):
16
+ {
17
+ "severity": "critical|high|medium|low",
18
+ "issue": "brief description",
19
+ "reasoning": "detailed explanation",
20
+ "recommended_actions": ["action1", "action2"],
21
+ "ssh_diagnostics": ["command1", "command2"],
22
+ "confidence": 0.85
23
+ }
24
+
25
+ Respond with JSON only. No extra text.`;
26
+ export class OllamaClient {
27
+ baseUrl;
28
+ model;
29
+ timeout;
30
+ constructor(config) {
31
+ this.baseUrl = config.ollamaUrl;
32
+ this.model = config.ollamaModel;
33
+ this.timeout = config.ollamaTimeout;
34
+ }
35
+ /**
36
+ * Analyze sensors using Ollama AI
37
+ */
38
+ async analyzeSensors(sensors) {
39
+ const sensorCount = Object.keys(sensors).length;
40
+ logger.info('Starting AI analysis', { sensorCount, model: this.model });
41
+ const startTime = Date.now();
42
+ const prompt = `${AI_SYSTEM_PROMPT}\n\nAnalyze these sensors: ${JSON.stringify(sensors)}\n\nProvide JSON only:`;
43
+ try {
44
+ const response = await fetch(`${this.baseUrl}/api/generate`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({
48
+ model: this.model,
49
+ prompt,
50
+ stream: false,
51
+ options: {
52
+ temperature: 0.3,
53
+ num_predict: 2000,
54
+ num_ctx: 4096,
55
+ },
56
+ }),
57
+ signal: AbortSignal.timeout(this.timeout),
58
+ });
59
+ if (!response.ok) {
60
+ const errorText = await response.text();
61
+ throw new Error(`Ollama request failed: ${response.status} ${errorText}`);
62
+ }
63
+ const result = await response.json();
64
+ const aiText = result.response ?? '';
65
+ if (!aiText) {
66
+ throw new Error('Empty response from Ollama');
67
+ }
68
+ // Extract JSON from response (handles potential text around JSON)
69
+ const jsonMatch = aiText.match(/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/);
70
+ if (!jsonMatch) {
71
+ throw new Error(`No JSON found in AI response: ${aiText.substring(0, 200)}`);
72
+ }
73
+ const analysis = JSON.parse(jsonMatch[0]);
74
+ const elapsed = (Date.now() - startTime) / 1000;
75
+ logger.info('AI analysis complete', {
76
+ severity: analysis.severity,
77
+ elapsed: `${elapsed.toFixed(2)}s`,
78
+ model: this.model,
79
+ });
80
+ return {
81
+ ...analysis,
82
+ model: this.model,
83
+ response_time: parseFloat(elapsed.toFixed(2)),
84
+ };
85
+ }
86
+ catch (error) {
87
+ const elapsed = (Date.now() - startTime) / 1000;
88
+ logger.error('AI analysis failed', {
89
+ error: error instanceof Error ? error.message : String(error),
90
+ elapsed: `${elapsed.toFixed(2)}s`,
91
+ });
92
+ throw error;
93
+ }
94
+ }
95
+ /**
96
+ * Check if Ollama is available
97
+ */
98
+ async checkHealth() {
99
+ try {
100
+ const response = await fetch(`${this.baseUrl}/api/tags`, {
101
+ signal: AbortSignal.timeout(5000),
102
+ });
103
+ return response.ok;
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+ //# sourceMappingURL=ollamaClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaClient.js","sourceRoot":"","sources":["../src/ollamaClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MCP Resources Registry
3
+ * Provides URI-based access to Home Assistant entities
4
+ */
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import type { HaClient } from '../haClient/index.js';
7
+ /**
8
+ * Register all Home Assistant resources with the MCP server
9
+ */
10
+ export declare function registerAllResources(server: Server, client: HaClient): void;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAwP3E"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * MCP Resources Registry
3
+ * Provides URI-based access to Home Assistant entities
4
+ */
5
+ import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
6
+ import { logger } from '../utils/logger.js';
7
+ /**
8
+ * Register all Home Assistant resources with the MCP server
9
+ */
10
+ export function registerAllResources(server, client) {
11
+ logger.debug('Registering MCP resources');
12
+ // List available resource templates
13
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
14
+ return {
15
+ resourceTemplates: [
16
+ {
17
+ uriTemplate: 'hass://entities/{entity_id}',
18
+ name: 'Entity State',
19
+ description: 'Get the current state of a specific Home Assistant entity',
20
+ mimeType: 'application/json',
21
+ },
22
+ {
23
+ uriTemplate: 'hass://entities/{entity_id}/detailed',
24
+ name: 'Entity Detailed',
25
+ description: 'Get detailed information about an entity including all attributes',
26
+ mimeType: 'application/json',
27
+ },
28
+ {
29
+ uriTemplate: 'hass://entities/domain/{domain}',
30
+ name: 'Domain Entities',
31
+ description: 'Get all entities for a specific domain',
32
+ mimeType: 'application/json',
33
+ },
34
+ {
35
+ uriTemplate: 'hass://search/{query}/{limit}',
36
+ name: 'Search Entities',
37
+ description: 'Search for entities matching a query with result limit',
38
+ mimeType: 'application/json',
39
+ },
40
+ ],
41
+ };
42
+ });
43
+ // List concrete resources (the static entities resource)
44
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
45
+ return {
46
+ resources: [
47
+ {
48
+ uri: 'hass://entities',
49
+ name: 'All Entities',
50
+ description: 'List all Home Assistant entities grouped by domain',
51
+ mimeType: 'application/json',
52
+ },
53
+ ],
54
+ };
55
+ });
56
+ // Read resource content
57
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
58
+ const uri = request.params.uri;
59
+ logger.debug('Reading resource', { uri });
60
+ try {
61
+ // Parse the URI
62
+ const url = new URL(uri);
63
+ const path = url.pathname;
64
+ // hass://entities - List all entities grouped by domain
65
+ if (uri === 'hass://entities') {
66
+ const entities = await client.getStates();
67
+ // Group by domain
68
+ const grouped = {};
69
+ for (const entity of entities) {
70
+ const domain = entity.entity_id.split('.')[0];
71
+ if (!grouped[domain]) {
72
+ grouped[domain] = [];
73
+ }
74
+ grouped[domain].push({
75
+ entity_id: entity.entity_id,
76
+ state: entity.state,
77
+ friendly_name: entity.attributes.friendly_name,
78
+ });
79
+ }
80
+ return {
81
+ contents: [
82
+ {
83
+ uri,
84
+ mimeType: 'application/json',
85
+ text: JSON.stringify({
86
+ total: entities.length,
87
+ domains: Object.keys(grouped).length,
88
+ entities: grouped,
89
+ }, null, 2),
90
+ },
91
+ ],
92
+ };
93
+ }
94
+ // hass://entities/{entity_id}/detailed - Detailed entity info
95
+ if (path.endsWith('/detailed')) {
96
+ const entityId = path.replace('/detailed', '').replace(/^\//, '');
97
+ const entity = await client.getState(entityId);
98
+ if (!entity) {
99
+ return {
100
+ contents: [
101
+ {
102
+ uri,
103
+ mimeType: 'application/json',
104
+ text: JSON.stringify({ error: 'Entity not found', entity_id: entityId }),
105
+ },
106
+ ],
107
+ };
108
+ }
109
+ return {
110
+ contents: [
111
+ {
112
+ uri,
113
+ mimeType: 'application/json',
114
+ text: JSON.stringify({
115
+ entity_id: entity.entity_id,
116
+ state: entity.state,
117
+ attributes: entity.attributes,
118
+ last_changed: entity.last_changed,
119
+ last_updated: entity.last_updated,
120
+ context: entity.context,
121
+ }, null, 2),
122
+ },
123
+ ],
124
+ };
125
+ }
126
+ // hass://entities/domain/{domain} - Entities by domain
127
+ if (path.startsWith('/domain/')) {
128
+ const domain = path.replace('/domain/', '');
129
+ const entities = await client.getEntitiesByDomain(domain);
130
+ return {
131
+ contents: [
132
+ {
133
+ uri,
134
+ mimeType: 'application/json',
135
+ text: JSON.stringify({
136
+ domain,
137
+ count: entities.length,
138
+ entities: entities.map(e => ({
139
+ entity_id: e.entity_id,
140
+ state: e.state,
141
+ friendly_name: e.attributes.friendly_name,
142
+ })),
143
+ }, null, 2),
144
+ },
145
+ ],
146
+ };
147
+ }
148
+ // hass://search/{query}/{limit} - Search entities
149
+ if (path.startsWith('/search/')) {
150
+ const parts = path.replace('/search/', '').split('/');
151
+ const query = decodeURIComponent(parts[0] || '');
152
+ const limit = parseInt(parts[1] || '50', 10);
153
+ let entities = await client.searchEntities(query);
154
+ if (limit > 0) {
155
+ entities = entities.slice(0, limit);
156
+ }
157
+ return {
158
+ contents: [
159
+ {
160
+ uri,
161
+ mimeType: 'application/json',
162
+ text: JSON.stringify({
163
+ query,
164
+ limit,
165
+ count: entities.length,
166
+ entities: entities.map(e => ({
167
+ entity_id: e.entity_id,
168
+ state: e.state,
169
+ friendly_name: e.attributes.friendly_name,
170
+ })),
171
+ }, null, 2),
172
+ },
173
+ ],
174
+ };
175
+ }
176
+ // hass://entities/{entity_id} - Simple entity state
177
+ const entityId = path.replace(/^\//, '');
178
+ if (entityId && !entityId.includes('/')) {
179
+ const entity = await client.getState(entityId);
180
+ if (!entity) {
181
+ return {
182
+ contents: [
183
+ {
184
+ uri,
185
+ mimeType: 'application/json',
186
+ text: JSON.stringify({ error: 'Entity not found', entity_id: entityId }),
187
+ },
188
+ ],
189
+ };
190
+ }
191
+ return {
192
+ contents: [
193
+ {
194
+ uri,
195
+ mimeType: 'application/json',
196
+ text: JSON.stringify({
197
+ entity_id: entity.entity_id,
198
+ state: entity.state,
199
+ friendly_name: entity.attributes.friendly_name,
200
+ last_changed: entity.last_changed,
201
+ }, null, 2),
202
+ },
203
+ ],
204
+ };
205
+ }
206
+ // Unknown resource
207
+ return {
208
+ contents: [
209
+ {
210
+ uri,
211
+ mimeType: 'application/json',
212
+ text: JSON.stringify({ error: 'Unknown resource', uri }),
213
+ },
214
+ ],
215
+ };
216
+ }
217
+ catch (error) {
218
+ logger.error('Failed to read resource', {
219
+ uri,
220
+ error: error instanceof Error ? error.message : String(error),
221
+ });
222
+ return {
223
+ contents: [
224
+ {
225
+ uri,
226
+ mimeType: 'application/json',
227
+ text: JSON.stringify({
228
+ error: 'Failed to read resource',
229
+ message: error instanceof Error ? error.message : String(error),
230
+ }),
231
+ },
232
+ ],
233
+ };
234
+ }
235
+ });
236
+ logger.info('MCP resources registered successfully', { resourceCount: 5 });
237
+ }
238
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Common MCP server creation
3
+ * Shared across all transport types (stdio, SSE, stream)
4
+ */
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import type { HaClient } from '../haClient/index.js';
7
+ import type { LocalAIClient } from '../localAI/index.js';
8
+ export declare function createServer(client: HaClient, aiClient?: LocalAIClient): Server;
9
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/server/common.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKzD,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,CAyB/E"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Common MCP server creation
3
+ * Shared across all transport types (stdio, SSE, stream)
4
+ */
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import { registerAllTools } from '../tools/registry.js';
7
+ import { registerAllResources } from '../resources/index.js';
8
+ import { logger } from '../utils/logger.js';
9
+ export function createServer(client, aiClient) {
10
+ logger.debug('Creating MCP server instance');
11
+ const server = new Server({
12
+ name: 'mcp-ha-connect',
13
+ version: '0.4.0',
14
+ }, {
15
+ capabilities: {
16
+ tools: {},
17
+ resources: {},
18
+ },
19
+ });
20
+ // Register all Home Assistant tools
21
+ registerAllTools(server, client, aiClient);
22
+ // Register all Home Assistant resources
23
+ registerAllResources(server, client);
24
+ logger.debug('MCP server instance created with 15 tools and 5 resources registered');
25
+ return server;
26
+ }
27
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/server/common.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,UAAU,YAAY,CAAC,MAAgB,EAAE,QAAwB;IACrE,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,SAAS,EAAE,EAAE;SACd;KACF,CACF,CAAC;IAEF,oCAAoC;IACpC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAE3C,wCAAwC;IACxC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErC,MAAM,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;IAErF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * SSE Event Subscription Endpoint
3
+ * Allows HTTP clients to subscribe to Home Assistant events via Server-Sent Events
4
+ */
5
+ import type { IncomingMessage, ServerResponse } from 'node:http';
6
+ import type { EventSubscriber } from '../haClient/events.js';
7
+ export interface SSEClient {
8
+ id: string;
9
+ res: ServerResponse;
10
+ subscriptionIds: string[];
11
+ domain?: string;
12
+ entityId?: string;
13
+ eventTypes?: string[];
14
+ createdAt: Date;
15
+ lastEventAt?: Date;
16
+ eventCount: number;
17
+ }
18
+ /**
19
+ * Handle SSE subscription request
20
+ */
21
+ export declare function handleEventSubscription(req: IncomingMessage, res: ServerResponse, eventSubscriber: EventSubscriber): Promise<void>;
22
+ /**
23
+ * Get list of active SSE clients
24
+ */
25
+ export declare function getActiveClients(): Array<{
26
+ id: string;
27
+ domain?: string;
28
+ entityId?: string;
29
+ eventTypes?: string[];
30
+ createdAt: Date;
31
+ lastEventAt?: Date;
32
+ eventCount: number;
33
+ }>;
34
+ /**
35
+ * Get count of active SSE clients
36
+ */
37
+ export declare function getClientCount(): number;
38
+ /**
39
+ * Broadcast event to all matching clients
40
+ */
41
+ export declare function broadcastEvent(event: string, data: unknown, filter?: {
42
+ domain?: string;
43
+ entityId?: string;
44
+ }): void;
45
+ /**
46
+ * Disconnect a specific client
47
+ */
48
+ export declare function disconnectClient(clientId: string): boolean;
49
+ /**
50
+ * Disconnect all clients
51
+ */
52
+ export declare function disconnectAllClients(): number;
53
+ //# sourceMappingURL=eventSubscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventSubscription.d.ts","sourceRoot":"","sources":["../../src/server/eventSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAW,MAAM,uBAAuB,CAAC;AAGtE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,cAAc,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAuCD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,IAAI,CAAC,CAyKf;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAUD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAcP;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAU7C"}