Litmus MCP Server

The official Litmus Automation Model Context Protocol (MCP) Server enables LLMs and intelligent systems to interact with Litmus Edge for device configuration, monitoring, and management. It is built on top of the MCP SDK and adheres to the Model Context Protocol spec.

Table of Contents


Quick Launch

Start an HTTP MCP Server using Docker

Run the server in Docker (HTTP only)

docker run -d --name litmus-mcp-server -p 8000:8000 ghcr.io/litmusautomation/litmus-mcp-server:latest

The HTTP server exposes both MCP transports on port 8000:

  • http://<host>:8000/mcp - Streamable HTTP (current MCP spec, recommended)
  • http://<host>:8000/sse - HTTP+SSE (legacy transport, kept for older clients)

Clients that support Streamable HTTP should point at /mcp (e.g. "type": "http", as in the Claude Code example below). The remaining client examples use the SSE endpoint; swap in /mcp if your client supports it, keeping the same headers.

NOTE: The Litmus MCP Server is built for linux/AMD64 platforms. If running in Docker on ARM64, specify the AMD64 platform type by including the --platform argument:

docker run -d --name litmus-mcp-server --platform linux/amd64 -p 8000:8000 ghcr.io/litmusautomation/litmus-mcp-server:main

HTTPS Deployment

The container serves plain HTTP and is intended to sit behind a TLS-terminating reverse proxy in production. deploy/docker-compose.https.yml ships that pattern using Caddy, which obtains and renews Let's Encrypt certificates automatically:

# DNS A/AAAA record for mcp.example.com must point at this machine
DOMAIN=mcp.example.com docker compose -f deploy/docker-compose.https.yml up -d

MCP clients then connect to https://mcp.example.com/mcp (no port) with the same headers as before. Notes:

  • Only Caddy is published to the host (ports 80/443); the MCP server stays on the internal compose network, and the web UI (:9000) is deliberately not proxied.
  • Certificates persist in the caddy_data volume across restarts.
  • For private networks without public DNS, uncomment tls internal in deploy/Caddyfile to use Caddy's internal CA instead (clients must trust that CA).
  • Any other TLS-terminating proxy (Traefik, nginx, a cloud load balancer) works the same way: forward to port 8000 and keep SSE responses unbuffered.

Web UI

The Docker image includes a built-in chat interface that lets you interact with Litmus Edge using natural language — no MCP client configuration required.

Start the server with both ports exposed:

docker run -d --name litmus-mcp-server \
  -p 8000:8000 -p 9000:9000 \
  -e ANTHROPIC_API_KEY=<key> \
  ghcr.io/litmusautomation/litmus-mcp-server:latest
  • :9000 — Web UI (chat interface). Open http://localhost:9000 in your browser, add a Litmus Edge instance via the config page, and start chatting.
  • :8000 — SSE endpoint for external MCP clients (Claude Desktop, Cursor, VS Code, etc.) — still available as normal.

Security note: the Web UI is a local operator console. It has no login and it stores LLM API keys and Litmus Edge credentials, so only publish port 9000 on networks you trust; port 8000 (/mcp) is the only endpoint intended for MCP clients. Outside Docker, the UI binds to 127.0.0.1 unless you set WEB_UI_HOST=0.0.0.0 (the Docker image sets this so the -p 9000:9000 mapping works; simply omit the mapping to keep the UI private). Cross-origin browser access to the UI is disabled unless WEB_UI_CORS_ORIGINS is set to a comma-separated list of explicit origins.

Supported LLM providers: Anthropic Claude, OpenAI, and Google Gemini. Provide one or more keys at startup (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY) or enter them through the Web UI's setup screen. The active provider and model are switchable from the Web UI's config page at any time.

Multiple Litmus Edge instances: The Web UI lets you register and switch between multiple Litmus Edge devices from a single MCP server. Each instance keeps its own URL and OAuth2 credentials; the active instance's credentials are mirrored into EDGE_URL / EDGE_API_CLIENT_ID / EDGE_API_CLIENT_SECRET automatically. Manage instances under Config → Litmus Edge Instances, or check status per-instance from the Health page.

