SmartThingsMCP
A comprehensive FastMCP 2.0 server and client for interacting with SmartThings devices, locations, rooms, modes, scenes, and automation rules through the SmartThings API.
SmartThingsMCP Server and Client
A comprehensive FastMCP 2.0 server and client for interacting with SmartThings devices, locations, rooms, modes, scenes, and automation rules through the SmartThings API.
Overview
SmartThingsMCP provides:
- FastMCP 2.0 Server: Exposes SmartThings API functionality as MCP tools
- Smart Client: Python client with intelligent caching, async support, and multiple transport options
- Modular Architecture: Organized by functionality (devices, locations, rooms, modes, scenes, rules)
- Two-Level Caching: Both client and server-side caching for optimal performance
- Multiple Transports: HTTP, SSE (Server-Sent Events), and STDIO support
- OAuth 2.0 Authentication: Secure token-based authentication with SmartThings API
Components
Server
- SmartThingsMCPServer.py: FastMCP 2.0 server exposing SmartThings API as MCP tools
- modules/server/: Server tool implementations
devices.py: Device management tools (list, get, update, delete, execute commands, etc.)locations.py: Location management tools (create, read, update, delete locations and rooms)rooms.py: Room management tools (list, create, update, delete rooms)modes.py: Mode management tools (list, get, set location modes)scenes.py: Scene management tools (list, get, execute, create, update, delete scenes)rules.py: Automation rule tools (list, get, create, update, delete, execute rules)structure_tools.py: Structure generation tools for LLM integrationcommon.py: Shared utilities for API requests, URL building, and parameter filtering
Client
- SmartThingsMCPClient.py: CLI for interacting with the MCP server
- modules/client/: Client implementation
main.py: Main SmartThingsMCPClient class combining all mixinsbase.py: BaseClient with transport handling and tool invocationcache.py: CacheMixin with LRU caching, TTL management, and cache statisticsdevices.py: DevicesMixin with device operation methodslocations.py: LocationsMixin with location and room methodsrooms.py: RoomsMixin with room-specific methodsmodes.py: ModesMixin with mode management methodsrules.py: RulesMixin with rule management methodsscenes.py: ScenesMixin with scene management methodsutils.py: Utility functions for tool conversion and action executionutils_ext.py: Extended utilities (note: currently unused)
API Endpoints
SmartThingsMCP exposes the following API endpoints as MCP tools:
Device Management
- list_devices: Get a list of all devices (supports filtering by capability, location, room, or device ID)
- get_device: Get details of a specific device
- update_device: Update a device's label
- delete_device: Delete a device
- execute_command: Execute a command on a device component
- get_device_status: Get the current status of a device
- get_device_components: Get all components of a device
- get_device_capabilities: Get capabilities of a device component
- get_device_health: Get the health/connectivity status of a device
- get_device_presentation: Get the UI presentation details of a device
Location Management
- list_locations: Get a list of all locations
- get_location: Get details of a specific location
- create_location: Create a new location with coordinates and address information
- update_location: Update location details (name, coordinates, address)
- delete_location: Delete a location
- get_location_rooms: Get all rooms in a location (convenience method)
Room Management
- list_rooms: Get all rooms in a location
- get_room: Get details of a specific room
- create_room: Create a new room in a location
- update_room: Update a room's name
- delete_room: Delete a room from a location
Mode Management
- list_modes: Get all available modes for a location
- get_mode: Get details of a specific mode
- get_current_mode: Get the currently active mode for a location
- set_mode: Change the current mode for a location
Scene Management
- list_scenes: Get all scenes (optionally filtered by location)
- get_scene: Get details of a specific scene
- execute_scene: Execute/run a scene
- create_scene: Create a new scene with actions and visual properties
- update_scene: Update an existing scene (name, icon, colors, actions)
- delete_scene: Delete a scene
Rule Management
- list_rules: Get all automation rules (optionally filtered by location)
- get_rule: Get details of a specific rule
- create_rule: Create a new automation rule with conditions and actions
- update_rule: Update an existing rule (name, triggers, actions, enabled state)
- delete_rule: Delete an automation rule
- execute_rule: Manually trigger execution of a rule
Features
Intelligent Caching
Both the SmartThingsMCPClient and SmartThingsMCPServer include comprehensive caching to improve performance:
Client-Side Caching
The SmartThingsMCPClient provides:
- Automatic caching of read-only operations (list_devices, list_locations, etc.)
- TTL-based expiration (default: 5 minutes, configurable)
- Smart cache invalidation on write operations (execute_command, update_device, etc.)
- LRU eviction when cache is full
- Cache statistics tracking (hits, misses, hit rate)
- Green visual feedback:
✓ Cache hit: list_locations
See CACHING.md for detailed documentation.
Server-Side Caching
The SmartThingsMCPServer provides:
- Automatic caching of all GET requests to SmartThings API
- TTL-based expiration (default: 5 minutes)
- Full cache invalidation on write operations (POST, PUT, DELETE)
- LRU eviction when cache is full
- Cache statistics tracking
- Green visual feedback:
✓ Server cache hit: GET devices
See SERVER_CACHING.md for detailed documentation.
Two-Level Caching: When both client and server caching are active, you get maximum performance with two layers of caching!
Performance Benefits:
- 60-80% reduction in API calls
- 5-10x faster response times for cached data
- Lower rate limit usage
Rule Management
The server provides comprehensive rule management capabilities:
- list_rules: List all automation rules for a location
- get_rule: Get details of a specific rule
- create_rule: Create a new automation rule with conditions and actions
- update_rule: Update an existing rule (name, triggers, actions, or enabled state)
- delete_rule: Delete a rule
- execute_rule: Manually execute a rule
Enable/Disable Rules:
# Disable a rule
client.update_rule(auth=token, rule_id="abc-123", enabled=False)
# Enable a rule
client.update_rule(auth=token, rule_id="abc-123", enabled=True)
The enabled parameter was added in December 2025 to support toggling rule state without deleting the rule.
Installation
Prerequisites
- Python 3.8 or higher
- pip or another Python package manager
Setup
- Install dependencies:
pip install -r requirements.txt
Required packages:
fastmcp>=2.0.0: FastMCP 2.0 framework for MCP server/clientrequests>=2.28.0: HTTP library for SmartThings API calls
- Obtain a SmartThings API Token:
- Visit SmartThings Developer Portal
- Create a new API token with the following scopes:
r:devices:*(read devices)w:devices:*(control devices)r:locations:*(read locations)w:locations:*(create/update locations)r:rules:*(read rules, requires Enterprise account)w:rules:*(write rules, requires Enterprise account)r:scenes:*(read scenes)x:scenes:*(execute scenes)
Authentication
SmartThingsMCP uses OAuth 2.0 bearer tokens for authentication with the SmartThings API.
Token Requirements
- Must be a valid SmartThings API token (OAuth 2.0 bearer token)
- Token must have appropriate scopes for the operations you want to perform
- Token never expires when obtained from the SmartThings Developer Portal
- Keep your token secure and never commit it to version control
Common Authentication Issues
401 Unauthorized:
Error calling tool list_devices: 401 Unauthorized
- Verify the token is valid and not expired
- Check that the token has been generated from SmartThings Developer Portal
- Ensure you're passing the token with the
--authflag
403 Forbidden:
Error calling tool list_devices: 403 Forbidden
- The token exists but lacks required scopes
- Some features (like Rules) require an Enterprise SmartThings account
- Grant additional scopes to the token in SmartThings Developer Portal
Scopes Required by Feature
| Feature | Required Scopes |
|---|---|
| List/Get Devices | r:devices:* |
| Control Devices | w:devices:* |
| List/Get Locations | r:locations:* |
| Create/Update/Delete Locations | w:locations:* |
| List/Get Scenes | r:scenes:* |
| Execute Scenes | x:scenes:* |
| Create/Update/Delete Scenes | w:scenes:* |
| List/Get Rules | r:rules:* |
| Create/Update/Delete Rules | w:rules:* |
| List/Get/Set Modes | r:locations:* |
Getting Started
Starting the Server
- Start the SmartThingsMCP server:
# Start with HTTP transport (default) on port 8000
python SmartThingsMCPServer.py
# Custom port
python SmartThingsMCPServer.py -port 9000
# Using SSE transport
python SmartThingsMCPServer.py -transport sse
# Using STDIO transport
python SmartThingsMCPServer.py -transport stdio
# With auth token override (if needed)
python SmartThingsMCPServer.py -auth YOUR_TOKEN
Using the Command-Line Client
The SmartThingsMCPClient.py provides a CLI interface:
# List available tools
python SmartThingsMCPClient.py --transport http --port 8000 --action list_tools
# List all devices (requires auth token)
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_devices
# List devices with pretty-printed output
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_devices --pretty
# Get a specific device
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action get_device --params '{"device_id": "DEVICE_ID"}'
# Get device status
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action get_device_status --params '{"device_id": "DEVICE_ID"}'
# Execute a device command
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action execute_command --params '{
"device_id": "DEVICE_ID",
"component": "main",
"capability": "switch",
"command": "on"
}'
# List all locations
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_locations
# List all scenes
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_scenes
# Execute a scene
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action execute_scene --params '{"scene_id": "SCENE_ID"}'
# Create a new location
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action create_location --params '{
"name": "Office",
"country_code": "US",
"region_code": "CA",
"locality": "San Francisco"
}'
# List all modes for a location
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_modes --params '{"location_id": "LOCATION_ID"}'
# Set mode for a location
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action set_mode --params '{
"location_id": "LOCATION_ID",
"mode_id": "MODE_ID"
}'
# List all rules
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action list_rules
# Enable/disable a rule
python SmartThingsMCPClient.py --auth YOUR_TOKEN --action update_rule --params '{
"rule_id": "RULE_ID",
"enabled": false
}'
Client Options
--host: MCP server host (default: localhost)
--port: MCP server port (default: 8000)
--auth: SmartThings API authentication token (required for most operations)
--transport: Transport type - http, sse, or stdio (default: http)
--action: Action/tool to execute (required)
--params: JSON string of parameters for the action (default: {})
--pretty: Pretty-print JSON output (flag)
Using Python Client Programmatically
import asyncio
from modules.client.main import SmartThingsMCPClient
async def main():
# Create client with caching enabled (default)
client = SmartThingsMCPClient(
host="localhost",
port=8000,
auth_token="YOUR_TOKEN",
transport="http",
enable_cache=True, # Enable automatic caching
cache_ttl=300, # Cache for 5 minutes
max_cache_size=1000 # Store up to 1000 cache entries
)
# List all devices
devices = await client.list_devices(auth="YOUR_TOKEN")
print(f"Found {len(devices['items'])} devices")
# Get specific device
device = await client.get_device(auth="YOUR_TOKEN", device_id="DEVICE_ID")
print(f"Device: {device['label']}")
# Execute device command
result = await client.execute_command(
auth="YOUR_TOKEN",
device_id="DEVICE_ID",
component="main",
capability="switch",
command="on"
)
# List locations
locations = await client.list_locations(auth="YOUR_TOKEN")
for loc in locations['items']:
print(f"Location: {loc['name']}")
# List and execute scenes
scenes = await client.list_scenes(auth="YOUR_TOKEN")
if scenes['items']:
scene_id = scenes['items'][0]['sceneId']
await client.execute_scene(auth="YOUR_TOKEN", scene_id=scene_id)
# Manage rules
rules = await client.list_rules(auth="YOUR_TOKEN")
for rule in rules['items']:
print(f"Rule: {rule['name']} - Enabled: {rule.get('enabled', True)}")
# Check cache statistics (when caching is enabled)
if hasattr(client, 'get_cache_stats'):
stats = client.get_cache_stats()
print(f"Cache hits: {stats['hits']}, misses: {stats['misses']}")
if __name__ == "__main__":
asyncio.run(main())
Troubleshooting
Transport Configuration
SmartThingsMCP supports three transport mechanisms for client-server communication:
HTTP Transport (Recommended for most use cases)
- Default port: 8000
- URL pattern:
http://localhost:8000/mcp - Best for: External integrations, LLM tools, web services
- Advantages:
- Simple HTTP/REST interface
- Easy to debug with standard tools
- Compatible with most firewalls
- Stateless connections
# Server
python SmartThingsMCPServer.py -transport http -port 8000
# Client
python SmartThingsMCPClient.py --transport http --port 8000
SSE Transport (Server-Sent Events)
- Default port: 8000
- URL pattern:
http://localhost:8000/sse - Best for: Real-time updates, event streaming, server push
- Advantages:
- Bidirectional communication
- Event-driven architecture
- Lower latency for updates
# Server
python SmartThingsMCPServer.py -transport sse -port 8000
# Client
python SmartThingsMCPClient.py --transport sse --port 8000
STDIO Transport (Direct integration)
- No network overhead
- Best for: Direct Python integration, embedded systems
- Advantages:
- No port/network configuration needed
- Direct process communication
- Lowest latency
# Server (runs in foreground)
python SmartThingsMCPServer.py -transport stdio
# Client
python SmartThingsMCPClient.py --transport stdio
Client Configuration
Cache Configuration
The SmartThingsMCPClient includes intelligent caching with full control:
client = SmartThingsMCPClient(
host="localhost",
port=8000,
auth_token="YOUR_TOKEN",
enable_cache=True, # Enable caching
cache_ttl=300, # TTL in seconds (default: 5 min)
max_cache_size=1000 # Max entries (default: 1000)
)
# Get cache statistics
stats = client.get_cache_stats()
print(f"Hit rate: {stats['hit_rate']:.2%}")
# Clear cache manually
client.clear_cache()
Cacheable Operations (automatic caching):
- list_devices
- get_device
- list_locations
- get_location
- list_rooms
- get_room
- list_modes
- get_mode
- get_current_mode
- list_scenes
- get_scene
- list_rules
- get_rule
Cache-Invalidating Operations (automatic cache clearing):
- update_device
- delete_device
- execute_command
- create_location
- update_location
- delete_location
- create_room
- update_room
- delete_room
- set_mode
- create_scene
- update_scene
- delete_scene
- create_rule
- update_rule
- delete_rule
- execute_rule
- execute_scene
Logging
SmartThingsMCP uses Python's standard logging module:
import logging
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('smartthings_mcp')
# Create client - will now output detailed logs
client = SmartThingsMCPClient(...)
Log levels:
DEBUG: Detailed diagnostic informationINFO: General informational messages (default)WARNING: Warning messagesERROR: Error messagesCRITICAL: Critical errors
Common Errors and Solutions
Common Errors and Solutions
Connection Errors
Error: Client failed to connect: Session terminated
Error calling tool list_devices: Client failed to connect: Session terminated
Causes and solutions:
- Server is not running: Start the server with
python SmartThingsMCPServer.py - Wrong transport type: Ensure client and server use same transport (http, sse, or stdio)
- Wrong port: Verify port matches between client and server
- Wrong host: Check hostname/IP address is correct
- Network/firewall: Ensure port is open and accessible
Debugging:
# Check if server is running on expected port
netstat -tuln | grep 8000
# Test HTTP connectivity
curl http://localhost:8000/mcp
# View server logs
python SmartThingsMCPServer.py 2>&1 | head -20
Authentication Errors
Error: 1 validation error for list_devicesArguments: auth: Field required
Error executing tool list_devices: 1 validation error for list_devicesArguments
auth: Field required
Solutions:
- Provide auth token with
--auth YOUR_TOKENflag - Ensure token is valid: verify in SmartThings Developer Portal
- Check token has not expired
- Verify token has required scopes
Example:
python SmartThingsMCPClient.py --auth "YOUR_VALID_TOKEN" --action list_devices
Error: 401 Unauthorized
Error calling tool list_devices: 401 Unauthorized
Solutions:
- Token is invalid or expired
- Token format is incorrect (must be OAuth 2.0 bearer token)
- Generate new token from SmartThings Developer Portal
Error: 403 Forbidden
Error calling tool create_rule: 403 Forbidden - Access Denied
Solutions:
- Token lacks required scopes for the operation
- SmartThings account doesn't have access to feature (e.g., Rules API requires Enterprise)
- Grant additional scopes in SmartThings Developer Portal
API Response Errors
Error: Device not found
{
"error": "Device not found",
"message": "No device found with ID: invalid-id"
}
Solutions:
- Device ID doesn't exist
- Device has been deleted
- List devices first to get valid IDs:
list_devicesaction
Error: Invalid component or capability
{
"error": "Component not found",
"message": "Component 'main' not found on device"
}
Solutions:
- Check valid components: Use
get_device_componentsto list available components - Check valid capabilities: Use
get_device_capabilitieswith correct component_id - Device doesn't support the command you're trying to execute
Rate Limiting
Error: 429 Too Many Requests
Error calling tool list_devices: 429 Too Many Requests
Solutions:
- SmartThings API rate limit exceeded
- Enable caching to reduce API calls (enabled by default)
- Increase cache TTL to keep data longer
- Implement request throttling in your code
Check cache effectiveness:
stats = client.get_cache_stats()
print(f"Cache hits: {stats['hits']}")
print(f"Cache misses: {stats['misses']}")
print(f"Hit rate: {stats['hit_rate']:.2%}")
Cache Issues
Problem: Stale data in cache
Solutions:
- Reduce cache TTL:
cache_ttl=60(1 minute) - Manually clear cache:
client.clear_cache() - Disable cache if data must be real-time:
enable_cache=False
Problem: Cache causing high memory usage
Solutions:
- Reduce max cache size:
max_cache_size=100 - Reduce cache TTL to expire entries sooner
- Periodically clear cache:
client.clear_cache()
Advanced Usage
Custom Tool Implementation
You can extend SmartThingsMCP with custom tools by modifying the server modules:
# In modules/server/devices.py, add:
@server_instance.tool()
def custom_device_operation(auth: str, device_id: str) -> Dict[str, Any]:
"""Your custom operation description"""
# Your implementation here
return make_request(auth, "GET", build_device_url(device_id))
Integration with LLMs
SmartThingsMCP tools are designed to work with Language Models:
# Get formatted tool descriptions for LLM
tools = await client.list_tools()
tool_descriptions = [
{
"name": tool["name"],
"description": tool["description"],
"params": tool["parameters"]
}
for tool in tools
]
Error Handling
import asyncio
async def safe_device_operation():
client = SmartThingsMCPClient(
host="localhost",
port=8000,
auth_token="YOUR_TOKEN"
)
try:
result = await client.get_device(
auth="YOUR_TOKEN",
device_id="DEVICE_ID"
)
return result
except ValueError as e:
print(f"Invalid input: {e}")
except ConnectionError as e:
print(f"Connection failed: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
asyncio.run(safe_device_operation())
Performance Optimization
-
Enable caching (default: enabled):
# Already enabled by default client = SmartThingsMCPClient(enable_cache=True) -
Adjust cache TTL for your use case:
# More frequent updates needed client = SmartThingsMCPClient(cache_ttl=60) # 1 minute # Stable data, longer TTL client = SmartThingsMCPClient(cache_ttl=900) # 15 minutes -
Use appropriate transport:
- HTTP: Best for most scenarios
- STDIO: Best latency for local integration
- SSE: Best for real-time updates
-
Batch operations:
# Get all data at once rather than in loops devices = await client.list_devices(auth=token) for device in devices['items']: # Use data from the single list_devices call # Don't call get_device for each one if not needed
API Response Format
All API responses follow a consistent structure:
Success response:
{
"items": [...],
"pageProperties": {
"currentPage": 1,
"pageSize": 50,
"totalCount": 100
}
}
Single item response:
{
"id": "unique-id",
"label": "Device Name",
"deviceTypeId": "type-id"
}
Error response:
{
"requestId": "request-id",
"errors": [
{
"code": "INVALID_PARAMETER",
"message": "Detailed error message"
}
]
}
Example Scripts
Monitor Device Status
import asyncio
from modules.client.main import SmartThingsMCPClient
async def monitor_devices(token):
client = SmartThingsMCPClient(auth_token=token)
# Get all devices
devices = await client.list_devices(auth=token)
for device in devices['items']:
try:
status = await client.get_device_status(
auth=token,
device_id=device['deviceId']
)
print(f"{device['label']}: {status}")
except Exception as e:
print(f"Error getting status for {device['label']}: {e}")
asyncio.run(monitor_devices("YOUR_TOKEN"))
Control Multiple Devices
import asyncio
from modules.client.main import SmartThingsMCPClient
async def control_devices(token, device_ids, command):
client = SmartThingsMCPClient(auth_token=token)
for device_id in device_ids:
try:
result = await client.execute_command(
auth=token,
device_id=device_id,
component="main",
capability="switch",
command=command
)
print(f"Device {device_id}: {result}")
except Exception as e:
print(f"Error controlling {device_id}: {e}")
asyncio.run(control_devices("YOUR_TOKEN", ["device1", "device2"], "on"))
Scene Execution
import asyncio
from modules.client.main import SmartThingsMCPClient
async def execute_morning_routine(token):
client = SmartThingsMCPClient(auth_token=token)
# Get morning scene
scenes = await client.list_scenes(auth=token)
morning_scene = next(
(s for s in scenes['items'] if 'morning' in s.get('sceneName', '').lower()),
None
)
if morning_scene:
result = await client.execute_scene(
auth=token,
scene_id=morning_scene['sceneId']
)
print(f"Executed scene: {result}")
asyncio.run(execute_morning_routine("YOUR_TOKEN"))
Environment Variables
You can optionally use environment variables for common settings:
export SMARTTHINGS_TOKEN="your-token-here"
export MCP_SERVER_HOST="localhost"
export MCP_SERVER_PORT="8000"
export MCP_TRANSPORT="http"
API Reference
Complete API reference is available through the MCP tools system. List all available tools:
python SmartThingsMCPClient.py --action list_tools --pretty
This will display all available tools with their parameters and descriptions.
Contributing
When extending SmartThingsMCP:
- Follow the existing module structure
- Add tools to appropriate module (devices.py, locations.py, etc.)
- Include proper docstrings with parameter and return descriptions
- Test with the client
- Update README.md with new tool documentation
License
See LICENSE file for license information.
Related Servers
SwitchBot MCP Server
Control SwitchBot devices interactively using the SwitchBot API.
MCP Minecraft Remote
Remotely control a Minecraft Java Edition server using the Model Context Protocol (MCP).
Cred Protocol
On-chain credit scoring, financial reporting, and identity verification for Ethereum addresses. Get credit scores (300-1000), portfolio values, and identity attestations.
F1 MCP Server
Provides advanced Formula 1 data analysis, including real-time telemetry, tire performance, weather prediction, and race strategy simulation.
CYAN ARROW Trading System
A high-performance trading system for Claude Desktop, providing real-time market data via Tiingo and optional Telegram alerts.
Robust Long‑Term Memory
A persistent, human‑like memory system for AI companions
Fibrous MCP Server
A server for Fibrous Finance, a DeFi aggregation platform.
teckel navigation toolbox
Give LLM/AI/Agents the ability to provide accurate navigation information (time & place, road-trips, general aviation).
SO-ARM100 Robot Control with MCP
Control SO-ARM100 and LeKiwi robot arms using LLM-based AI agents.
OSINT MCP
Real-time OSINT intelligence platform for global security monitoring.