@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.4.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 (293) hide show
  1. package/.env.example +1 -1
  2. package/README.md +24 -2
  3. package/dist/omadaClient/accessControl.d.ts +290 -0
  4. package/dist/omadaClient/accessControl.js +509 -0
  5. package/dist/omadaClient/accessControl.js.map +1 -0
  6. package/dist/omadaClient/client.d.ts +6 -1
  7. package/dist/omadaClient/client.js +12 -1
  8. package/dist/omadaClient/client.js.map +1 -1
  9. package/dist/omadaClient/diagnose.d.ts +68 -0
  10. package/dist/omadaClient/diagnose.js +164 -0
  11. package/dist/omadaClient/diagnose.js.map +1 -0
  12. package/dist/omadaClient/index.d.ts +9 -0
  13. package/dist/omadaClient/index.js +19 -0
  14. package/dist/omadaClient/index.js.map +1 -1
  15. package/dist/omadaClient/macGroups.d.ts +58 -0
  16. package/dist/omadaClient/macGroups.js +110 -0
  17. package/dist/omadaClient/macGroups.js.map +1 -0
  18. package/dist/omadaClient/serialize.d.ts +13 -0
  19. package/dist/omadaClient/serialize.js +29 -0
  20. package/dist/omadaClient/serialize.js.map +1 -0
  21. package/dist/omadaClient/timeRange.d.ts +41 -0
  22. package/dist/omadaClient/timeRange.js +109 -0
  23. package/dist/omadaClient/timeRange.js.map +1 -0
  24. package/dist/tools/infra/actions.d.ts +1 -1
  25. package/dist/tools/infra/actions.js +1 -1
  26. package/dist/tools/omada/accessControl.d.ts +151 -0
  27. package/dist/tools/omada/accessControl.js +158 -0
  28. package/dist/tools/omada/accessControl.js.map +1 -0
  29. package/dist/tools/omada/index.js +9 -0
  30. package/dist/tools/omada/index.js.map +1 -1
  31. package/dist/tools/omada/macGroups.d.ts +19 -0
  32. package/dist/tools/omada/macGroups.js +77 -0
  33. package/dist/tools/omada/macGroups.js.map +1 -0
  34. package/dist/tools/omada/namespace.js +16 -0
  35. package/dist/tools/omada/namespace.js.map +1 -1
  36. package/dist/version.d.ts +1 -1
  37. package/dist/version.js +1 -1
  38. package/package.json +5 -1
  39. package/.codex/review-rules.md +0 -16
  40. package/.dockerignore +0 -8
  41. package/.gitattributes +0 -30
  42. package/.github/workflows/ci.yml +0 -193
  43. package/AGENTS.md +0 -389
  44. package/Dockerfile +0 -50
  45. package/docker-compose.yml +0 -23
  46. package/docs/CHANGELOG.md +0 -341
  47. package/docs/COVERAGE.md +0 -219
  48. package/docs/QUICK_START.md +0 -240
  49. package/eslint.config.js +0 -33
  50. package/n8n/ai-agent-safety-monitor.json +0 -355
  51. package/openapi.json +0 -1259
  52. package/scripts/check-version-sync.mjs +0 -69
  53. package/scripts/generate-jwt.ts +0 -121
  54. package/src/config.ts +0 -440
  55. package/src/haClient/automations.ts +0 -261
  56. package/src/haClient/calendars.ts +0 -94
  57. package/src/haClient/config.ts +0 -52
  58. package/src/haClient/devices.ts +0 -653
  59. package/src/haClient/entities.ts +0 -128
  60. package/src/haClient/events.ts +0 -689
  61. package/src/haClient/history.ts +0 -73
  62. package/src/haClient/index.ts +0 -336
  63. package/src/haClient/request.ts +0 -142
  64. package/src/haClient/services.ts +0 -45
  65. package/src/haClient/states.ts +0 -60
  66. package/src/haClient/updates.ts +0 -58
  67. package/src/haClient/wsCommand.ts +0 -44
  68. package/src/index.ts +0 -164
  69. package/src/localAI/index.ts +0 -88
  70. package/src/localAI/prompts.ts +0 -50
  71. package/src/localAI/providers/base.ts +0 -120
  72. package/src/localAI/providers/ollama.ts +0 -78
  73. package/src/localAI/providers/openai.ts +0 -86
  74. package/src/localAI/types.ts +0 -67
  75. package/src/omadaClient/auth.ts +0 -178
  76. package/src/omadaClient/client.ts +0 -337
  77. package/src/omadaClient/device.ts +0 -118
  78. package/src/omadaClient/index.ts +0 -310
  79. package/src/omadaClient/network.ts +0 -284
  80. package/src/omadaClient/request.ts +0 -365
  81. package/src/omadaClient/security.ts +0 -51
  82. package/src/omadaClient/site.ts +0 -344
  83. package/src/ownerQuestions/service.ts +0 -536
  84. package/src/permissions/index.ts +0 -143
  85. package/src/resources/index.ts +0 -213
  86. package/src/server/auth.ts +0 -175
  87. package/src/server/chatFace.ts +0 -789
  88. package/src/server/chatSlice.ts +0 -57
  89. package/src/server/common.ts +0 -170
  90. package/src/server/eventSubscription.ts +0 -343
  91. package/src/server/http.ts +0 -626
  92. package/src/server/instructions.ts +0 -97
  93. package/src/server/rateLimiter.ts +0 -227
  94. package/src/server/stdio.ts +0 -41
  95. package/src/server/stream.ts +0 -205
  96. package/src/tools/ai/analyzeSensors.ts +0 -33
  97. package/src/tools/ai/index.ts +0 -20
  98. package/src/tools/common.ts +0 -442
  99. package/src/tools/homeassistant/askOwner.ts +0 -133
  100. package/src/tools/homeassistant/automationControls.ts +0 -66
  101. package/src/tools/homeassistant/calendar.ts +0 -97
  102. package/src/tools/homeassistant/callService.ts +0 -25
  103. package/src/tools/homeassistant/controlClimate.ts +0 -68
  104. package/src/tools/homeassistant/controlCover.ts +0 -48
  105. package/src/tools/homeassistant/controlFan.ts +0 -44
  106. package/src/tools/homeassistant/controlLight.ts +0 -38
  107. package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
  108. package/src/tools/homeassistant/createAutomation.ts +0 -35
  109. package/src/tools/homeassistant/deleteAutomation.ts +0 -24
  110. package/src/tools/homeassistant/entityAction.ts +0 -35
  111. package/src/tools/homeassistant/entityGuard.ts +0 -28
  112. package/src/tools/homeassistant/getAllSensors.ts +0 -46
  113. package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
  114. package/src/tools/homeassistant/getDomainSummary.ts +0 -29
  115. package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
  116. package/src/tools/homeassistant/getHistory.ts +0 -24
  117. package/src/tools/homeassistant/getState.ts +0 -24
  118. package/src/tools/homeassistant/getStates.ts +0 -46
  119. package/src/tools/homeassistant/getVersion.ts +0 -21
  120. package/src/tools/homeassistant/index.ts +0 -121
  121. package/src/tools/homeassistant/listAutomations.ts +0 -35
  122. package/src/tools/homeassistant/listEntities.ts +0 -44
  123. package/src/tools/homeassistant/listPersons.ts +0 -46
  124. package/src/tools/homeassistant/sceneAndScript.ts +0 -53
  125. package/src/tools/homeassistant/searchEntities.ts +0 -58
  126. package/src/tools/homeassistant/sendNotification.ts +0 -179
  127. package/src/tools/homeassistant/systemTools.ts +0 -52
  128. package/src/tools/homeassistant/triggerAutomation.ts +0 -24
  129. package/src/tools/index.ts +0 -78
  130. package/src/tools/infra/actions.ts +0 -95
  131. package/src/tools/infra/index.ts +0 -138
  132. package/src/tools/omada/blockClient.ts +0 -28
  133. package/src/tools/omada/cyclePoePort.ts +0 -32
  134. package/src/tools/omada/deleteClient.ts +0 -27
  135. package/src/tools/omada/disableClientRateLimit.ts +0 -23
  136. package/src/tools/omada/getClient.ts +0 -14
  137. package/src/tools/omada/getDevice.ts +0 -14
  138. package/src/tools/omada/getFirewallSetting.ts +0 -14
  139. package/src/tools/omada/getInternetInfo.ts +0 -14
  140. package/src/tools/omada/getLanNetworkList.ts +0 -14
  141. package/src/tools/omada/getLanProfileList.ts +0 -14
  142. package/src/tools/omada/getPortForwardingStatus.ts +0 -26
  143. package/src/tools/omada/getRateLimitProfiles.ts +0 -14
  144. package/src/tools/omada/getSiteNtpStatus.ts +0 -14
  145. package/src/tools/omada/getSsidDetail.ts +0 -22
  146. package/src/tools/omada/getSsidList.ts +0 -21
  147. package/src/tools/omada/getSwitchStackDetail.ts +0 -14
  148. package/src/tools/omada/getThreatList.ts +0 -42
  149. package/src/tools/omada/getWlanGroupList.ts +0 -14
  150. package/src/tools/omada/graph.ts +0 -187
  151. package/src/tools/omada/index.ts +0 -153
  152. package/src/tools/omada/listBlockedClients.ts +0 -17
  153. package/src/tools/omada/listClients.ts +0 -14
  154. package/src/tools/omada/listClientsActivity.ts +0 -25
  155. package/src/tools/omada/listClientsPastConnections.ts +0 -44
  156. package/src/tools/omada/listDevices.ts +0 -14
  157. package/src/tools/omada/listDevicesStats.ts +0 -41
  158. package/src/tools/omada/listMostActiveClients.ts +0 -14
  159. package/src/tools/omada/listSites.ts +0 -18
  160. package/src/tools/omada/namespace.ts +0 -1164
  161. package/src/tools/omada/searchDevices.ts +0 -20
  162. package/src/tools/omada/setClientRateLimit.ts +0 -26
  163. package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
  164. package/src/tools/omada/setSiteNtpServers.ts +0 -36
  165. package/src/tools/omada/setSsidEnabled.ts +0 -38
  166. package/src/tools/omada/unblockClient.ts +0 -26
  167. package/src/tools/types.ts +0 -11
  168. package/src/tools/utils/pagination-schema.ts +0 -27
  169. package/src/types/ai/index.ts +0 -11
  170. package/src/types/ai/types.ts +0 -67
  171. package/src/types/homeassistant/automations.ts +0 -43
  172. package/src/types/homeassistant/calendars.ts +0 -26
  173. package/src/types/homeassistant/config.ts +0 -14
  174. package/src/types/homeassistant/entities.ts +0 -14
  175. package/src/types/homeassistant/errors.ts +0 -33
  176. package/src/types/homeassistant/haConfig.ts +0 -7
  177. package/src/types/homeassistant/history.ts +0 -13
  178. package/src/types/homeassistant/index.ts +0 -46
  179. package/src/types/homeassistant/request.ts +0 -6
  180. package/src/types/homeassistant/serviceCall.ts +0 -18
  181. package/src/types/homeassistant/states.ts +0 -58
  182. package/src/types/homeassistant/updates.ts +0 -28
  183. package/src/types/index.ts +0 -12
  184. package/src/types/omada/activeClientInfo.ts +0 -17
  185. package/src/types/omada/clientActivity.ts +0 -32
  186. package/src/types/omada/clientBlockStatus.ts +0 -11
  187. package/src/types/omada/clientPastConnection.ts +0 -82
  188. package/src/types/omada/index.ts +0 -14
  189. package/src/types/omada/omadaApiResponse.ts +0 -5
  190. package/src/types/omada/omadaClientInfo.ts +0 -11
  191. package/src/types/omada/omadaDeviceInfo.ts +0 -11
  192. package/src/types/omada/omadaDeviceStats.ts +0 -31
  193. package/src/types/omada/omadaSiteSummary.ts +0 -5
  194. package/src/types/omada/oswStackDetail.ts +0 -11
  195. package/src/types/omada/paginatedResult.ts +0 -6
  196. package/src/types/omada/rateLimitProfile.ts +0 -58
  197. package/src/types/omada/threatInfo.ts +0 -38
  198. package/src/types/omada/tokenResult.ts +0 -6
  199. package/src/types.ts +0 -2
  200. package/src/utils/config-validations.ts +0 -68
  201. package/src/utils/jwt.ts +0 -112
  202. package/src/utils/logger.ts +0 -121
  203. package/src/utils/plainText.ts +0 -48
  204. package/src/utils/redact.ts +0 -59
  205. package/src/utils/sanitizeError.ts +0 -18
  206. package/src/utils/tlsDispatcher.ts +0 -69
  207. package/src/version.ts +0 -5
  208. package/tests/bdd/automation-creation.spec.ts +0 -214
  209. package/tests/bdd/automation-management.spec.ts +0 -267
  210. package/tests/bdd/calendar.spec.ts +0 -190
  211. package/tests/bdd/configuration.spec.ts +0 -283
  212. package/tests/bdd/device-control.spec.ts +0 -344
  213. package/tests/bdd/entity-listing.spec.ts +0 -208
  214. package/tests/bdd/entity-search.spec.ts +0 -183
  215. package/tests/bdd/history-retrieval.spec.ts +0 -195
  216. package/tests/bdd/notifications.spec.ts +0 -238
  217. package/tests/bdd/service-calls.spec.ts +0 -144
  218. package/tests/bdd/state-retrieval.spec.ts +0 -204
  219. package/tests/bench/hotpaths.bench.ts +0 -68
  220. package/tests/config.test.ts +0 -355
  221. package/tests/features/automation-creation.feature +0 -36
  222. package/tests/features/automation-management.feature +0 -54
  223. package/tests/features/calendar.feature +0 -37
  224. package/tests/features/configuration.feature +0 -70
  225. package/tests/features/device-control.feature +0 -100
  226. package/tests/features/entity-listing.feature +0 -51
  227. package/tests/features/entity-search.feature +0 -44
  228. package/tests/features/history-retrieval.feature +0 -38
  229. package/tests/features/notifications.feature +0 -37
  230. package/tests/features/service-calls.feature +0 -35
  231. package/tests/features/state-retrieval.feature +0 -37
  232. package/tests/fixtures/openapi-default-slice.json +0 -290
  233. package/tests/haClient/automationTrace.test.ts +0 -59
  234. package/tests/haClient/automations.test.ts +0 -149
  235. package/tests/haClient/config.test.ts +0 -117
  236. package/tests/haClient/entities.test.ts +0 -188
  237. package/tests/haClient/events.test.ts +0 -455
  238. package/tests/haClient/eventsTls.test.ts +0 -52
  239. package/tests/haClient/history.test.ts +0 -228
  240. package/tests/haClient/index.test.ts +0 -243
  241. package/tests/haClient/request.test.ts +0 -217
  242. package/tests/haClient/services.test.ts +0 -120
  243. package/tests/haClient/states.test.ts +0 -119
  244. package/tests/haClient/updates.test.ts +0 -193
  245. package/tests/index.test.ts +0 -160
  246. package/tests/integration/homeassistant.test.ts +0 -144
  247. package/tests/integration/omada.test.ts +0 -167
  248. package/tests/integration/server.test.ts +0 -151
  249. package/tests/localAI/index.test.ts +0 -177
  250. package/tests/localAI/ollama.test.ts +0 -187
  251. package/tests/localAI/openai.test.ts +0 -257
  252. package/tests/omadaClient/actions.test.ts +0 -161
  253. package/tests/omadaClient/clientBlocks.test.ts +0 -170
  254. package/tests/omadaClient/ntp.test.ts +0 -381
  255. package/tests/omadaClient/site.test.ts +0 -37
  256. package/tests/ownerQuestions/service.test.ts +0 -499
  257. package/tests/ownerQuestions/tools.test.ts +0 -186
  258. package/tests/permissions/index.test.ts +0 -217
  259. package/tests/resources/index.test.ts +0 -288
  260. package/tests/scripts/generateJwt.test.ts +0 -44
  261. package/tests/security/accessControl.test.ts +0 -223
  262. package/tests/security/authentication.test.ts +0 -117
  263. package/tests/security/configuration.test.ts +0 -170
  264. package/tests/security/cryptoTransport.test.ts +0 -172
  265. package/tests/security/dependencies.test.ts +0 -152
  266. package/tests/security/injection.test.ts +0 -117
  267. package/tests/security/insecureDesign.test.ts +0 -121
  268. package/tests/security/logging.test.ts +0 -131
  269. package/tests/security/resourceConsumption.test.ts +0 -142
  270. package/tests/server/auth.test.ts +0 -249
  271. package/tests/server/chatFace.test.ts +0 -320
  272. package/tests/server/common.test.ts +0 -84
  273. package/tests/server/http.test.ts +0 -561
  274. package/tests/server/instructions.test.ts +0 -152
  275. package/tests/server/memoizeJsonSchema.test.ts +0 -71
  276. package/tests/server/stdio.test.ts +0 -99
  277. package/tests/server/stream.test.ts +0 -285
  278. package/tests/server/toolVisibility.http.test.ts +0 -111
  279. package/tests/server/toolVisibility.test.ts +0 -129
  280. package/tests/tools/ai/analyzeSensors.test.ts +0 -227
  281. package/tests/tools/common.test.ts +0 -123
  282. package/tests/tools/homeassistant/handlers.test.ts +0 -872
  283. package/tests/tools/infra/invokeAction.test.ts +0 -280
  284. package/tests/tools/omada/graph.test.ts +0 -385
  285. package/tests/tools/omada/handlers.test.ts +0 -897
  286. package/tests/tools/omada/namespace.test.ts +0 -483
  287. package/tests/tools/registry.test.ts +0 -168
  288. package/tests/utils/config-validations.test.ts +0 -352
  289. package/tests/utils/jwt.test.ts +0 -115
  290. package/tests/utils/logger.test.ts +0 -327
  291. package/tests/utils/redact.test.ts +0 -105
  292. package/tsconfig.json +0 -24
  293. package/vitest.config.ts +0 -38
