Skip to content

Commit 8cbfa5b

Browse files
author
Alex J Lennon
committed
Release v0.3.0: Tasmota power display, device detection, and SSH fixes
- Added Tasmota power state and consumption display in device list - Added automatic Tasmota and test equipment detection - Added device cache system for faster discovery - Added SSH status display with detailed error information - Fixed Tasmota detection bug (timeout parameter) - Fixed SSH authentication and credential caching - Fixed cache race conditions and error handling - Improved device type detection and identification - Optimized parallel device discovery
1 parent 5aa0833 commit 8cbfa5b

20 files changed

+2608
-115
lines changed

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
[Semantic Versioning](https://semver.org/)
44

5+
## [0.3.0] - 2025-11-17
6+
7+
### Added
8+
- **Tasmota Power State Display**: Tasmota devices now show power state (ON/OFF) and power consumption (Watts) in the device list
9+
- **Enhanced Device Detection**: Automatic detection of Tasmota devices and test equipment (DMMs) via network protocols
10+
- **Device Type Detection**: Improved device type inference from hostname patterns (eink, sentai boards)
11+
- **SSH Status Display**: Device list now shows detailed SSH connection status (OK, Timeout, Refused, Auth Failed)
12+
- **Firmware Version Display**: Device list displays firmware version information from `/etc/os-release`
13+
- **VPN Discovery Indicator**: Devices discovered over VPN are marked with a VPN indicator
14+
- **Device Cache System**: JSON-based caching of device information (hostname, unique ID, firmware) to reduce repeated SSH queries
15+
- **Friendly Name Management**: Ability to update friendly names for discovered devices via `update_device_friendly_name` tool
16+
- **Parallel Device Identification**: Optimized device discovery with parallel SSH identification attempts
17+
18+
### Fixed
19+
- **Tasmota Detection Bug**: Fixed timeout parameter in Tasmota HTTP API detection (was incorrectly passed to Request instead of urlopen)
20+
- **SSH Authentication**: Fixed credential caching to use correct function signature (username/password parameters)
21+
- **SSH Error Handling**: Fixed cache to re-verify devices with SSH errors but no hostname instead of returning stale errors
22+
- **Cache Race Conditions**: Fixed cache merge logic to preserve successful identifications and prevent failures from overwriting successes
23+
- **Host Key Verification**: Improved SSH host key handling with `StrictHostKeyChecking=accept-new` for new/changed host keys
24+
- **Device Type Detection**: Fixed device type detection to properly use cached Tasmota/test equipment detection results
25+
- **Cache Persistence**: Tasmota and test equipment detection results are now properly saved to persistent cache
26+
27+
### Changed
28+
- **Device List Format**: Device list now displays as a markdown table with improved readability
29+
- **Device Discovery**: Optimized device discovery to check all devices for Tasmota/test equipment detection, not just uncached ones
30+
- **SSH Credential Priority**: SSH authentication now prioritizes "fio" user over "root" for device identification
31+
532
## [0.2.0] - 2025-11-16
633

734
### Changed

README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
MCP server exposing remote embedded hardware testing capabilities to AI assistants.
99

10-
**Version**: 0.2.0
10+
**Version**: 0.3.0
1111

1212
> **⚠️ ALPHA QUALITY WARNING**: This package is currently in **alpha** development status. It is **not ready for professional or production use**. The API may change, features may be incomplete, and there may be bugs. Use at your own risk. See [PUBLISHING.md](PUBLISHING.md) for more details.
1313
@@ -41,6 +41,8 @@ python3.10 lab_testing/test_server.py
4141

4242
## Configuration
4343

44+
### MCP Server Configuration
45+
4446
Add to Cursor MCP config (`~/.cursor/mcp.json`):
4547

4648
```json
@@ -60,6 +62,46 @@ Add to Cursor MCP config (`~/.cursor/mcp.json`):
6062

6163
**Important:** Use `python3.10` (or `python3.11+`) since MCP SDK requires Python 3.10+.
6264

65+
### Target Network Configuration
66+
67+
Configure the target network for lab testing operations:
68+
69+
**Option 1: Environment Variable** (in `~/.cursor/mcp.json`):
70+
```json
71+
{
72+
"mcpServers": {
73+
"ai-lab-testing": {
74+
"command": "python3.10",
75+
"args": ["/path/to/ai-lab-testing/lab_testing/server.py"],
76+
"env": {
77+
"LAB_TESTING_ROOT": "/path/to/ai-lab-testing",
78+
"TARGET_NETWORK": "192.168.2.0/24"
79+
}
80+
}
81+
}
82+
}
83+
```
84+
85+
**Option 2: Config File** (in `lab_devices.json`):
86+
```json
87+
{
88+
"lab_infrastructure": {
89+
"network_access": {
90+
"target_network": "192.168.2.0/24",
91+
"lab_networks": ["192.168.2.0/24"]
92+
}
93+
}
94+
}
95+
```
96+
97+
**Default**: `192.168.2.0/24` if not configured.
98+
99+
### Tool Timeouts
100+
101+
Some tools like `create_network_map` may take longer than 30 seconds for full network scans. If tool calls timeout:
102+
- Use `quick_mode: true` to skip network scanning (completes in <5s)
103+
- Network scanning has been optimized with faster timeouts and increased parallelism
104+
63105
### VPN Setup
64106

65107
The server auto-detects WireGuard VPN configs. If you don't have one:

docs/SETUP.md

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,33 @@ Uses existing lab testing framework:
2727

2828
- `LAB_TESTING_ROOT`: Path to lab testing framework (default: `/data_drive/esl/ai-lab-testing`)
2929
- `VPN_CONFIG_PATH`: Path to WireGuard config file (optional, auto-detected if not set)
30+
- `TARGET_NETWORK`: Target network for lab testing operations (default: `192.168.2.0/24`)
31+
- `MCP_DEV_MODE`: Enable development mode with auto-reload (set to `1`, `true`, or `yes` to enable)
32+
33+
### Target Network Configuration
34+
35+
The target network determines which network is used for lab testing operations. It can be configured in three ways (priority order):
36+
37+
1. **Environment Variable**: Set `TARGET_NETWORK` environment variable
38+
```bash
39+
export TARGET_NETWORK=192.168.2.0/24
40+
```
41+
42+
2. **Config File**: Add to `lab_devices.json`:
43+
```json
44+
{
45+
"lab_infrastructure": {
46+
"network_access": {
47+
"target_network": "192.168.2.0/24",
48+
"lab_networks": ["192.168.2.0/24"]
49+
}
50+
}
51+
}
52+
```
53+
54+
3. **Default**: `192.168.2.0/24` (if not configured)
55+
56+
The `lab_networks` list can contain multiple networks for scanning, but `target_network` specifies the primary network for lab operations.
3057

3158
### VPN Configuration
3259

@@ -51,7 +78,10 @@ Add to `~/.cursor/mcp.json`:
5178
"ai-lab-testing": {
5279
"command": "python3.10",
5380
"args": ["/absolute/path/to/lab_testing/server.py"],
54-
"env": {"LAB_TESTING_ROOT": "/data_drive/esl/ai-lab-testing"}
81+
"env": {
82+
"LAB_TESTING_ROOT": "/data_drive/esl/ai-lab-testing",
83+
"MCP_DEV_MODE": "1"
84+
}
5585
}
5686
}
5787
}
@@ -61,7 +91,30 @@ Add to `~/.cursor/mcp.json`:
6191

6292
Or use installed package: `"command": "python3.10", "args": ["-m", "lab_testing.server"]`
6393

64-
Restart Cursor.
94+
### Development Mode (Auto-Reload)
95+
96+
During development, you can enable auto-reload so that code changes are picked up automatically without restarting Cursor. This is especially useful when modifying tool handlers or network mapping code.
97+
98+
**To enable:** Add `"MCP_DEV_MODE": "1"` to the `env` section in your MCP configuration (as shown above).
99+
100+
**How it works:**
101+
- The server checks for file changes before each tool call
102+
- Modified Python modules are automatically reloaded using `importlib.reload()`
103+
- No need to restart Cursor after making code changes
104+
- Reloaded modules are logged for debugging
105+
106+
**Note:** Auto-reload only works for modules in the `lab_testing` package. Changes to `server.py` itself still require a restart.
107+
108+
Restart Cursor after initial setup.
109+
110+
### Tool Call Timeouts
111+
112+
**Note:** Some tools (like `create_network_map`) may take longer than 30 seconds if they perform network scans. Cursor has a default 30-second timeout for MCP tool calls.
113+
114+
**Solutions:**
115+
1. **Use Quick Mode**: For `create_network_map`, set `quick_mode: true` to skip network scanning and only show configured devices (completes in <5 seconds).
116+
2. **Optimized Scanning**: The network scanner has been optimized with faster ping timeouts (0.5s) and increased parallelism (100 workers) to reduce scan time.
117+
3. **Client Timeout**: Currently, there's no way to configure the MCP client timeout in Cursor's `mcp.json`. The timeout is hardcoded in the Cursor client. If you need full network scans, consider running the tool directly via Python or use quick mode for faster results.
65118

66119
## Verification
67120

lab_testing/config.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
# If not set, searches common locations
2828
VPN_CONFIG_PATH_ENV = os.getenv("VPN_CONFIG_PATH")
2929

30+
# Target network configuration - can be overridden via TARGET_NETWORK environment variable
31+
# Default target network for lab testing operations
32+
DEFAULT_TARGET_NETWORK = os.getenv("TARGET_NETWORK", "192.168.2.0/24")
33+
3034

3135
def get_lab_devices_config() -> Path:
3236
"""Get path to lab devices configuration file"""
@@ -99,6 +103,72 @@ def get_logs_dir() -> Path:
99103
return LOGS_DIR
100104

101105

106+
def get_target_network() -> str:
107+
"""
108+
Get the target network for lab testing operations.
109+
110+
Priority:
111+
1. TARGET_NETWORK environment variable
112+
2. Value from lab_devices.json config file (if exists)
113+
3. Default: 192.168.2.0/24
114+
115+
Returns:
116+
Network CIDR string (e.g., "192.168.2.0/24")
117+
"""
118+
# Check environment variable first
119+
env_network = os.getenv("TARGET_NETWORK")
120+
if env_network:
121+
return env_network
122+
123+
# Check config file
124+
try:
125+
if LAB_DEVICES_JSON.exists():
126+
import json
127+
with open(LAB_DEVICES_JSON) as f:
128+
config = json.load(f)
129+
infrastructure = config.get("lab_infrastructure", {})
130+
network_access = infrastructure.get("network_access", {})
131+
target_network = network_access.get("target_network")
132+
if target_network:
133+
return target_network
134+
except Exception:
135+
# If config read fails, fall back to default
136+
pass
137+
138+
# Default target network
139+
return DEFAULT_TARGET_NETWORK
140+
141+
142+
def get_lab_networks() -> list[str]:
143+
"""
144+
Get list of lab networks for scanning.
145+
146+
Priority:
147+
1. Networks from lab_devices.json config file
148+
2. TARGET_NETWORK environment variable (as single-item list)
149+
3. Default: [target_network]
150+
151+
Returns:
152+
List of network CIDR strings
153+
"""
154+
# Check config file first
155+
try:
156+
if LAB_DEVICES_JSON.exists():
157+
import json
158+
with open(LAB_DEVICES_JSON) as f:
159+
config = json.load(f)
160+
infrastructure = config.get("lab_infrastructure", {})
161+
network_access = infrastructure.get("network_access", {})
162+
lab_networks = network_access.get("lab_networks")
163+
if lab_networks and isinstance(lab_networks, list):
164+
return lab_networks
165+
except Exception:
166+
pass
167+
168+
# Fall back to target network
169+
return [get_target_network()]
170+
171+
102172
def validate_config() -> tuple:
103173
"""Validate that required configuration files exist"""
104174
errors = []

lab_testing/server.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import sys
1616
import time
1717
import uuid
18-
from typing import Any, Dict, List
18+
from typing import Any, Dict, List, Union
1919

2020
# MCP SDK imports
2121
# Note: MCP SDK structure may vary - adjust imports based on actual SDK version
@@ -59,6 +59,13 @@
5959
setup_logger()
6060
logger = get_logger()
6161

62+
# Development mode: Set up auto-reload
63+
try:
64+
from lab_testing.server.dev_reload import setup_auto_reload
65+
setup_auto_reload()
66+
except ImportError:
67+
pass # dev_reload module not available
68+
6269
# Initialize MCP server
6370
server = Server("ai-lab-testing-mcp")
6471

@@ -82,7 +89,7 @@ async def handle_list_tools() -> List[Tool]:
8289

8390

8491
@server.call_tool()
85-
async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:
92+
async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[Union[TextContent, ImageContent]]:
8693
"""Handle tool execution requests"""
8794
request_id = str(uuid.uuid4())[:8]
8895
start_time = time.time()

0 commit comments

Comments
 (0)