Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
FROM python:3.12-slim
LABEL authors="Litmus Automation, Inc."
LABEL description="Litmus MCP Server - SSE-based Model Context Protocol server for Litmus Edge"


# Install system dependencies
RUN apt-get update && apt-get install -y \
build-essential curl \
build-essential \
curl \
&& rm -rf /var/lib/apt/lists/*

# Install uv for fast package management
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
COPY --from=ghcr.io/astral-sh/uv:latest /uvx /bin/uvx

# Set working directory
WORKDIR /app

COPY . .
RUN uv venv && uv sync --all-groups
# Copy project files
COPY pyproject.toml uv.lock ./
COPY src ./src
COPY run.sh ./

# Install dependencies using uv
RUN uv venv && uv sync --frozen

# Activate virtual environment
ENV PATH="/app/.venv/bin:$PATH"

#CMD python src/server.py --transport=sse & python src/webclient.py src/server.py && wait
# Expose the MCP server port (default 8000)
EXPOSE 8000

# Make run script executable
RUN chmod +x run.sh

# Run the server
CMD ["./run.sh"]
149 changes: 124 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The official [Litmus Automation](https://litmus.io) **Model Context Protocol (MC
- [Getting Started](#getting-started)
- [Quick Launch (Docker)](#quick-launch-docker)
- [Cursor IDE Setup](#cursor-ide-setup)
- [API](#api)
- [Tools](#available-tools)
- [Usage](#usage)
- [Server-Sent Events (SSE)](#server-sent-events-sse)
- [Litmus Central](#litmus-central)
Expand All @@ -52,7 +52,7 @@ The official [Litmus Automation](https://litmus.io) **Model Context Protocol (MC
Run the server in Docker:

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

### Cursor IDE Setup
Expand All @@ -63,36 +63,79 @@ Example `mcp.json` configuration:
{
"mcpServers": {
"litmus-mcp-server": {
"url": "http://<IP Address>:8000/sse"
"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_USER": "<access_token_username>",
"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>"
}
}
}
}
```

**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)
- `NATS_USER` / `NATS_PASSWORD`: Access token credentials from **System → Access Control → Tokens**
- `INFLUX_HOST`: Litmus Edge IP (no http/https)
- `INFLUX_USERNAME` / `INFLUX_PASSWORD`: DataHub user credentials

See the [Cursor docs](https://docs.cursor.com/context/model-context-protocol) for more info.

---

## API
## Available Tools

| Category | Function Name | Description |
|---------------------------|----------------------------------------|-------------|
| **Edge System Config** | `get_current_environment_config` | Get current environment configuration used for Litmus Edge connectivity. |
| | `update_environment_config` | Update environment variable config for connecting to Litmus Edge. |
| | `get_current_config` | Retrieve current Litmus Edge instance configuration. |
| | `update_config` | Update configuration of the device or container running Litmus Edge. |
| **DeviceHub** | `get_litmusedge_driver_list` | List supported Litmus Edge drivers. |
| | `get_devicehub_devices` | List devices configured in DeviceHub. |
| | `get_devicehub_device_tags` | Retrieve tags for a specific DeviceHub device. |
| | `get_current_value_of_devicehub_tag` | Get current value of a specific device tag. |
| | `create_devicehub_device` | Register a new DeviceHub device. Supports various protocols and templates for register-based data polling. |
| **Device Identity** | `get_litmusedge_friendly_name` | Retrieve the user-friendly name of the device. |
| | `set_litmusedge_friendly_name` | Assign or update the friendly name. |
| **LEM Integration** | `get_cloud_activation_status` | Check cloud activation and Litmus Edge Manager (LEM) connection status. |
| **Docker Management** | `get_all_containers_on_litmusedge` | List all containers on Litmus Edge. |
| | `run_docker_container_on_litmusedge` | Launch a Docker container via Litmus Edge Marketplace (not the MCP host). |
| **Topic Subscription** | `get_current_value_on_topic` | Subscribe to current values on a Litmus Edge topic. Use global `NATS_STATUS = False` to unsubscribe. |
| | `get_multiple_values_from_topic` | Retrieve multiple values from a topic for plotting or batch access. |
| **DeviceHub** | `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_devicehub_device_tags` | Retrieve all tags (data points/registers) for a specific device. |
| | `get_current_value_of_devicehub_tag` | Read the current real-time value of a specific device tag. |
| **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. |
| **LEM Integration** | `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** ** | `get_historical_data_from_influxdb` | Query historical time-series data from InfluxDB by measurement and time range. |
| **Digital Twins** | `list_digital_twin_models` | List all Digital Twin models with ID, name, description, and version. |
| | `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 or instance. |
| | `list_dynamic_attributes` | List dynamic attributes (real-time data points) for a model or instance. |
| | `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. |

### Configuration 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 Tools Requirements:**
To use `get_historical_data_from_influxdb`, 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

---

Expand Down Expand Up @@ -126,7 +169,21 @@ Add to `~/.cursor/mcp.json` or `.cursor/mcp.json`:
{
"mcpServers": {
"litmus-mcp-server": {
"url": "http://<IP Address>:8000/sse"
"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_USER": "<access_token_username>",
"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>"
}
}
}
}
Expand All @@ -144,7 +201,21 @@ Add to `claude_desktop_config.json`:
{
"mcpServers": {
"litmus-mcp-server": {
"url": "http://<IP Address>:8000/sse"
"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_USER": "<access_token_username>",
"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>"
}
}
}
}
Expand All @@ -158,14 +229,28 @@ Add to `claude_desktop_config.json`:

#### Manual Configuration

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

```json
{
"mcpServers": {
"litmus-mcp-server": {
"url": "http://<IP Address>:8000/sse"
"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_USER": "<access_token_username>",
"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>"
}
}
}
}
Expand All @@ -185,7 +270,21 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
{
"mcpServers": {
"litmus-mcp-server": {
"url": "http://<IP Address>:8000/sse"
"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_USER": "<access_token_username>",
"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>"
}
}
}
}
Expand Down
27 changes: 13 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[project]
name = "litmus-mcp-server"
version = "0.1.0"
description = "Litmus MCP Server and client combo"
description = "Litmus MCP Server"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.12",
"jinja2>=3.1.6",
"influxdb>=5.3.2",
"litmussdk",
"mcp[cli]>=1.8.0",
"nats-py>=2.10.0",
"numpy>=2.2.5",
"mcp[cli]>=1.17.0",
"nats-py>=2.11.0",
"numpy>=2.3.4",
"pandas>=2.3.3",
"python-multipart>=0.0.20",
]

Expand All @@ -19,18 +19,17 @@ cve-patches = [
"h11>=0.16.0",
]
lint = [
"black>=25.1.0",
"black>=25.9.0",
"radon>=6.0.1",
"ruff>=0.11.4",
"ruff>=0.14.0",
]
llm-sdks = [
"anthropic>=0.49.0",
"openai-agents>=0.0.13",
]
test = []
test = [
"pytest>=8.4.2",
]


[tool.uv.sources]
litmussdk = { url = "https://github.com/litmusautomation/litmus-sdk-releases/releases/download/1.0.0/litmussdk-1.0.0-py3-none-any.whl" }
litmussdk = { url = "https://github.com/litmusautomation/litmus-sdk-releases/releases/download/1.1.1/litmussdk-1.1.1-py3-none-any.whl" }

[tool.ruff]
exclude = [
Expand Down
13 changes: 3 additions & 10 deletions run.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
#!/bin/bash
set -e

# Start server
mcp run src/server.py --transport=sse &
SERVER_PID=$!

# Start web client
python src/web_client.py src/server.py &
CLIENT_PID=$!

# Wait for both
wait $SERVER_PID $CLIENT_PID
# Start the MCP server directly with Python
# The server uses uvicorn internally and runs on port 8000 by default
python src/server.py
24 changes: 0 additions & 24 deletions src/cli_client.py

This file was deleted.

Loading