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
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues