@mp-consulting/homebridge-mcp-server 1.0.0 → 1.0.2
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/README.md +9 -3
- package/dist/homebridge-client.d.ts.map +1 -1
- package/dist/homebridge-client.js +40 -35
- package/dist/homebridge-client.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/tools/accessories.d.ts +2 -2
- package/dist/tools/accessories.js +23 -23
- package/dist/tools/config.d.ts +2 -2
- package/dist/tools/config.js +9 -9
- package/dist/tools/plugins.d.ts +2 -2
- package/dist/tools/plugins.js +20 -20
- package/dist/tools/server.d.ts +2 -2
- package/dist/tools/server.js +25 -25
- package/dist/tools/system.d.ts +2 -2
- package/dist/tools/system.js +3 -3
- package/dist/types.d.ts +2 -2
- package/package.json +17 -3
- package/dist/__tests__/homebridge-client.test.d.ts +0 -2
- package/dist/__tests__/homebridge-client.test.d.ts.map +0 -1
- package/dist/__tests__/homebridge-client.test.js +0 -262
- package/dist/__tests__/homebridge-client.test.js.map +0 -1
- package/dist/__tests__/tools/accessories.test.d.ts +0 -2
- package/dist/__tests__/tools/accessories.test.d.ts.map +0 -1
- package/dist/__tests__/tools/accessories.test.js +0 -252
- package/dist/__tests__/tools/accessories.test.js.map +0 -1
- package/dist/__tests__/tools/config.test.d.ts +0 -2
- package/dist/__tests__/tools/config.test.d.ts.map +0 -1
- package/dist/__tests__/tools/config.test.js +0 -85
- package/dist/__tests__/tools/config.test.js.map +0 -1
- package/dist/__tests__/tools/plugins.test.d.ts +0 -2
- package/dist/__tests__/tools/plugins.test.d.ts.map +0 -1
- package/dist/__tests__/tools/plugins.test.js +0 -119
- package/dist/__tests__/tools/plugins.test.js.map +0 -1
- package/dist/__tests__/tools/server.test.d.ts +0 -2
- package/dist/__tests__/tools/server.test.d.ts.map +0 -1
- package/dist/__tests__/tools/server.test.js +0 -126
- package/dist/__tests__/tools/server.test.js.map +0 -1
- package/dist/__tests__/tools/system.test.d.ts +0 -2
- package/dist/__tests__/tools/system.test.d.ts.map +0 -1
- package/dist/__tests__/tools/system.test.js +0 -62
- package/dist/__tests__/tools/system.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ npx @modelcontextprotocol/inspector homebridge-mcp-server
|
|
|
75
75
|
|
|
76
76
|
| Tool | Description |
|
|
77
77
|
|------|-------------|
|
|
78
|
-
| `list_accessories` | List all accessories with current state |
|
|
78
|
+
| `list_accessories` | List all accessories with current state. Supports filtering by `room`, `type`, `name`, `manufacturer`, and `excludeManufacturer` |
|
|
79
79
|
| `get_accessory` | Get detailed info for a specific accessory |
|
|
80
80
|
| `set_accessory` | Control an accessory (on/off, brightness, temperature, etc.) |
|
|
81
81
|
| `get_accessory_layout` | Get the room layout from the Homebridge UI |
|
|
@@ -85,7 +85,7 @@ npx @modelcontextprotocol/inspector homebridge-mcp-server
|
|
|
85
85
|
| Tool | Description |
|
|
86
86
|
|------|-------------|
|
|
87
87
|
| `get_homebridge_status` | Check if Homebridge is running |
|
|
88
|
-
| `get_server_status` | Get server version, uptime, Node.js version |
|
|
88
|
+
| `get_server_status` | Get server version, uptime, Node.js version, OS details, and instance ID |
|
|
89
89
|
| `restart_homebridge` | Restart the Homebridge service |
|
|
90
90
|
| `get_pairing_info` | Get HomeKit pairing code / QR info |
|
|
91
91
|
| `get_cached_accessories` | List cached accessories |
|
|
@@ -131,12 +131,18 @@ Once configured, you can ask Claude things like:
|
|
|
131
131
|
## Development
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
git clone https://github.com/
|
|
134
|
+
git clone https://github.com/mp-consulting/homebridge-mcp-server.git
|
|
135
135
|
cd homebridge-mcp-server
|
|
136
136
|
npm install
|
|
137
137
|
npm run build
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
```bash
|
|
141
|
+
npm run dev # Run with auto-reload (tsx)
|
|
142
|
+
npm test # Run tests
|
|
143
|
+
npm run test:watch # Run tests in watch mode
|
|
144
|
+
```
|
|
145
|
+
|
|
140
146
|
## License
|
|
141
147
|
|
|
142
148
|
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homebridge-client.d.ts","sourceRoot":"","sources":["../src/homebridge-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAuB;;
|
|
1
|
+
{"version":3,"file":"homebridge-client.d.ts","sourceRoot":"","sources":["../src/homebridge-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAuB;;YAwBtB,YAAY;YAgBZ,YAAY;YA0BZ,mBAAmB;YAQnB,OAAO;IAiDf,cAAc,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIpC,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC,0BAA0B,CAC9B,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,MAAM,EAC1B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAC/B,OAAO,CAAC,OAAO,CAAC;IASb,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAIvC,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IAIxC,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAIlC,oBAAoB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrD,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC;IAM1C,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAI7B,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAM/C,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIhC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAIhD,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlD,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIvD,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3D,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMxD,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;CAGxC"}
|
|
@@ -11,21 +11,24 @@ export class HomebridgeClient {
|
|
|
11
11
|
const url = process.env.HOMEBRIDGE_URL;
|
|
12
12
|
const username = process.env.HOMEBRIDGE_USERNAME;
|
|
13
13
|
const password = process.env.HOMEBRIDGE_PASSWORD;
|
|
14
|
-
if (!url)
|
|
15
|
-
throw new Error(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
if (!url) {
|
|
15
|
+
throw new Error('HOMEBRIDGE_URL environment variable is required');
|
|
16
|
+
}
|
|
17
|
+
if (!username) {
|
|
18
|
+
throw new Error('HOMEBRIDGE_USERNAME environment variable is required');
|
|
19
|
+
}
|
|
20
|
+
if (!password) {
|
|
21
|
+
throw new Error('HOMEBRIDGE_PASSWORD environment variable is required');
|
|
22
|
+
}
|
|
23
|
+
this.baseUrl = url.replace(/\/+$/, '');
|
|
21
24
|
this.username = username;
|
|
22
25
|
this.password = password;
|
|
23
26
|
}
|
|
24
27
|
// ── Authentication ──────────────────────────────────────────────
|
|
25
28
|
async authenticate() {
|
|
26
29
|
const res = await fetch(`${this.baseUrl}/api/auth/login`, {
|
|
27
|
-
method:
|
|
28
|
-
headers: {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
32
|
body: JSON.stringify({ username: this.username, password: this.password }),
|
|
30
33
|
});
|
|
31
34
|
if (!res.ok) {
|
|
@@ -36,18 +39,20 @@ export class HomebridgeClient {
|
|
|
36
39
|
this.token = data.access_token;
|
|
37
40
|
}
|
|
38
41
|
async refreshToken() {
|
|
39
|
-
if (!this.token)
|
|
42
|
+
if (!this.token) {
|
|
40
43
|
return false;
|
|
44
|
+
}
|
|
41
45
|
try {
|
|
42
46
|
const res = await fetch(`${this.baseUrl}/api/auth/refresh`, {
|
|
43
|
-
method:
|
|
47
|
+
method: 'POST',
|
|
44
48
|
headers: {
|
|
45
|
-
|
|
49
|
+
'Content-Type': 'application/json',
|
|
46
50
|
Authorization: `Bearer ${this.token}`,
|
|
47
51
|
},
|
|
48
52
|
});
|
|
49
|
-
if (!res.ok)
|
|
53
|
+
if (!res.ok) {
|
|
50
54
|
return false;
|
|
55
|
+
}
|
|
51
56
|
const data = (await res.json());
|
|
52
57
|
this.token = data.access_token;
|
|
53
58
|
return true;
|
|
@@ -69,7 +74,7 @@ export class HomebridgeClient {
|
|
|
69
74
|
Authorization: `Bearer ${this.token}`,
|
|
70
75
|
};
|
|
71
76
|
if (body !== undefined) {
|
|
72
|
-
headers[
|
|
77
|
+
headers['Content-Type'] = 'application/json';
|
|
73
78
|
}
|
|
74
79
|
return fetch(`${this.baseUrl}${path}`, {
|
|
75
80
|
method,
|
|
@@ -90,76 +95,76 @@ export class HomebridgeClient {
|
|
|
90
95
|
const text = await res.text();
|
|
91
96
|
throw new Error(`Homebridge API error ${res.status} ${method} ${path}: ${text}`);
|
|
92
97
|
}
|
|
93
|
-
const contentType = res.headers.get(
|
|
94
|
-
if (contentType.includes(
|
|
98
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
99
|
+
if (contentType.includes('application/json')) {
|
|
95
100
|
return (await res.json());
|
|
96
101
|
}
|
|
97
102
|
return (await res.text());
|
|
98
103
|
}
|
|
99
104
|
// ── Accessories ─────────────────────────────────────────────────
|
|
100
105
|
async getAccessories() {
|
|
101
|
-
return this.request(
|
|
106
|
+
return this.request('GET', '/api/accessories');
|
|
102
107
|
}
|
|
103
108
|
async getAccessoryLayout() {
|
|
104
|
-
return this.request(
|
|
109
|
+
return this.request('GET', '/api/accessories/layout');
|
|
105
110
|
}
|
|
106
111
|
async setAccessoryCharacteristic(uniqueId, characteristicType, value) {
|
|
107
|
-
return this.request(
|
|
112
|
+
return this.request('PUT', `/api/accessories/${encodeURIComponent(uniqueId)}`, {
|
|
108
113
|
characteristicType,
|
|
109
114
|
value,
|
|
110
115
|
});
|
|
111
116
|
}
|
|
112
117
|
// ── Server / Status ─────────────────────────────────────────────
|
|
113
118
|
async getHomebridgeStatus() {
|
|
114
|
-
return this.request(
|
|
119
|
+
return this.request('GET', '/api/status/homebridge');
|
|
115
120
|
}
|
|
116
121
|
async getServerInformation() {
|
|
117
|
-
return this.request(
|
|
122
|
+
return this.request('GET', '/api/status/server-information');
|
|
118
123
|
}
|
|
119
124
|
async restartServer() {
|
|
120
|
-
return this.request(
|
|
125
|
+
return this.request('PUT', '/api/server/restart');
|
|
121
126
|
}
|
|
122
127
|
async getPairingInfo() {
|
|
123
|
-
return this.request(
|
|
128
|
+
return this.request('GET', '/api/server/pairing');
|
|
124
129
|
}
|
|
125
130
|
async getCachedAccessories() {
|
|
126
|
-
return this.request(
|
|
131
|
+
return this.request('GET', '/api/server/cached-accessories');
|
|
127
132
|
}
|
|
128
133
|
async removeCachedAccessory(uuid) {
|
|
129
|
-
return this.request(
|
|
134
|
+
return this.request('DELETE', `/api/server/cached-accessories/${encodeURIComponent(uuid)}`);
|
|
130
135
|
}
|
|
131
136
|
async resetCachedAccessories() {
|
|
132
|
-
return this.request(
|
|
137
|
+
return this.request('PUT', '/api/server/reset-cached-accessories');
|
|
133
138
|
}
|
|
134
139
|
// ── Config ──────────────────────────────────────────────────────
|
|
135
140
|
async getConfig() {
|
|
136
|
-
return this.request(
|
|
141
|
+
return this.request('GET', '/api/config-editor');
|
|
137
142
|
}
|
|
138
143
|
async updateConfig(config) {
|
|
139
|
-
return this.request(
|
|
144
|
+
return this.request('POST', '/api/config-editor', config);
|
|
140
145
|
}
|
|
141
146
|
// ── Plugins ─────────────────────────────────────────────────────
|
|
142
147
|
async getPlugins() {
|
|
143
|
-
return this.request(
|
|
148
|
+
return this.request('GET', '/api/plugins');
|
|
144
149
|
}
|
|
145
150
|
async searchPlugins(query) {
|
|
146
|
-
return this.request(
|
|
151
|
+
return this.request('GET', `/api/plugins/search/${encodeURIComponent(query)}`);
|
|
147
152
|
}
|
|
148
153
|
async lookupPlugin(pluginName) {
|
|
149
|
-
return this.request(
|
|
154
|
+
return this.request('GET', `/api/plugins/lookup/${encodeURIComponent(pluginName)}`);
|
|
150
155
|
}
|
|
151
156
|
async getPluginVersions(pluginName) {
|
|
152
|
-
return this.request(
|
|
157
|
+
return this.request('GET', `/api/plugins/lookup/${encodeURIComponent(pluginName)}/versions`);
|
|
153
158
|
}
|
|
154
159
|
async getPluginConfigSchema(pluginName) {
|
|
155
|
-
return this.request(
|
|
160
|
+
return this.request('GET', `/api/plugins/config-schema/${encodeURIComponent(pluginName)}`);
|
|
156
161
|
}
|
|
157
162
|
async getPluginChangelog(pluginName) {
|
|
158
|
-
return this.request(
|
|
163
|
+
return this.request('GET', `/api/plugins/changelog/${encodeURIComponent(pluginName)}`);
|
|
159
164
|
}
|
|
160
165
|
// ── Platform Tools ──────────────────────────────────────────────
|
|
161
166
|
async getSystemInfo() {
|
|
162
|
-
return this.request(
|
|
167
|
+
return this.request('GET', '/api/platform-tools/system-information');
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
//# sourceMappingURL=homebridge-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homebridge-client.js","sourceRoot":"","sources":["../src/homebridge-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,QAAQ,CAAS;IAC1B,KAAK,GAAkB,IAAI,CAAC;IAEpC;QACE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAEjD,IAAI,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"homebridge-client.js","sourceRoot":"","sources":["../src/homebridge-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { McpServer } from
|
|
3
|
-
import { StdioServerTransport } from
|
|
4
|
-
import { HomebridgeClient } from
|
|
5
|
-
import { register as registerAccessories } from
|
|
6
|
-
import { register as registerServer } from
|
|
7
|
-
import { register as registerConfig } from
|
|
8
|
-
import { register as registerPlugins } from
|
|
9
|
-
import { register as registerSystem } from
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { HomebridgeClient } from './homebridge-client.js';
|
|
5
|
+
import { register as registerAccessories } from './tools/accessories.js';
|
|
6
|
+
import { register as registerServer } from './tools/server.js';
|
|
7
|
+
import { register as registerConfig } from './tools/config.js';
|
|
8
|
+
import { register as registerPlugins } from './tools/plugins.js';
|
|
9
|
+
import { register as registerSystem } from './tools/system.js';
|
|
10
10
|
const server = new McpServer({
|
|
11
|
-
name:
|
|
12
|
-
version:
|
|
11
|
+
name: 'homebridge-mcp-server',
|
|
12
|
+
version: '1.0.1',
|
|
13
13
|
});
|
|
14
14
|
const client = new HomebridgeClient();
|
|
15
15
|
// Register all tool groups
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { HomebridgeClient } from
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { HomebridgeClient } from '../homebridge-client.js';
|
|
3
3
|
export declare function register(server: McpServer, client: HomebridgeClient): void;
|
|
4
4
|
//# sourceMappingURL=accessories.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
function compactAccessory(acc) {
|
|
3
3
|
return {
|
|
4
4
|
uniqueId: acc.uniqueId,
|
|
@@ -10,12 +10,12 @@ function compactAccessory(acc) {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
export function register(server, client) {
|
|
13
|
-
server.tool(
|
|
14
|
-
room: z.string().optional().describe(
|
|
13
|
+
server.tool('list_accessories', 'List all Homebridge accessories with their current state (on/off, brightness, temperature, etc.)', {
|
|
14
|
+
room: z.string().optional().describe('Filter by room name (case-insensitive)'),
|
|
15
15
|
type: z.string().optional().describe("Filter by accessory type (e.g. 'Lightbulb', 'Switch', 'Thermostat')"),
|
|
16
|
-
manufacturer: z.string().optional().describe(
|
|
17
|
-
excludeManufacturer: z.string().optional().describe(
|
|
18
|
-
name: z.string().optional().describe(
|
|
16
|
+
manufacturer: z.string().optional().describe('Filter by manufacturer (case-insensitive, contains match)'),
|
|
17
|
+
excludeManufacturer: z.string().optional().describe('Exclude accessories from this manufacturer (case-insensitive, contains match)'),
|
|
18
|
+
name: z.string().optional().describe('Filter by service name (case-insensitive, contains match)'),
|
|
19
19
|
}, async ({ room, type, manufacturer, excludeManufacturer, name }) => {
|
|
20
20
|
try {
|
|
21
21
|
let accessories = (await client.getAccessories());
|
|
@@ -25,7 +25,7 @@ export function register(server, client) {
|
|
|
25
25
|
const matchedRoom = layout.find((r) => r.name.toLowerCase() === room.toLowerCase());
|
|
26
26
|
if (!matchedRoom) {
|
|
27
27
|
return {
|
|
28
|
-
content: [{ type:
|
|
28
|
+
content: [{ type: 'text', text: `Room not found: "${room}". Available rooms: ${layout.map((r) => r.name).join(', ')}` }],
|
|
29
29
|
isError: true,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
@@ -49,60 +49,60 @@ export function register(server, client) {
|
|
|
49
49
|
}
|
|
50
50
|
const compact = accessories.map(compactAccessory);
|
|
51
51
|
return {
|
|
52
|
-
content: [{ type:
|
|
52
|
+
content: [{ type: 'text', text: JSON.stringify(compact, null, 2) }],
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
catch (error) {
|
|
56
56
|
return {
|
|
57
|
-
content: [{ type:
|
|
57
|
+
content: [{ type: 'text', text: `Error listing accessories: ${error}` }],
|
|
58
58
|
isError: true,
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
|
-
server.tool(
|
|
62
|
+
server.tool('get_accessory', 'Get detailed information about a specific accessory by its uniqueId. Use list_accessories first to find the uniqueId.', { uniqueId: z.string().describe('The unique identifier of the accessory') }, async ({ uniqueId }) => {
|
|
63
63
|
try {
|
|
64
64
|
const accessories = await client.getAccessories();
|
|
65
65
|
const accessory = accessories.find((a) => a.uniqueId === uniqueId);
|
|
66
66
|
if (!accessory) {
|
|
67
67
|
return {
|
|
68
|
-
content: [{ type:
|
|
68
|
+
content: [{ type: 'text', text: `Accessory not found with uniqueId: ${uniqueId}` }],
|
|
69
69
|
isError: true,
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
return {
|
|
73
|
-
content: [{ type:
|
|
73
|
+
content: [{ type: 'text', text: JSON.stringify(accessory, null, 2) }],
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
catch (error) {
|
|
77
77
|
return {
|
|
78
|
-
content: [{ type:
|
|
78
|
+
content: [{ type: 'text', text: `Error getting accessory: ${error}` }],
|
|
79
79
|
isError: true,
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
|
-
server.tool(
|
|
84
|
-
uniqueId: z.string().describe(
|
|
83
|
+
server.tool('set_accessory', 'Control a Homebridge accessory — turn it on/off, set brightness, color temperature, etc. Use list_accessories first to find the uniqueId and available characteristicTypes.', {
|
|
84
|
+
uniqueId: z.string().describe('The unique identifier of the accessory'),
|
|
85
85
|
characteristicType: z
|
|
86
86
|
.string()
|
|
87
87
|
.describe("The characteristic to set (e.g. 'On', 'Brightness', 'ColorTemperature', 'Hue', 'Saturation', 'TargetTemperature', 'TargetDoorState')"),
|
|
88
88
|
value: z
|
|
89
89
|
.union([z.string(), z.number(), z.boolean()])
|
|
90
|
-
.describe(
|
|
90
|
+
.describe('The value to set (e.g. true/false for On, 0-100 for Brightness)'),
|
|
91
91
|
}, async ({ uniqueId, characteristicType, value }) => {
|
|
92
92
|
try {
|
|
93
93
|
const result = await client.setAccessoryCharacteristic(uniqueId, characteristicType, value);
|
|
94
94
|
return {
|
|
95
|
-
content: [{ type:
|
|
95
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
catch (error) {
|
|
99
99
|
return {
|
|
100
|
-
content: [{ type:
|
|
100
|
+
content: [{ type: 'text', text: `Error setting accessory: ${error}` }],
|
|
101
101
|
isError: true,
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
104
|
});
|
|
105
|
-
server.tool(
|
|
105
|
+
server.tool('get_accessory_layout', 'Get the accessories room layout as configured in the Homebridge UI.', {}, async () => {
|
|
106
106
|
try {
|
|
107
107
|
const [layout, accessories] = await Promise.all([
|
|
108
108
|
client.getAccessoryLayout(),
|
|
@@ -118,19 +118,19 @@ export function register(server, client) {
|
|
|
118
118
|
const acc = accessoryMap.get(svc.uniqueId);
|
|
119
119
|
return {
|
|
120
120
|
uniqueId: svc.uniqueId,
|
|
121
|
-
serviceName: acc?.serviceName ?? svc.customName ??
|
|
122
|
-
type: acc?.type ??
|
|
121
|
+
serviceName: acc?.serviceName ?? svc.customName ?? 'Unknown',
|
|
122
|
+
type: acc?.type ?? 'Unknown',
|
|
123
123
|
manufacturer: acc?.accessoryInformation?.Manufacturer ?? null,
|
|
124
124
|
};
|
|
125
125
|
}),
|
|
126
126
|
}));
|
|
127
127
|
return {
|
|
128
|
-
content: [{ type:
|
|
128
|
+
content: [{ type: 'text', text: JSON.stringify(enriched, null, 2) }],
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
catch (error) {
|
|
132
132
|
return {
|
|
133
|
-
content: [{ type:
|
|
133
|
+
content: [{ type: 'text', text: `Error getting layout: ${error}` }],
|
|
134
134
|
isError: true,
|
|
135
135
|
};
|
|
136
136
|
}
|
package/dist/tools/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { HomebridgeClient } from
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { HomebridgeClient } from '../homebridge-client.js';
|
|
3
3
|
export declare function register(server: McpServer, client: HomebridgeClient): void;
|
|
4
4
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/tools/config.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
export function register(server, client) {
|
|
3
|
-
server.tool(
|
|
3
|
+
server.tool('get_config', 'Read the current Homebridge config.json file content. Returns the full configuration including bridge settings, accessories, and platforms.', {}, async () => {
|
|
4
4
|
try {
|
|
5
5
|
const config = await client.getConfig();
|
|
6
6
|
return {
|
|
7
|
-
content: [{ type:
|
|
7
|
+
content: [{ type: 'text', text: JSON.stringify(config, null, 2) }],
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
catch (error) {
|
|
11
11
|
return {
|
|
12
|
-
content: [{ type:
|
|
12
|
+
content: [{ type: 'text', text: `Error getting config: ${error}` }],
|
|
13
13
|
isError: true,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
|
-
server.tool(
|
|
17
|
+
server.tool('update_config', 'Update the Homebridge config.json file. You must provide the FULL config object — it replaces the entire file. Use get_config first to read the current config, then modify and pass back the complete object.', {
|
|
18
18
|
config: z
|
|
19
19
|
.record(z.string(), z.unknown())
|
|
20
|
-
.describe(
|
|
20
|
+
.describe('The complete config.json object to write'),
|
|
21
21
|
}, async ({ config }) => {
|
|
22
22
|
try {
|
|
23
23
|
const result = await client.updateConfig(config);
|
|
24
24
|
return {
|
|
25
25
|
content: [
|
|
26
26
|
{
|
|
27
|
-
type:
|
|
27
|
+
type: 'text',
|
|
28
28
|
text: result
|
|
29
29
|
? JSON.stringify(result, null, 2)
|
|
30
|
-
:
|
|
30
|
+
: 'Config updated successfully. A Homebridge restart may be required for changes to take effect.',
|
|
31
31
|
},
|
|
32
32
|
],
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
catch (error) {
|
|
36
36
|
return {
|
|
37
|
-
content: [{ type:
|
|
37
|
+
content: [{ type: 'text', text: `Error updating config: ${error}` }],
|
|
38
38
|
isError: true,
|
|
39
39
|
};
|
|
40
40
|
}
|
package/dist/tools/plugins.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { HomebridgeClient } from
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { HomebridgeClient } from '../homebridge-client.js';
|
|
3
3
|
export declare function register(server: McpServer, client: HomebridgeClient): void;
|
|
4
4
|
//# sourceMappingURL=plugins.d.ts.map
|
package/dist/tools/plugins.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
export function register(server, client) {
|
|
3
|
-
server.tool(
|
|
3
|
+
server.tool('list_plugins', 'List all currently installed Homebridge plugins with their versions and update status.', {}, async () => {
|
|
4
4
|
try {
|
|
5
5
|
const plugins = await client.getPlugins();
|
|
6
6
|
return {
|
|
7
|
-
content: [{ type:
|
|
7
|
+
content: [{ type: 'text', text: JSON.stringify(plugins, null, 2) }],
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
catch (error) {
|
|
11
11
|
return {
|
|
12
|
-
content: [{ type:
|
|
12
|
+
content: [{ type: 'text', text: `Error listing plugins: ${error}` }],
|
|
13
13
|
isError: true,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
|
-
server.tool(
|
|
17
|
+
server.tool('search_plugins', 'Search the npm registry for Homebridge plugins matching a query.', {
|
|
18
18
|
query: z.string().describe("Search query (e.g. 'hue', 'camera', 'thermostat')"),
|
|
19
19
|
}, async ({ query }) => {
|
|
20
20
|
try {
|
|
21
21
|
const results = await client.searchPlugins(query);
|
|
22
22
|
return {
|
|
23
|
-
content: [{ type:
|
|
23
|
+
content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
catch (error) {
|
|
27
27
|
return {
|
|
28
|
-
content: [{ type:
|
|
28
|
+
content: [{ type: 'text', text: `Error searching plugins: ${error}` }],
|
|
29
29
|
isError: true,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
server.tool(
|
|
33
|
+
server.tool('lookup_plugin', 'Get detailed information about a specific Homebridge plugin from the npm registry.', {
|
|
34
34
|
pluginName: z
|
|
35
35
|
.string()
|
|
36
36
|
.describe("The npm package name of the plugin (e.g. 'homebridge-hue')"),
|
|
@@ -38,17 +38,17 @@ export function register(server, client) {
|
|
|
38
38
|
try {
|
|
39
39
|
const plugin = await client.lookupPlugin(pluginName);
|
|
40
40
|
return {
|
|
41
|
-
content: [{ type:
|
|
41
|
+
content: [{ type: 'text', text: JSON.stringify(plugin, null, 2) }],
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
catch (error) {
|
|
45
45
|
return {
|
|
46
|
-
content: [{ type:
|
|
46
|
+
content: [{ type: 'text', text: `Error looking up plugin: ${error}` }],
|
|
47
47
|
isError: true,
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
|
-
server.tool(
|
|
51
|
+
server.tool('get_plugin_versions', 'Get available versions and dist-tags for a specific Homebridge plugin.', {
|
|
52
52
|
pluginName: z
|
|
53
53
|
.string()
|
|
54
54
|
.describe("The npm package name of the plugin (e.g. 'homebridge-hue')"),
|
|
@@ -56,17 +56,17 @@ export function register(server, client) {
|
|
|
56
56
|
try {
|
|
57
57
|
const versions = await client.getPluginVersions(pluginName);
|
|
58
58
|
return {
|
|
59
|
-
content: [{ type:
|
|
59
|
+
content: [{ type: 'text', text: JSON.stringify(versions, null, 2) }],
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
catch (error) {
|
|
63
63
|
return {
|
|
64
|
-
content: [{ type:
|
|
64
|
+
content: [{ type: 'text', text: `Error getting plugin versions: ${error}` }],
|
|
65
65
|
isError: true,
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
|
-
server.tool(
|
|
69
|
+
server.tool('get_plugin_config_schema', 'Get the config.schema.json for a plugin, which describes how to configure it in Homebridge.', {
|
|
70
70
|
pluginName: z
|
|
71
71
|
.string()
|
|
72
72
|
.describe("The npm package name of the plugin (e.g. 'homebridge-hue')"),
|
|
@@ -74,17 +74,17 @@ export function register(server, client) {
|
|
|
74
74
|
try {
|
|
75
75
|
const schema = await client.getPluginConfigSchema(pluginName);
|
|
76
76
|
return {
|
|
77
|
-
content: [{ type:
|
|
77
|
+
content: [{ type: 'text', text: JSON.stringify(schema, null, 2) }],
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
catch (error) {
|
|
81
81
|
return {
|
|
82
|
-
content: [{ type:
|
|
82
|
+
content: [{ type: 'text', text: `Error getting plugin config schema: ${error}` }],
|
|
83
83
|
isError: true,
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
});
|
|
87
|
-
server.tool(
|
|
87
|
+
server.tool('get_plugin_changelog', 'Get the CHANGELOG.md content for an installed Homebridge plugin.', {
|
|
88
88
|
pluginName: z
|
|
89
89
|
.string()
|
|
90
90
|
.describe("The npm package name of the plugin (e.g. 'homebridge-hue')"),
|
|
@@ -94,15 +94,15 @@ export function register(server, client) {
|
|
|
94
94
|
return {
|
|
95
95
|
content: [
|
|
96
96
|
{
|
|
97
|
-
type:
|
|
98
|
-
text: typeof changelog ===
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: typeof changelog === 'string' ? changelog : JSON.stringify(changelog, null, 2),
|
|
99
99
|
},
|
|
100
100
|
],
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
catch (error) {
|
|
104
104
|
return {
|
|
105
|
-
content: [{ type:
|
|
105
|
+
content: [{ type: 'text', text: `Error getting plugin changelog: ${error}` }],
|
|
106
106
|
isError: true,
|
|
107
107
|
};
|
|
108
108
|
}
|
package/dist/tools/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { HomebridgeClient } from
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { HomebridgeClient } from '../homebridge-client.js';
|
|
3
3
|
export declare function register(server: McpServer, client: HomebridgeClient): void;
|
|
4
4
|
//# sourceMappingURL=server.d.ts.map
|