@@ -1,355 +0,0 @@
1
- /**
2
- * Configuration tests
3
- */
4
-
5
- import { describe, it, expect, beforeEach, vi } from 'vitest';
6
- import { loadConfig, validateConfig } from '../src/config.js';
7
- import type { EnvironmentConfig } from '../src/config.js';
8
-
9
- describe('loadConfig', () => {
10
- let originalEnv: NodeJS.ProcessEnv;
11
-
12
- beforeEach(() => {
13
- originalEnv = { ...process.env };
14
- });
15
-
16
- it('should load valid configuration from environment', () => {
17
- const env = {
18
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
19
- HA_TOKEN: 'test-token-12345',
20
- HA_STRICT_SSL: 'false',
21
- HA_TIMEOUT: '30000',
22
- MCP_SERVER_LOG_LEVEL: 'info',
23
- MCP_SERVER_LOG_FORMAT: 'plain',
24
- MCP_SERVER_USE_HTTP: 'false',
25
- MCP_SERVER_STATEFUL: 'false',
26
- };
27
-
28
- const config = loadConfig(env);
29
-
30
- expect(config.baseUrl).toBe('http://homeassistant.10.0.0.19.nip.io:8123');
31
- expect(config.token).toBe('test-token-12345');
32
- expect(config.strictSsl).toBe(false);
33
- expect(config.timeout).toBe(30000);
34
- expect(config.logLevel).toBe('info');
35
- expect(config.logFormat).toBe('plain');
36
- expect(config.useHttp).toBe(false);
37
- expect(config.stateful).toBe(false);
38
- });
39
-
40
- it('parses owner question settings (enabled by default; HA users as a trimmed list)', () => {
41
- const base = { HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123', HA_TOKEN: 't' };
42
-
43
- const defaults = loadConfig(base);
44
- expect(defaults.ownerQuestionsEnabled).toBe(true);
45
- expect(defaults.ownerQuestionsHaUsers).toEqual([]);
46
-
47
- const set = loadConfig({ ...base, MCP_OWNER_QUESTIONS_ENABLED: 'false', MCP_OWNER_QUESTIONS_HA_USERS: ' a1b2 , c3d4 ,' });
48
- expect(set.ownerQuestionsEnabled).toBe(false);
49
- expect(set.ownerQuestionsHaUsers).toEqual(['a1b2', 'c3d4']);
50
- });
51
-
52
- it('should apply default values for optional fields', () => {
53
- const env = {
54
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
55
- HA_TOKEN: 'test-token-12345',
56
- };
57
-
58
- const config = loadConfig(env);
59
-
60
- expect(config.strictSsl).toBe(true); // default
61
- expect(config.timeout).toBe(30000); // default
62
- expect(config.logLevel).toBe('info'); // default
63
- expect(config.logFormat).toBe('plain'); // default
64
- expect(config.useHttp).toBe(false); // default
65
- expect(config.stateful).toBe(false); // default
66
- expect(config.toolRegistrationMode).toBe('eager'); // default
67
- expect(config.httpEnableHealthcheck).toBe(true); // default
68
- expect(config.httpAllowCors).toBe(true); // default
69
- });
70
-
71
- describe('toolRegistrationMode (MCP_TOOL_REGISTRATION_MODE)', () => {
72
- it('defaults to "eager" when unset', () => {
73
- const config = loadConfig({
74
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
75
- HA_TOKEN: 'test-token-12345',
76
- });
77
- expect(config.toolRegistrationMode).toBe('eager');
78
- });
79
-
80
- it('parses "graph"', () => {
81
- const config = loadConfig({
82
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
83
- HA_TOKEN: 'test-token-12345',
84
- MCP_TOOL_REGISTRATION_MODE: 'graph',
85
- });
86
- expect(config.toolRegistrationMode).toBe('graph');
87
- });
88
-
89
- it('rejects an unknown mode', () => {
90
- expect(() =>
91
- loadConfig({
92
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
93
- HA_TOKEN: 'test-token-12345',
94
- MCP_TOOL_REGISTRATION_MODE: 'lazy',
95
- })
96
- ).toThrow('Invalid environment configuration');
97
- });
98
- });
99
-
100
- it('should remove trailing slash from baseUrl', () => {
101
- const env = {
102
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123/',
103
- HA_TOKEN: 'test-token-12345',
104
- };
105
-
106
- const config = loadConfig(env);
107
-
108
- expect(config.baseUrl).toBe('http://homeassistant.10.0.0.19.nip.io:8123');
109
- });
110
-
111
- it('should allow missing HA_URL (Omada-only mode)', () => {
112
- const env = {
113
- HA_TOKEN: 'test-token-12345',
114
- };
115
-
116
- const config = loadConfig(env);
117
- expect(config.baseUrl).toBeUndefined();
118
- expect(config.token).toBe('test-token-12345');
119
- });
120
-
121
- it('should allow missing HA_TOKEN (Omada-only mode)', () => {
122
- const env = {
123
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
124
- };
125
-
126
- const config = loadConfig(env);
127
- expect(config.baseUrl).toBe('http://homeassistant.10.0.0.19.nip.io:8123');
128
- expect(config.token).toBeUndefined();
129
- });
130
-
131
- it('should throw error for invalid HA_URL', () => {
132
- const env = {
133
- HA_URL: 'not-a-url',
134
- HA_TOKEN: 'test-token-12345',
135
- };
136
-
137
- expect(() => loadConfig(env)).toThrow('Invalid environment configuration');
138
- });
139
-
140
- it('should parse HTTP configuration when USE_HTTP is true', () => {
141
- const env = {
142
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
143
- HA_TOKEN: 'test-token-12345',
144
- MCP_SERVER_USE_HTTP: 'true',
145
- MCP_HTTP_PORT: '3000',
146
- MCP_HTTP_BIND_ADDR: '127.0.0.1',
147
- MCP_HTTP_PATH: '/mcp',
148
- MCP_HTTP_ENABLE_HEALTHCHECK: 'true',
149
- MCP_HTTP_HEALTHCHECK_PATH: '/health',
150
- MCP_HTTP_ALLOW_CORS: 'true',
151
- MCP_HTTP_ALLOWED_ORIGINS: '127.0.0.1,localhost',
152
- };
153
-
154
- const config = loadConfig(env);
155
-
156
- expect(config.useHttp).toBe(true);
157
- expect(config.httpPort).toBe(3000);
158
- expect(config.httpBindAddr).toBe('127.0.0.1');
159
- expect(config.httpPath).toBe('/mcp');
160
- expect(config.httpEnableHealthcheck).toBe(true);
161
- expect(config.httpHealthcheckPath).toBe('/health');
162
- expect(config.httpAllowCors).toBe(true);
163
- expect(config.httpAllowedOrigins).toEqual(['127.0.0.1', 'localhost']);
164
- });
165
-
166
- it('should use default httpPath /mcp', () => {
167
- const env = {
168
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
169
- HA_TOKEN: 'test-token-12345',
170
- };
171
-
172
- const config = loadConfig(env);
173
- expect(config.httpPath).toBe('/mcp');
174
- });
175
-
176
- it('should handle wildcard in allowed origins', () => {
177
- const env = {
178
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
179
- HA_TOKEN: 'test-token-12345',
180
- MCP_HTTP_ALLOWED_ORIGINS: '*',
181
- };
182
-
183
- const config = loadConfig(env);
184
-
185
- // Wildcard should result in empty array to disable SDK validation
186
- expect(config.httpAllowedOrigins).toEqual([]);
187
- });
188
-
189
- it('should parse comma-separated origins', () => {
190
- const env = {
191
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
192
- HA_TOKEN: 'test-token-12345',
193
- MCP_HTTP_ALLOWED_ORIGINS: 'http://mcpserver.10.0.0.18.nip.io:3000,http://192.168.0.10:8080,localhost',
194
- };
195
-
196
- const config = loadConfig(env);
197
-
198
- expect(config.httpAllowedOrigins).toEqual([
199
- 'http://mcpserver.10.0.0.18.nip.io:3000',
200
- 'http://192.168.0.10:8080',
201
- 'localhost',
202
- ]);
203
- });
204
-
205
- it('should throw error for invalid bind address', () => {
206
- const env = {
207
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
208
- HA_TOKEN: 'test-token-12345',
209
- MCP_HTTP_BIND_ADDR: 'invalid-ip',
210
- };
211
-
212
- expect(() => loadConfig(env)).toThrow('MCP_HTTP_BIND_ADDR must be a valid IPv4 or IPv6 address');
213
- });
214
-
215
- it('should accept valid IPv4 bind address', () => {
216
- const env = {
217
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
218
- HA_TOKEN: 'test-token-12345',
219
- MCP_HTTP_BIND_ADDR: '192.168.1.100',
220
- // H5: a non-loopback bind requires authentication.
221
- MCP_AUTH_METHOD: 'bearer',
222
- MCP_AUTH_SECRET: 'test-secret-key-32chars-minimum!',
223
- };
224
-
225
- const config = loadConfig(env);
226
- expect(config.httpBindAddr).toBe('192.168.1.100');
227
- });
228
-
229
- it('should accept valid IPv6 bind address', () => {
230
- const env = {
231
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
232
- HA_TOKEN: 'test-token-12345',
233
- MCP_HTTP_BIND_ADDR: '::1',
234
- };
235
-
236
- const config = loadConfig(env);
237
- expect(config.httpBindAddr).toBe('::1');
238
- });
239
-
240
- it('should parse numeric timeout', () => {
241
- const env = {
242
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
243
- HA_TOKEN: 'test-token-12345',
244
- HA_TIMEOUT: '45000',
245
- };
246
-
247
- const config = loadConfig(env);
248
- expect(config.timeout).toBe(45000);
249
- });
250
-
251
- it('should support all log levels', () => {
252
- const levels = ['debug', 'info', 'warn', 'error'] as const;
253
-
254
- for (const level of levels) {
255
- const env = {
256
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
257
- HA_TOKEN: 'test-token-12345',
258
- MCP_SERVER_LOG_LEVEL: level,
259
- };
260
-
261
- const config = loadConfig(env);
262
- expect(config.logLevel).toBe(level);
263
- }
264
- });
265
-
266
- it('should support all log formats', () => {
267
- const formats = ['plain', 'json', 'gcp-json'] as const;
268
-
269
- for (const format of formats) {
270
- const env = {
271
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
272
- HA_TOKEN: 'test-token-12345',
273
- MCP_SERVER_LOG_FORMAT: format,
274
- };
275
-
276
- const config = loadConfig(env);
277
- expect(config.logFormat).toBe(format);
278
- }
279
- });
280
-
281
-
282
- it('should parse boolean strings correctly', () => {
283
- const envTrue = {
284
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
285
- HA_TOKEN: 'test-token-12345',
286
- HA_STRICT_SSL: 'true',
287
- MCP_SERVER_USE_HTTP: 'true',
288
- MCP_SERVER_STATEFUL: 'true',
289
- };
290
-
291
- const configTrue = loadConfig(envTrue);
292
- expect(configTrue.strictSsl).toBe(true);
293
- expect(configTrue.useHttp).toBe(true);
294
- expect(configTrue.stateful).toBe(true);
295
-
296
- const envFalse = {
297
- HA_URL: 'http://homeassistant.10.0.0.19.nip.io:8123',
298
- HA_TOKEN: 'test-token-12345',
299
- HA_STRICT_SSL: 'false',
300
- MCP_SERVER_USE_HTTP: 'false',
301
- MCP_SERVER_STATEFUL: 'false',
302
- };
303
-
304
- const configFalse = loadConfig(envFalse);
305
- expect(configFalse.strictSsl).toBe(false);
306
- expect(configFalse.useHttp).toBe(false);
307
- expect(configFalse.stateful).toBe(false);
308
- });
309
- });
310
-
311
- describe('validateConfig', () => {
312
- it('should validate valid configuration', () => {
313
- const config: EnvironmentConfig = {
314
- baseUrl: 'http://homeassistant.10.0.0.19.nip.io:8123',
315
- token: 'test-token-12345',
316
- strictSsl: false,
317
- timeout: 30000,
318
- aiProvider: 'ollama',
319
- aiUrl: 'http://ollama.10.0.0.17.nip.io:11434',
320
- aiModel: 'qwen3:14b',
321
- aiTimeout: 60000,
322
- logLevel: 'info',
323
- logFormat: 'plain',
324
- useHttp: false,
325
- stateful: false,
326
-
327
- httpEnableHealthcheck: true,
328
- httpAllowCors: true,
329
- sseEventsEnabled: true,
330
- sseEventsPath: '/subscribe_events',
331
- rateLimitEnabled: true,
332
- rateLimitWindowMs: 60000,
333
- rateLimitMaxRequests: 100,
334
- authMethod: 'none',
335
- };
336
-
337
- expect(() => validateConfig(config)).not.toThrow();
338
- });
339
-
340
- it('should throw error for missing baseUrl', () => {
341
- const config = {
342
- token: 'test-token-12345',
343
- } as EnvironmentConfig;
344
-
345
- expect(() => validateConfig(config)).toThrow('Invalid configuration');
346
- });
347
-
348
- it('should throw error for missing token', () => {
349
- const config = {
350
- baseUrl: 'http://homeassistant.10.0.0.19.nip.io:8123',
351
- } as EnvironmentConfig;
352
-
353
- expect(() => validateConfig(config)).toThrow('Invalid configuration');
354
- });
355
- });
@@ -1,36 +0,0 @@
1
- Feature: Automation Creation
2
- As a Home Assistant user
3
- I want to create automations via the MCP server
4
- So that I can automate my smart home devices
5
-
6
- Background:
7
- Given a connected Home Assistant client
8
-
9
- Scenario: Create a simple time-based automation
10
- Given an automation config with alias "Morning Lights"
11
- And a time trigger at "06:00:00"
12
- And an action to turn on "light.bedroom"
13
- When I create the automation
14
- Then the automation should be created successfully
15
- And the automation ID should be returned
16
-
17
- Scenario: Create an automation with state trigger
18
- Given an automation config with alias "Motion Alert"
19
- And a state trigger for "binary_sensor.motion" changing to "on"
20
- And an action to send notification "Motion detected!"
21
- When I create the automation
22
- Then the automation should be created successfully
23
-
24
- Scenario: Reject automation without required fields
25
- Given an automation config without alias
26
- When I attempt to create the automation
27
- Then it should fail with error "alias, trigger, and action are required"
28
-
29
- Scenario: Create automation with multiple actions
30
- Given an automation config with alias "Goodnight Routine"
31
- And a time trigger at "23:00:00"
32
- And an action to turn off "light.living_room"
33
- And an action to turn off "light.kitchen"
34
- And an action to set "climate.thermostat" to 18 degrees
35
- When I create the automation
36
- Then the automation should be created successfully
@@ -1,54 +0,0 @@
1
- Feature: Automation Management
2
- As a Home Assistant user
3
- I want to manage my automations
4
- So that I can control when and how my smart home responds to events
5
-
6
- Scenario: List all automations
7
- Given a Home Assistant with automations
8
- When I list all automations
9
- Then I should get all automation entities
10
- And each automation should have id, alias, and state
11
-
12
- Scenario: Get automation details
13
- Given an automation "automation.morning_lights" exists
14
- When I get the automation details
15
- Then I should see the automation alias "Morning Lights"
16
- And the state should be "on"
17
- And the mode should be "single"
18
-
19
- Scenario: Trigger an automation manually
20
- Given an automation "automation.morning_lights" exists
21
- When I trigger the automation
22
- Then the automation.trigger service should be called
23
- And the target should be "automation.morning_lights"
24
-
25
- Scenario: Trigger automation with variables
26
- Given an automation "automation.dynamic_scene" exists
27
- When I trigger the automation with variables {"brightness": 100}
28
- Then the automation.trigger service should be called
29
- And the variables should be passed
30
-
31
- Scenario: Enable a disabled automation
32
- Given a disabled automation "automation.night_mode" exists
33
- When I enable the automation
34
- Then the automation.turn_on service should be called
35
-
36
- Scenario: Disable an enabled automation
37
- Given an enabled automation "automation.morning_lights" exists
38
- When I disable the automation
39
- Then the automation.turn_off service should be called
40
-
41
- Scenario: Toggle automation state
42
- Given an automation "automation.morning_lights" exists
43
- When I toggle the automation
44
- Then the automation.toggle service should be called
45
-
46
- Scenario: Reload automations from configuration
47
- Given a Home Assistant with automations
48
- When I reload automations
49
- Then the automation.reload service should be called
50
-
51
- Scenario: Delete an automation
52
- Given an automation with ID "1234567890" exists
53
- When I delete the automation
54
- Then a DELETE request should be made to the config API
@@ -1,37 +0,0 @@
1
- Feature: Calendar Operations
2
- As a Home Assistant user
3
- I want to access my calendar events
4
- So that I can see upcoming appointments and reminders
5
-
6
- Scenario: List all calendars
7
- Given a Home Assistant with calendar entities
8
- When I list all calendars
9
- Then I should see all calendar entities
10
- And each calendar should have entity_id, name, and state
11
-
12
- Scenario: Get events from a specific calendar
13
- Given a calendar "calendar.family" with events
14
- When I get events from "calendar.family"
15
- Then I should receive calendar events
16
- And each event should have summary and start date
17
-
18
- Scenario: Get events with custom date range
19
- Given a calendar "calendar.work" with events
20
- When I get events from January 1 to January 31
21
- Then the events should be within the date range
22
-
23
- Scenario: Get events using days parameter
24
- Given a calendar "calendar.reminders" with events
25
- When I get events for the next 7 days
26
- Then the end date should be 7 days from now
27
-
28
- Scenario: Get events from all calendars
29
- Given multiple calendars with events
30
- When I get events without specifying a calendar
31
- Then I should receive events from all calendars
32
- And results should be grouped by calendar
33
-
34
- Scenario: Get events from calendar with no events
35
- Given a calendar "calendar.empty" with no events
36
- When I get events from "calendar.empty"
37
- Then I should receive an empty events list
@@ -1,70 +0,0 @@
1
- Feature: Server Configuration
2
- As an MCP server administrator
3
- I want to configure the server with my Home Assistant details
4
- So that I can connect to my smart home
5
-
6
- Scenario: Load valid configuration
7
- Given environment variables with HA_URL and HA_TOKEN
8
- When I load the configuration
9
- Then the configuration should be valid
10
- And baseUrl should be set correctly
11
- And token should be set correctly
12
-
13
- Scenario: Apply default values for optional settings
14
- Given only required environment variables
15
- When I load the configuration
16
- Then strictSsl should default to true
17
- And timeout should default to 30000
18
- And logLevel should default to "info"
19
- And logFormat should default to "plain"
20
-
21
- Scenario: Remove trailing slash from URL
22
- Given HA_URL with trailing slash "http://ha.local:8123/"
23
- When I load the configuration
24
- Then baseUrl should not have a trailing slash
25
-
26
- Scenario: Allow missing HA_URL for Omada-only mode
27
- Given environment variables without HA_URL
28
- When I attempt to load the configuration
29
- Then it should load successfully with baseUrl undefined
30
-
31
- Scenario: Allow missing HA_TOKEN for Omada-only mode
32
- Given environment variables without HA_TOKEN
33
- When I attempt to load the configuration
34
- Then it should load successfully with token undefined
35
-
36
- Scenario: Reject invalid URL format
37
- Given HA_URL with invalid format "not-a-url"
38
- When I attempt to load the configuration
39
- Then it should throw an error about invalid configuration
40
-
41
- Scenario: Parse HTTP server configuration
42
- Given HTTP mode is enabled
43
- When I load the configuration
44
- Then useHttp should be true
45
- And httpPort should be set
46
-
47
- Scenario: Validate bind address format
48
- Given an invalid bind address "invalid-ip"
49
- When I attempt to load the configuration
50
- Then it should throw an error about invalid bind address
51
-
52
- Scenario: Accept valid IPv4 bind address
53
- Given a valid IPv4 bind address "192.168.1.100"
54
- When I load the configuration
55
- Then httpBindAddr should be "192.168.1.100"
56
-
57
- Scenario: Accept valid IPv6 bind address
58
- Given a valid IPv6 bind address "::1"
59
- When I load the configuration
60
- Then httpBindAddr should be "::1"
61
-
62
- Scenario: Handle wildcard in allowed origins
63
- Given allowed origins set to "*"
64
- When I load the configuration
65
- Then httpAllowedOrigins should be an empty array
66
-
67
- Scenario: Parse comma-separated allowed origins
68
- Given allowed origins "http://localhost:3000,http://192.168.1.100"
69
- When I load the configuration
70
- Then httpAllowedOrigins should contain both origins
@@ -1,100 +0,0 @@
1
- Feature: Device Control
2
- As a Home Assistant user
3
- I want to control my smart home devices through the MCP server
4
- So that I can manage my home automation
5
-
6
- # Light Control
7
- Scenario: Turn on a light
8
- Given a light entity "light.living_room" that is "off"
9
- When I turn on the light
10
- Then the light service "turn_on" should be called
11
- And the target should be "light.living_room"
12
-
13
- Scenario: Turn on a light with brightness
14
- Given a light entity "light.bedroom"
15
- When I turn on the light with brightness 75%
16
- Then the light service "turn_on" should be called
17
- And the service data should include brightness_pct 75
18
-
19
- Scenario: Set light color temperature
20
- Given a light entity "light.kitchen"
21
- When I set the color temperature to 4000K
22
- Then the light service "turn_on" should be called
23
- And the service data should include color_temp_kelvin 4000
24
-
25
- Scenario: Set light RGB color
26
- Given a light entity "light.office"
27
- When I set the RGB color to red (255, 0, 0)
28
- Then the light service "turn_on" should be called
29
- And the service data should include rgb_color [255, 0, 0]
30
-
31
- # Climate Control
32
- Scenario: Set thermostat temperature
33
- Given a climate entity "climate.living_room"
34
- When I set the temperature to 22 degrees
35
- Then the climate service "set_temperature" should be called
36
- And the service data should include temperature 22
37
-
38
- Scenario: Set HVAC mode to heat
39
- Given a climate entity "climate.bedroom"
40
- When I set the HVAC mode to "heat"
41
- Then the climate service "set_hvac_mode" should be called
42
- And the service data should include hvac_mode "heat"
43
-
44
- Scenario: Set climate preset mode
45
- Given a climate entity "climate.office"
46
- When I set the preset mode to "eco"
47
- Then the climate service "set_preset_mode" should be called
48
- And the service data should include preset_mode "eco"
49
-
50
- # Media Player Control
51
- Scenario: Play media player
52
- Given a media player entity "media_player.living_room"
53
- When I play the media player
54
- Then the media_player service "media_play" should be called
55
-
56
- Scenario: Pause media player
57
- Given a media player entity "media_player.bedroom"
58
- When I pause the media player
59
- Then the media_player service "media_pause" should be called
60
-
61
- Scenario: Set media player volume
62
- Given a media player entity "media_player.kitchen"
63
- When I set the volume to 50%
64
- Then the media_player service "volume_set" should be called
65
- And the service data should include volume_level 0.5
66
-
67
- # Cover Control
68
- Scenario: Open a cover
69
- Given a cover entity "cover.garage_door"
70
- When I open the cover
71
- Then the cover service "open_cover" should be called
72
-
73
- Scenario: Close a cover
74
- Given a cover entity "cover.blinds"
75
- When I close the cover
76
- Then the cover service "close_cover" should be called
77
-
78
- Scenario: Set cover position
79
- Given a cover entity "cover.living_room_blinds"
80
- When I set the cover position to 50%
81
- Then the cover service "set_cover_position" should be called
82
- And the service data should include position 50
83
-
84
- # Fan Control
85
- Scenario: Turn on a fan
86
- Given a fan entity "fan.bedroom"
87
- When I turn on the fan
88
- Then the fan service "turn_on" should be called
89
-
90
- Scenario: Set fan speed
91
- Given a fan entity "fan.living_room"
92
- When I set the fan speed to 75%
93
- Then the fan service "set_percentage" should be called
94
- And the service data should include percentage 75
95
-
96
- Scenario: Toggle fan oscillation
97
- Given a fan entity "fan.office"
98
- When I enable oscillation
99
- Then the fan service "oscillate" should be called
100
- And the service data should include oscillating true