Live Litmus documentation as MCP Resources: The server exposes litmus://docs/<section> URIs that fetch live content from docs.litmus.io on demand, so MCP-aware clients can pull current reference material directly into the model's context.

If you deploy the MCP server and web client on separate hosts, set MCP_SSE_URL to point the web client at the server:

-e MCP_SSE_URL=http://<mcp-server-host>:8000/sse

Persistent Configuration

By default, configuration saved through the Web UI (API keys, Litmus Edge instances, model preferences, connection settings) is written to .env inside the container and is lost when the container is removed.

To retain configuration across container restarts and replacements, mount a host file over /app/.env:

# One-time setup — the host file must exist before docker run
mkdir -p /opt/litmus-mcp
touch /opt/litmus-mcp/.env

# Run with the volume mount
docker run -d --name litmus-mcp-server \
  -p 8000:8000 -p 9000:9000 \
  -v /opt/litmus-mcp/.env:/app/.env \
  ghcr.io/litmusautomation/litmus-mcp-server:latest

Any configuration you save in the UI is written to /opt/litmus-mcp/.env on the host. A new container started with the same -v flag will pick it up automatically on startup.

Note: The host-side file must be created with touch before running the container. If it does not exist, Docker creates a directory at that path and the application will fail to write configuration.

Docker Compose equivalent:

services:
  litmus-mcp-server:
    image: ghcr.io/litmusautomation/litmus-mcp-server:latest
    ports:
      - "8000:8000"
      - "9000:9000"
    volumes:
      - /opt/litmus-mcp/.env:/app/.env

