etxahun/ttlock-mcp
If you are the rightful owner of ttlock-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
The TTLock MCP server facilitates access and management of TTLock data through MCP-compatible clients, supporting OAuth, lock management, IC card operations, and unlock record retrieval.
🔒 TTLock MCP
An MCP (Model Context Protocol) server to access and manage TTLock data from MCP-compatible clients (VS Code, MCP Inspector, etc.).
It supports OAuth, lock management, IC card operations (add/delete/list, bulk), and reading unlock records.
📁 Table of Contents
- Architecture & Repository Layout
- Requirements
- Installation
- Configuration
- NPM Scripts
- Run & Test
- Tools Catalog (MCP)
- TTLock Integration Notes
- Troubleshooting
- Security & Best Practices
- Roadmap
- License
🏗️ Architecture & Repository Layout
ttlock-mcp/
├─ src/
│ ├─ env.ts # Loads/validates environment variables (.env) with zod
│ ├─ server.ts # MCP server (STDIO) + tool definitions (with auth guard)
│ └─ ttlock.ts # TTLock HTTP client (OAuth + v3 endpoints)
├─ dist/ # Compiled output (tsc)
├─ .vscode/
│ └─ mcp.json # VS Code config to launch the MCP server
├─ .env # Local environment variables (DO NOT commit)
├─ package.json
├─ tsconfig.json
└─ README.md # This document
Tech highlights
- Node.js 20+ with ESM (
moduleResolution: "NodeNext") - TypeScript
- @modelcontextprotocol/sdk (STDIO server)
- axios, qs, zod, dotenv
- (optional) dotenv-cli to load
.envfor the Inspector command
NodeNext/ESM note: use
.jsextension in relative imports even in.tsfiles
(e.g.import { Env } from './env.js').
📋 Requirements
- Node.js >= 20
- TTLock Cloud credentials:
clientId,clientSecret - A TTLock gateway online for remote operations (unlock/lock and IC card add/delete)
🛠️ Installation
# 1) Install deps
npm install
# 2) (optional) Convenient for Inspector to auto-load .env
npm i -D dotenv-cli
# 3) Build once
npm run build
⚙️ Configuration
🔐 .env
Create a .env file at the repo root:
TTLOCK_CLIENT_ID=xxxxxxxx
TTLOCK_CLIENT_SECRET=xxxxxxxx
TTLOCK_API_BASE=https://api.sciener.com
MCP_SERVER_NAME=ttlock-mcp
# Optional: auto-login on first use
TTLOCK_USERNAME=your_ttat_account_or_email
TTLOCK_PASSWORD_MD5=32_char_lowercase_md5_of_your_password
Get MD5 on Linux:
echo -n 'your_password' | md5sum | awk '{print $1}'
💻 VS Code (.vscode/mcp.json)
Recommended workspace configuration:
{
"servers": {
"ttlock-mcp": {
"type": "stdio",
"command": "node",
"args": ["${workspaceFolder}/dist/server.js"],
"envFile": "${workspaceFolder}/.env"
}
}
}
This lets VS Code start the server and load your .env automatically.
📜 NPM Scripts
{
"scripts": {
"build": "tsc",
"start": "node dist/server.js",
"watch": "tsc -w",
"inspect": "dotenv -e .env -- npx @modelcontextprotocol/inspector node dist/server.js"
}
}
If you don’t use
dotenv-cli, pass your variables via the Inspector UI or your shell environment.
🧪 Run & Test
🔍 MCP Inspector
npm run build
npm run inspect
Inspector UI settings:
- Transport Type:
STDIO - Command:
node - Arguments:
dist/server.js
Quick tests:
- ping
{ "text": "hello" } - auth.login (if you didn’t configure auto-login):
{ "username": "YOUR_EMAIL", "passwordMd5": "32_char_lowercase_md5" } - locks.list
{ "pageNo": 1, "pageSize": 50 }
💻 VS Code
- Open the project (WSL or local) with
code .. - With the
mcp.jsonabove, open the Chat view (Copilot).
The ttlock-mcp server appears and tools are available. - Invoke tools directly (e.g., select
locks.listor type#locks.list).
🧪 Tools Catalog (MCP)
All handlers return
CallToolResult({ content: [{ type: "text", text }] }).
Tools marked with 🔒 require authentication (auto-login ifTTLOCK_USERNAMEandTTLOCK_PASSWORD_MD5are present in.env).
🔑 Auth
auth.login{ username: string, passwordMd5: string }auth.refresh{}
🔒 Locks
- 🔒
locks.list{ pageNo?: number=1, pageSize?: number=50 } - 🔒
locks.detail{ lockId: number } - 🔒
locks.unlock{ lockId: number }(requires gateway online) - 🔒
locks.lock{ lockId: number }(requires gateway online)
🪪 IC Cards
- 🔒
cards.list{ lockId: number, pageNo?: number=1, pageSize?: number=50 } - 🔒
cards.add{ lockId: number, cardNumber: string, cardName?: string, startDate?: ms, endDate?: ms }
IfstartDate/endDateare omitted (or0), the card is permanent. - 🔒
cards.bulkAdd
{ lockId: number, cards: Array<{cardNumber, cardName?, startDate?, endDate?}>, delayMs?: 0–5000, continueOnError?: boolean } - 🔒
cards.delete{ lockId: number, cardId: number, deleteType?: 1|2|3=2 } - 🔒
cards.bulkDelete{ lockId: number, cardIds: number[], deleteType?: 1|2|3=2, delayMs?: 0–5000, continueOnError?: boolean } - 🔒
cards.clear{ lockId: number, confirm?: boolean=false }
⚠️ Deletes all cards on the lock.
cardId vs cardNumber: deleting requires
cardId(fetch it viacards.list).
deleteType:2= Gateway (remote) is most useful;1= BLE;3= NB-IoT (if applicable).
📋 Unlock Records (Access Logs)
- 🔒
records.list
{ lockId: number, pageNo?: number=1, pageSize?: number=50, startDate?: ms, endDate?: ms }
Time format: startDate/endDate are epoch milliseconds (UTC).
Example (Madrid CEST, today 06:00–10:00): startDate=1756699200000, endDate=1756713600000.
🔗 TTLock Integration Notes
- OAuth: login uses
username+passwordMd5(32 chars, lowercase). dateparameter (v3 APIs): each call sendsdate = Date.now(). TTLock servers accept roughly ±5 minutes.
If you seedate must be current time, in 5 minutes, sync your system clock (NTP).
The client also supports a retry with server time offset (from HTTPDateheader) to mitigate small drifts.- Gateway: remote operations (unlock/lock, add/delete card) need a compatible gateway online.
- ESM: keep relative imports ending with
.js.
🧯 Troubleshooting
date must be current time, in 5 minutes
Your machine clock is off. Enable NTP:timedatectl set-ntp true sudo systemctl restart systemd-timesyncd- Not authenticated
Runauth.loginor setTTLOCK_USERNAMEandTTLOCK_PASSWORD_MD5in.env. - Gateway offline / Not support
Ensure your lock/gateway supports the operation and is online. - Inspector “Command not found”
Check Command =node, Arguments =dist/server.js, and that you built the project. - ESM import errors
Ensure relative imports end with.jsandtsconfig.jsonusesmoduleResolution: "NodeNext".
🗺️ Roadmap
- Persist/rotate tokens on disk (cache).
- Webhook Lock Records Notify for real-time events.
- More management endpoints (rename card, change validity window, etc.).
- Tests and linting (Vitest/ESLint).
📄 License
This project is licensed under Apache-2.0.