alexa-mcp 0.1.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/README.md +193 -0
- package/dist/auth-flow.d.ts +7 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +67 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/auth.d.ts +13 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +70 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +434 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +156 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +660 -0
- package/dist/client.js.map +1 -0
- package/dist/config-store.d.ts +6 -0
- package/dist/config-store.d.ts.map +1 -0
- package/dist/config-store.js +44 -0
- package/dist/config-store.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-tools.d.ts +5 -0
- package/dist/mcp-tools.d.ts.map +1 -0
- package/dist/mcp-tools.js +489 -0
- package/dist/mcp-tools.js.map +1 -0
- package/dist/tunnel.d.ts +7 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +100 -0
- package/dist/tunnel.js.map +1 -0
- package/package.json +53 -0
- package/patches/alexa-cookie2+5.0.3.patch +89 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AlexaClient } from "./client.js";
|
|
3
|
+
import { loadRefreshToken, loadDomain } from "./auth.js";
|
|
4
|
+
export function registerAlexaTools(server, clientFactory) {
|
|
5
|
+
server.registerTool("alexa_list_devices", {
|
|
6
|
+
title: "List Alexa Devices",
|
|
7
|
+
description: "List all Echo devices on the account",
|
|
8
|
+
inputSchema: z.object({}),
|
|
9
|
+
}, async () => {
|
|
10
|
+
const client = await clientFactory();
|
|
11
|
+
const devices = await client.getDevices();
|
|
12
|
+
return {
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: JSON.stringify(devices, null, 2),
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.registerTool("alexa_speak", {
|
|
22
|
+
title: "Speak on Device",
|
|
23
|
+
description: "Text-to-speech on a specific Echo device",
|
|
24
|
+
inputSchema: z.object({
|
|
25
|
+
device: z.string().describe("Device name or serial number"),
|
|
26
|
+
text: z.string().describe("Text to speak"),
|
|
27
|
+
}),
|
|
28
|
+
}, async ({ device, text }) => {
|
|
29
|
+
const client = await clientFactory();
|
|
30
|
+
const d = await client.resolveDevice(device);
|
|
31
|
+
if (!d) {
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: `Device not found: ${device}` }],
|
|
34
|
+
isError: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
await client.speak(d.serialNumber, d.deviceType, d.deviceOwnerCustomerId, text);
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: `Spoke on ${d.accountName}` }],
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
server.registerTool("alexa_announce", {
|
|
43
|
+
title: "Announce to All",
|
|
44
|
+
description: "Announce a message to all Echo devices",
|
|
45
|
+
inputSchema: z.object({
|
|
46
|
+
text: z.string().describe("Message to announce"),
|
|
47
|
+
}),
|
|
48
|
+
}, async ({ text }) => {
|
|
49
|
+
const client = await clientFactory();
|
|
50
|
+
const devices = await client.getDevices();
|
|
51
|
+
if (devices.length === 0) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: "No devices found" }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const customerId = devices[0].deviceOwnerCustomerId;
|
|
58
|
+
await client.announce(customerId, text);
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: "Announcement sent" }],
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
server.registerTool("alexa_command", {
|
|
64
|
+
title: "Voice Command",
|
|
65
|
+
description: "Send a voice command to Alexa (e.g. play music, set alarm). For smart home control, prefer control_by_pattern or switch_by_name—voice commands can hit 'Can't control for other account' profile issues and we do not receive Alexa's response.",
|
|
66
|
+
inputSchema: z.object({
|
|
67
|
+
device: z.string().describe("Device name or serial number"),
|
|
68
|
+
text: z.string().describe("Command text (e.g. 'turn off living room light')"),
|
|
69
|
+
}),
|
|
70
|
+
}, async ({ device, text }) => {
|
|
71
|
+
const client = await clientFactory();
|
|
72
|
+
const d = await client.resolveDevice(device);
|
|
73
|
+
if (!d) {
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: "text", text: `Device not found: ${device}` }],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
await client.command(d.serialNumber, d.deviceType, d.deviceOwnerCustomerId, text);
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: "text", text: `Command sent to ${d.accountName}` }],
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
server.registerTool("alexa_list_appliances", {
|
|
85
|
+
title: "List Smart Home Devices",
|
|
86
|
+
description: "List smart home appliances (lights, plugs, etc.) with endpointId (amzn1.alexa.endpoint.*) and friendlyName when available. Use endpointId with control_appliance for direct control.",
|
|
87
|
+
inputSchema: z.object({}),
|
|
88
|
+
}, async () => {
|
|
89
|
+
const client = await clientFactory();
|
|
90
|
+
const appliances = await client.listAppliances();
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: JSON.stringify(appliances, null, 2),
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
server.registerTool("alexa_control_appliance", {
|
|
101
|
+
title: "Control Smart Home Device",
|
|
102
|
+
description: "Turn on/off or set brightness of a smart home device. Use endpointId (amzn1.alexa.endpoint.*) from list_appliances for direct GraphQL control. Opaque IDs use phoenix API.",
|
|
103
|
+
inputSchema: z.object({
|
|
104
|
+
entityId: z
|
|
105
|
+
.string()
|
|
106
|
+
.describe("Endpoint ID (amzn1.alexa.endpoint.*) or entity ID from list_appliances. Prefer endpointId for direct control."),
|
|
107
|
+
action: z.enum(["turnOn", "turnOff", "setBrightness"]),
|
|
108
|
+
brightness: z.number().min(0).max(100).optional().describe("Required for setBrightness"),
|
|
109
|
+
}),
|
|
110
|
+
}, async ({ entityId, action, brightness }) => {
|
|
111
|
+
const client = await clientFactory();
|
|
112
|
+
if (action === "setBrightness" && brightness === undefined) {
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: "text", text: "brightness required for setBrightness" }],
|
|
115
|
+
isError: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
await client.controlAppliance(entityId, action, brightness);
|
|
119
|
+
return {
|
|
120
|
+
content: [{ type: "text", text: `Done: ${action} ${entityId}` }],
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
server.registerTool("alexa_control_by_group", {
|
|
124
|
+
title: "Control Devices in Group (Room)",
|
|
125
|
+
description: "Turn on/off smart home devices in an Alexa room group (e.g. 'Kitchen', 'Living room'). Uses list_device_groups—matches by group name and controls all lights in that group via direct GraphQL. Prefer over voice for 'all lights in group X'.",
|
|
126
|
+
inputSchema: z.object({
|
|
127
|
+
groupName: z
|
|
128
|
+
.string()
|
|
129
|
+
.describe("Room group name from list_device_groups (e.g. 'Kitchen', 'Living room')"),
|
|
130
|
+
state: z.enum(["on", "off"]),
|
|
131
|
+
lightsOnly: z
|
|
132
|
+
.boolean()
|
|
133
|
+
.optional()
|
|
134
|
+
.default(true)
|
|
135
|
+
.describe("If true (default), only control devices with light/lamp/bulb in name"),
|
|
136
|
+
}),
|
|
137
|
+
}, async ({ groupName, state, lightsOnly }) => {
|
|
138
|
+
const client = await clientFactory();
|
|
139
|
+
const action = state === "on" ? "turnOn" : "turnOff";
|
|
140
|
+
try {
|
|
141
|
+
const { controlled, errors } = await client.controlAppliancesByGroup(groupName, action, {
|
|
142
|
+
lightsOnly,
|
|
143
|
+
});
|
|
144
|
+
const lines = [];
|
|
145
|
+
if (controlled.length > 0) {
|
|
146
|
+
lines.push(`Done (group ${groupName}): ${action} → ${controlled.join(", ")}`);
|
|
147
|
+
}
|
|
148
|
+
if (errors.length > 0) {
|
|
149
|
+
lines.push(`Errors: ${errors.join("; ")}`);
|
|
150
|
+
}
|
|
151
|
+
if (controlled.length === 0 && errors.length === 0) {
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: `No lights controlled in group "${groupName}". Try list_device_groups to see groups.`,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
163
|
+
isError: errors.length > 0 && controlled.length === 0,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: "text", text: String(e) }],
|
|
169
|
+
isError: true,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
server.registerTool("alexa_control_by_pattern", {
|
|
174
|
+
title: "Control Devices by Pattern (Room/Name)",
|
|
175
|
+
description: "Turn on/off smart home devices matching a pattern (e.g. 'kitchen lights', 'living room'). Resolves devices by friendlyName and uses direct GraphQL control. For 'all lights in group Kitchen', use control_by_group instead.",
|
|
176
|
+
inputSchema: z.object({
|
|
177
|
+
pattern: z
|
|
178
|
+
.string()
|
|
179
|
+
.describe("Pattern to match (e.g. 'kitchen lights', 'living room'). All words must appear in device name."),
|
|
180
|
+
state: z.enum(["on", "off"]),
|
|
181
|
+
}),
|
|
182
|
+
}, async ({ pattern, state }) => {
|
|
183
|
+
const client = await clientFactory();
|
|
184
|
+
const action = state === "on" ? "turnOn" : "turnOff";
|
|
185
|
+
const { controlled, errors } = await client.controlAppliancesByPattern(pattern, action);
|
|
186
|
+
const lines = [];
|
|
187
|
+
if (controlled.length > 0) {
|
|
188
|
+
lines.push(`Done (direct control): ${action} → ${controlled.join(", ")}`);
|
|
189
|
+
}
|
|
190
|
+
if (errors.length > 0) {
|
|
191
|
+
lines.push(`Errors: ${errors.join("; ")}`);
|
|
192
|
+
}
|
|
193
|
+
if (controlled.length === 0 && errors.length === 0) {
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: "text",
|
|
198
|
+
text: `No devices matched "${pattern}". Use list_appliances to see device names.`,
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
isError: true,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
206
|
+
isError: errors.length > 0 && controlled.length === 0,
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
server.registerTool("alexa_switch_by_name", {
|
|
210
|
+
title: "Turn Smart Home Device On/Off by Name",
|
|
211
|
+
description: "Turn a single smart plug or light on or off by its exact Alexa name (e.g. 'Lounge light 2', 'TV'). For room/pattern (e.g. 'kitchen lights'), use control_by_pattern instead—it avoids profile issues.",
|
|
212
|
+
inputSchema: z.object({
|
|
213
|
+
name: z.string().describe("Smart home device name as known to Alexa (e.g. 'Lounge light 2', 'TV')"),
|
|
214
|
+
state: z.enum(["on", "off"]),
|
|
215
|
+
device: z
|
|
216
|
+
.string()
|
|
217
|
+
.optional()
|
|
218
|
+
.describe("Echo device for voice fallback only (e.g. 'Lounge Echo'); required if direct control fails"),
|
|
219
|
+
}),
|
|
220
|
+
}, async ({ name, state, device }) => {
|
|
221
|
+
const client = await clientFactory();
|
|
222
|
+
const action = state === "on" ? "turnOn" : "turnOff";
|
|
223
|
+
const app = await client.resolveApplianceByName(name);
|
|
224
|
+
if (app?.endpointId) {
|
|
225
|
+
await client.controlAppliance(app.endpointId, action);
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: "text", text: `Done: ${action} ${app.friendlyName} (direct control)` }],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (!device) {
|
|
231
|
+
return {
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: "text",
|
|
235
|
+
text: `Could not resolve "${name}" to a controllable device. Try list_appliances to see names. If the device exists, provide 'device' for voice fallback.`,
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
isError: true,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const d = await client.resolveDevice(device);
|
|
242
|
+
if (!d) {
|
|
243
|
+
return {
|
|
244
|
+
content: [{ type: "text", text: `Echo device not found: ${device}` }],
|
|
245
|
+
isError: true,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const text = state === "on" ? `turn on ${name}` : `turn off ${name}`;
|
|
249
|
+
await client.command(d.serialNumber, d.deviceType, d.deviceOwnerCustomerId, text);
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: "text", text: `Sent "${text}" via ${d.accountName} (voice fallback)` }],
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
server.registerTool("alexa_list_device_groups", {
|
|
255
|
+
title: "List Device Groups",
|
|
256
|
+
description: "List room/space groups (Living room, Kitchen, etc.) from the Alexa app. Returns group names, IDs, and appliance counts.",
|
|
257
|
+
inputSchema: z.object({}),
|
|
258
|
+
}, async () => {
|
|
259
|
+
const client = await clientFactory();
|
|
260
|
+
const groups = await client.listDeviceGroups();
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{
|
|
264
|
+
type: "text",
|
|
265
|
+
text: JSON.stringify(groups, null, 2),
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
server.registerTool("alexa_control_group", {
|
|
271
|
+
title: "Control Room Group (Lights)",
|
|
272
|
+
description: "Turn on/off all lights in a room/space group (e.g. Kitchen, Living room). Uses group membership from the Alexa app. By default only controls devices with 'light', 'lamp', or 'bulb' in the name.",
|
|
273
|
+
inputSchema: z.object({
|
|
274
|
+
group: z.string().describe("Group/room name (e.g. 'Kitchen', 'Living room')"),
|
|
275
|
+
state: z.enum(["on", "off"]),
|
|
276
|
+
lightsOnly: z
|
|
277
|
+
.boolean()
|
|
278
|
+
.optional()
|
|
279
|
+
.default(true)
|
|
280
|
+
.describe("If true, only control lights (default). If false, control all appliances in the group."),
|
|
281
|
+
}),
|
|
282
|
+
}, async ({ group, state, lightsOnly }) => {
|
|
283
|
+
const client = await clientFactory();
|
|
284
|
+
const action = state === "on" ? "turnOn" : "turnOff";
|
|
285
|
+
const { controlled, errors } = await client.controlAppliancesByGroup(group, action, { lightsOnly });
|
|
286
|
+
const lines = [];
|
|
287
|
+
if (controlled.length > 0) {
|
|
288
|
+
lines.push(`Done: ${action} → ${controlled.join(", ")}`);
|
|
289
|
+
}
|
|
290
|
+
if (errors.length > 0) {
|
|
291
|
+
lines.push(`Errors: ${errors.join("; ")}`);
|
|
292
|
+
}
|
|
293
|
+
if (controlled.length === 0 && errors.length === 0) {
|
|
294
|
+
return {
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: "text",
|
|
298
|
+
text: `No lights found in group "${group}". Use list_device_groups and list_appliances to inspect.`,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
isError: true,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
306
|
+
isError: errors.length > 0 && controlled.length === 0,
|
|
307
|
+
};
|
|
308
|
+
});
|
|
309
|
+
server.registerTool("alexa_list_audio_groups", {
|
|
310
|
+
title: "List Audio Groups",
|
|
311
|
+
description: "List multi-room audio groups (Downstairs, Everywhere, etc.) with Echo device members for whole-home music playback.",
|
|
312
|
+
inputSchema: z.object({}),
|
|
313
|
+
}, async () => {
|
|
314
|
+
const client = await clientFactory();
|
|
315
|
+
const groups = await client.listAudioGroups();
|
|
316
|
+
return {
|
|
317
|
+
content: [
|
|
318
|
+
{
|
|
319
|
+
type: "text",
|
|
320
|
+
text: JSON.stringify(groups, null, 2),
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
server.registerTool("alexa_list_routines", {
|
|
326
|
+
title: "List Routines",
|
|
327
|
+
description: "List Alexa routines",
|
|
328
|
+
inputSchema: z.object({}),
|
|
329
|
+
}, async () => {
|
|
330
|
+
const client = await clientFactory();
|
|
331
|
+
const routines = await client.listRoutines();
|
|
332
|
+
return {
|
|
333
|
+
content: [
|
|
334
|
+
{
|
|
335
|
+
type: "text",
|
|
336
|
+
text: JSON.stringify(routines, null, 2),
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
server.registerTool("alexa_auth_status", {
|
|
342
|
+
title: "Auth Status",
|
|
343
|
+
description: "Check Alexa authentication status. Returns whether configured and device count if valid.",
|
|
344
|
+
inputSchema: z.object({}),
|
|
345
|
+
}, async () => {
|
|
346
|
+
const token = loadRefreshToken();
|
|
347
|
+
if (!token) {
|
|
348
|
+
return {
|
|
349
|
+
content: [
|
|
350
|
+
{
|
|
351
|
+
type: "text",
|
|
352
|
+
text: JSON.stringify({
|
|
353
|
+
configured: false,
|
|
354
|
+
message: "Not configured. Run 'alexa-mcp auth' to authenticate.",
|
|
355
|
+
}),
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
const client = await clientFactory();
|
|
362
|
+
const devices = await client.getDevices();
|
|
363
|
+
return {
|
|
364
|
+
content: [
|
|
365
|
+
{
|
|
366
|
+
type: "text",
|
|
367
|
+
text: JSON.stringify({
|
|
368
|
+
configured: true,
|
|
369
|
+
valid: true,
|
|
370
|
+
deviceCount: devices.length,
|
|
371
|
+
}),
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
catch (e) {
|
|
377
|
+
return {
|
|
378
|
+
content: [
|
|
379
|
+
{
|
|
380
|
+
type: "text",
|
|
381
|
+
text: JSON.stringify({
|
|
382
|
+
configured: true,
|
|
383
|
+
valid: false,
|
|
384
|
+
error: String(e),
|
|
385
|
+
message: "Token invalid. Run 'alexa-mcp auth' to re-authenticate.",
|
|
386
|
+
}),
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
isError: true,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
server.registerTool("alexa_run_routine", {
|
|
394
|
+
title: "Run Routine",
|
|
395
|
+
description: "Run an Alexa routine by automation ID",
|
|
396
|
+
inputSchema: z.object({
|
|
397
|
+
automationId: z.string().describe("Automation ID from list_routines"),
|
|
398
|
+
}),
|
|
399
|
+
}, async ({ automationId }) => {
|
|
400
|
+
const client = await clientFactory();
|
|
401
|
+
const routines = await client.listRoutines();
|
|
402
|
+
const r = routines.find((x) => x.automationId === automationId);
|
|
403
|
+
if (!r) {
|
|
404
|
+
return {
|
|
405
|
+
content: [{ type: "text", text: `Routine not found: ${automationId}` }],
|
|
406
|
+
isError: true,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
const sequenceJson = r.sequence != null ? JSON.stringify(r.sequence) : undefined;
|
|
410
|
+
await client.runRoutine(r.automationId, sequenceJson);
|
|
411
|
+
return {
|
|
412
|
+
content: [{ type: "text", text: `Ran routine: ${r.name}` }],
|
|
413
|
+
};
|
|
414
|
+
});
|
|
415
|
+
server.registerTool("alexa_now_playing", {
|
|
416
|
+
title: "Now Playing",
|
|
417
|
+
description: "Get now-playing state for an Echo device (includes taskSessionId for transport control)",
|
|
418
|
+
inputSchema: z.object({
|
|
419
|
+
device: z.string().describe("Device name or serial number"),
|
|
420
|
+
}),
|
|
421
|
+
}, async ({ device }) => {
|
|
422
|
+
const client = await clientFactory();
|
|
423
|
+
const d = await client.resolveDevice(device);
|
|
424
|
+
if (!d) {
|
|
425
|
+
return {
|
|
426
|
+
content: [{ type: "text", text: `Device not found: ${device}` }],
|
|
427
|
+
isError: true,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
const state = await client.getNowPlaying(d.serialNumber, d.deviceType);
|
|
431
|
+
return {
|
|
432
|
+
content: [
|
|
433
|
+
{
|
|
434
|
+
type: "text",
|
|
435
|
+
text: JSON.stringify({ device: d.accountName, ...state }, null, 2),
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
});
|
|
440
|
+
server.registerTool("alexa_media_control", {
|
|
441
|
+
title: "Media Control",
|
|
442
|
+
description: "Play, pause, resume, stop, next, or previous on an Echo device's current playback",
|
|
443
|
+
inputSchema: z.object({
|
|
444
|
+
device: z.string().describe("Device name or serial number"),
|
|
445
|
+
command: z
|
|
446
|
+
.enum(["play", "pause", "resume", "stop", "next", "previous"])
|
|
447
|
+
.describe("Transport command"),
|
|
448
|
+
}),
|
|
449
|
+
}, async ({ device, command }) => {
|
|
450
|
+
const client = await clientFactory();
|
|
451
|
+
const d = await client.resolveDevice(device);
|
|
452
|
+
if (!d) {
|
|
453
|
+
return {
|
|
454
|
+
content: [{ type: "text", text: `Device not found: ${device}` }],
|
|
455
|
+
isError: true,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const state = await client.getNowPlaying(d.serialNumber, d.deviceType);
|
|
459
|
+
const taskSessionId = state?.taskSessionId;
|
|
460
|
+
if (!taskSessionId) {
|
|
461
|
+
return {
|
|
462
|
+
content: [
|
|
463
|
+
{
|
|
464
|
+
type: "text",
|
|
465
|
+
text: `No active playback on ${d.accountName}. Start something (e.g. "Alexa, play jazz") then try again.`,
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
isError: true,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
await client.controlMediaSession(d, taskSessionId, command);
|
|
472
|
+
return {
|
|
473
|
+
content: [
|
|
474
|
+
{
|
|
475
|
+
type: "text",
|
|
476
|
+
text: `Sent ${command} to ${d.accountName}`,
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
};
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
export async function createClient(refreshTokenOverride) {
|
|
483
|
+
const token = loadRefreshToken(refreshTokenOverride) ?? refreshTokenOverride;
|
|
484
|
+
if (!token) {
|
|
485
|
+
throw new Error("No refresh token. Set ALEXA_REFRESH_TOKEN or run 'alexa-mcp auth' to authenticate.");
|
|
486
|
+
}
|
|
487
|
+
return new AlexaClient({ refreshToken: token, domain: loadDomain() });
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=mcp-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../src/mcp-tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tunnel.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAsB,WAAW,CAAC,IAAI,GAAE,MAAmB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAQzF"}
|
package/dist/tunnel.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const PROXY_PORT = 8080;
|
|
3
|
+
export async function startTunnel(port = PROXY_PORT) {
|
|
4
|
+
const cloudflared = await tryCloudflared(port);
|
|
5
|
+
if (cloudflared)
|
|
6
|
+
return cloudflared;
|
|
7
|
+
const lt = await tryLocaltunnel(port);
|
|
8
|
+
if (lt)
|
|
9
|
+
return lt;
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
async function tryCloudflared(port) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
let resolved = false;
|
|
15
|
+
const proc = spawn("cloudflared", ["tunnel", "--url", `http://127.0.0.1:${port}`], {
|
|
16
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
17
|
+
});
|
|
18
|
+
const check = (data) => {
|
|
19
|
+
const m = data.match(/https:\/\/([a-z0-9-]+\.trycloudflare\.com)/);
|
|
20
|
+
if (m && !resolved) {
|
|
21
|
+
resolved = true;
|
|
22
|
+
resolve({ url: m[0], host: m[1], close: () => proc.kill("SIGTERM") });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
let buf = "";
|
|
26
|
+
proc.stdout?.on("data", (chunk) => {
|
|
27
|
+
buf += chunk.toString();
|
|
28
|
+
check(buf);
|
|
29
|
+
});
|
|
30
|
+
proc.stderr?.on("data", (chunk) => {
|
|
31
|
+
buf += chunk.toString();
|
|
32
|
+
check(buf);
|
|
33
|
+
});
|
|
34
|
+
proc.on("error", () => {
|
|
35
|
+
if (!resolved) {
|
|
36
|
+
resolved = true;
|
|
37
|
+
resolve(null);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
proc.on("exit", (code) => {
|
|
41
|
+
if (!resolved && code !== 0 && code !== null) {
|
|
42
|
+
resolved = true;
|
|
43
|
+
resolve(null);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
if (!resolved) {
|
|
48
|
+
resolved = true;
|
|
49
|
+
proc.kill("SIGTERM");
|
|
50
|
+
resolve(null);
|
|
51
|
+
}
|
|
52
|
+
}, 12000);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function tryLocaltunnel(port) {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
let resolved = false;
|
|
58
|
+
const proc = spawn("npx", ["-y", "localtunnel", "--port", String(port)], {
|
|
59
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
60
|
+
});
|
|
61
|
+
const check = (data) => {
|
|
62
|
+
const m = data.match(/https:\/\/([a-z0-9-]+\.(?:loca\.lt|localtunnel\.me))/);
|
|
63
|
+
if (m && !resolved) {
|
|
64
|
+
resolved = true;
|
|
65
|
+
const url = m[0].trim();
|
|
66
|
+
const host = m[1];
|
|
67
|
+
resolve({ url, host, close: () => proc.kill("SIGTERM") });
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
let buf = "";
|
|
71
|
+
proc.stdout?.on("data", (chunk) => {
|
|
72
|
+
buf += chunk.toString();
|
|
73
|
+
check(buf);
|
|
74
|
+
});
|
|
75
|
+
proc.stderr?.on("data", (chunk) => {
|
|
76
|
+
buf += chunk.toString();
|
|
77
|
+
check(buf);
|
|
78
|
+
});
|
|
79
|
+
proc.on("error", () => {
|
|
80
|
+
if (!resolved) {
|
|
81
|
+
resolved = true;
|
|
82
|
+
resolve(null);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
proc.on("exit", (code) => {
|
|
86
|
+
if (!resolved && code !== 0 && code !== null) {
|
|
87
|
+
resolved = true;
|
|
88
|
+
resolve(null);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
if (!resolved) {
|
|
93
|
+
resolved = true;
|
|
94
|
+
proc.kill("SIGTERM");
|
|
95
|
+
resolve(null);
|
|
96
|
+
}
|
|
97
|
+
}, 15000);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"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"}
|