Note: NATS_SOURCE, NATS_PORT, INFLUX_HOST, and INFLUX_PORT are optional in all of the client configurations below. When omitted, the server derives the hosts from EDGE_URL (defaulting to nats://<edge-host>:4222 and http://<edge-host>:8086) and mentions the fallback in tool responses. Set them only when the data plane is reachable at a different address or port than the Edge web UI.

Claude Code CLI

Run Claude from a directory that includes a configuration file at ~/.claude/mcp.json:

{
  "mcpServers": {
    "litmus-mcp-server": {
      "type": "http",
      "url": "http://localhost:8000/mcp",
      "headers": {
        "EDGE_URL": "${EDGE_URL}",
        "EDGE_API_CLIENT_ID": "${EDGE_API_CLIENT_ID}",
        "EDGE_API_CLIENT_SECRET": "${EDGE_API_CLIENT_SECRET}",
        "NATS_SOURCE": "${NATS_SOURCE}",
        "NATS_PORT": "${NATS_PORT:-4222}",
        "NATS_PASSWORD": "${NATS_PASSWORD}",
        "INFLUX_HOST": "${INFLUX_HOST}",
        "INFLUX_PORT": "${INFLUX_PORT:-8086}",
        "INFLUX_DB_NAME": "${INFLUX_DB_NAME:-tsdata}",
        "INFLUX_USERNAME": "${INFLUX_USERNAME}",
        "INFLUX_PASSWORD": "${INFLUX_PASSWORD}"
      }
    }
  }
}

Anthropic Docs


Cursor IDE

Add to ~/.cursor/mcp.json or .cursor/mcp.json:

{
  "mcpServers": {
    "litmus-mcp-server": {
      "url": "http://<MCP_SERVER_IP>:8000/sse",
      "headers": {
        "EDGE_URL": "https://<LITMUSEDGE_IP>",
        "EDGE_API_CLIENT_ID": "<oauth2_client_id>",
        "EDGE_API_CLIENT_SECRET": "<oauth2_client_secret>",
        "NATS_SOURCE": "<LITMUSEDGE_IP>",
        "NATS_PORT": "4222",
        "NATS_PASSWORD": "<access_token_from_litmusedge>",
        "INFLUX_HOST": "<LITMUSEDGE_IP>",
        "INFLUX_PORT": "8086",
        "INFLUX_DB_NAME": "tsdata",
        "INFLUX_USERNAME": "<datahub_username>",
        "INFLUX_PASSWORD": "<datahub_password>"
      }
    }
  }
}

Cursor docs


VS Code / GitHub Copilot

Manual Configuration

In VS Code: Open User Settings (JSON) → Add:

{
  "mcpServers": {
    "litmus-mcp-server": {
      "url": "http://<MCP_SERVER_IP>:8000/sse",
      "headers": {
        "EDGE_URL": "https://<LITMUSEDGE_IP>",
        "EDGE_API_CLIENT_ID": "<oauth2_client_id>",
        "EDGE_API_CLIENT_SECRET": "<oauth2_client_secret>",
        "NATS_SOURCE": "<LITMUSEDGE_IP>",
        "NATS_PORT": "4222",
        "NATS_PASSWORD": "<access_token_from_litmusedge>",
        "INFLUX_HOST": "<LITMUSEDGE_IP>",
        "INFLUX_PORT": "8086",
        "INFLUX_DB_NAME": "tsdata",
        "INFLUX_USERNAME": "<datahub_username>",
        "INFLUX_PASSWORD": "<datahub_password>"
      }
    }
  }
}

Or use .vscode/mcp.json in your project.

VS Code MCP Docs


Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "litmus-mcp-server": {
      "url": "http://<MCP_SERVER_IP>:8000/sse",
      "headers": {
        "EDGE_URL": "https://<LITMUSEDGE_IP>",
        "EDGE_API_CLIENT_ID": "<oauth2_client_id>",
        "EDGE_API_CLIENT_SECRET": "<oauth2_client_secret>",
        "NATS_SOURCE": "<LITMUSEDGE_IP>",
        "NATS_PORT": "4222",
        "NATS_PASSWORD": "<access_token_from_litmusedge>",
        "INFLUX_HOST": "<LITMUSEDGE_IP>",
        "INFLUX_PORT": "8086",
        "INFLUX_DB_NAME": "tsdata",
        "INFLUX_USERNAME": "<datahub_username>",
        "INFLUX_PASSWORD": "<datahub_password>"
      }
    }
  }
}

Windsurf MCP Docs

STDIO with Claude Desktop

This MCP server supports local connections with Claude Desktop and other applications via Standard file Input/Output (STDIO): https://modelcontextprotocol.io/legacy/concepts/transports

To use STDIO: Clone, install dependencies, and add the server to the Claude Desktop configuration file with ENABLE_STDIO set to true. Claude Desktop launches the server process itself; without ENABLE_STDIO the server starts in HTTP mode, never answers on stdin/stdout, and Claude Desktop disconnects after its 60-second initialize timeout.

Clone and install dependencies

git clone https://github.com/litmusautomation/litmus-mcp-server.git
cd litmus-mcp-server

# Using uv
uv sync

# Otherwise
pip install -e .

Add json server definision to your Claude Desktop config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "litmus-mcp-server": {
      "command": "/path/to/.venv/bin/python3",
      "args": [
        "/absolute/path/to/litmus-mcp-server/src/server.py"
      ],
      "env": {
        "ENABLE_STDIO": "true",
        "PYTHONPATH": "/absolute/path/to/litmus-mcp-server/src",
        "EDGE_URL": "https://<LITMUSEDGE_IP>",
        "EDGE_API_CLIENT_ID": "<oauth2_client_id>",
        "EDGE_API_CLIENT_SECRET": "<oauth2_client_secret>",
        "NATS_SOURCE": "<LITMUSEDGE_IP>",
        "NATS_PORT": "4222",
        "NATS_PASSWORD": "<access_token_from_litmusedge>",
        "INFLUX_HOST": "<LITMUSEDGE_IP>",
        "INFLUX_PORT": "8086",
        "INFLUX_DB_NAME": "tsdata",
        "INFLUX_USERNAME": "<datahub_username>",
        "INFLUX_PASSWORD": "<datahub_password>"
      }
    }
  }
}

