@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,24 @@
1
+ type LogFields = Record<string, unknown>;
2
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
3
+ type LogFormat = 'plain' | 'json' | 'gcp-json';
4
+ /**
5
+ * Initialize the logger with a specific log level and format.
6
+ * This should be called once during application startup.
7
+ * @param level - The minimum log level to output
8
+ * @param format - The output format (plain, json, or gcp-json)
9
+ * @param useStderr - If true, logs to stderr instead of stdout (required for stdio transport)
10
+ */
11
+ export declare function initLogger(level: LogLevel, format?: LogFormat, useStderr?: boolean): void;
12
+ /**
13
+ * Set the logger level dynamically
14
+ * @param level - The new log level
15
+ */
16
+ export declare function setLevel(level: LogLevel): void;
17
+ export declare const logger: {
18
+ debug(message: string, meta?: LogFields): void;
19
+ info(message: string, meta?: LogFields): void;
20
+ warn(message: string, meta?: LogFields): void;
21
+ error(message: string, meta?: LogFields): void;
22
+ };
23
+ export type { LogLevel, LogFormat, LogFields };
24
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzC,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/D,KAAK,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AA6C/C;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAE,SAAmB,EAAE,SAAS,UAAQ,GAAG,IAAI,CAEhG;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAE9C;AA6BD,eAAO,MAAM,MAAM;mBACF,MAAM,SAAS,SAAS;kBAGzB,MAAM,SAAS,SAAS;kBAGxB,MAAM,SAAS,SAAS;mBAGvB,MAAM,SAAS,SAAS;CAGxC,CAAC;AAGF,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,94 @@
1
+ import pino from 'pino';
2
+ const levelToSeverity = {
3
+ trace: 'DEBUG',
4
+ debug: 'DEBUG',
5
+ info: 'INFO',
6
+ warn: 'WARNING',
7
+ error: 'ERROR',
8
+ fatal: 'CRITICAL',
9
+ };
10
+ let instance;
11
+ function createLogger(level = 'info', format = 'plain', useStderr = false) {
12
+ const baseConfig = {
13
+ level,
14
+ base: undefined,
15
+ messageKey: 'message',
16
+ timestamp: pino.stdTimeFunctions.isoTime,
17
+ };
18
+ // Configure formatters based on format
19
+ if (format === 'gcp-json') {
20
+ baseConfig.formatters = {
21
+ level(label) {
22
+ return { severity: levelToSeverity[label] ?? label.toUpperCase() };
23
+ },
24
+ };
25
+ }
26
+ else if (format === 'plain') {
27
+ baseConfig.formatters = {
28
+ level(label) {
29
+ return { level: label.toUpperCase() };
30
+ },
31
+ };
32
+ }
33
+ // For 'json' format, use default pino JSON output (no special formatters)
34
+ // When running in stdio mode, always log to stderr to avoid interfering with MCP protocol on stdout
35
+ return useStderr ? pino(baseConfig, process.stderr) : pino(baseConfig);
36
+ }
37
+ // Initialize with default, will be reconfigured by calling initLogger
38
+ const defaultLevel = process.env.MCP_SERVER_LOG_LEVEL ?? 'info';
39
+ instance = createLogger(defaultLevel);
40
+ /**
41
+ * Initialize the logger with a specific log level and format.
42
+ * This should be called once during application startup.
43
+ * @param level - The minimum log level to output
44
+ * @param format - The output format (plain, json, or gcp-json)
45
+ * @param useStderr - If true, logs to stderr instead of stdout (required for stdio transport)
46
+ */
47
+ export function initLogger(level, format = 'plain', useStderr = false) {
48
+ instance = createLogger(level, format, useStderr);
49
+ }
50
+ /**
51
+ * Set the logger level dynamically
52
+ * @param level - The new log level
53
+ */
54
+ export function setLevel(level) {
55
+ instance.level = level;
56
+ }
57
+ function normalizeMeta(meta) {
58
+ if (!meta) {
59
+ return undefined;
60
+ }
61
+ const normalized = {};
62
+ for (const [key, value] of Object.entries(meta)) {
63
+ if (value instanceof Error) {
64
+ normalized[key] = { message: value.message, stack: value.stack };
65
+ continue;
66
+ }
67
+ normalized[key] = value;
68
+ }
69
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
70
+ }
71
+ function write(level, message, meta) {
72
+ const fields = normalizeMeta(meta);
73
+ if (fields) {
74
+ instance[level](fields, message);
75
+ }
76
+ else {
77
+ instance[level](message);
78
+ }
79
+ }
80
+ export const logger = {
81
+ debug(message, meta) {
82
+ write('debug', message, meta);
83
+ },
84
+ info(message, meta) {
85
+ write('info', message, meta);
86
+ },
87
+ warn(message, meta) {
88
+ write('warn', message, meta);
89
+ },
90
+ error(message, meta) {
91
+ write('error', message, meta);
92
+ },
93
+ };
94
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * HTTP Wrapper for Home Assistant MCP Server
4
+ * Provides REST API endpoints that call MCP tools under the hood
5
+ * Compatible with legacy mcp-wrapper.js behavior
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * HTTP Wrapper for Home Assistant MCP Server
4
+ * Provides REST API endpoints that call MCP tools under the hood
5
+ * Compatible with legacy mcp-wrapper.js behavior
6
+ */
7
+ import { createServer } from 'http';
8
+ import { spawn } from 'child_process';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { existsSync } from 'fs';
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+ // Use relative path from wrapper location
15
+ const MCP_PATH = path.join(__dirname, 'index.js');
16
+ const PORT = parseInt(process.env.PORT || '3000', 10);
17
+ // ====== FAIL EARLY VALIDATION ======
18
+ function validateConfig() {
19
+ const errors = [];
20
+ if (!process.env.HA_URL)
21
+ errors.push('ERROR: HA_URL environment variable not set');
22
+ if (!process.env.HA_TOKEN)
23
+ errors.push('ERROR: HA_TOKEN environment variable not set');
24
+ if (process.env.HA_URL && !process.env.HA_URL.startsWith('http')) {
25
+ errors.push('ERROR: HA_URL must start with http:// or https://');
26
+ }
27
+ if (!existsSync(MCP_PATH))
28
+ errors.push(`ERROR: MCP script not found at: ${MCP_PATH}`);
29
+ const nodeVersion = process.versions.node.split('.')[0];
30
+ if (parseInt(nodeVersion) < 18) {
31
+ errors.push(`ERROR: Node.js 18+ required, found: ${process.versions.node}`);
32
+ }
33
+ return errors;
34
+ }
35
+ const configErrors = validateConfig();
36
+ if (configErrors.length > 0) {
37
+ console.error('\nConfiguration Errors:\n');
38
+ configErrors.forEach(err => console.error(err));
39
+ console.error('\nFix these issues before starting:');
40
+ console.error('export HA_URL=http://homeassistant.10.0.0.19.nip.io:8123');
41
+ console.error('export HA_TOKEN=your_long_lived_access_token\n');
42
+ process.exit(1);
43
+ }
44
+ // ====== CORS ======
45
+ const ALLOWED_ORIGINS = new Set([
46
+ "http://127.0.0.1:8282",
47
+ "http://localhost:8282"
48
+ ]);
49
+ function setCors(req, res) {
50
+ const origin = req.headers.origin;
51
+ if (origin && ALLOWED_ORIGINS.has(origin)) {
52
+ res.setHeader("Access-Control-Allow-Origin", origin);
53
+ res.setHeader("Vary", "Origin");
54
+ }
55
+ else {
56
+ // LAN/dev friendly. Tighten if you expose this publicly.
57
+ res.setHeader("Access-Control-Allow-Origin", "*");
58
+ }
59
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
60
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
61
+ res.setHeader("Access-Control-Max-Age", "86400");
62
+ }
63
+ function extractText(result) {
64
+ return result?.result?.content?.[0]?.text;
65
+ }
66
+ function tryParseJson(text) {
67
+ if (typeof text !== 'string')
68
+ return null;
69
+ const t = text.trim();
70
+ if (!t)
71
+ return null;
72
+ try {
73
+ return JSON.parse(t);
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ function sendJson(res, statusCode, obj) {
80
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
81
+ res.end(JSON.stringify(obj));
82
+ }
83
+ function readBody(req) {
84
+ return new Promise((resolve, reject) => {
85
+ let body = '';
86
+ req.on('data', chunk => body += chunk);
87
+ req.on('end', () => {
88
+ if (!body.trim())
89
+ return resolve(null);
90
+ try {
91
+ resolve(JSON.parse(body));
92
+ }
93
+ catch (e) {
94
+ reject(new Error(`Invalid JSON body: ${e.message}`));
95
+ }
96
+ });
97
+ });
98
+ }
99
+ // This runs the MCP stdio script once per request
100
+ function runMcpWithJsonInput(jsonObj) {
101
+ return new Promise((resolve, reject) => {
102
+ const mcp = spawn('node', [MCP_PATH], {
103
+ env: {
104
+ ...process.env,
105
+ HA_URL: process.env.HA_URL,
106
+ HA_TOKEN: process.env.HA_TOKEN,
107
+ },
108
+ stdio: ['pipe', 'pipe', 'pipe']
109
+ });
110
+ let mcpOutput = '';
111
+ let mcpError = '';
112
+ let headerSeen = false;
113
+ mcp.stdout.on('data', (data) => {
114
+ const str = data.toString();
115
+ if (str.includes('Home Assistant MCP server running') || str.includes('MCP server connected and ready')) {
116
+ headerSeen = true;
117
+ return;
118
+ }
119
+ if (headerSeen)
120
+ mcpOutput += str;
121
+ });
122
+ mcp.stderr.on('data', (data) => {
123
+ const str = data.toString();
124
+ if (!str.includes('Home Assistant MCP server running') && !str.includes('MCP server connected and ready')) {
125
+ mcpError += str;
126
+ }
127
+ else {
128
+ headerSeen = true;
129
+ }
130
+ });
131
+ mcp.stdin.write(JSON.stringify(jsonObj) + '\n');
132
+ mcp.stdin.end();
133
+ const timeout = setTimeout(() => {
134
+ mcp.kill();
135
+ reject(new Error('MCP timeout after 30s'));
136
+ }, 30000);
137
+ mcp.on('close', (code) => {
138
+ clearTimeout(timeout);
139
+ if (!mcpOutput.trim()) {
140
+ reject(new Error(`No output from MCP (exit=${code}). stderr=${mcpError}`));
141
+ return;
142
+ }
143
+ try {
144
+ const parsed = JSON.parse(mcpOutput.trim());
145
+ resolve(parsed);
146
+ }
147
+ catch (e) {
148
+ reject(new Error(`Invalid JSON from MCP: ${e.message}. raw=${mcpOutput}`));
149
+ }
150
+ });
151
+ mcp.on('error', (err) => {
152
+ clearTimeout(timeout);
153
+ reject(err);
154
+ });
155
+ });
156
+ }
157
+ function callMcpTool(name, argumentsObj) {
158
+ const request = {
159
+ jsonrpc: "2.0",
160
+ id: 1,
161
+ method: "tools/call",
162
+ params: { name, arguments: argumentsObj ?? {} }
163
+ };
164
+ return runMcpWithJsonInput(request);
165
+ }
166
+ // ====== SERVER ======
167
+ const server = createServer(async (req, res) => {
168
+ setCors(req, res);
169
+ // Preflight
170
+ if (req.method === "OPTIONS") {
171
+ res.writeHead(204);
172
+ res.end();
173
+ return;
174
+ }
175
+ // Health
176
+ if (req.method === 'GET' && req.url === '/health') {
177
+ sendJson(res, 200, {
178
+ status: 'ok',
179
+ mcp_path: MCP_PATH,
180
+ ha_url: process.env.HA_URL,
181
+ token_configured: !!process.env.HA_TOKEN,
182
+ });
183
+ return;
184
+ }
185
+ // OpenAPI served from disk
186
+ if (req.method === 'GET' && (req.url === '/openapi.json' || req.url === '/openapi')) {
187
+ try {
188
+ const openApiPath = path.join(__dirname, '..', 'openapi.json');
189
+ const { readFileSync } = await import('fs');
190
+ const content = readFileSync(openApiPath, 'utf8');
191
+ res.writeHead(200, { 'Content-Type': 'application/json' });
192
+ res.end(content);
193
+ }
194
+ catch (e) {
195
+ sendJson(res, 500, {
196
+ error: "Failed to read openapi.json",
197
+ details: e.message
198
+ });
199
+ }
200
+ return;
201
+ }
202
+ // ===== Pretty REST endpoints =====
203
+ if (req.method === 'POST' && req.url === '/get_all_sensors') {
204
+ try {
205
+ const raw = await callMcpTool('getStates', {});
206
+ const text = extractText(raw);
207
+ const parsed = tryParseJson(text);
208
+ if (!parsed || !Array.isArray(parsed.entities)) {
209
+ sendJson(res, 502, { error: "Unexpected MCP response format", raw });
210
+ return;
211
+ }
212
+ // Filter to sensors only to match legacy behavior
213
+ const sensors = parsed.entities.filter((e) => e.entity_id?.startsWith('sensor.'));
214
+ sendJson(res, 200, { count: sensors.length, sensors, raw });
215
+ }
216
+ catch (e) {
217
+ sendJson(res, 500, { error: e.message });
218
+ }
219
+ return;
220
+ }
221
+ if (req.method === 'POST' && req.url === '/get_sensor_state') {
222
+ try {
223
+ const body = await readBody(req);
224
+ const entity_id = body?.entity_id;
225
+ if (!entity_id || typeof entity_id !== 'string') {
226
+ sendJson(res, 400, { error: "Missing required field: entity_id (string)" });
227
+ return;
228
+ }
229
+ const raw = await callMcpTool('getState', { entity_id });
230
+ const text = extractText(raw);
231
+ const entity = tryParseJson(text);
232
+ if (!entity || typeof entity !== 'object') {
233
+ sendJson(res, 502, { error: "Unexpected MCP response format", raw });
234
+ return;
235
+ }
236
+ sendJson(res, 200, { entity, raw });
237
+ }
238
+ catch (e) {
239
+ sendJson(res, 500, { error: e.message });
240
+ }
241
+ return;
242
+ }
243
+ if (req.method === 'POST' && req.url === '/control_device') {
244
+ try {
245
+ const body = await readBody(req);
246
+ const domain = body?.domain;
247
+ const service = body?.service;
248
+ const data = body?.data ?? {};
249
+ if (!domain || typeof domain !== 'string') {
250
+ sendJson(res, 400, { error: "Missing required field: domain (string)" });
251
+ return;
252
+ }
253
+ if (!service || typeof service !== 'string') {
254
+ sendJson(res, 400, { error: "Missing required field: service (string)" });
255
+ return;
256
+ }
257
+ if (typeof data !== 'object' || Array.isArray(data) || data === null) {
258
+ sendJson(res, 400, { error: "Field 'data' must be an object" });
259
+ return;
260
+ }
261
+ const raw = await callMcpTool('callService', {
262
+ domain,
263
+ service,
264
+ service_data: data,
265
+ });
266
+ const text = extractText(raw);
267
+ const parsed = tryParseJson(text);
268
+ sendJson(res, 200, { ok: true, result: parsed ?? text ?? null, raw });
269
+ }
270
+ catch (e) {
271
+ sendJson(res, 500, { error: e.message });
272
+ }
273
+ return;
274
+ }
275
+ // ===== Raw passthrough endpoint (for n8n compatibility) =====
276
+ if (req.method === 'POST' && req.url === '/') {
277
+ try {
278
+ const body = await readBody(req);
279
+ if (!body) {
280
+ sendJson(res, 400, { error: "Empty JSON body" });
281
+ return;
282
+ }
283
+ const result = await runMcpWithJsonInput(body);
284
+ sendJson(res, 200, result);
285
+ }
286
+ catch (e) {
287
+ sendJson(res, 500, { error: e.message });
288
+ }
289
+ return;
290
+ }
291
+ sendJson(res, 404, { error: 'Not found' });
292
+ });
293
+ server.listen(PORT, '0.0.0.0', () => {
294
+ console.log('MCP Wrapper started successfully!');
295
+ console.log(`Listening on 0.0.0.0:${PORT}`);
296
+ console.log(`MCP script: ${MCP_PATH}`);
297
+ console.log(`Home Assistant: ${process.env.HA_URL}`);
298
+ console.log(`Token: ${process.env.HA_TOKEN ? '***configured***' : 'MISSING'}`);
299
+ console.log(`\nTest with: curl http://localhost:${PORT}/health\n`);
300
+ });
301
+ //# sourceMappingURL=wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ services:
2
+ mcp-ha-connect:
3
+ build: .
4
+ container_name: mcp-ha-connect
5
+ restart: unless-stopped
6
+ ports:
7
+ - "3000:3000"
8
+ extra_hosts:
9
+ - "host.docker.internal:host-gateway"
10
+ env_file:
11
+ - .env
12
+ healthcheck:
13
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
14
+ interval: 30s
15
+ timeout: 10s
16
+ retries: 3
17
+ start_period: 10s
@@ -0,0 +1,86 @@
1
+ ### 0.5.0 (January 2026)
2
+ - **Real-time SSE Event Subscription**: Subscribe to Home Assistant events via Server-Sent Events
3
+ - Filter by domain, entity_id, or event types
4
+ - Automatic WebSocket connection to Home Assistant
5
+ - Keep-alive support for persistent connections
6
+ - **Enhanced Automation Management**: Full automation lifecycle support
7
+ - `triggerAutomation`: Manually trigger automations with variables
8
+ - `enableAutomation`/`disableAutomation`/`toggleAutomation`: Control automation state
9
+ - `createAutomation`: Create new automations via API
10
+ - `deleteAutomation`: Remove automations
11
+ - `reloadAutomations`: Reload from configuration
12
+ - `getAutomationTrace`: View execution history
13
+ - **Advanced Device Control Tools**:
14
+ - `controlLight`: Brightness, color, color temperature, transitions
15
+ - `controlClimate`: Temperature, HVAC mode, fan mode, presets
16
+ - `controlMediaPlayer`: Playback, volume, mute controls
17
+ - `controlCover`: Position and tilt control
18
+ - `controlFan`: Speed, oscillation, direction
19
+ - `activateScene`: Scene activation
20
+ - `runScript`: Script execution with variables
21
+ - `sendNotification`: Send notifications through Home Assistant
22
+ - **Rate Limiting**: Built-in token bucket rate limiter
23
+ - Configurable window and request limits
24
+ - Per-IP tracking with automatic cleanup
25
+ - Skip paths for health checks
26
+ - **New Configuration Options**:
27
+ - `MCP_SSE_EVENTS_ENABLED`: Enable/disable SSE
28
+ - `MCP_SSE_EVENTS_PATH`: Customize SSE endpoint
29
+ - `MCP_RATE_LIMIT_ENABLED`: Enable/disable rate limiting
30
+ - `MCP_RATE_LIMIT_WINDOW_MS`: Rate limit window
31
+ - `MCP_RATE_LIMIT_MAX_REQUESTS`: Max requests per window
32
+ - Total tools increased from 16 to 33
33
+
34
+ ### 0.4.0 (January 2026)
35
+ - **Extensible AI Provider System**: Refactored AI client to support multiple providers
36
+ - New `src/localAI/` folder with provider-based architecture
37
+ - Supports Ollama (native API) and OpenAI-compatible APIs (LocalAI, LM Studio, vLLM)
38
+ - New environment variables: `AI_PROVIDER`, `AI_URL`, `AI_MODEL`, `AI_TIMEOUT`, `AI_API_KEY`
39
+ - Refactored `haClient.ts` into modular folder structure (`src/haClient/`)
40
+ - Split monolithic client into dedicated operation classes:
41
+ - `request.ts` - HTTP request handler
42
+ - `states.ts` - State operations (getStates, getState, getAllSensors)
43
+ - `services.ts` - Service operations (callService, restartServer)
44
+ - `entities.ts` - Entity operations (getEntitiesByDomain, searchEntities, listEntities, getDomainSummary)
45
+ - `automations.ts` - Automation operations (getAutomations)
46
+ - `history.ts` - History operations (getHistory, getSystemLog)
47
+ - `updates.ts` - Update operations (getAvailableUpdates)
48
+ - `config.ts` - Config operations (getVersion, getConfig, checkApi)
49
+ - `index.ts` - Main HaClient class composing all operations
50
+ - Improved code organization following modular architecture pattern
51
+ - No changes to public API or tools - fully backward compatible
52
+ - All 325 tests pass
53
+
54
+ ### 0.3.0 (January 2026)
55
+ - Added 8 new tools: `getVersion`, `entityAction`, `listEntities`, `getDomainSummary`, `listAutomations`, `restartHomeAssistant`, `getSystemLog`, `checkUpdates`
56
+ - Added MCP Resources support with 5 URI-based endpoints (`hass://entities`, etc.)
57
+ - Added `entityAction` tool for simplified turn_on/turn_off/toggle operations
58
+ - Added `listEntities` tool with domain, state, search, and limit filtering
59
+ - Added `getDomainSummary` tool for domain statistics
60
+ - Added `listAutomations` tool for automation management
61
+ - Added `restartHomeAssistant` tool for server control
62
+ - Added `getSystemLog` tool for viewing logbook entries (events, state changes)
63
+ - Added `checkUpdates` tool to check for available updates (Core, Supervisor, OS, add-ons)
64
+ - Total tools increased from 8 to 16
65
+ - Enhanced type definitions for Automation, DomainSummary, HaVersion, LogbookEntry, UpdateInfo
66
+
67
+ ### 0.2.0 (January 2026)
68
+ - Added AI-powered sensor analysis with Ollama
69
+ - Added `getAllSensors` tool
70
+ - Added `analyzeSensors` tool
71
+ - Added `getHistory` tool
72
+ - Added phi4:14b as recommended model (9.5/10, 6.65s avg)
73
+ - Added qwen3:14b support (10/10 accuracy, 12.5s avg)
74
+ - Added comprehensive security documentation
75
+ - Added UFW firewall configuration guide
76
+ - Added n8n workflow examples and import instructions
77
+ - Updated to Node.js 20+ (v20.19.6) and npm 10.8+
78
+ - Updated installation instructions with verified versions
79
+ - Added Docker CLI workflow import method
80
+ - Enhanced troubleshooting with network/firewall diagnostics
81
+
82
+ ### 0.1.0 (Initial Release)
83
+ - Basic Home Assistant integration
84
+ - 5 core tools (getStates, getState, callService, getEntitiesByDomain, searchEntities)
85
+ - Multiple transport modes (stdio, SSE, HTTP streaming)
86
+ - Full TypeScript support