
IP cameras (ONVIF/RTSP)
io.github.aidev-iprokszinPublished by GitHub account aidev-iprokszinv0.4.1Updated Nov 7, 2026
MCP server for local IP cameras (ONVIF/RTSP): snapshots, recordings, pan/tilt, presets
Overview
Lets an assistant view and control local ONVIF/RTSP IP cameras: snapshots, crops, short recordings, pan/tilt presets and change detection.
- What you can do
- List configured cameras and scenes, with capabilities and capture history
- Take snapshots, crop regions at full resolution, and record short mp4 clips
- Save named baselines and compare a view against them or the previous snapshot
- Pan and tilt the camera and list, save, go to or delete presets
- Capture and compare every camera in a scene, and browse a scene timeline by date
- Add, rename, move, remove or delete cameras and reload the config
- When to use it
- Useful when you want an assistant to check what a local IP camera sees, compare a view against a saved reference, record a short clip, or move the camera, without a cloud service. Suited to home or office cameras on the same network as the machine running the server.
- Requirements
- Runs locally on Linux or WSL2 on the same network as the camera, with uv on PATH and ffmpeg installed. Needs an ONVIF-capable camera with ONVIF and RTSP enabled and its local camera account (username and password), not a cloud login. Config path is set by IPCAM_MCP_CONFIG, defaulting to a cameras.toml under the user config directory; secrets live in separate files.
Installation
In SourceWeft
- Open IP cameras (ONVIF/RTSP) in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
ipcam-mcp
An MCP server that lets Claude Code, or another MCP client, see through and control the IP cameras on your local network (ONVIF + RTSP): snapshots, video clips, pan/tilt and change detection, all handled locally.
Any ONVIF camera should work. See known cameras for what has been tested.
What you can ask
Once a camera is added, ask in plain words, for example:
- "Take a snapshot of the front door."
- "Save this view as door-closed." Later: "Does the front door still look like door-closed?"
- "Did anything change at the front door since the last snapshot?"
- "Pan the office camera a bit to the left."
- "Record 10 seconds from the garage."
- "Show me what the garage cameras captured yesterday."
Prerequisites
- Linux or WSL2, on the same network as the camera
- uv on your
PATH(it installs Python 3.13+ and the dependencies for you) - ffmpeg:
sudo apt install ffmpeg - An ONVIF-capable IP camera with a local camera account (username and password), with ONVIF and RTSP enabled
- Claude Code or another MCP client that supports stdio servers
Install
Pick one. All of them run the ipcam-mcp package from PyPI and need ffmpeg and, except pipx, uv (see Prerequisites).
-
Claude Code plugin (recommended for Claude Code):
/plugin install ipcam --marketplace aidev-iprokszin/ipcam-mcpOn Claude Code older than 2.1.275, run
/plugin marketplace add aidev-iprokszin/ipcam-mcp, then/plugin install ipcam@ipcam-mcp. The plugin runs the server from a lockfile (every dependency pinned with hashes). Update it withclaude plugin update ipcam@ipcam-mcp, which also updates the server; a new server version reaches the plugin shortly after its PyPI release. -
Claude Code, without the plugin:
claude mcp add ipcam -s user -- uvx ipcam-mcp -
Other MCP clients (Cursor, VS Code, Codex CLI, …): configure the stdio command
uvx ipcam-mcp. See Other MCP clients. -
A permanent
ipcam-mcpcommand:uv tool install ipcam-mcp(orpipx install ipcam-mcp), then configure your client to runipcam-mcp. Update withuv tool upgrade ipcam-mcp(orpipx upgrade ipcam-mcp).
Then add your first camera.
Add your first camera
- Camera account: create or find the camera's local ONVIF/RTSP account (username and password). This is not your cloud login. See known cameras for where your brand hides it.
- IP address: look it up in the camera's app or your router. Network discovery is not supported (WSL2 NAT blocks it).
- Ask Claude to add it, for example "add my camera at 192.0.2.10 as front-door". Claude
calls
add_camera, which asks for the username and password in a login form, so they never pass through the model. Before you type the password, check that the IP in the form is your camera's. Without a config file the server starts with no cameras;add_cameracreatescameras.tomland the camera's secrets file. See Managing cameras for the other management tools and for clients that cannot show forms.
Or configure it by hand
- Secrets file (outside any repo), e.g.
~/.config/ipcam-mcp/secrets.env: Make it readable only by you:chmod 600 <file>. The server warns at startup if other users can read it. - Camera config: copy
cameras.example.tomlto~/.config/ipcam-mcp/cameras.toml(or pointIPCAM_MCP_CONFIGat another path) and adjust the camera name / variable names. Only variable names go in this file, never the secrets themselves. Usetype = "onvif".
After editing cameras.toml by hand while the server runs, ask Claude to reload the cameras
(reload_cameras).
Camera settings
All optional, set in the camera's section of cameras.toml. A wrong type is reported when the
config loads.
ptz = false means the camera has no pan/tilt tools. Set stream_high/stream_low if the
ONVIF lookup fails or picks the wrong stream. Set invert_pan = true if ptz_move left turns
the view to the right. Some brands need other values; see
known cameras.
Other MCP clients
Any client that supports stdio servers (Cursor, VS Code, Codex CLI, …) can run the same
command: uvx ipcam-mcp, or uv --directory /absolute/path/to/ipcam-mcp run ipcam-mcp for a
clone.
Claude Desktop on Windows: the server runs inside WSL2, so install uv and ffmpeg there
(see Prerequisites). In Claude Desktop, open Settings → Developer → Edit Config, add the
ipcam entry below to mcpServers and keep the rest of the file:
Replace <you> with your WSL user name (which uvx in WSL shows the path). With several WSL
distributions, add "-d", "<distro>" before "-e". Then quit Claude Desktop from the tray icon
(closing the window is not enough) and start it again. The server uses the same cameras.toml
and media folder inside WSL as Claude Code there. Use Edit Config rather than a fixed path: the
Microsoft Store version keeps the file under %LOCALAPPDATA%, not %APPDATA%\Claude. For a
clone, use "args": ["-e", "/home/<you>/.local/bin/uv", "--directory", "/home/<you>/path/to/ipcam-mcp", "run", "ipcam-mcp"].
WSL2 networking
If the camera can't be reached from WSL (nc -zv <ip> 554 fails), enable mirrored networking
in %UserProfile%\.wslconfig:
then run wsl --shutdown from Windows.
Tools
camera is a camera's name: its section name in cameras.toml. quality="high" uses the
camera's main stream (1080p), "low" the sub stream (smaller, quicker). Media is saved to the
camera's own folder, <media_dir>/<uid>/<camera>_<YYYYmmdd-HHMMSS>.jpg|.mp4 (media_dir
defaults to ~/.local/share/ipcam-mcp/media).
Tool hints. Every tool carries MCP annotations so clients can tell what it does:
list_cameras, list_scenes, scene_timeline and ptz_list_presets are read-only;
camera_save_baseline, ptz_save_preset, ptz_remove_preset, remove_camera and
delete_camera may replace or delete data; everything else only adds files or moves the
camera. Snapshots and recordings are not marked read-only because they save files. These are
hints for the client; the server's own safeguards (such as delete_camera's approval form)
still apply.
Compare and crop. camera_compare lists the grid cells that changed (the same names as
region) and a box around them. Pass a changed cell as region to camera_snapshot, ideally
with from_path set to the snapshot you just looked at, to see it closer. Baselines live in
<media_dir>/<uid>/baselines/ as a JPEG plus a small JSON file.
Managing cameras
Instead of editing cameras.toml by hand you can let Claude add, rename, remove and delete
cameras. This is on by default. To turn it off, set allow_management = false in
cameras.toml (see cameras.example.toml), then run /mcp reconnect ipcam; the flag is only
read at startup. Claude Code still asks before each tool call unless you allowlist it; if you
allowlist the camera tools, consider leaving remove_camera, delete_camera and
ptz_remove_preset off the list.
add_camera logs into whatever host it is given. Before you type a password into the login form,
check that the IP it shows is your camera's (from the camera's app or your router), not one the
agent picked up elsewhere.
Changes apply immediately, without restarting the server. If loading the new config fails, the
previous cameras.toml is restored.
Credentials never pass through the model. Two routes:
- Form (default): your client shows a login form. MCP forms have no masked field, so the
password is visible while you type it, but it is not stored in the conversation. Some clients
cannot show a form during a tool call (those on MCP protocol 2026-07-28, some phone (Remote
Control) views); there
add_camerauses the file route and says so in its result. - File (
credentials_via="file"):add_cameracreates<secrets_dir>/<name>.env(mode0600, defaultsecrets_diris~/.config/ipcam-mcp/secrets) withHOST=, emptyUSER=andPASSWORD=. Fill in USER and PASSWORD yourself, then ask Claude to calladd_cameraagain with the same name and host, keepingcredentials_via="file". Calling it with the defaultformwould ask for the credentials again instead of reading the file.
Each camera added this way has its own <name>.env, and files at <secrets_dir>/<name>.env are
treated as managed: renamed and deleted along with the camera. Keep hand-made files elsewhere;
those, such as a shared secrets.env, are never renamed or deleted. Secrets files are read
literally: ${VAR} in a value is not expanded.
How it works
Camera uids. Every camera has a permanent uid (8 characters, a-z0-9) in its
cameras.toml section. The server fills it in when it is missing, so you never write one
yourself; don't change or copy it. The uid names the camera's media folder, which also holds a
camera.json with the camera's current name. Because of it, a renamed camera keeps its
snapshots and baselines, and a new camera that reuses an old name starts with an empty history.
Scenes. A scene is the place a camera watches, such as front-door or garage. By default
it is the camera's name; set scene = "..." in the camera's section (or use set_scene) when
they differ, for example when several cameras watch one place. Renaming a camera keeps its
scene. Moving a camera to another scene starts a new period in its camera.json: snapshots and
baselines from before the move stay with the old scene, and camera_compare only compares within
the current one, so it never reports a different place as a change.
Replacing a camera. When a camera enters a scene where a removed camera was last (with
add_camera, or set_scene), you are asked in a form whether it replaces one of them, is an
additional camera, or to cancel. A replacement is its successor: until it has a snapshot of
its own there, camera_compare compares with the old camera's newest snapshot in the scene, and
baselines are looked up along the predecessors (up to 10). The result then says which camera
took the reference, since angle, lens or resolution may differ. Without form support the camera
is added as an additional one; call set_scene with its current scene later, from a client that
shows forms, to declare it a successor. A camera that moves away and later returns to the
scene keeps its predecessor there. delete_camera mentions when a camera is another's
predecessor.
Transports
ipcam-mcp uses stdio by default. ipcam-mcp --transport http [--host 127.0.0.1] [--port 8765]
serves streamable HTTP, but without authentication, so only use it on a trusted machine
and keep it bound to localhost. On 127.0.0.1, localhost or ::1 the server rejects
requests addressed to other hosts, such as from web pages (DNS-rebinding protection). Any other
--host is refused unless you also pass --allow-remote; then anyone who can reach the port
controls your cameras.
Privacy
The project collects no data; everything stays on your machine except what your MCP client receives as tool results. See PRIVACY.md.
Security
See SECURITY.md for the threat model and how to report a vulnerability.
- Credentials are read only from your secrets file, never from the repo, and are not put into environment variables.
- They are kept in memory by the camera's config and adapter, and are excluded from
repr. - The password is scrubbed (raw and URL-encoded) from every error message the server returns or logs.
- RTSP URLs are masked (
rtsp://***@host…), which also hides the username. The username is not scrubbed anywhere else. - Logs go to stderr; stdout carries only the MCP protocol.
Troubleshooting
- Auth errors /
401/ ONVIF error on every PTZ call: use the camera's local account, not a cloud login. See known cameras. - Snapshots fail but ONVIF works: set
stream_high/stream_low(see Camera settings). timed out … (camera unreachable?): the camera is offline or not reachable from this machine. See WSL2 networking.ffmpeg not installed:sudo apt install ffmpeg.camera.json … unreadable, kept as camera.json.bad-…in the log: a camera'scamera.jsoncould not be read (for example after a bad hand edit), so a new one was written and the old one kept next to it. To get the camera's creation time and scene history back, fix the kept file and rename it tocamera.jsonwhile the server is stopped (scene changes made since are then lost; redo them withset_scene). Timestamps without a UTC offset are read as local time.
Known limitations
- While the camera is offline, failed ONVIF connection attempts aren't cleaned up, and you may
see
Unclosed client sessionwarnings on stderr. They're harmless. - Filenames have one-second resolution; a second capture in the same second gets a
-2,-3, … suffix. - Filenames carry local time without a UTC offset. In the hour that repeats when daylight saving time ends, a capture counts as taken in the first of the two hours, and after the machine's time zone changes, older captures shift by the difference. Both only matter for captures close to a scene change: they can be assigned to the neighbouring scene.
- Media files are never deleted automatically.
delete_cameradeletes a camera's files after you approve it; otherwise clean up~/.local/share/ipcam-mcp/media/yourself. - HTTP transport has no authentication (see above).
Development
To work on the code, clone the repo:
The repo ships a project-scoped .mcp.json, so running claude anywhere inside the clone
offers the ipcam server, run from your checkout. Approve it when prompted. If you rejected it
by mistake, run claude mcp reset-project-choices and start claude again.
To use the checkout from every folder, also register it in your user scope (inside the repo the project entry takes precedence, so there are no duplicates):
Tests and lint:
⚠️ The live tests physically move the camera (a small pan left and back) and save snapshots and a 3 s clip to the media folder. They also create and delete a preset and a baseline, both named
cmcp_test.
Adding a camera type
- Add an adapter in
src/ipcam_mcp/adapters/taking(DeviceConfig, media_dir)and implementing theCameraprotocol (andPTZif it can pan/tilt) fromsrc/ipcam_mcp/capabilities.py. - Map its config
typeto the adapter inADAPTERSinsrc/ipcam_mcp/registry.py.
A new camera feature (e.g. privacy mode) gets a Protocol in capabilities.py, registered in
CAPABILITIES, plus its tools in src/ipcam_mcp/server.py.
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md and the Code of Conduct.
This project was built with Claude Code.
License
Terms of use: TERMS.md.
Source: README.md at commit 51bb0e1
Tools
0Version history
2- v0.4.1LatestNov 7, 2026
- v0.4.0Nov 4, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts