Skip to main content
Glama
jgonzalez007

kwikset-mcp

by jgonzalez007
README.md
# kwikset-mcp

An MCP server that lets Claude check and control Kwikset Halo-family smart
locks (Halo, Halo Keypad, Halo Touch, Halo Select / Select Plus).

It's a thin wrapper around [`aiokwikset`](https://github.com/explosivo22/aiokwikset),
the community-maintained Python client for Kwikset's cloud API — the same
one used by the [Home Assistant Kwikset integration](https://github.com/explosivo22/kwikset-ha).

**Important:** Kwikset does not publish or officially support this API.
`aiokwikset` reverse-engineers it, so it can break if Kwikset changes
something server-side. This server includes a `debug_api_surface` tool and
defensive lookups specifically to make that kind of breakage easy to
diagnose and patch rather than a silent hard failure.

**This has not been tested end-to-end against a real account or lock** —
it was built from `aiokwikset`'s published documentation and the Home
Assistant integration's source, without access to Kwikset credentials or
a physical lock. Run through the steps below and treat the first `lock`/
`unlock` call as a smoke test; if anything throws an `api_mismatch` error,
paste it (and the `debug_api_surface` output) back to Claude to get the
one or two mismatched method names fixed.

## Why login is a separate step

Your Kwikset password should never pass through an LLM conversation. So
authentication happens once, in a plain terminal, via `auth_setup.py`,
which saves only the resulting session tokens locally (never the
password). The MCP server reads and silently refreshes those tokens —
it never asks Claude, or you via Claude, for your password.

## Setup

1. **Install dependencies** (Python 3.10+):

   ```bash
   cd kwikset-mcp
   python3 -m venv .venv
   ```

   Activate the virtual environment — the command depends on your shell:

   ```bash
   # macOS / Linux (bash or zsh)
   source .venv/bin/activate
   ```

   ```powershell
   # Windows PowerShell
   .venv\Scripts\Activate.ps1
   ```

   ```cmd
   :: Windows Command Prompt (cmd.exe)
   .venv\Scripts\activate.bat
   ```

   You'll know it worked when your prompt gets a `(.venv)` prefix. If
   PowerShell refuses to run the script ("running scripts is disabled on
   this system"), run `Set-ExecutionPolicy -Scope Process -ExecutionPolicy
   Bypass` first, then retry the activation command.

   Then, with the venv active:

   ```bash
   pip install -e .
   ```

2. **Log in once.** Credentials can be given three ways, checked in this
   order:

   ```bash
   # 1. Command-line flags (any OS/shell)
   python auth_setup.py --email you@example.com --password 'hunter2'

   # 3. Interactive prompt (any OS/shell; default if nothing else is given)
   python auth_setup.py
   ```

   Option 2, setting environment variables first, is preferred over the
   `--password` flag above (a command-line password is visible to other
   processes via `ps aux`/Task Manager and lands in shell history) — but
   the syntax is shell-specific:

   ```bash
   # macOS / Linux (bash or zsh)
   KWIKSET_EMAIL=you@example.com KWIKSET_PASSWORD='hunter2' python auth_setup.py
   ```

   ```powershell
   # Windows PowerShell
   $env:KWIKSET_EMAIL = "you@example.com"
   $env:KWIKSET_PASSWORD = "hunter2"
   python auth_setup.py
   ```

   If your account has MFA enabled you'll be prompted for the code (or
   pass one up front with `--mfa-code` / `$KWIKSET_MFA_CODE`). Either way
   this writes `~/.kwikset-mcp/tokens.json` (owner-read/write only) and
   never touches your password again after this step — the MCP server
   only ever reads and refreshes the saved token.

3. **Point Claude at the server.**

   For **Claude Code**, from this project directory:

   ```bash
   # macOS / Linux
   claude mcp add kwikset -- "$(pwd)/.venv/bin/python" -m kwikset_mcp.server
   ```

   ```powershell
   # Windows PowerShell
   claude mcp add kwikset -- "$PWD\.venv\Scripts\python.exe" -m kwikset_mcp.server
   ```

   For **Claude Desktop**, add this to your `claude_desktop_config.json`
   (Settings → Developer → Edit Config), substituting the absolute path to
   this directory's `.venv`:

   ```json
   {
     "mcpServers": {
       "kwikset": {
         "command": "/absolute/path/to/kwikset-mcp/.venv/bin/python",
         "args": ["-m", "kwikset_mcp.server"]
       }
     }
   }
   ```

   On Windows, `command` should point at
   `C:\\absolute\\path\\to\\kwikset-mcp\\.venv\\Scripts\\python.exe`
   (use double backslashes, since this is JSON).

   Then restart the Claude client so it picks up the new server.

4. **Try it.** Ask Claude something like "list my Kwikset locks" or "is the
   front door locked?" — it should call `list_locks` / `get_lock_status`.
   Unlocking requires an explicit ask, since `unlock_door` refuses to act
   unless called with `confirm=true`, which Claude will only do when
   you've clearly asked it to unlock that door.

## Tools exposed

| Tool | Description |
|---|---|
| `list_locks` | All locks on the account, with status, battery %, home |
| `get_lock_status(device_id)` | Status/battery/Wi-Fi for one lock |
| `lock_door(device_id)` | Lock a door |
| `unlock_door(device_id, confirm)` | Unlock a door (`confirm=true` required) |
| `debug_api_surface` | Diagnostic dump of the installed aiokwikset library's real method names |

## Re-authenticating

If tokens expire and can't silently refresh (e.g. the Kwikset password was
changed, or MFA was reset), tool calls will return an `auth_required`
error with instructions — just re-run `python auth_setup.py`.

## Files

```
kwikset-mcp/
├── auth_setup.py           # run once, by hand, to log in
├── src/kwikset_mcp/
│   ├── auth.py              # local token file read/write
│   ├── client.py            # aiokwikset wrapper (locks, status, etc.)
│   └── server.py            # FastMCP server + tool definitions
├── pyproject.toml
└── requirements.txt
```