alexa-mcp
# alexa-mcp
> A robust, TypeScript-based [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that lets Claude, Perplexity, and any other MCP-compatible LLM control Amazon Alexa devices: speak announcements, execute text voice commands, manage smart-home groups, run routines, query sensor states, and more.
[](./LICENSE)
[](https://nodejs.org)
[](https://www.typescriptlang.org/)
[](./test)
Built on top of [`alexa-remote2`](https://github.com/Apollon77/alexa-remote) (the actively maintained client for Amazon's Alexa API) with complete compile-time type safety, automated tests, and dual-transport architecture (Stdio + Streamable HTTP / SSE).
---
## Architecture & Transports
`alexa-mcp` offers two flexible transport modes:
```
┌────────────────────────────────────────────────────────────────────────┐
│ Clients │
│ Claude Desktop │ Claude Code │ Antigravity IDE │ Perplexity │ Web UIs │
└────────────────────────────────────┬───────────────────────────────────┘
│
┌────────────────────────┴────────────────────────┐
│ │
[1] Stdio Transport (Local) [2] HTTP / SSE Transport
node dist/index.js (or src/index.js) node dist/server.js
• Standard input/output pipe • Streamable HTTP (POST /mcp)
• Opens no network ports • Legacy SSE (GET /sse)
• Ideal for desktop assistants • CORS-enabled for web/remote
│ │
└────────────────────────┬────────────────────────┘
▼
┌───────────────────────────────┐
│ AlexaClient │
│ • Session token cache │
│ • Atomic 0600/0700 storage │
│ • Amazon Alexa REST & Push │
└───────────────┬───────────────┘
▼
┌───────────────────────────────┐
│ Amazon Alexa API │
│ Echoes • Smart Home • Rooms │
└───────────────────────────────┘
```
1. **Stdio Transport (`src/index.ts` / `dist/index.js` / `src/index.js`)**:
Standard input/output communication for local LLM clients (Claude Desktop, Claude Code, Antigravity IDE). Opens no network ports.
2. **Streamable HTTP & SSE Server (`src/server.ts` / `dist/server.js`)**:
High-performance Express server supporting the modern **MCP Streamable HTTP** specification (`POST /mcp` or `POST /`) as well as **Legacy SSE** (`GET /sse` with `POST /messages`). Includes CORS headers and session management, ideal for remote LLMs, Perplexity, Open WebUI, and Cloudflare Tunnels.
---
## Features (19 Tools)
Every tool is strictly typed with Zod schema validation and comprehensive error handling:
| Tool Name | Domain | Description | Key Arguments |
|---|---|---|---|
| `alexa_list_devices` | Echo Devices | List all Amazon Echo devices with serial numbers, model types, and online status | *None* |
| `alexa_set_volume` | Audio Control | Set device volume (0–100) | `serialNumber`, `volume` (0–100) |
| `alexa_get_volumes` | Audio Control | Read current volume levels across all Echo devices | *None* |
| `alexa_do_not_disturb` | Device Settings | Enable or disable Do Not Disturb mode | `serialNumber`, `enabled` (boolean) |
| `alexa_announce` | Voice & Audio | Push a spoken announcement with chime to an Echo | `serialNumber`, `message` |
| `alexa_text_command` | Voice Simulation | Send any voice command as text (*e.g.*, "turn on kitchen lights") | `serialNumber`, `command` |
| `alexa_speak` | Voice & Audio | Make Alexa speak plain text directly (no chime) | `serialNumber`, `text` |
| `alexa_speak_ssml` | Voice & Audio | Speak SSML markup with pauses, whispers, and emphasis | `serialNumber`, `ssml` |
| `alexa_list_smarthome_devices` | Smart Home | List paired smart-home entities (lights, plugs, thermostats, sensors) | *None* |
| `alexa_query_device` | Smart Home | Query real-time power, brightness, or sensor states | `entityIds` (string array) |
| `alexa_list_groups` | Smart Home Rooms | List configured smart-home groups/rooms and assigned appliances | *None* |
| `alexa_create_group` | Smart Home Rooms | Create a new room/group and assign appliance IDs | `name`, `applianceIds` |
| `alexa_update_group` | Smart Home Rooms | Update name and appliances in an existing room/group | `groupId`, `name`, `applianceIds` |
| `alexa_delete_group` | Smart Home Rooms | Remove a smart-home group/room | `groupId` |
| `alexa_list_routines` | Automations | List all routines, trigger phrases, and sequence actions | *None* |
| `alexa_execute_routine` | Automations | Trigger an existing automation routine | `routine` (routine object) |
| `alexa_list_lists` | Lists | List shopping, to-do, and custom lists | *None* |
| `alexa_get_list_items` | Lists | Retrieve all items from a specified list | `listId` |
| `alexa_add_list_item` | Lists | Append a new item to a shopping or to-do list | `listId`, `value` |
---
## Requirements
- **Node.js ≥ 18.0.0**
- An Amazon account with at least one registered Alexa/Echo device
- An MCP-compatible client (Claude Desktop, Claude Code, Antigravity IDE, Perplexity, etc.)
---
## Installation & Setup
```bash
# Clone repository
git clone https://github.com/James-Tucke-r/alexa-mcp.git
cd alexa-mcp
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run automated tests
npm test
```
---
## Authentication
Amazon's Alexa API is private and requires a browser-based login. The server includes an interactive authentication helper:
```bash
npm run auth
```
### What `npm run auth` does:
1. Starts a secure local HTTP proxy on `127.0.0.1:3457` (automatically opens your default browser on macOS).
2. You log in to your Amazon account securely. Handles 2FA / OTP seamlessly because it proxies Amazon's real authentication pages.
3. The proxy captures both the session cookies and the **device registration** (`macDms`) Amazon issues.
4. Credentials are automatically saved to `.auth-data/auth.json` with owner-only permissions (`0600`, directory `0700`).
You only need to run this once. `alexa-remote2` refreshes the token automatically during normal operation.
### Why manual cookie pasting is unsupported:
`alexa-remote2` gates initialization on `macDms` (device private key and ADP token) minted during browser registration. A raw session cookie lacks `macDms`, causing infinite initialization loops. The browser proxy is the only supported, reliable authentication mechanism.
### Multi-Account / Multi-Instance Setup
To serve multiple Alexa accounts from a single installation, point `ALEXA_MCP_AUTH_DIR` to a dedicated directory per instance:
```bash
# Authenticate personal account
ALEXA_MCP_AUTH_DIR=~/.alexa-mcp/personal npm run auth
# Authenticate work / second account
ALEXA_MCP_AUTH_DIR=~/.alexa-mcp/work npm run auth
```
Each instance maintains its own credentials in isolation.
---
## Client Configurations
### 1. Claude Desktop (Stdio)
Edit your Claude Desktop configuration:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"alexa": {
"command": "node",
"args": ["/absolute/path/to/alexa-mcp/dist/index.js"]
}
}
}
```
> **Backward Compatibility:** Existing configurations pointing to `/Users/jtucker/src/alexa-mcp/src/index.js` continue working seamlessly through the built-in forwarder shim.
### 2. Claude Code (CLI)
```bash
claude mcp add alexa -- node "$(pwd)/dist/index.js"
```
Verify connection:
```bash
claude mcp list
```
### 3. Streamable HTTP / SSE Server (Remote Clients & Web UIs)
Run the server:
```bash
# Production
npm run serve
# Development (hot reload)
npm run serve:dev
```
By default, the server listens on `0.0.0.0:8000` (configurable via `PORT` environment variable):
- **Streamable HTTP Endpoint (Recommended):** `http://localhost:8000/mcp` or `http://localhost:8000/`
- **Legacy SSE Endpoint:** `http://localhost:8000/sse` (messages at `POST /messages`)
Configure in remote MCP clients (*e.g.*, Perplexity, Open WebUI, LibreChat):
```json
{
"mcpServers": {
"alexa": {
"url": "http://localhost:8000/mcp"
}
}
}
```
---
## Environment Variables
| Variable | Default | Purpose |
|---|---|---|
| `ALEXA_MCP_AUTH_DIR` | `.auth-data/` | Path to store `auth.json` (supports `~/` expansion) |
| `ALEXA_AMAZON_PAGE` | `amazon.com` | Amazon marketplace host (*e.g.*, `amazon.co.uk`, `amazon.de`, `amazon.com.mx`) |
| `ALEXA_ACCEPT_LANGUAGE` | `en-US` | Preferred HTTP Accept-Language header (*e.g.*, `en-GB`, `de-DE`, `es-MX`) |
| `ALEXA_PROXY_LANGUAGE` | `en_US` | Proxy language parameter (*e.g.*, `en_GB`, `de_DE`, `es_MX`) |
| `ALEXA_PROXY_PORT` | `3457` | Local port used exclusively during `npm run auth` |
| `PORT` | `8000` | HTTP port used by `npm run serve` (Streamable HTTP / SSE) |
---
## Development & Scripts
| Command | Action |
|---|---|
| `npm run build` | Compiles TypeScript source to `dist/` with types and maps |
| `npm run watch` | Runs `tsc --watch` for incremental background compilation |
| `npm test` | Runs the full automated test suite (builds first) |
| `npm start` | Runs the compiled Stdio server (`node dist/index.js`) |
| `npm run dev` | Runs the Stdio server directly in TS via `tsx` |
| `npm run serve` | Starts the production HTTP/SSE server (`node dist/server.js`) |
| `npm run serve:dev` | Starts the HTTP/SSE server in TS via `tsx` |
| `npm run auth` | Starts the interactive browser proxy auth flow |
---
## Testing & Quality Assurance
`alexa-mcp` ships with a comprehensive test suite built on Node's native test runner (`node:test`) and `@modelcontextprotocol/sdk/inMemory.js`:
```bash
npm test
```
### Test Coverage (19 Tests across 4 Suites):
1. **`test/tools.test.ts`**:
- In-memory MCP client/server integration.
- Verifies registration, schemas, and descriptions for all 19 tools.
- Tests mock execution of every device, routine, smart home, audio, and list tool.
- Verifies Zod input validation (e.g. volume out-of-bounds rejection).
- Tests error handling when the upstream Alexa API fails.
2. **`test/stdio-transport.test.ts`**:
- Spawns subprocesses over actual stdin/stdout pipes.
- Tests MCP `initialize` and `tools/list` handshakes on `src/index.js` (backward-compat shim).
- Tests MCP handshakes on `dist/index.js` (compiled binary).
- Verifies JSON-RPC error codes on unrecognized methods (`-32601`).
3. **`test/server-transport.test.ts`**:
- Express server lifecycle and ephemeral port binding.
- Tests CORS headers (`Access-Control-Allow-Origin: *`, `mcp-session-id`).
- Tests Streamable HTTP `POST /mcp` stateful sessions.
- Tests SSE `GET /sse` streams.
- Tests automatic `Accept` header normalization (`application/json, text/event-stream`).
4. **`test/auth-storage.test.ts`**:
- Atomic file write verification (temp file -> sync -> atomic rename).
- File permission verification (`0600` for `auth.json`, `0700` for directory).
- Automatic tightening of insecure directory permissions.
- Rejection of corrupt or missing device registrations (`macDms`).
See [docs/TESTING.md](./docs/TESTING.md) for deep-dive testing documentation.
---
## Security Model
- **Atomic File Writing**: Credentials in `.auth-data/auth.json` are written to a unique temporary file opened with `O_CREAT | O_EXCL` at mode `0600`, flushed to disk via `fsync`, and atomically replaced via `rename`. No partial files, race conditions, or unencrypted leaks.
- **Directory Hardening**: Auth directories are verified at mode `0700` and tightened immediately if found looser.
- **Local Proxy Binding**: `npm run auth` binds strictly to `127.0.0.1`, never exposing authentication cookies to external network interfaces.
- **Git Safety**: `.auth-data/`, cookies, and tokens are permanently ignored in `.gitignore`.
- **Dependency Pinning**: Enforces `alexa-cookie2 >= 5.0.4` to avoid Amazon `400 InvalidToken` refresh regressions.
---
## Project Structure
```
alexa-mcp/
├── src/
│ ├── index.ts # MCP Stdio server entrypoint & factory
│ ├── index.js # Backward-compatibility shim (forwards to dist/)
│ ├── alexa-client.ts # Typed wrapper around alexa-remote2 with atomic auth
│ ├── tools.ts # 19 MCP tool registrations with Zod schemas
│ ├── server.ts # Streamable HTTP & SSE Express server
│ ├── auth.ts # Interactive proxy login flow
│ └── types/
│ └── alexa.ts # Domain interfaces (AuthData, Devices, Groups, etc.)
├── dist/ # Compiled JavaScript, TypeScript declarations & maps
├── test/
│ ├── tools.test.ts # In-memory tests for all 19 tools & schemas
│ ├── stdio-transport.test.ts # Subprocess stdio JSON-RPC handshake tests
│ ├── server-transport.test.ts # Express Streamable HTTP & SSE transport tests
│ └── auth-storage.test.ts # File mode (0600/0700) & atomic write security tests
├── docs/
│ ├── ARCHITECTURE.md # Architectural deep dive & protocol mechanics
│ └── TESTING.md # Comprehensive test strategy & execution guide
├── .auth-data/ # Git-ignored local credentials store (mode 0700)
│ └── auth.json # Session cookies & device registration (mode 0600)
├── CHANGELOG.md # Detailed release and migration history
├── package.json # Package manifest & build scripts
├── tsconfig.json # TypeScript compiler configuration (ES2022/NodeNext)
├── LICENSE # MIT License
└── README.md # Project documentation
```
---
## Acknowledgments
- **Renato Ascencio** for authoring the original `alexa-mcp` project.
- **Apollon77** for maintaining [`alexa-remote2`](https://github.com/Apollon77/alexa-remote), which powers communication with Amazon's private Alexa endpoints.
- The **Model Context Protocol** team at Anthropic.
---
## License
[MIT](./LICENSE) © Renato Ascencio, James Tucker
TDQS
Scored across 19 tools
Tools mostly target distinct resources/actions; however the three speaking tools (alexa_announce, alexa_speak, alexa_speak_ssml) plus alexa_text_command create some overlap in output modality. Descriptions clarify differences (chime vs TTS vs SSML vs simulated command), so an agent can usually distinguish them, but confusion is possible.
All tools use the alexa_ snake_case prefix and typically follow verb_noun (list_devices, set_volume, create_group). Minor deviations (alexa_announce, alexa_text_command, alexa_do_not_disturb) are still readable and consistent enough.
19 tools is slightly above the ideal 3-15 range, but the breadth of Alexa's domain (devices, smart home, groups, routines, lists, TTS, DND) justifies most tools. No excessive redundancy, though some consolidation could be possible.
Core workflows for announcements, routines, volume, groups, and querying are covered, but list management lacks update/delete/remove-item operations, and there is no direct set-device-state tool for smart home control (only natural-language alexa_text_command). These are notable gaps an agent must work around.