ESP RainMaker MCP Server
OfficialAllows interaction with ESP RainMaker IoT devices, enabling management of nodes, parameters, schedules, and groups via the Espressif cloud platform.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ESP RainMaker MCP Server list all my RainMaker devices"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ESP RainMaker MCP Server
This project provides a Model Context Protocol (MCP) server wrapper around the esp-rainmaker-cli Python library.
It allows MCP-compatible clients (like LLMs or applications such as Cursor, Claude Desktop, and Windsurf) to interact with your ESP RainMaker devices using the official CLI.
Introduction to Model Context Protocol (MCP)
The Model Context Protocol (MCP) is a standardized framework that enables AI systems to interact with external tools, data sources, and services in a unified manner. Introduced by Anthropic and adopted by major AI organizations, MCP acts as a universal interface, much like USB-C for hardware, allowing seamless integration across different platforms.
Key Benefits of MCP in ESP RainMaker
Unified Interaction: MCP allows AI models to access and control IoT devices using natural language prompts, making interactions more intuitive and accessible.
Real-time Control: With MCP, users can execute actions such as turning devices on/off, adjusting settings, and managing schedules directly through AI interfaces.
Local Server, Cloud-Backed Control: The ESP RainMaker MCP server runs locally and stores credentials on your machine. However, device management actions are performed via the official ESP RainMaker cloud APIs through the esp-rainmaker-cli.
By integrating MCP, the ESP RainMaker platform enhances its capabilities, allowing tools like Claude, Cursor, Windsurf, and Gemini CLI to manage IoT devices efficiently and securely.
Related MCP server: WiseVision/mcp_server_ros_2
Prerequisites
Python: Version 3.10 or higher
uv: The
uvPython package manager. Install from Astral's uv documentation.ESP RainMaker CLI Login: You must have successfully logged into ESP RainMaker using the standard
esp-rainmaker-cli logincommand in your terminal at least once. This server relies on the credentials saved by that process.RainMaker Nodes added into your account since onboarding isn't supported by the MCP server.
Installation & Setup
Clone the Repository:
git clone https://github.com/espressif/esp-rainmaker-mcp.git cd esp-rainmaker-mcpInstall Dependencies using uv: This command installs
esp-rainmaker-cli,mcp[cli], and any other dependencies listed inpyproject.tomlinto a virtual environment managed byuv.uv sync(This assumes
uvis installed)Login to ESP Rainmaker using
esp-rainmaker-cliuv run esp-rainmaker-cli login
Direct login via username/password within MCP is not supported for security reasons. Please use the standard CLI login flow first.
Client Configuration
To add this project as an MCP server in supported MCP clients (Cursor, Claude Desktop, Windsurf, and Gemini CLI), you'll need to add the same JSON configuration to each client's config file. The configuration is identical across all clients:
MCP Server Configuration (All Clients)
Use the following JSON configuration for all MCP clients:
{
"mcpServers": {
"ESP-RainMaker-MCP": {
"command": "uv",
"args": [
"run",
"--with",
"esp-rainmaker-cli",
"--with",
"mcp[cli]",
"mcp",
"run",
"<absolute_path_to_repo>/server.py"
]
}
}
}Replace<absolute_path_to_repo>/server.py with the actual absolute path to the server.py file within the cloned esp-rainmaker-mcp directory on your system.
Cursor MCP Server Setup
Open Cursor and click on the settings (gear icon) at the top right.
Navigate to "Tools & Integrations" from the settings menu.
Click on "MCP Tools" in the integrations section.
Click on "New MCP Server" to add a new server.
This will open the mcp.json file. Add the JSON configuration shown above.
Claude Desktop MCP Server Setup
Open Claude Desktop and go to Settings -> Developer -> Edit Config.
This will open the configuration file (claude_desktop_config.json). Add the JSON configuration shown above.
Save the changes and restart Claude Desktop to apply the new settings.
Windsurf MCP Server Setup
Open Windsurf and look for the hammer-type icon under the chat text input area.
Click on the hammer icon and select "Configure" from the options. This will open the plugins window.
Click on "View raw config" which will show you the
~/.codium/windsurf/mcp_config.jsonfile.Add the JSON configuration shown above to the file.
Save the changes and click on "Refresh" under the chat text window to load the ESP RainMaker MCP tools.
Gemini CLI MCP Server Setup
Locate your Gemini CLI settings file. On macOS, this is typically at
~/.gemini/settings.json.Open the
settings.jsonfile in your preferred text editor.Add the JSON configuration shown above to the
mcpServerssection of the file. If the section does not exist, create it as shown in the example.Save the file and restart Gemini CLI if it is running.
The configuration for all four applications (Cursor, Claude Desktop, Windsurf, and Gemini CLI) is the same, so you can use the same JSON structure for all of them.
The--with arguments ensure uv includes the necessary dependencies when running the mcp run command.
How it Works
This server acts as a bridge. It uses the mcp library to handle the Model Context Protocol communication. When a tool is called:
It uses functions from the installed
esp-rainmaker-clilibrary.The library functions read locally stored authentication tokens.
It makes the necessary API calls to the ESP RainMaker cloud.
It returns the results (or errors) back through the MCP protocol.
Available Tools
This MCP server exposes the following tools for interacting with ESP RainMaker:
Authentication & Configuration
login_instructions():Provides instructions (formatted with Markdown) on how to log in using the standard
esp-rainmaker-cli logincommand in your terminal. This server relies on the external CLI's browser-based login flow to securely store credentials. Rendering as Markdown depends on the MCP client's capabilities.
check_login_status():Checks if a valid login session exists based on credentials stored locally by
esp-rainmaker-cli. Confirms if the server can communicate with the ESP RainMaker backend.
Node Management
get_nodes():Lists all node IDs associated with the logged-in user.
get_node_details(node_id: str = None, fields: str = None, name: str = None, type_: str = None):Get detailed information for nodes including config, status, and params.
Supports filtering and field selection:
fields: comma-separated list of fields to include (e.g. "node_id,name,type,config,params,status.connectivity,fw_version,mapping_timestamp")name: substring match (user-visible name from params)type_: substring match (device type)node_id: single node ID (for one node) or None (for all)
Returns a dict (single node) or list of dicts (all nodes).
Example:
get_node_details(ctx, fields="node_id,name,type")
get_node_status(node_id: str):Get the online/offline connectivity status for a specific node ID.
get_params(node_id: str):Get current parameter values for a device.
set_params(node_id: str, params_dict: dict):Set parameters for one or more devices.
node_id: Single ID or comma-separated list (e.g., "light1,light2")params_dict: Parameters to set, e.g.,{"Light": {"Power": true}}
Schedule Management
get_schedules(node_id: str):Get schedules for a device.
set_schedule(node_id: str, operation: str, ...):Manage device schedules.
operation: "add", "edit", "remove", "enable", or "disable"For add/edit: Provide
name,trigger, andactionCommon triggers:
Daily 8 AM:
{"m": 480, "d": 127}Weekdays 6:30 PM:
{"m": 1110, "d": 31}
Example action:
{"Light": {"Power": true}}
Group Management (Home/Room Hierarchy)
create_group(name: str, group_type: str = None, ...):Create a home or room.
Required:
name,group_type("home" or "room")For rooms:
parent_group_idrequiredExample:
create_group("Living Room", "room", parent_group_id="home_id")
get_group_details(group_id: str = None, include_nodes: bool = False):Get group information. For all groups, use
group_id=None.Set
include_nodes=Trueto include device details.Returns: Group hierarchy, members, and metadata.
update_group(group_id: str, ...):Update group properties or manage devices.
Optional:
name,description,add_nodes,remove_nodesExamples:
Rename:
update_group("group_id", name="New Name")Add devices:
update_group("group_id", add_nodes="light1,light2")
add_device_to_room(device_node_id: str, room_group_id: str):Add device to room (handles parent group automatically).
Example:
add_device_to_room("light1", "kitchen_id")
License
This project is licensed under the terms specified in the LICENSE file.
Available Tools
13 toolsadd_device_to_roomA
Add a device to a room with automatic parent group handling.
This function automatically handles the ESP RainMaker hierarchy requirement:
First adds the device to the parent group (e.g., "My Home")
Then adds the device to the target room group (e.g., "Kitchen")
Parameters:
device_node_id: The node ID of the device to add
room_group_id: The group ID of the room to add the device to
This is a convenience function that makes the hierarchical behavior explicit.
Inputs: device_node_id (required), room_group_id (required). Returns: result
check_login_statusA
Checks if a valid login session exists based on stored credentials.
Inputs: no named parameters. Returns: result
create_groupA
Create a new group (home, room, or custom group) using Python library API.
Parameters:
name: Name of the group (required)
group_type: Type of group ('home', 'room', or custom type)
description: Description of the group (optional)
mutually_exclusive: Set mutually exclusive flag (recommended for homes and rooms)
parent_group_id: Parent group ID (required for rooms under a home)
nodes: Comma-separated list of node IDs to add to the group (optional)
custom_data: Custom data as JSON string (optional)
Examples:
Create home: create_group("My Home", "home", mutually_exclusive=True)
Create room: create_group("Living Room", "room", mutually_exclusive=True, parent_group_id="home_id")
Inputs: name (required), group_type, description, mutually_exclusive, +3 more. Returns: result
get_group_detailsA
Get comprehensive group information using Python library API.
Parameters:
group_id: ID of specific group to show (optional - if None, lists all groups)
include_nodes: Include detailed node information for groups
fields: List of group/sub-group keys to include (if None, includes all fields)
node_fields: List of node keys to include (if None, includes all node fields)
When group_id is None: Lists all groups with hierarchy When group_id is provided: Shows detailed information for that specific group When include_nodes is True: Includes comprehensive node details within groups
IMPORTANT USAGE GUIDELINES:
For home/room structure overview (recommended for most queries):
{ "include_nodes": true, "fields": ["group_id", "group_name", "type", "total", "sub_groups", "node_details"], "node_fields": ["node_id", "name", "type"] }For home/room structure with basic device info:
{ "include_nodes": true, "fields": ["group_id", "group_name", "type", "total", "sub_groups", "node_details"], "node_fields": ["node_id", "name", "type", "model", "fw_version"] }For detailed technical information:
{ "include_nodes": true, "fields": ["group_id", "group_name", "type", "total", "sub_groups", "node_details", "is_matter", "fabric_id", "primary", "mutually_exclusive"], "node_fields": ["node_id", "name", "type", "model", "fw_version", "status", "params"] }
Common Use Cases:
Query Type | Recommended Fields |
"Show my home" | Basic fields (option 1) to avoid large responses |
"List my devices" | Basic fields (option 1) for clear device listing |
"Check my rooms" | Basic fields (option 1) for room structure |
"Device details" | Detailed fields (option 3) for full information |
Note: When fields/node_fields are not provided, defaults to summary mode (basic fields) to avoid overwhelming responses.
Inputs: group_id, include_nodes, fields, node_fields. Returns: result
get_node_detailsA
PREFERRED TOOL for getting comprehensive node information efficiently. Gets config, status, and params in a single API call instead of multiple separate calls.
USAGE:
To get all nodes: set
node_id=None(default).To get a single node: set
node_idto a single node ID string.Only a single node ID is supported. Do NOT use a comma-separated list or array.
If the node is not found or not accessible, the result will be an empty dict or contain empty/unknown fields.
FILTERING & FIELD SELECTION:
fields: comma-separated list of fields to include in the output (e.g. "node_id,name,type,config,params,status.connectivity,fw_version,mapping_timestamp").name: substring match (matches user-visible name, extracted from params.{DeviceType}.Name).type_: substring match (matches device type, from config.devices[].type).node_id: single node ID string (for a single node), or None (for all nodes).
MULTIPLE NODE FILTERING:
To filter for multiple node IDs, set
node_id=Noneand use filtering (e.g. by name or type) in post-processing.Passing a comma-separated list of node IDs is NOT supported and will result in an error.
RETURN VALUE:
If a single node is requested, returns a dict (or empty dict if not found).
If all nodes are requested, returns a list of dicts (one per node).
EXAMPLES:
Get all nodes, only node_id and name: get_node_details(ctx, fields="node_id,name")
Get a single node by ID: get_node_details(ctx, node_id="30EDA0E0AF48", fields="node_id,name,config")
Get all nodes of type 'lightbulb': get_node_details(ctx, type_="lightbulb", fields="node_id,name,type")
Inputs: node_id, fields, name, type_. Returns: result
get_nodesA
Get ONLY the list of node IDs (names) without detailed information.
Use this tool only when:
User specifically asks for "node IDs", "device names", or "list of devices"
You need just the names/IDs for reference
For comprehensive device information, use get_node_details instead.
Inputs: no named parameters. Returns: result
get_node_statusA
Get ONLY the online/offline status for a specific node.
Use this tool only when:
User specifically asks about "status", "online", "offline" of a particular device
You already have other info and need just the status
For comprehensive device information, use get_node_details instead.
Inputs: node_id (required). Returns: result
get_paramsA
Get ONLY the current parameters (state) for a specific node.
Use this tool only when:
User specifically asks for "parameters", "state", or "current values" of a particular device
You already have other info and need just the current state
For comprehensive device information, use get_node_details instead.
Inputs: node_id (required). Returns: result
get_schedulesA
Get schedule information for a specific node. Returns the schedules configured for the node if any exist, along with support status.
Response includes:
schedules_supported: Whether the node supports scheduling
schedules: Array of schedule objects with trigger and action details
schedule_count: Number of configured schedules
Each schedule object contains:
id: Unique schedule identifier
name: Human-readable schedule name
enabled: Whether the schedule is active
triggers: Array of trigger conditions (format explained below)
action: What the schedule will do when triggered
TRIGGER FORMAT GUIDE (for understanding schedule responses):
"m": Minutes since midnight (0-1439). Example: 480 = 8:00 AM, 1110 = 6:30 PM
"d": Day bitmap for which days to trigger:
31 = Weekdays (Mon-Fri)
96 = Weekends (Sat-Sun)
127 = Every day
0 = One-time only
Individual days: 1=Mon, 2=Tue, 4=Wed, 8=Thu, 16=Fri, 32=Sat, 64=Sun
"dd": Day of month (1-31)
"mm": Month bitmap (4095 = all months)
"rsec": Relative seconds from creation time
"ts": Exact Unix timestamp when schedule was created or will trigger
Example: {"m": 1110, "d": 31} means "6:30 PM on weekdays"
NOTE: Schedule actions use device type names (like "Light") not display names. See get_node_details for the mapping between device types and their display names.
Inputs: node_id (required). Returns: result
login_instructionsA
Provides instructions (formatted with Markdown) on how to log in using the standard ESP RainMaker CLI. This server relies on credentials saved locally by that process. Rendering as Markdown depends on the MCP client capabilities.
Inputs: no named parameters. Returns: result
set_paramsA
Set parameters for one or more nodes using a JSON object (dictionary).
Parameters:
node_id: Single node ID or comma-separated list of node IDs (e.g., "node1" or "node1,node2,node3")
params_dict: Dictionary containing the parameters to set
Example params_dict value: {'Thermostat': {'Power': False}}
When multiple node IDs are provided, the same parameters will be applied to all specified nodes. This is useful for bulk operations like turning off multiple devices or setting common configurations.
Inputs: node_id (required), params_dict (required). Returns: result
set_scheduleA
Manage schedules for one or more nodes.
Parameters:
node_id: Single node ID or comma-separated list of node IDs (e.g., "node1" or "node1,node2,node3")
operation: Operation to perform (add, edit, remove, enable, disable)
schedule_id: Schedule ID (required for edit, remove, enable, disable operations)
name: Schedule name (required for add operation, optional for edit)
trigger: Dictionary defining when to trigger (required for add, optional for edit)
action: Dictionary defining what to do (required for add, optional for edit)
info: Additional information for the schedule (optional)
flags: General purpose flags for the schedule (optional)
When multiple node IDs are provided:
For 'add' operations: Creates the same schedule on all specified nodes with a common schedule ID
For 'edit/remove/enable/disable' operations: Applies the operation to the specified schedule on all nodes
This is useful for bulk schedule management across multiple devices
TRIGGER FORMAT GUIDE: Time-based triggers use these fields:
"m": Minutes since midnight (0-1439). Example: 480 = 8:00 AM, 1110 = 6:30 PM
"d": Day bitmap for which days to trigger:
31 = Weekdays (Mon-Fri)
96 = Weekends (Sat-Sun)
127 = Every day
0 = One-time only
Individual days: 1=Mon, 2=Tue, 4=Wed, 8=Thu, 16=Fri, 32=Sat, 64=Sun
"dd": Day of month (1-31)
"mm": Month bitmap (4095 = all months)
"rsec": Relative seconds from now
"ts": Exact Unix timestamp
COMMON TRIGGER EXAMPLES:
Daily 8:00 AM: {"m": 480, "d": 127}
Weekdays 6:30 PM: {"m": 1110, "d": 31}
Weekends 10:00 AM: {"m": 600, "d": 96}
One-time 7:00 PM: {"m": 1140, "d": 0}
15th of every month at noon: {"m": 720, "dd": 15, "mm": 4095}
In 1 hour: {"rsec": 3600}
ACTION EXAMPLES:
Turn on light: {"Light": {"Power": true}}
Set brightness: {"Light": {"Power": true, "Brightness": 80}}
Control thermostat: {"Thermostat": {"Power": true, "Temperature": 22}}
NOTE: Action keys use device type names (like "Light") not display names. Use get_node_details to see device types in config.devices[].name.
Inputs: node_id (required), operation (required), schedule_id, name, +4 more. Returns: result
update_groupA
Edit an existing group's properties and manage nodes using Python library API.
Parameters:
group_id: ID of the group to edit (required)
name: New name for the group (optional)
description: New description for the group (optional)
custom_data: New custom data as JSON string (optional)
add_nodes: Comma-separated list of node IDs to add to the group (optional)
remove_nodes: Comma-separated list of node IDs to remove from the group (optional)
At least one parameter must be provided.
Inputs: group_id (required), name, description, custom_data, +2 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Each tool has a clearly distinct purpose, even those that seem similar (e.g., get_nodes vs get_node_details vs get_node_status vs get_params) are well-differentiated with explicit usage guidance in descriptions. The convenience function add_device_to_room is distinct from create_group and update_group.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., create_group, get_node_details, set_params). Even login_instructures, while noun_verb, is a clear action. No mixing of conventions.
With 13 tools, the server is well-scoped for the ESP RainMaker domain. The count is within the recommended range, covering login, groups, nodes, and schedules without unnecessary duplication.
The tool surface covers core CRUD for groups and nodes (create, read, update) and schedule management (add, edit, remove, enable, disable). However, missing operations like delete_group and delete_node represent minor gaps that agents might encounter.
Maintenance
Related MCP Connectors
Manage CloudPepper servers, Odoo instances, backups, and deployments over MCP.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Tailscale device, route, DNS, key, user, and ACL management over MCP and CLI.
Manage Nife.io cloud apps, sites, secrets and Git integrations from MCP clients.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables users to control Govee LED devices using the Govee API, with features for turning devices on/off, setting colors, and adjusting brightness through a CLI or MCP clients.6MIT
- AlicenseNot gradedqualityBmaintenancePublic implementation of MCP for ROS 2 enabling to interact with system visible various robots, capable of: List available topics List available services Call service Subscribe topic to get messages Publish message on topic and more98Mozilla Public 2.0
- FlicenseNot gradedqualityDmaintenanceEnables interaction with The Things Industries LoRaWAN platform via MCP tools, supporting application, device, gateway, and webhook management.1-
- FlicenseNot gradedqualityCmaintenanceEnables agents to connect to remote MCP servers once, access their tools through a compact MCP endpoint, pair a CLI inside sandboxes, and create watches that turn command or tool output into pollable structured events.2-