
tolpo
io.github.signerless由 GitHub 帳號 signerless 發布v0.2.1更新於 Oct 24, 2026
Local-first control of TP-Link Tapo smart-home devices for AI agents
概覽
本地優先的 MCP 伺服器,讓 AI 助理透過家用區域網路讀取並控制 TP-Link Tapo 燈具、插座、中樞、感測器、攝影機和掃地機器人。
- 可以做什麼
- 總覽住家:全屋概況、裝置清單、單一裝置全部功能與重新掃描,以及房間與裝置的 3D 平面圖和已記錄的門窗歷史統計。控制燈具與插座:開關、亮度、色溫、顏色、預設、排程和能耗讀數。讀取中樞與感測器:門窗、漏水、移動和按鈕事件記錄、溫度與低電量標記。處理攝影機與門鈴:為你啟用的攝影機拍攝靜態圖片、偵測設定、雲台、記憶卡與錄影片段。管理裝置設定、本機自動化規則、配對和網路可見性,皆受操作等級限制。
- 適用情境
- 適合讓助理回答關於 Tapo 智慧家庭的问题或直接操作,例如調暗燈光、查看門窗是否開啟或是否漏水、取得攝影機快照,且請求不經過廠商雲端。
- 執行需求
- 以 stdio 在本機執行,通常透過 npx;npm 套件內含 Python 程式碼,需要 Node、uv 和 Python 3.11 以上版本,首次執行會下載大量套件。需要同一網路上一個或多個已在 Tapo 應用程式中設定好的 Tapo 裝置,以及 Tapo 帳號電子郵件和密碼(TAPO_EMAIL、TAPO_PASSWORD)。只有攝影機拍照需要 ffmpeg。Linux 上也可用 Docker 搭配主機網路。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 tolpo,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Local-first control of TP-Link Tapo smart-home devices for AI agents.
[CI] [License: MIT] [Python 3.11+]
tolpo turns the Tapo devices on your network into a single interface that an AI agent, or
your own code, can read and control. It talks to each device directly over the LAN through the open
source python-kasa library, so no request ever leaves
your home and no vendor cloud sits in the path. The only credential it needs is the Tapo account the
devices already belong to.
It ships two interfaces over the same core:
- An MCP server that assistants such as Claude use as tools (
turn off the office lights,is any door open?). - An HTTP API with an OpenAPI description at
/docs, for scripts and dashboards.
The aim is that everything the Tapo app can do on your network can also be done by the agent: lights, plugs, hubs and their sensors, cameras, doorbells, robot vacuums, schedules, firmware, rooms, pairing, and even what the devices say to the internet. That is a lot of power, so every action has a level, and only the first levels are on until you raise them. See What an agent can do and the Security model.
Features
- Lights, plugs, the H100/H200 hub and its sensors, cameras and the doorbell, each with live state and a list of what can be changed.
- The parts of the Tapo app are split into areas, such as lights, plugs, cameras, doorbells and the network. tolpo remembers which kinds of device it found in earlier runs, and an area for a kind you have never had stays off.
- Every action has a level from 0 to 4. Reading and reversible control (power, brightness, color) are on. Settings, security changes and things that are hard to undo, such as pairing or a factory reset, stay off until you raise the level, and the last two kinds also need a confirmation phrase on every call. Wi-Fi names, setup codes, passwords and tokens are never returned.
- A camera you name in the config gives an agent a still picture, a short run of pictures or a saved clip, through the same video channel the Tapo app uses. No extra camera account is needed.
- Discovery combines a broadcast with a direct per-address sweep, remembers devices between runs and retries the ones that are slow to wake. When a device cannot be reached, the answer says which one and why.
- State is cached briefly and device names resolve at once, so an agent is not blocked on a slow hub.
- A full test suite runs against simulated devices, so it needs no hardware.
Supported devices
tolpo works with whatever python-kasa can talk to, so the list is longer than the hardware we own. The table keeps two things apart: what we have run against real devices, and what python-kasa documents as supported but we have not tried.
The C610 and the C465 are not on python-kasa's list yet, but both connected fine. The C465 needs the small
certificate fix in compat.py. The full upstream list is in
python-kasa's SUPPORTED.md.
A model that is not listed may still work, because tolpo hands the device to python-kasa and shows whatever it
reports. Run tolpo scan to find out. If a device works or does not, tell us through a
device support issue so the table can improve.
Requirements
- Python 3.11 or newer
- One or more TP-Link Tapo devices on the same network, already set up in the Tapo app
- Your Tapo account email and password
- ffmpeg, only if you want pictures from cameras
- uv (or plain
pip) to install
Installation
With npx
You need Node and uv. Nothing is installed globally:
tolpo is a Python program. The npm package carries the Python code and runs it with uv, so the first run
downloads about forty Python packages and takes longer than later runs. If an AI client gives up waiting, run
npx -y tolpo --help once and start the client again.
With Docker
For a machine that stays on, such as a Raspberry Pi or a Linux home server. The image is public, so pulling it needs no login, and it is built for amd64 and arm64.
Keep the credentials in a file that only you can read, and pass it with --env-file:
That runs the MCP server over stdio. For the HTTP API, add a token, because it is no longer bound to loopback:
--network host lets the container find devices by UDP broadcast, and it only works on Linux. Docker Desktop on
macOS and Windows runs containers in a virtual machine that cannot see your devices that way, so use the npx
install there.
CI builds the image for both architectures and checks the MCP handshake inside it. Finding real devices from inside a container has not been tried yet. The image has no ffmpeg, so camera pictures do not work in it yet.
From source
Configuration
Credentials can come from environment variables or a config file. The server reads the file first, then lets the environment override it.
Or ~/.config/tolpo/config.toml (run chmod 600 on it, since it holds a password):
Environment variables override the file: TOLPO_CONFIG (the file itself), TOLPO_CREDENTIALS_FILE, TOLPO_TIER,
TOLPO_AREAS (names separated by commas), TOLPO_SNAPSHOTS, TOLPO_CLIP_DIR, TOLPO_FFMPEG,
TOLPO_CAMERA_USERNAME and TOLPO_CAMERA_PASSWORD. A tier that is not a whole number from 0 to 4 stops the
server from starting.
Some parts keep their own files, so that no secret ends up in the main one. Automation keeps its rules and alert
outbox, and the local rooms and groups are kept in ~/.local/state/tolpo (change it with TOLPO_STATE_DIR). The
network area reads ~/.config/tolpo/network.toml (change it with TOLPO_NETWORK_CONFIG), which names the
environment variable that holds each router password and never holds the password itself.
Verify your setup with a read-only scan: npx -y tolpo scan, or .venv/bin/tolpo scan from a source checkout.
Usage with Claude (MCP)
Put your credentials in ~/.config/tolpo/config.toml (see Configuration, and chmod 600 it). The server
reads that file by itself, so nothing secret ends up in your AI client's settings. Then register the server
once:
From a source checkout, point at your own copy instead:
If you would rather keep the credentials out of a file, pass them with -e TAPO_EMAIL=... -e TAPO_PASSWORD=...,
but your client will then store them in its own settings in plain text.
After the next restart you can ask things like "dim office-1 to 30%", "is any door open?" or "what is the temperature upstairs?".
Read tools are marked read-only and set_feature is marked destructive, so MCP clients can ask for
confirmation where it matters. Responses are compact: all the devices of a typical home fit in under a
thousand tokens.
What an agent can do
The Tapo app is split into areas. Each area is a group of MCP tools with its own page that lists every tool.
tolpo remembers the kinds of device it found in earlier runs, and an area for a kind you have never had is off, so a
house without a vacuum does not load vacuum tools. On a first run, or when a model is not recognized, every area is
on. Pick the areas yourself with areas under [server], or TOLPO_AREAS. The tool tolpo_areas tells an agent
what is on.
On top of these, home_overview, list_devices, get_device, set_power, set_light, set_feature,
camera_snapshot and rescan work for every device.
All the areas together are 242 tools. Their names, descriptions and parameter lists come to about 40,000 tokens. The
standard setup switches on only the areas that match the devices found at home. A client that loads every tool at once
can use areas to keep only what it needs.
Most of this was built from analysis of the Tapo app and tested against simulated devices. Each area page says
which parts were tried on real devices and which were not. Where the exact form of a request was a guess, the
page marks it UNVERIFIED, and the tool refuses when the device does not report support for it.
Usage over HTTP
A device is addressed by its short id (office-1), by its name in the Tapo app (case-insensitive),
or, in the batch endpoints, by a glob such as office*. If a name matches several devices the server
returns 409 with the candidates instead of guessing.
The house in 3D
tolpo serve also serves a 3D view of the house at http://127.0.0.1:8765/home. It draws the rooms, puts every
device in its room and shows its state: lights glow in their real color, a door or window drawn on the wall opens when
its sensor reports open, a water leak turns red, the temperature floats over its sensor. Click a device to switch it,
dim it or change its color. Click a camera or the doorbell to watch it live. Rooms without a device are left out.
The floor plan is yours and stays on your machine, in ~/.config/tolpo/home.json (server.home_layout or
TOLPO_HOME_LAYOUT to move it). The easiest way to make one is to ask your agent to "build my home plan": with the
home_plan_draft, home_plan_get and home_plan_set tools it drafts a plan from your devices, asks you about your
rooms and saves it. You can also press Edit layout in the view, drag devices where they belong, and save. The format
is in docs/areas/home_plan.md:
Live video comes from GET /devices/{id}/live, a stream of JPEG pictures (about 10 per second) from a camera you listed
in cameras.snapshots. One stream per camera and two cameras at once. A view ends after 15 minutes, or after 2 minutes
on a battery camera, because live video keeps it awake. The page loads three.js from one pinned jsDelivr path and may
talk to this server only. It asks battery cameras for their state every five minutes, not every few seconds, so it does
not wake them.
Door and window history
A Tapo hub keeps no history of its own for sensors connected to TP-Link's cloud: asked the way the app asks, an H200 answers with an empty list for a door sensor, and the app reads that history from the cloud instead. So tolpo records its own:
It reads the sensor every 5 seconds (--every to change it) and saves each opening and closing, with its time, in
~/.local/share/tolpo/history.jsonl (server.history_file or TOLPO_HISTORY_FILE), a file only you can read. Leave
out the name to record every door and window sensor. It records only while it runs, so run it as a background service
for a history without holes; times when the computer slept or the sensor was out of reach are written down as gaps.
The recorded_history tool then tells an agent how often a door opened, for how long, per day and per hour, and
lists the times nothing was recorded instead of guessing about them.
Camera pictures
An agent can ask a camera for one still picture. Every camera is off until you name it in the config, with the name it has in the Tapo app:
You also need ffmpeg on the machine that runs tolpo. Check the setup yourself before an agent uses it. This saves one picture to a file that only you can read:
To watch a camera live on your own screen, use npx -y tolpo watch "Hallway Cam". It opens ffplay, which comes with
ffmpeg, and closes when you close the window. --seconds 30 stops it sooner. Nothing is recorded and nothing goes to
an agent.
tolpo takes one frame from the camera's live stream with ffmpeg and returns it as a JPEG, at most 1280 pixels
wide. --quality high asks for the main stream instead of the small one. There are two ways to reach the stream:
- The video channel of the Tapo app, on port 8800 of the camera. It uses the Tapo account tolpo already has, so there is nothing more to set up.
- RTSP, if you create a camera account in the Tapo app and add it under
[cameras]asusernameandpassword. When a camera account is configured, tolpo uses RTSP.
What to know before you turn it on:
- A picture goes to the AI model your agent runs on. Enable only the cameras you are happy for it to see.
- A camera in privacy mode gives no picture. An agent cannot switch privacy mode off unless you allow
camera.stateinallow_write. - Every picture is logged with the camera and the time, never with the picture itself.
- If a camera rejects the login, tolpo leaves it alone for five minutes, because repeated failures can lock a camera out.
- A picture is one frame from now, not a recording. Battery cameras can be asleep and may not answer.
- With RTSP, ffmpeg receives the camera account on its command line, so other users on the same machine can see it for a moment.
- A doorbell behind the hub has no address of its own. Its pictures and live video come through the hub, like the app's, and the first picture takes about 5 s while a battery doorbell wakes up. Its recordings are not reachable yet.
The camera_media area builds on this. It can read the memory card and its recording index, return the thumbnail
of a past event, take a short run of pictures from the live stream, and save a recording to the one folder you set
as clip_dir. Thumbnails, runs of pictures and clips follow the same rules as pictures: only cameras you named, never
in privacy mode, and the tool that saves a clip returns the path and never the video. Reading the card status, the
record plan and the list of recordings and events works for any camera. Formatting a card is a level 4 action.
Security model
This server controls physical things, so it refuses by default and widens only on request.
Every action on a device has a level. You choose the highest level an agent may use with tier under [policy]
(1 by default), and you can allow single device methods above it with allow_methods.
Levels 3 and 4 also need a confirmation phrase on every call, such as setLedStatus hallway-cam. The refusal says
what the phrase is, so the phrase is a pause for the agent to ask the person, not proof that the person agreed. The
phrase names the action and the device (a few name a change or a plan instead), so one confirmation cannot be reused
for another device or another action. A refusal says what the action is, and never how to widen the permission.
Cameras are read-only through set_feature: the state switch on a camera is its privacy shutter, not a power
relay, so it is not treated as one. Enable it deliberately with allow_write = ["camera.state"], or use the
privacy tool at level 3. A feature named in allow_write is allowed at any level and needs no phrase, so name only
what you mean to give away.
Rules that run without anyone asking (automation) are held to the same levels at the moment they run, not only when
they are made. Setting them up needs level 2. An agent can stop all rules at any time, but starting them again
needs level 3 and a phrase. You can do it yourself with tolpo automation resume, which a server that is already
running picks up when it restarts.
The server listens on 127.0.0.1 only. It refuses to start on any other address without a bearer
token, and without a token it also rejects requests whose Host header is not local, which blocks
DNS-rebinding attacks from a web page.
Device names are free text typed by whoever set the device up. The server flattens and shortens them before an agent sees them, and the instructions it sends tell the agent to treat names and readings as data, not commands. A shared Tapo account still means anyone in it can rename a device, so keep the account to people you trust.
How discovery handles a busy network
Homes often have many devices, some battery-powered and slow to answer. Discovery is designed for that:
- A UDP broadcast, followed by a direct query to each address in the subnet (
discovery.sweep), because some battery cameras ignore broadcasts yet always answer a direct question. - Devices seen before are remembered in
~/.cache/tolpo/hosts.json(address, name and model, no secrets) and queried directly at startup. A device missing from one scan is never forgotten; entries unseen for 30 days are dropped. - Devices that do not answer are retried after 5, 15 and 45 seconds, and again on every rescan.
Startup is staged so the server is useful immediately: the first scan runs in the background, and each device is connected the moment it answers. A device you name exactly is usable as soon as it is up, without waiting for the hub, which can take about ten seconds from cold. Operations that span the whole house wait for the scan, but never longer than fifteen seconds; anything still connecting finishes in the background.
When something cannot be reached, the answers say so. home_overview and list_devices carry
complete: false and a not_connected list with the name, model and reason for each unreachable
device, so an agent does not mistake an offline door sensor for a closed door.
For AI agents
Call tolpo_areas first. It lists the parts of tolpo that are on, what each one offers, and the level the owner
allows. If you are an AI agent asked to set tolpo up or to use it, start with
llms.txt. If you are asked to change the code,
read AGENTS.md first.
Development
Project layout:
See CONTRIBUTING.md for the ground rules, docs/protocols.md for the protocol notes and SECURITY.md to report a vulnerability.
Background
The protocols behind Tapo devices are not documented by the vendor. Part of this project is independent analysis of the official Tapo app and of real devices, done so that software can interoperate with hardware its owners already have. The result is written down in docs/protocols.md: which transport each model uses, how discovery works, what the newer TPAP protocol looks like, and what we could not establish. The notes are in our own words. They contain no vendor code, keys or credentials, and tolpo itself only ever signs in with your own Tapo account.
Compatibility and status
This is version 0.2.1. Lights, plugs, hubs and sensors are supported over the KLAP and SSL-AES
transports through python-kasa, plus a small patch (compat.py) for cameras with an ECDSA certificate, such as
the C465, that python-kasa cannot reach on its own.
The areas beyond the first release were built from analysis of the Tapo app and tested with simulated devices. Reading was tried on a real home with four bulbs, a hub, eight sensors, a doorbell, three cameras and a plug. A few reversible writes were tried there too: the bulbs (power, brightness, color, power-on defaults, saved presets and disabled rules), the plug (power, countdown, LED, power-on default and disabled rules), a camera light, the hub light, a microphone volume, a detection switch and an automation rule, each set back afterwards. Most other writes have not been tried on real hardware, and the area pages say which. Robot vacuums, door locks, radiator valves and the firewall providers were never tried on the real thing.
Known limits: cameras give still pictures, short runs of pictures and saved clips, but no continuous video to an
agent, and a doorbell behind the hub gives pictures but not its recordings; the cloud-only parts of the app (account, homes, sharing, push notifications,
Tapo Care, voice assistants) are not reachable, and the automation area replaces some of them locally; the MCP
server runs over stdio, one process per client, with no shared HTTP transport yet; the HTTP API has the original
routes plus a few for the camera memory card (/devices/{id}/storage, /recordings/...) and the door lock state, and
the other areas are MCP tools only; and devices on a second subnet have not been tested.
License
MIT, see LICENSE.
This project is not affiliated with or endorsed by TP-Link. Tapo is a trademark of TP-Link. All device communication goes through the open source python-kasa library.
來源:README.md,提交 07fdd5c
工具
0版本歷史
3- v0.2.1最新Oct 15, 2026
- v0.2.0Oct 13, 2026
- v0.1.0Oct 11, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分