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 ADDED
@@ -0,0 +1,193 @@
1
+ # @m0nkmaster/alexa-mcp
2
+
3
+ MCP server and CLI for Alexa devices and smart home control via the unofficial Alexa API.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 18+
8
+ - Amazon Alexa account (amazon.com, amazon.co.uk, or amazon.de)
9
+
10
+ ## Setup
11
+
12
+ 1. Install:
13
+ ```bash
14
+ npm install @m0nkmaster/alexa-mcp # local install
15
+ npm install -g @m0nkmaster/alexa-mcp # global install (adds alexa-mcp to PATH)
16
+ npx @m0nkmaster/alexa-mcp auth # run without installing
17
+ ```
18
+
19
+ 2. Authenticate:
20
+ ```bash
21
+ alexa-mcp auth
22
+ ```
23
+ Opens a URL (tunnel or localhost) for you to log in to Amazon. Works locally or headless (remote server) — same behaviour either way. Uses cloudflared or localtunnel automatically; no account required.
24
+
25
+ Or headless:
26
+ ```bash
27
+ alexa-mcp auth --token "Atnr|..."
28
+ alexa-mcp auth --token-file /path/to/token.txt
29
+ alexa-mcp auth --domain amazon.com # US account (default: amazon.co.uk)
30
+ alexa-mcp auth --no-save # validate token without saving
31
+ ```
32
+
33
+ 3. Config stored in `~/.alexa-mcp/config.json`. Also reads `~/.alexa-cli/config.json` or `ALEXA_REFRESH_TOKEN`.
34
+
35
+ ### Environment variables
36
+
37
+ | Variable | Description |
38
+ |----------|-------------|
39
+ | `ALEXA_REFRESH_TOKEN` | Refresh token; skips config file lookup |
40
+ | `ALEXA_DOMAIN` | Amazon domain when using env token (default: `amazon.co.uk`; options: `amazon.com`, `amazon.de`) |
41
+ | `ALEXA_DEBUG` | Set to any value to log API request/response details to stderr |
42
+
43
+ ## CLI
44
+
45
+ ```bash
46
+ alexa-mcp auth # Interactive auth (browser / tunnel URL)
47
+ alexa-mcp auth --token <token> # Save token (headless)
48
+ alexa-mcp auth --token-file <path> # Read token from file
49
+ alexa-mcp auth --domain amazon.com # Specify Amazon domain (default: amazon.co.uk)
50
+ alexa-mcp auth --no-save # Validate token without saving
51
+ alexa-mcp auth status [--verify] # Show auth status (--verify calls API)
52
+ alexa-mcp auth logout # Remove credentials
53
+ alexa-mcp devices # List Echo devices
54
+ alexa-mcp devices --owners # Show device names and owner customer IDs (profile matching)
55
+ alexa-mcp speak "Hello" -d Office # Speak text on a specific device
56
+ alexa-mcp announce "Dinner ready" # Announce to all devices
57
+ alexa-mcp command -d Office "play jazz" # Voice command (no response returned)
58
+ alexa-mcp groups # List room/space groups (Kitchen, Living room, etc.)
59
+ alexa-mcp switch-group Kitchen off # Turn off all lights in a group
60
+ alexa-mcp switch-group Kitchen off --all # Turn off ALL appliances in group (not just lights)
61
+ alexa-mcp switch-room "kitchen lights" off # Turn off all devices matching name pattern
62
+ alexa-mcp switch "Lounge light 2" off # Turn off single device by name (direct control; -d for voice fallback)
63
+ alexa-mcp appliances # List smart home devices (endpointId + friendlyName when available)
64
+ alexa-mcp control <entityId> turnOn|turnOff|setBrightness [--brightness 50]
65
+ alexa-mcp routines # List routines
66
+ alexa-mcp run <automationId> # Run a routine
67
+ alexa-mcp now-playing -d Office # Now-playing state (EU/UK)
68
+ alexa-mcp media play|pause|resume|stop|next|previous -d Office # Transport control (EU/UK)
69
+ ```
70
+
71
+ **Smart home:** For "all lights in group Kitchen", use `switch-group Kitchen off` (use `groups` to list group names). For pattern matching (e.g. "kitchen lights"), use `switch-room`. Both use direct control—avoids voice profile issues. `switch` is for a single device. Voice commands (`command`) do not return Alexa's response. `switch-group` targets only lights by default; add `--all` to include all appliances. `media` commands require active playback (`resume` re-starts paused playback). See [docs/API.md](docs/API.md).
72
+
73
+ ### "Can't control – may need to switch user accounts"
74
+
75
+ If the Echo says it can't control the device and suggests switching user accounts:
76
+
77
+ - **Who the CLI uses:** The CLI always acts as the **Amazon account you signed in with** when you last ran `alexa-mcp auth`. It does not use the Echo’s current profile. Changing the Echo’s profile in the Alexa app does **not** change which account the CLI uses.
78
+ - **When you use profiles (e.g. Rob vs Emma):** You must run the CLI as the **same account that owns the smart home device**. So:
79
+ 1. Run `alexa-mcp auth logout`.
80
+ 2. Run `alexa-mcp auth` and sign in as the **household member who can say “Alexa, turn off Lounge Lamp”** on that Echo and have it work (the account that “owns” the lamp in the Alexa app).
81
+ 3. Then run `alexa-mcp switch "Lounge Lamp" off -d "Lounge Echo"` again.
82
+ - **Single account:** If there’s only one account, ensure the lamp is linked to that account in the Alexa app (Devices → Lights/Plugs).
83
+
84
+ ### Seeing which profile owns devices
85
+
86
+ Each Echo and smart home device has a **deviceOwnerCustomerId** (Amazon’s internal account ID). The CLI uses the account you signed in with; that account has one or more such IDs. To see who owns what:
87
+
88
+ - **Echo devices:**
89
+ `alexa-mcp devices --owners`
90
+ Prints each device name and its `deviceOwnerCustomerId`. Use the same account for `alexa-mcp auth` as the one that owns the Echo you’re targeting.
91
+
92
+ - **Smart home appliances:**
93
+ `alexa-mcp appliances`
94
+ The JSON includes `deviceOwnerCustomerId` per device (when the API provides it). Match this to the account you use for auth.
95
+
96
+ - **Which account the CLI is using:**
97
+ `alexa-mcp auth status --verify`
98
+ Shows “Account (deviceOwnerCustomerId): …” for the current session. Control will work when this matches the owner of the Echo and the smart home device.
99
+
100
+ ## MCP Server
101
+
102
+ **Cursor** (`~/.cursor/mcp.json`) or **VS Code** (`.vscode/mcp.json`):
103
+
104
+ ```json
105
+ {
106
+ "mcpServers": {
107
+ "alexa": {
108
+ "command": "node",
109
+ "args": ["/path/to/alexa-mcp/dist/index.js"]
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ **Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "alexa": {
121
+ "command": "node",
122
+ "args": ["/path/to/alexa-mcp/dist/index.js"]
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ **With environment variable token** (no file-based config needed):
129
+
130
+ ```json
131
+ {
132
+ "mcpServers": {
133
+ "alexa": {
134
+ "command": "node",
135
+ "args": ["/path/to/alexa-mcp/dist/index.js"],
136
+ "env": {
137
+ "ALEXA_REFRESH_TOKEN": "Atnr|...",
138
+ "ALEXA_DOMAIN": "amazon.co.uk"
139
+ }
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ When installed locally, use the path to `node_modules/@m0nkmaster/alexa-mcp/dist/index.js`. When installed globally (`npm install -g @m0nkmaster/alexa-mcp`), use `npx @m0nkmaster/alexa-mcp` as the command instead of `node`:
146
+
147
+ ```json
148
+ {
149
+ "mcpServers": {
150
+ "alexa": {
151
+ "command": "npx",
152
+ "args": ["@m0nkmaster/alexa-mcp"]
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### MCP Tools
159
+
160
+ | Tool | Description |
161
+ |------|-------------|
162
+ | `alexa_list_devices` | List Echo devices |
163
+ | `alexa_speak` | TTS on a device |
164
+ | `alexa_announce` | Announce to all |
165
+ | `alexa_command` | Voice command (no response returned; prefer direct control for smart home) |
166
+ | `alexa_list_appliances` | List smart home devices (endpointId + friendlyName when available) |
167
+ | `alexa_control_appliance` | turnOn/turnOff/setBrightness by entity/endpoint ID |
168
+ | `alexa_control_by_group` | Turn on/off lights in a room group (e.g. "Kitchen") — **for "all lights in group X"** |
169
+ | `alexa_control_group` | Alias for `alexa_control_by_group`; also supports `lightsOnly` toggle |
170
+ | `alexa_control_by_pattern` | Turn on/off devices matching name pattern (e.g. "kitchen lights") |
171
+ | `alexa_switch_by_name` | Turn single device on/off by friendly name |
172
+ | `alexa_list_device_groups` | List room groups (Living room, Kitchen, etc.) |
173
+ | `alexa_list_audio_groups` | List multi-room audio groups |
174
+ | `alexa_list_routines` | List routines |
175
+ | `alexa_run_routine` | Run a routine by automation ID |
176
+ | `alexa_now_playing` | Now-playing state for a device (includes `taskSessionId`) |
177
+ | `alexa_media_control` | play, pause, resume, stop, next, previous (EU/UK) |
178
+ | `alexa_auth_status` | Check auth status (configured/valid/deviceCount) |
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ npm install
184
+ npm run build
185
+ npm test
186
+ npm run test:integration # Requires ALEXA_REFRESH_TOKEN
187
+ ```
188
+
189
+ ## API Reference
190
+
191
+ The single authoritative API reference is **[docs/API.md](docs/API.md)** — region base URLs, authentication, all endpoints (devices, routines, smart home, behaviors, alarms, media), request/response bodies, and headers.
192
+
193
+ **API usage:** All supported regions use the **app API** (eu-api-alexa for UK/EU, na-api-alexa for US): devices-v2, routinesandgroups, behaviors/preview, smarthome/v2/endpoints, layouts, and GraphQL for smart home control.
@@ -0,0 +1,7 @@
1
+ import type { Domain } from "./config.js";
2
+ export interface AuthFlowResult {
3
+ refreshToken: string;
4
+ domain: string;
5
+ }
6
+ export declare function runBrowserAuth(domain?: Domain): Promise<AuthFlowResult>;
7
+ //# sourceMappingURL=auth-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-flow.d.ts","sourceRoot":"","sources":["../src/auth-flow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAW1C,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAuB,GAAG,OAAO,CAAC,cAAc,CAAC,CA+D7F"}
@@ -0,0 +1,67 @@
1
+ import { createServer } from "node:http";
2
+ import { startTunnel } from "./tunnel.js";
3
+ const PROXY_PORT = 8080;
4
+ const LOCALE_MAP = {
5
+ "amazon.co.uk": { amazonPageProxyLanguage: "en_GB", acceptLanguage: "en-GB" },
6
+ "amazon.com": { amazonPageProxyLanguage: "en_US", acceptLanguage: "en-US" },
7
+ "amazon.de": { amazonPageProxyLanguage: "de_DE", acceptLanguage: "de-DE" },
8
+ };
9
+ export async function runBrowserAuth(domain = "amazon.co.uk") {
10
+ const locale = LOCALE_MAP[domain] ?? LOCALE_MAP["amazon.co.uk"];
11
+ const baseAmazonPage = domain === "amazon.co.jp" ? "amazon.co.jp" : "amazon.com";
12
+ let tunnel = null;
13
+ let proxyOwnIp = "127.0.0.1";
14
+ let proxyPort = PROXY_PORT;
15
+ const placeholder = createServer((_, res) => {
16
+ res.writeHead(200);
17
+ res.end("Starting...");
18
+ });
19
+ placeholder.listen(PROXY_PORT, "127.0.0.1", () => { });
20
+ try {
21
+ tunnel = await startTunnel(PROXY_PORT);
22
+ if (tunnel) {
23
+ proxyOwnIp = tunnel.host;
24
+ }
25
+ }
26
+ finally {
27
+ placeholder.close();
28
+ await new Promise((r) => setTimeout(r, 500));
29
+ }
30
+ const alexaCookie = (await import("alexa-cookie2")).default;
31
+ const opts = {
32
+ amazonPage: domain,
33
+ baseAmazonPage,
34
+ proxyOnly: true,
35
+ setupProxy: true,
36
+ proxyOwnIp,
37
+ proxyPort: PROXY_PORT,
38
+ proxyListenBind: "127.0.0.1",
39
+ proxyLogLevel: "warn",
40
+ amazonPageProxyLanguage: locale.amazonPageProxyLanguage,
41
+ acceptLanguage: locale.acceptLanguage,
42
+ deviceAppName: "alexa-mcp",
43
+ ...(tunnel ? { proxyTunnelUrl: tunnel.url } : {}),
44
+ };
45
+ return new Promise((resolve, reject) => {
46
+ const url = tunnel ? tunnel.url : `http://127.0.0.1:${PROXY_PORT}`;
47
+ console.error(`Visit this URL to log in: ${url}\n`);
48
+ alexaCookie.generateAlexaCookie(opts, (err, result) => {
49
+ if (err && err.message.includes("Please open")) {
50
+ return; // Proxy is ready; keep running, callback will fire again on success
51
+ }
52
+ tunnel?.close();
53
+ alexaCookie.stopProxyServer?.();
54
+ if (err) {
55
+ reject(err);
56
+ return;
57
+ }
58
+ const token = result?.refreshToken;
59
+ if (!token) {
60
+ reject(new Error("No refresh token in result"));
61
+ return;
62
+ }
63
+ resolve({ refreshToken: token, domain });
64
+ });
65
+ });
66
+ }
67
+ //# sourceMappingURL=auth-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-flow.js","sourceRoot":"","sources":["../src/auth-flow.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { type Domain } from "./config.js";
2
+ export interface AlexaCredentials {
3
+ cookies: string;
4
+ csrf: string;
5
+ }
6
+ export interface AuthOptions {
7
+ refreshToken: string;
8
+ domain?: Domain;
9
+ }
10
+ export declare function loadRefreshToken(prefer?: string): string | null;
11
+ export declare function loadDomain(): Domain;
12
+ export declare function authenticate(options: AuthOptions): Promise<AlexaCredentials>;
13
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiElF"}
package/dist/auth.js ADDED
@@ -0,0 +1,70 @@
1
+ import { getConfig } from "./config.js";
2
+ import { loadConfig } from "./config-store.js";
3
+ import { fetch } from "undici";
4
+ export function loadRefreshToken(prefer) {
5
+ if (prefer)
6
+ return prefer;
7
+ const cfg = loadConfig();
8
+ return cfg?.refreshToken ?? null;
9
+ }
10
+ export function loadDomain() {
11
+ const cfg = loadConfig();
12
+ return (cfg?.domain ?? "amazon.co.uk");
13
+ }
14
+ export async function authenticate(options) {
15
+ const { refreshToken, domain = "amazon.co.uk" } = options;
16
+ const config = getConfig(domain);
17
+ const cookieDomain = `.${config.domain}`;
18
+ const tokenRes = await fetch("https://api.amazon.com/ap/exchangetoken/cookies", {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/x-www-form-urlencoded",
22
+ "x-amzn-identity-auth-domain": `api.${config.domain}`,
23
+ },
24
+ body: new URLSearchParams({
25
+ app_name: "Amazon Alexa",
26
+ requested_token_type: "auth_cookies",
27
+ source_token_type: "refresh_token",
28
+ source_token: refreshToken,
29
+ domain: cookieDomain,
30
+ }),
31
+ });
32
+ if (!tokenRes.ok) {
33
+ const text = await tokenRes.text();
34
+ throw new Error(`Token exchange failed: ${tokenRes.status} ${text}`);
35
+ }
36
+ const tokenData = (await tokenRes.json());
37
+ const cookieList = tokenData.response?.tokens?.cookies?.[cookieDomain];
38
+ if (!cookieList?.length) {
39
+ throw new Error("No cookies in token response");
40
+ }
41
+ const cookieParts = cookieList.map((c) => {
42
+ let v = c.Value;
43
+ if (v.startsWith('"') && v.endsWith('"'))
44
+ v = v.slice(1, -1);
45
+ return `${c.Name}=${v}`;
46
+ });
47
+ const cookieString = cookieParts.join("; ");
48
+ const csrfRes = await fetch(`${config.alexaBase}/api/language`, {
49
+ headers: {
50
+ Cookie: cookieString,
51
+ Accept: "application/json",
52
+ },
53
+ });
54
+ if (!csrfRes.ok) {
55
+ throw new Error(`CSRF fetch failed: ${csrfRes.status}`);
56
+ }
57
+ const setCookie = csrfRes.headers.get("set-cookie");
58
+ let csrf = "";
59
+ if (setCookie) {
60
+ const match = setCookie.match(/csrf=([^;]+)/);
61
+ if (match)
62
+ csrf = match[1];
63
+ }
64
+ if (!csrf) {
65
+ throw new Error("Could not extract CSRF token");
66
+ }
67
+ const fullCookie = `${cookieString}; csrf=${csrf}`;
68
+ return { cookies: fullCookie, csrf };
69
+ }
70
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}