Skip to main content

easy_onvif_mcp 0.1.0 copy "easy_onvif_mcp: ^0.1.0" to clipboard
easy_onvif_mcp: ^0.1.0 copied to clipboard

MCP server exposing ONVIF IP camera and NVR control (device management, media, PTZ, imaging, recordings) over stdio.

easy_onvif_mcp #

An MCP (Model Context Protocol) server that exposes ONVIF IP cameras and NVRs as tools, built on easy_onvif.

Point a model at a camera: list profiles, resolve RTSP and snapshot URIs, drive PTZ, read device information, and discover devices over WS-Discovery — without writing a single SOAP request by hand.

Pub Version

Why is there a second package? #

The server exists exactly once, in lib/src/onvif_tools.dart + lib/src/onvif_mcp_server.dart, and neither file touches dart:io. Two hosts then plug themselves in through the small McpRuntime seam (stdio, stderr logging, environment, HTTP client, discovery probe, credentials file):

Host Entry point How you run it
Dart VM bin/easy_onvif_mcp_server.dart dart pub global activate easy_onvif_mcp
Node.js easy_onvif_mcp_js (this package compiled with dart compile js) npx easy-onvif-mcp

Adding a tool means adding one entry to buildOnvifTools() — both hosts pick it up. See test/tool_defs_test.dart, which checks the hand-written schemas stay self-consistent.

Credentials #

Resolved lazily on the first tool call, environment winning over the config file:

  1. ONVIF_HOST, ONVIF_USERNAME, ONVIF_PASSWORD
  2. $HOME/.onvif/credentials.json — the same file easy_onvif_cli reads, so onvif authorize sets up this server too. Override the path with ONVIF_CONFIG_FILE.
  3. Or call the onvif_connect tool explicitly.

ONVIF_HOST may carry a port (192.168.1.10:8080) or a scheme. Nothing is read until a tool needs it, so the server always starts.

Client configuration #

{
  "mcpServers": {
    "onvif": {
      "command": "npx",
      "args": ["-y", "easy-onvif-mcp"],
      "env": {
        "ONVIF_HOST": "192.168.1.10",
        "ONVIF_USERNAME": "admin",
        "ONVIF_PASSWORD": "secret"
      }
    }
  }
}

With the Dart VM binary, use "command": "dart", "args": ["run", "easy_onvif_mcp:easy_onvif_mcp_server"].

Tools #

52 tools, all prefixed onvif_. Media and PTZ tools take a profile_token; get one from onvif_get_profiles. Run dart run example/serve_stdio.dart --list-tools to print the live list with each tool's required arguments.

Connection — onvif_connect, onvif_disconnect, onvif_is_connected, onvif_status, onvif_probe

Device management (read-only) — onvif_get_device_information, onvif_get_services, onvif_get_capabilities, onvif_get_system_date_and_time, onvif_get_hostname, onvif_get_dns, onvif_get_ntp, onvif_get_dynamic_dns, onvif_get_network_protocols, onvif_get_users, onvif_get_relay_outputs, onvif_get_storage_configurations, onvif_get_discovery_mode, onvif_get_endpoint_reference

Media — onvif_get_profiles, onvif_get_profile, onvif_get_stream_uri, onvif_get_snapshot_uri, onvif_get_video_sources, onvif_get_audio_sources, onvif_get_media_service_capabilities

PTZ — onvif_ptz_get_status, onvif_ptz_get_presets, onvif_ptz_get_configurations, onvif_ptz_goto_preset, onvif_ptz_set_preset, onvif_ptz_remove_preset, onvif_ptz_absolute_move, onvif_ptz_relative_move, onvif_ptz_continuous_move, onvif_ptz_stop, onvif_ptz_move, onvif_ptz_move_up, onvif_ptz_move_down, onvif_ptz_move_left, onvif_ptz_move_right, onvif_ptz_zoom, onvif_ptz_get_service_capabilities

Imaging (read-only) — onvif_imaging_get_status, onvif_imaging_get_presets, onvif_imaging_get_current_preset

Recordings / replay / search — onvif_get_recordings, onvif_get_recording_jobs, onvif_get_replay_uri, onvif_get_recording_summary, onvif_find_recordings, onvif_get_recording_search_results

What is deliberately not exposed #

Device-mutating operations — system_reboot, user creation/deletion, hostname, DNS, NTP, network protocol and IP-filter writes — are not tools here. A stdio server holding live camera credentials should not hand a model a reboot button by default. Everything exposed is either a read or a camera movement.

Two reads the ONVIF spec defines have no counterpart in the easy_onvif API and so are absent: GetScopes, and imaging options/settings beyond ImagingStatus20 (onvif_imaging_get_status is the closest available). Add them once the core exposes those requests — one ToolDef entry each.

Credentials are never echoed back #

onvif_connect deliberately skips dart_mcp's automatic argument validation and validates in-handler. The library's validation failure message quotes the rejected value — Value `12345` is not of type `String` at path #root["password"] — and numeric default passwords are common on ONVIF cameras, so a mistyped credential would otherwise be written into the model's transcript. Errors name the offending field only.

One device at a time #

Tool calls are serialized. easy_onvif's SOAP layer keeps its clock offset and XML builder in static state (Transport.timeDelta, Transport.builder), so two in-flight requests would corrupt each other's WS-Security timestamps and XML fragments. Serializing keeps correctness at the cost of throughput, and means this server talks to one device per process — connect to a second camera by running a second server.

Diagnostics #

stdout is the JSON-RPC channel, so every log line, including SOAP failures and stack traces, goes to stderr. Tool failures come back as a normal MCP result with isError: true and a one-line message.

Development #

dart test
{ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'; sleep 2; } | dart run bin/easy_onvif_mcp_server.dart

The sleep matters: closing stdin ends the session, and a piped heredoc closes before the async reply is written.

1
likes
160
points
35
downloads

Documentation

API reference

Publisher

verified publishercdavis.ca

Weekly Downloads

MCP server exposing ONVIF IP camera and NVR control (device management, media, PTZ, imaging, recordings) over stdio.

Repository (GitHub)
View/report issues

Topics

#onvif #mcp #ip-camera #ptz #ai

Funding

Consider supporting this project:

buymeacoffee.com

License

MIT (license)

Dependencies

dart_mcp, dio, easy_onvif, loggy, stream_channel

More

Packages that depend on easy_onvif_mcp