Tips

For development, use Python Virtual environments, for example to bridge mcp lib version diffs between dev clients like 'npx @modelcontextprotocol/inspector' & litmus-mcp-server

{
  "mcpServers": {
    "litmus-mcp-server": {
      "command": "/absolute/path/to/litmus-mcp-server/.venv/bin/python",
      "args": ["/absolute/path/to/litmus-mcp-server/src/server.py"],
      "env": { /* same as above */ }
    }
  }
}

See claude_desktop_config_venv.example.json for the complete template.

Header Configuration Guide:

  • EDGE_URL: Litmus Edge base URL (include https://)
  • EDGE_API_CLIENT_ID / EDGE_API_CLIENT_SECRET: OAuth2 credentials from Litmus Edge
  • NATS_SOURCE: Litmus Edge IP (no http/https); optional, derived from EDGE_URL when omitted
  • NATS_PASSWORD: Access token from System → Access Control → Tokens (no username needed)
  • INFLUX_HOST: Litmus Edge IP (no http/https)
  • INFLUX_USERNAME / INFLUX_PASSWORD: DataHub user credentials

Available Tools

59 tools across 12 categories. Tools accept structured arguments and return JSON.

Category Function Name Description
DeviceHub, Devices get_litmusedge_driver_list List supported Litmus Edge drivers (e.g., ModbusTCP, OPCUA, BACnet).
get_devicehub_devices List all configured DeviceHub devices with connection settings and status.
create_devicehub_device Create a new device with specified driver and default configuration.
get_device_connection_status ** Check whether devices are actively publishing data via InfluxDB heartbeat (connected/stale/no_data).
DeviceHub, Tags get_devicehub_device_tags Retrieve tags (data points/registers) for a specific device or all devices, paginated via limit/offset so any tag count can be paged through.
get_current_value_of_devicehub_tag Read the current real-time value of a specific device tag.
create_devicehub_tag Create a new tag (register) on a device. Driver-required properties auto-fill from defaults.
update_devicehub_tag Update mutable fields of an existing tag (display name, description, properties).
delete_devicehub_tag Delete a tag from a device. Destructive.
get_tag_status Return runtime state (OK/Failed/Unknown) for tags on a specific device. Optionally filter to a single tag.
get_all_tags_status Return tag status across all devices. Defaults to non-OK only so issues surface first.
Device Identity get_litmusedge_friendly_name Get the human-readable name assigned to the Litmus Edge device.
set_litmusedge_friendly_name Update the friendly name of the Litmus Edge device.
Cloud / LEM Activation get_cloud_activation_status Check cloud registration and Litmus Edge Manager (LEM) connection status.
Docker Management get_all_containers_on_litmusedge List all Docker containers running on Litmus Edge Marketplace.
run_docker_container_on_litmusedge Deploy and run a new Docker container on Litmus Edge Marketplace.
NATS Topics * get_current_value_from_topic Subscribe to a NATS topic and return the next published message.
get_multiple_values_from_topic Collect multiple sequential values from a NATS topic for trend analysis.
InfluxDB / Time Series ** get_historical_data_from_influxdb Query historical time-series data from InfluxDB by measurement and time range.
list_influxdb_measurements List all measurement names in the tsdata database, discovery for downstream queries.
get_device_historical_data Fuzzy-match device names to InfluxDB measurements and pull historical data per match.
query_tag_data Query historical data for a specific tag by resolving its output topic. Newest-first.
get_tag_statistics Aggregate stats for a tag: mean, min, max, stddev, count, plus baseline range (mean +/- 2 sigma).
get_device_data_for_inference Composite payload for AI inference: device metadata, all tags, per-tag stats, and recent samples.
System, Events get_system_events Retrieve system events filtered by time range, component, and severity (INFO/WARN/ALERT/ERROR).
get_system_event_stats System and event health snapshot: event store size, last-hour event counts by severity, memory/storage usage, CPU count.
Server get_mcp_server_info Version info about the MCP server itself (server, litmussdk, litmus-cli, Python). Optional check_updates compares against the latest GitHub releases; upgrade_cli downloads and activates the newest litmus-cli. Needs no edge connection.
System, Network get_firewall_rules Return configured firewall rules: ports, protocols, ALLOW/DENY actions.
get_network_interface_info Network interface details: IP, MAC, gateway, link status, MTU, speed. Defaults to eth0.
get_packet_capture_interfaces List network interfaces available for packet capture.
get_packet_capture_status Current packet capture state and list of captured .pcap files with metadata.
start_packet_capture Start a packet capture on an interface. Duration 1-30 minutes.
stop_packet_capture Stop an in-progress packet capture.
Digital Twins list_digital_twin_models List all Digital Twin models with ID, name, description, and version.
create_digital_twin_model Create a new Digital Twin model.
list_digital_twin_instances List all Digital Twin instances or filter by model ID.
create_digital_twin_instance Create a new Digital Twin instance from an existing model.
list_static_attributes List static attributes (fixed key-value pairs) for a model, an instance (by id or name), or every instance at once (all_instances).
list_dynamic_attributes List dynamic attributes (real-time data points) for a model, an instance (by id or name), or every instance at once (all_instances).
list_transformations List data transformation rules configured for a Digital Twin model.
get_digital_twin_hierarchy Get the hierarchy configuration for a Digital Twin model.
save_digital_twin_hierarchy Save a new hierarchy configuration to a Digital Twin model.
Litmus Edge Manager (LEM) *** lem_list_devices List edge devices registered in a LEM project (paginated).
lem_get_device_details Full LEM-side record for a single edge device (versions, license, last seen, config).
lem_list_device_versions List Litmus Edge versions registered in a LEM project.
lem_list_device_groups List device group labels (project-level groupings) defined in a LEM project.
lem_get_license_expiry List devices whose license expires within the next N days.
lem_get_expired_licenses List devices in a LEM project whose license has already expired.
lem_dashboard_usage Project usage summary (device counts, license usage, deployment stats).
lem_get_project_alerts List active project-level alerts (device offline, license issues, etc.).
lem_list_companies List all companies on the LEM tenant with project/device/model counts.
lem_get_company_details Full details for a single company by name (teams, license, quotas).
lem_list_company_projects List all projects belonging to a given company.
lem_get_project_details Single-project details (timezone, data TTL, allocated slots, billing plan).
lem_deployment_info LEM tenant deployment info (version, build, release metadata).
lem_get_system_time LEM server clock; useful when comparing edge timestamps.
LEM Bridge *** lem_bridge_list_devicehub_devices List devicehub devices on a specific edge by tunneling through LEM (no active-instance switch).
lem_bridge_get_le_info Identity info (friendly name, cloud activation) for an edge via the LEM bridge.
SDK Fallback (CLI) **** litmus_sdk_discover Browse the full generated SDK catalog (~550 functions) by dotted-path prefix.
litmus_sdk_read Invoke a read-only SDK function (Get/List/Browse/...) by dotted path.
litmus_sdk_write Invoke a state-changing SDK function by dotted path. Approval-gated; potentially destructive.

Tool Use Notes

* NATS Topic Tools Requirements: To use get_current_value_from_topic and get_multiple_values_from_topic, you must configure access control on Litmus Edge:

  1. Navigate to: Litmus Edge → System → Access Control → Tokens
  2. Create or configure an access token with appropriate permissions
  3. Provide the token in your MCP client configuration headers

** InfluxDB / Time Series Tools Requirements: To use any tool marked with ** (get_historical_data_from_influxdb, list_influxdb_measurements, get_device_historical_data, query_tag_data, get_tag_statistics, get_device_data_for_inference, get_device_connection_status), you must allow InfluxDB port access:

  1. Navigate to: Litmus Edge -> System -> Network -> Firewall
  2. Add a firewall rule to allow port 8086 on TCP
  3. Ensure InfluxDB is accessible from the MCP server host
  4. Provide INFLUX_HOST, INFLUX_PORT, INFLUX_DB_NAME, INFLUX_USERNAME, INFLUX_PASSWORD in your MCP client headers

*** LEM Tools Requirements: LEM tools talk to a Litmus Edge Manager (cloud) tenant rather than a single edge. To use any tool marked with ***, provide these headers in your MCP client configuration:

  • EDGE_MANAGER_URL: Litmus Edge Manager base URL (include https://)
  • EDGE_API_TOKEN: API token issued by LEM
  • EDGE_MANAGER_PROJECT_ID (optional): default project id, used when a tool's project_id argument is omitted
  • EDGE_MANAGER_ADMIN_URL (optional): admin URL, defaults to the EDGE_MANAGER_URL host on port 8446

**** SDK Fallback Tools Requirements: litmus_sdk_discover, litmus_sdk_read, and litmus_sdk_write are backed by the standalone litmus-cli Go binary, as are the curated digital twin attribute and tag status tools. The Docker image installs it at build time, and run.sh installs or updates it automatically for local runs (checksum-verified into .venv/bin, pinned to the same version as the Docker image via the Dockerfile ARG LITMUS_CLI_VERSION). If the server is started without it (e.g. a bare python src/server.py), it self-installs the pinned release on first use: downloaded from the official releases, SHA256-verified, and cached under ~/.cache/litmus-mcp-server. Air-gapped hosts without GitHub access should pre-install the binary instead. To use a different binary, set LITMUS_CLI_PATH (skips all bootstrapping), or install one from the cli-v* releases at https://github.com/litmusautomation/litmus-sdk-releases/releases and put it on PATH. They expose the full generated SDK surface beyond the curated tools above. Notes:

  • Connection headers are forwarded to the CLI per call; no CLI profile is read or written.
  • litmus_sdk_read accepts only read-only functions (final segment starting with Get, List, Browse, Describe, Read, Search, Find, Query, or Count); everything else goes through litmus_sdk_write.
  • litmus_sdk_write can invoke destructive SDK functions (create/update/delete/restart). Every call requires explicit user approval via the user_approved argument, which the assistant may only set after you approve the exact function and arguments.
  • Prefer the dedicated tools above when one covers the operation.
  • VALIDATE_CERTIFICATE (optional): true to verify TLS certs on the LEM bridge (default false)

lem_bridge_* tools additionally tunnel through LEM to a specific edge and require both project_id and device_id as call arguments. The Web UI's Config -> Litmus Edge Manager page manages multiple LEM connections and writes these headers automatically.

Per-call LEM bridge routing for edge tools: When EDGE_MANAGER_URL is configured, every edge-targeting tool (DeviceHub, Digital Twins, system, marketplace, and the SDK fallback tools) additionally accepts optional project_id and device_id arguments. Passing both routes that single call to the corresponding managed edge through the LEM bridge, so a LEM-only configuration (URL + token, no EDGE_URL) can still use the full Litmus Edge toolset: the assistant discovers ids with lem_list_devices and then calls edge tools directly against any device in the fleet. EDGE_MANAGER_PROJECT_ID and EDGE_MANAGER_DEVICE_ID headers remain supported as static defaults.

CLI-backed curated tools: The digital twin attribute/transformation listing tools and the tag status tools are executed through the bundled litmus-cli binary (same connection layer as the SDK fallback tools) rather than the Python SDK, so devices or twins with unusual data no longer fail strict client-side validation, and LEM bridge routing applies uniformly.


Litmus Central

Download or try Litmus Edge via Litmus Central.


MCP server registries


© 2026 Litmus Automation, Inc. All rights reserved.