@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.
- package/.dockerignore +8 -0
- package/.env.example +149 -0
- package/.gitattributes +30 -0
- package/Dockerfile +33 -0
- package/LICENSE +21 -0
- package/README.md +394 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +183 -0
- package/dist/config.js.map +1 -0
- package/dist/haClient/automations.d.ts +67 -0
- package/dist/haClient/automations.d.ts.map +1 -0
- package/dist/haClient/automations.js +181 -0
- package/dist/haClient/automations.js.map +1 -0
- package/dist/haClient/config.d.ts +28 -0
- package/dist/haClient/config.d.ts.map +1 -0
- package/dist/haClient/config.js +38 -0
- package/dist/haClient/config.js.map +1 -0
- package/dist/haClient/devices.d.ts +219 -0
- package/dist/haClient/devices.d.ts.map +1 -0
- package/dist/haClient/devices.js +506 -0
- package/dist/haClient/devices.js.map +1 -0
- package/dist/haClient/entities.d.ts +35 -0
- package/dist/haClient/entities.d.ts.map +1 -0
- package/dist/haClient/entities.js +97 -0
- package/dist/haClient/entities.js.map +1 -0
- package/dist/haClient/events.d.ts +138 -0
- package/dist/haClient/events.d.ts.map +1 -0
- package/dist/haClient/events.js +344 -0
- package/dist/haClient/events.js.map +1 -0
- package/dist/haClient/history.d.ts +26 -0
- package/dist/haClient/history.d.ts.map +1 -0
- package/dist/haClient/history.js +54 -0
- package/dist/haClient/history.js.map +1 -0
- package/dist/haClient/index.d.ts +153 -0
- package/dist/haClient/index.d.ts.map +1 -0
- package/dist/haClient/index.js +223 -0
- package/dist/haClient/index.js.map +1 -0
- package/dist/haClient/request.d.ts +34 -0
- package/dist/haClient/request.d.ts.map +1 -0
- package/dist/haClient/request.js +93 -0
- package/dist/haClient/request.js.map +1 -0
- package/dist/haClient/services.d.ts +22 -0
- package/dist/haClient/services.d.ts.map +1 -0
- package/dist/haClient/services.js +39 -0
- package/dist/haClient/services.js.map +1 -0
- package/dist/haClient/states.d.ts +26 -0
- package/dist/haClient/states.d.ts.map +1 -0
- package/dist/haClient/states.js +53 -0
- package/dist/haClient/states.js.map +1 -0
- package/dist/haClient/updates.d.ts +22 -0
- package/dist/haClient/updates.d.ts.map +1 -0
- package/dist/haClient/updates.js +48 -0
- package/dist/haClient/updates.js.map +1 -0
- package/dist/haClient.d.ts +97 -0
- package/dist/haClient.d.ts.map +1 -0
- package/dist/haClient.js +344 -0
- package/dist/haClient.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/localAI/index.d.ts +37 -0
- package/dist/localAI/index.d.ts.map +1 -0
- package/dist/localAI/index.js +73 -0
- package/dist/localAI/index.js.map +1 -0
- package/dist/localAI/prompts.d.ts +20 -0
- package/dist/localAI/prompts.d.ts.map +1 -0
- package/dist/localAI/prompts.js +48 -0
- package/dist/localAI/prompts.js.map +1 -0
- package/dist/localAI/providers/base.d.ts +51 -0
- package/dist/localAI/providers/base.d.ts.map +1 -0
- package/dist/localAI/providers/base.js +80 -0
- package/dist/localAI/providers/base.js.map +1 -0
- package/dist/localAI/providers/ollama.d.ts +22 -0
- package/dist/localAI/providers/ollama.d.ts.map +1 -0
- package/dist/localAI/providers/ollama.js +63 -0
- package/dist/localAI/providers/ollama.js.map +1 -0
- package/dist/localAI/providers/openai.d.ts +23 -0
- package/dist/localAI/providers/openai.d.ts.map +1 -0
- package/dist/localAI/providers/openai.js +63 -0
- package/dist/localAI/providers/openai.js.map +1 -0
- package/dist/localAI/types.d.ts +61 -0
- package/dist/localAI/types.d.ts.map +1 -0
- package/dist/localAI/types.js +6 -0
- package/dist/localAI/types.js.map +1 -0
- package/dist/ollamaClient.d.ts +37 -0
- package/dist/ollamaClient.d.ts.map +1 -0
- package/dist/ollamaClient.js +110 -0
- package/dist/ollamaClient.js.map +1 -0
- package/dist/resources/index.d.ts +11 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +238 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server/common.d.ts +9 -0
- package/dist/server/common.d.ts.map +1 -0
- package/dist/server/common.js +27 -0
- package/dist/server/common.js.map +1 -0
- package/dist/server/eventSubscription.d.ts +53 -0
- package/dist/server/eventSubscription.d.ts.map +1 -0
- package/dist/server/eventSubscription.js +257 -0
- package/dist/server/eventSubscription.js.map +1 -0
- package/dist/server/http.d.ts +12 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +491 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/rateLimiter.d.ts +70 -0
- package/dist/server/rateLimiter.d.ts.map +1 -0
- package/dist/server/rateLimiter.js +156 -0
- package/dist/server/rateLimiter.js.map +1 -0
- package/dist/server/sse.d.ts +32 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +76 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/server/stdio.d.ts +8 -0
- package/dist/server/stdio.d.ts.map +1 -0
- package/dist/server/stdio.js +16 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/server/stream.d.ts +26 -0
- package/dist/server/stream.d.ts.map +1 -0
- package/dist/server/stream.js +81 -0
- package/dist/server/stream.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +30 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/callService.d.ts +8 -0
- package/dist/tools/callService.d.ts.map +1 -0
- package/dist/tools/callService.js +100 -0
- package/dist/tools/callService.js.map +1 -0
- package/dist/tools/getClient.d.ts +8 -0
- package/dist/tools/getClient.d.ts.map +1 -0
- package/dist/tools/getClient.js +94 -0
- package/dist/tools/getClient.js.map +1 -0
- package/dist/tools/getDevice.d.ts +8 -0
- package/dist/tools/getDevice.d.ts.map +1 -0
- package/dist/tools/getDevice.js +94 -0
- package/dist/tools/getDevice.js.map +1 -0
- package/dist/tools/getEntitiesByDomain.d.ts +8 -0
- package/dist/tools/getEntitiesByDomain.d.ts.map +1 -0
- package/dist/tools/getEntitiesByDomain.js +80 -0
- package/dist/tools/getEntitiesByDomain.js.map +1 -0
- package/dist/tools/getState.d.ts +8 -0
- package/dist/tools/getState.d.ts.map +1 -0
- package/dist/tools/getState.js +90 -0
- package/dist/tools/getState.js.map +1 -0
- package/dist/tools/getStates.d.ts +8 -0
- package/dist/tools/getStates.d.ts.map +1 -0
- package/dist/tools/getStates.js +70 -0
- package/dist/tools/getStates.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/listClients.d.ts +8 -0
- package/dist/tools/listClients.d.ts.map +1 -0
- package/dist/tools/listClients.js +73 -0
- package/dist/tools/listClients.js.map +1 -0
- package/dist/tools/listDevices.d.ts +8 -0
- package/dist/tools/listDevices.d.ts.map +1 -0
- package/dist/tools/listDevices.js +73 -0
- package/dist/tools/listDevices.js.map +1 -0
- package/dist/tools/listSites.d.ts +8 -0
- package/dist/tools/listSites.d.ts.map +1 -0
- package/dist/tools/listSites.js +67 -0
- package/dist/tools/listSites.js.map +1 -0
- package/dist/tools/registry.d.ts +9 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +1382 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/searchDevices.d.ts +8 -0
- package/dist/tools/searchDevices.d.ts.map +1 -0
- package/dist/tools/searchDevices.js +84 -0
- package/dist/tools/searchDevices.js.map +1 -0
- package/dist/tools/searchEntities.d.ts +8 -0
- package/dist/tools/searchEntities.d.ts.map +1 -0
- package/dist/tools/searchEntities.js +80 -0
- package/dist/tools/searchEntities.js.map +1 -0
- package/dist/types/entity.d.ts +98 -0
- package/dist/types/entity.d.ts.map +1 -0
- package/dist/types/entity.js +2 -0
- package/dist/types/entity.js.map +1 -0
- package/dist/types/errors.d.ts +16 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +32 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/haConfig.d.ts +8 -0
- package/dist/types/haConfig.d.ts.map +1 -0
- package/dist/types/haConfig.js +2 -0
- package/dist/types/haConfig.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/request.d.ts +7 -0
- package/dist/types/request.d.ts.map +1 -0
- package/dist/types/request.js +2 -0
- package/dist/types/request.js.map +1 -0
- package/dist/types/serviceCall.d.ts +18 -0
- package/dist/types/serviceCall.d.ts.map +1 -0
- package/dist/types/serviceCall.js +2 -0
- package/dist/types/serviceCall.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config-validations.d.ts +12 -0
- package/dist/utils/config-validations.d.ts.map +1 -0
- package/dist/utils/config-validations.js +43 -0
- package/dist/utils/config-validations.js.map +1 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +94 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wrapper.d.ts +8 -0
- package/dist/wrapper.d.ts.map +1 -0
- package/dist/wrapper.js +301 -0
- package/dist/wrapper.js.map +1 -0
- package/docker-compose.yml +17 -0
- package/docs/CHANGELOG.md +86 -0
- package/docs/LOCAL_CLIENT.md +268 -0
- package/docs/SSE_API.md +341 -0
- package/eslint.config.js +33 -0
- package/n8n/ai-agent-safety-monitor.json +355 -0
- package/openapi.json +166 -0
- package/package.json +51 -0
- package/src/config.ts +260 -0
- package/src/haClient/automations.ts +217 -0
- package/src/haClient/config.ts +41 -0
- package/src/haClient/devices.ts +653 -0
- package/src/haClient/entities.ts +128 -0
- package/src/haClient/events.ts +456 -0
- package/src/haClient/history.ts +68 -0
- package/src/haClient/index.ts +287 -0
- package/src/haClient/request.ts +127 -0
- package/src/haClient/services.ts +45 -0
- package/src/haClient/states.ts +60 -0
- package/src/haClient/updates.ts +58 -0
- package/src/index.ts +99 -0
- package/src/localAI/index.ts +88 -0
- package/src/localAI/prompts.ts +50 -0
- package/src/localAI/providers/base.ts +120 -0
- package/src/localAI/providers/ollama.ts +78 -0
- package/src/localAI/providers/openai.ts +86 -0
- package/src/localAI/types.ts +67 -0
- package/src/resources/index.ts +266 -0
- package/src/server/common.ts +38 -0
- package/src/server/eventSubscription.ts +318 -0
- package/src/server/http.ts +546 -0
- package/src/server/rateLimiter.ts +195 -0
- package/src/server/sse.ts +120 -0
- package/src/server/stdio.ts +22 -0
- package/src/server/stream.ts +113 -0
- package/src/tools/callService.ts +114 -0
- package/src/tools/getEntitiesByDomain.ts +92 -0
- package/src/tools/getState.ts +103 -0
- package/src/tools/getStates.ts +80 -0
- package/src/tools/index.ts +9 -0
- package/src/tools/registry.ts +1521 -0
- package/src/tools/searchEntities.ts +92 -0
- package/src/types/entity.ts +110 -0
- package/src/types/errors.ts +33 -0
- package/src/types/haConfig.ts +7 -0
- package/src/types/index.ts +5 -0
- package/src/types/request.ts +6 -0
- package/src/types/serviceCall.ts +18 -0
- package/src/types.ts +2 -0
- package/src/utils/config-validations.ts +46 -0
- package/src/utils/logger.ts +114 -0
- package/src/wrapper.ts +340 -0
- package/tests/config.test.ts +332 -0
- package/tests/haClient/automations.test.ts +133 -0
- package/tests/haClient/config.test.ts +96 -0
- package/tests/haClient/entities.test.ts +188 -0
- package/tests/haClient/history.test.ts +170 -0
- package/tests/haClient/index.test.ts +221 -0
- package/tests/haClient/request.test.ts +217 -0
- package/tests/haClient/services.test.ts +120 -0
- package/tests/haClient/states.test.ts +119 -0
- package/tests/haClient/updates.test.ts +193 -0
- package/tests/index.test.ts +164 -0
- package/tests/localAI/index.test.ts +168 -0
- package/tests/localAI/ollama.test.ts +187 -0
- package/tests/localAI/openai.test.ts +257 -0
- package/tests/server/common.test.ts +64 -0
- package/tests/server/http.test.ts +326 -0
- package/tests/server/sse.test.ts +240 -0
- package/tests/server/stdio.test.ts +102 -0
- package/tests/server/stream.test.ts +287 -0
- package/tests/tools/registry.test.ts +355 -0
- package/tests/utils/config-validations.test.ts +289 -0
- package/tests/utils/logger.test.ts +327 -0
- package/tsconfig.json +25 -0
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|
package/dist/wrapper.js
ADDED
|
@@ -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
|