Provides read-only access to Vivint home security systems, enabling monitoring of system armed states, security sensors, cameras, smart locks, thermostats, recent events, and device health status through eight comprehensive tools.
Vivint Security System MCP Server
A FastMCP server that exposes read-only access to your Vivint home security system over the Model Context Protocol (MCP) via Streamable HTTP at the /mcp endpoint.
Important: This integration uses an unofficial, reverse‑engineered API (vivintpy). Vivint has no official public API. Use at your own risk and review your Terms of Service.
Features
Eight read-only tools are exposed to MCP clients:
get_system_status — Overall system armed state and metadata
get_all_devices — Complete device inventory
get_security_sensors — Motion/door/window/smoke/CO/flood sensors
get_cameras — Camera status and capabilities
get_locks — Smart lock states and battery level
get_thermostats — Climate data and setpoints
get_recent_events — Recent activity snapshots
get_device_health — Battery/online/attention summaries
Endpoint base path: /mcp (clients must include this path).
Prerequisites
Python 3.13+
A Vivint account (recommend a dedicated, least‑privilege user)
Node.js (for MCP Inspector via npx)
Optional: Cloudflared (to expose your local server)
macOS, Linux, or Windows. Commands below use macOS/zsh patterns.
Quick start (local)
Clone and enter the project
Create an environment and install dependencies
Option A: venv
Option B: conda
Configure environment
Enable authentication (recommended)
Generate a strong HMAC secret and add it to .env:
Generate a short‑lived JWT for local testing:
Start the server
Test with MCP Inspector
Then connect with:
Transport: Streamable HTTP
If AUTH_ENABLED=true: add the header Authorization: Bearer <your_jwt>
Example .env
Copy/paste and edit values as needed. Do not commit this file.
Notes:
The server binds to HOST and PORT (defaults provided). For containers, bind‑all is recommended; for strict local, use a loopback address. The default HOST in code is redacted (*******).
All URLs must include the /mcp base path.
Authentication options
JWT (HMAC, HS256) — recommended for single‑user/local
Generate secret: python src/generate_token.py --type secret
Configure .env: AUTH_ENABLED=true, AUTH_TYPE=jwt, JWT_ALGORITHM=HS256, AUTH_SECRET=...
Create token: python src/generate_token.py --type token --hours 24 --subject local-dev
Verify token: python src/generate_token.py --verify ""
Use with Inspector: Authorization: Bearer
JWT (RSA, RS256) — multi‑client
Generate keys: python src/generate_token.py --type keypair
Configure .env: JWT_PRIVATE_KEY, JWT_PUBLIC_KEY, JWT_ALGORITHM=RS256
Generate tokens with the private key (same script) and verify with the public key.
OAuth 2.0 — optional
Generate a client: python src/generate_oauth_credentials.py
Ensure OAUTH_REDIRECT_URIS includes https://claude.ai/api/mcp/auth_callback (for Claude) and any local callbacks.
Start the server and complete the flow using the server’s OAuth endpoints. In production, consider setting OAUTH_DISABLE_NEW_CLIENTS=true.
Disable auth (development only)
Warning: Do not disable authentication if your server is reachable from the internet.
2FA/MFA setup and token persistence
Interactive (recommended)
What it does:
Prompts for a fresh 6‑digit code when required
Saves refresh tokens to VIVINT_REFRESH_TOKEN_FILE (default: .vivint_tokens.json)
Validates the connection
Non‑interactive (one‑off)
Validation
Token file security: treat .vivint_tokens.json as a secret and restrict permissions (chmod 600).
Running and debugging
Start:
Explicit host/port:
Verbose logs:
Debug endpoint (when available): /debug/oauth requires DEBUG_MODE=true.
Testing with MCP Inspector
Launch: npx @modelcontextprotocol/inspector
Transport: Streamable HTTP
If auth enabled: add Authorization: Bearer
Try tools: get_system_status, get_all_devices, get_device_health
Cloudflare tunnel (optional)
If you want to test over the internet without opening ports:
Helper scripts in repo:
OAuth redirect URIs can be updated automatically:
Manual alternative:
Deploying to Render
Use the button above or set up a Web Service that runs:
Build: pip install -r requirements.txt
Start: python src/server.py
Environment variables (minimum):
ENVIRONMENT=production
AUTH_ENABLED=true
AUTH_TYPE=jwt (or oauth)
For JWT HS: AUTH_SECRET=, JWT_ALGORITHM=HS256
For JWT RS: JWT_PRIVATE_KEY, JWT_PUBLIC_KEY, JWT_ALGORITHM=RS256
VIVINT_USERNAME, VIVINT_PASSWORD
Optional: VIVINT_SYSTEM_ID, LOG_LEVEL=WARNING/ERROR
Your endpoint will be: https://.onrender.com/mcp
Tool reference
get_system_status() → { armed, arm_state, is_disarmed, is_armed_stay, is_armed_away, system_id, panel_id, panel_name, timestamp, ... }
get_all_devices() → [ { id, name, type, panel_id, system_id, state, is_online, battery_level, last_update_time, ... } ]
get_security_sensors() → [ { id, name, sensor_type, triggered, bypassed, zone_id, ... } ]
get_cameras() → [ { id, name, resolution, night_vision, motion_detection, rtsp_available, ... } ]
get_locks() → [ { id, name, locked, tamper_status, battery_level, last_operated_at, ... } ]
get_thermostats() → [ { id, name, current_temperature, target_temperature, heat_setpoint, cool_setpoint, mode, ... } ]
get_recent_events(hours=24) → [ { id, type, description, timestamp, device_id, device_name } ]
get_device_health() → { total_devices, online_devices, offline_devices, low_battery_devices, devices_needing_attention, ... }
Return fields are best‑effort and depend on your account/devices; errors are returned as { error, timestamp }.
Architecture
Core files
src/server.py — FastMCP app, auth setup (JWT/OAuth), tool registration, HTTP transport on /mcp
src/vivint_client.py — vivintpy wrapper, session lifecycle, MFA handling
src/token_manager.py — secure token persistence and validation
src/config.py — environment variable parsing and validation
setup_mfa.py, test_mfa.py — interactive MFA onboarding and validation
start_tunnel.sh, tunnel_status.sh, stop_tunnel.sh — Cloudflared helpers
render.yaml — Render deployment config
Session notes
Sessions are refreshed periodically; tokens auto‑refresh ~5–6 hours
Device and state shapes come from vivintpy and can change upstream
Troubleshooting
Authentication
“AUTH_SECRET is required” → Add AUTH_SECRET for HS* or JWT_PUBLIC_KEY for RS*
“MFA required” → export VIVINT_MFA_CODE or run setup_mfa.py
OAuth redirect mismatch → Ensure the exact URL is in OAUTH_REDIRECT_URIS, restart server
Connectivity
Inspector can’t connect → Server running? Port correct? URL includes /mcp?
Render 502 → Ensure HOST/PORT are correct for container; ENVIRONMENT=production
Devices
No devices → Confirm account/system access; set VIVINT_SYSTEM_ID when multiple systems exist
Rate limits
Login locked → Adjust RATE_LIMIT_* or wait for lockout to expire
Debugging
DEBUG_MODE=true LOG_LEVEL=DEBUG for verbose logs
/debug/oauth (if enabled) inspects OAuth configuration
Security
Keep AUTH_ENABLED=true in production
Rotate AUTH_SECRET/keys regularly
Use a dedicated Vivint user
Do not commit .env or token files; treat .vivint_tokens.json as a secret (chmod 600)
Keep DEBUG_MODE=false in production
Be mindful that vivintpy is unofficial and may break without notice
Limitations & disclaimers
Unofficial API usage via vivintpy (no guarantees; subject to breakage)
Read‑only access only; no device control
May violate provider terms — proceed responsibly
License
MIT — see LICENSE.
This project is not affiliated with or endorsed by Vivint.
This server cannot be installed
hybrid server
The server is able to function both locally and remotely, depending on the configuration or use case.
Provides read-only access to Vivint home security systems through an unofficial API. Enables monitoring of system status, devices, sensors, cameras, locks, thermostats, and recent events through natural language.