Skip to content

Commit ed5bff4

Browse files
author
Alex J Lennon
committed
Release v0.4.0: Enhanced device list with filtering, summary stats, and test equipment support
- Device list now returns brief summary first (always visible) then full table - Added filtering by type, status, and search query - Added summary statistics (counts by type/status/SSH status) - Added test equipment detection and querying tools (list_test_equipment, query_test_equipment) - Added last seen timestamps and power switch relationships to device list - Improved cache with atomic writes and thread-safe locking - Updated help documentation with new features and best practices - Optimized device discovery with parallel SSH identification
1 parent 8cbfa5b commit ed5bff4

11 files changed

Lines changed: 1088 additions & 289 deletions

File tree

CHANGELOG.md

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

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

5+
## [0.4.0] - 2025-11-17
6+
7+
### Added
8+
- **Device List Summary Display**: `list_devices` now returns a brief summary first (always visible without expanding) followed by the full detailed table
9+
- **Device Filtering**: `list_devices` supports filtering by `device_type_filter`, `status_filter`, and `search_query` for quick device discovery
10+
- **Summary Statistics**: Device list includes summary statistics showing counts by type, status, and SSH status
11+
- **Test Equipment Detection**: Automatic detection of test equipment (DMMs, oscilloscopes) via SCPI protocol on common ports (5025, 5024, 3490, 3491)
12+
- **Test Equipment Tools**: New `list_test_equipment` and `query_test_equipment` tools for managing and querying test equipment with SCPI commands
13+
- **Last Seen Timestamps**: Device list displays "Last Seen" timestamps showing when each device was last successfully identified
14+
- **Power Switch Relationships**: Device list shows which power switch (Tasmota device) controls each device
15+
- **Friendly Name Management**: `update_device_friendly_name` tool to update friendly names for discovered devices in cache
16+
17+
### Fixed
18+
- **Device List Visibility**: Fixed device list display in Cursor by returning brief summary as separate TextContent item (always visible)
19+
- **Cache Thread Safety**: Improved cache operations with atomic file writes and thread-safe locking to prevent race conditions during parallel device discovery
20+
- **Cache Corruption**: Fixed cache corruption issues by using temporary files and `os.replace` for atomic writes
21+
- **Tasmota Detection Persistence**: Fixed Tasmota detection results being overwritten by ensuring proper cache merging
22+
23+
### Changed
24+
- **Device Discovery Optimization**: Further optimized device discovery with parallel SSH identification for uncached devices
25+
- **SSH User Priority**: SSH authentication now prioritizes "fio" user, then "root" for device identification
26+
- **Device List Format**: Enhanced device list with additional columns (Last Seen, Power Switch) and improved formatting
27+
- **Help Documentation**: Updated help documentation with new features, workflows, and best practices
28+
529
## [0.3.0] - 2025-11-17
630

731
### Added

README.md

Lines changed: 5 additions & 4 deletions
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.3.0
10+
**Version**: 0.4.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
@@ -146,17 +146,18 @@ Data flow: AI → MCP Server → Tools → Lab Framework → Hardware
146146

147147
## Tools
148148

149-
- **Device**: `list_devices`, `test_device`, `ssh_to_device`
149+
- **Device**: `list_devices` (with filtering, summary stats, power state), `test_device`, `ssh_to_device`, `verify_device_identity`, `verify_device_by_ip`, `update_device_ip`, `update_device_friendly_name`
150150
- **VPN**: `vpn_status`, `connect_vpn`, `disconnect_vpn`
151151
- **Power**: `start_power_monitoring` (DMM or Tasmota), `get_power_logs`, `analyze_power_logs`, `monitor_low_power`, `compare_power_profiles` - Power monitoring via DMM (SCPI) or Tasmota energy monitoring
152-
- **Tasmota**: `tasmota_control`, `list_tasmota_devices`, `power_cycle_device` - Power cycle devices via Tasmota switches
152+
- **Tasmota**: `tasmota_control`, `list_tasmota_devices`, `power_cycle_device` - Power cycle devices via Tasmota switches. Tasmota devices show power state (ON/OFF) and consumption (Watts) in device list
153+
- **Test Equipment**: `list_test_equipment`, `query_test_equipment` - Auto-detect and query test equipment (DMM, oscilloscopes) via SCPI protocol
153154
- **OTA/Containers**: `check_ota_status`, `trigger_ota_update`, `list_containers`, `deploy_container`, `get_system_status`, `get_firmware_version`, `get_foundries_registration_status`, `get_secure_boot_status`, `get_device_identity`
154155
- **Process Management**: `kill_stale_processes` - Kill duplicate processes that might interfere
155156
- **Remote Access**: `create_ssh_tunnel`, `list_ssh_tunnels`, `close_ssh_tunnel`, `access_serial_port`, `list_serial_devices` - SSH tunnels and serial port access
156157
- **Change Tracking**: `get_change_history`, `revert_changes` - Track and revert changes for security/debugging
157158
- **Batch/Regression**: `batch_operation`, `regression_test`, `get_device_groups`
158159
- **Network Mapping**: `create_network_map` - Visual map of network with device type, uptime, friendly names, power switches
159-
- **Device Verification**: `verify_device_identity`, `verify_device_by_ip`, `update_device_ip` - Verify device identity in DHCP environments
160+
- **Device Verification**: `verify_device_identity`, `verify_device_by_ip`, `update_device_ip` - Verify device identity in DHCP environments. Device list shows SSH status, last seen timestamps, and power switch relationships
160161
- **Help**: `help` - Get usage documentation and examples
161162

162163
## Resources

lab_testing/resources/help.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def get_help_content() -> Dict[str, Any]:
1212
"""Get comprehensive help documentation"""
1313
return {
1414
"overview": "MCP server for remote embedded hardware testing in lab environment",
15-
"version": "0.1.0",
15+
"version": "0.4.0",
1616
"usage": {
1717
"basic": "Ask AI assistant to use tools (e.g., 'List devices in the lab', 'Connect to VPN')",
1818
"examples": [
@@ -26,9 +26,13 @@ def get_help_content() -> Dict[str, Any]:
2626
},
2727
"tools": {
2828
"device_management": {
29-
"list_devices": "List all configured lab devices with status, IPs, and types",
30-
"test_device": "Test connectivity to a device (ping and SSH check)",
31-
"ssh_to_device": "Execute SSH command on a device (requires device_id, command, optional username)",
29+
"list_devices": "List all devices with status, IPs, types, firmware, SSH status, last seen, and power switches. Returns brief summary (always visible) then full table. Supports filtering by device_type_filter, status_filter, search_query. Includes summary statistics (counts by type/status/SSH status). Shows Tasmota power state/consumption and test equipment detection.",
30+
"test_device": "Test connectivity to a device (ping and SSH check). Best practice: Use before running operations on devices. In DHCP environments, use verify_device_identity to ensure correct device.",
31+
"ssh_to_device": "Execute SSH command on a device (requires device_id, command, optional username). Best practice: Test device connectivity first with test_device.",
32+
"verify_device_identity": "Verify device identity at given IP matches expected device (important for DHCP). Updates IP in config if verified and changed.",
33+
"verify_device_by_ip": "Identify which device (if any) is at a given IP address by checking hostname/unique ID.",
34+
"update_device_ip": "Verify device identity and update IP address in config if device is verified and IP has changed (for DHCP environments).",
35+
"update_device_friendly_name": "Update friendly name for a discovered device in the cache. Allows custom names when referencing devices.",
3236
},
3337
"vpn_management": {
3438
"vpn_status": "Get current WireGuard VPN connection status",
@@ -41,7 +45,12 @@ def get_help_content() -> Dict[str, Any]:
4145
},
4246
"tasmota_control": {
4347
"tasmota_control": "Control Tasmota power switch (device_id, action: on|off|toggle|status|energy)",
44-
"list_tasmota_devices": "List all configured Tasmota devices",
48+
"list_tasmota_devices": "List all configured Tasmota devices and the devices they control",
49+
"power_cycle_device": "Power cycle a device by controlling its Tasmota power switch (turns off, waits, then turns on). Optional: off_duration (default: 5 seconds).",
50+
},
51+
"test_equipment": {
52+
"list_test_equipment": "List all test equipment devices (DMM, oscilloscopes, etc.) found on the network. Includes both configured devices and auto-discovered devices.",
53+
"query_test_equipment": "Send a SCPI command to test equipment (DMM, etc.) and get the response. Common commands: *IDN? (identify), MEAS:VOLT:DC? (measure DC voltage), MEAS:CURR:DC? (measure DC current). Supports device_id from config or IP address.",
4554
},
4655
"ota_management": {
4756
"check_ota_status": "Check Foundries.io OTA update status (device_id)",
@@ -62,7 +71,7 @@ def get_help_content() -> Dict[str, Any]:
6271
"power_analysis": {
6372
"analyze_power_logs": "Analyze power logs for low power/suspend detection (test_name?, device_id?, threshold_mw?)",
6473
"monitor_low_power": "Monitor device for low power consumption (device_id, duration?, threshold_mw?, sample_rate?)",
65-
"compare_power_profiles": "Compare power consumption across test runs (test_names[], device_id?)",
74+
"compare_power_profiles": "Compare power consumption across multiple test runs (test_names[], device_id?). Visualizes differences between test sessions.",
6675
},
6776
},
6877
"resources": {
@@ -81,8 +90,18 @@ def get_help_content() -> Dict[str, Any]:
8190
"common_workflows": {
8291
"check_lab_status": [
8392
"1. Use 'vpn_status' to check VPN connection",
84-
"2. Use 'list_devices' to see available devices",
85-
"3. Use 'test_device' to verify connectivity",
93+
"2. Use 'list_devices' to see available devices (shows brief summary first, then full table)",
94+
"3. Filter devices: 'list_devices(device_type_filter=\"tasmota_device\")' or 'list_devices(status_filter=\"online\")'",
95+
"4. Search devices: 'list_devices(search_query=\"192.168.2.18\")'",
96+
"5. Use 'test_device' to verify connectivity",
97+
],
98+
"device_discovery": [
99+
"1. Devices are automatically discovered via network scanning",
100+
"2. Tasmota devices detected via HTTP API (port 80)",
101+
"3. Test equipment (DMM) detected via SCPI ports (5025, 5024, 3490, 3491)",
102+
"4. Device information cached to speed up subsequent scans",
103+
"5. Use 'list_devices' to see all discovered devices with their status",
104+
"6. Update friendly names: 'update_device_friendly_name(ip, friendly_name)'",
86105
],
87106
"remote_device_access": [
88107
"1. Ensure VPN connected (use 'connect_vpn' if needed)",
@@ -121,9 +140,11 @@ def get_help_content() -> Dict[str, Any]:
121140
},
122141
"troubleshooting": {
123142
"vpn_not_connecting": "Check VPN config exists, may require NetworkManager or sudo",
124-
"device_not_found": "Verify device_id in device inventory (use list_devices)",
125-
"ssh_fails": "Check SSH keys configured, device online, VPN connected",
143+
"device_not_found": "Verify device_id in device inventory (use list_devices). In DHCP environments, use verify_device_identity to ensure correct device.",
144+
"ssh_fails": "Check SSH keys configured, device online, VPN connected. SSH authentication prioritizes 'fio' user, then 'root'. Check SSH status in device list.",
126145
"tools_fail": "Verify lab_testing_root path correct, underlying scripts work",
146+
"device_list_not_visible": "Device list returns brief summary first (always visible), then full table. If not visible, restart MCP server connection.",
147+
"cache_errors": "Device cache uses atomic writes and thread-safe locking. If errors occur, cache may be corrupted - clear cache directory and rescan.",
127148
},
128149
"best_practices": [
129150
"Always check VPN status before accessing lab devices",
@@ -135,6 +156,12 @@ def get_help_content() -> Dict[str, Any]:
135156
"For low power: set appropriate threshold_mw, monitor for sufficient duration",
136157
"For regression: organize devices by tags/groups, use batch operations",
137158
"Tag devices in config for easy rack management and grouping",
159+
"Use list_devices filters to quickly find specific devices (type, status, search)",
160+
"Device list shows brief summary first - always visible without expanding",
161+
"In DHCP environments: verify device identity before operations, use update_device_ip if IP changed",
162+
"Device discovery is optimized with parallel SSH identification and caching",
163+
"Tasmota devices show power state and consumption in device list",
164+
"Test equipment (DMM) can be queried with SCPI commands via query_test_equipment",
138165
],
139166
"foundries_io_integration": {
140167
"device_config": "Add 'fio_factory', 'fio_target', 'fio_current' to device config",

lab_testing/server/tool_definitions.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,33 @@ def get_all_tools() -> List[Tool]:
1717
return [
1818
Tool(
1919
name="list_devices",
20-
description="List all configured lab devices with their status",
21-
inputSchema={"type": "object", "properties": {}, "required": []},
20+
description=(
21+
"List all devices on the target network with their status, firmware, and relationships. "
22+
"Supports filtering by type, status, and search queries. Includes summary statistics."
23+
),
24+
inputSchema={
25+
"type": "object",
26+
"properties": {
27+
"device_type_filter": {
28+
"type": "string",
29+
"description": "Filter by device type (e.g., 'tasmota_device', 'eink_board', 'test_equipment', 'sentai_board')",
30+
},
31+
"status_filter": {
32+
"type": "string",
33+
"description": "Filter by status (e.g., 'online', 'offline', 'discovered')",
34+
},
35+
"search_query": {
36+
"type": "string",
37+
"description": "Search by IP address, hostname, friendly name, or device ID (case-insensitive)",
38+
},
39+
"show_summary": {
40+
"type": "boolean",
41+
"description": "Include summary statistics (counts by type/status) in response (default: true)",
42+
"default": True,
43+
},
44+
},
45+
"required": [],
46+
},
2247
),
2348
Tool(
2449
name="test_device",
@@ -291,6 +316,29 @@ def get_all_tools() -> List[Tool]:
291316
description="List all configured Tasmota devices and the devices they control",
292317
inputSchema={"type": "object", "properties": {}, "required": []},
293318
),
319+
Tool(
320+
name="list_test_equipment",
321+
description="List all test equipment devices (DMM, oscilloscopes, etc.) found on the network. Includes both configured devices and auto-discovered devices.",
322+
inputSchema={"type": "object", "properties": {}, "required": []},
323+
),
324+
Tool(
325+
name="query_test_equipment",
326+
description="Send a SCPI command to test equipment (DMM, etc.) and get the response. Common commands: *IDN? (identify), MEAS:VOLT:DC? (measure DC voltage), MEAS:CURR:DC? (measure DC current)",
327+
inputSchema={
328+
"type": "object",
329+
"properties": {
330+
"device_id_or_ip": {
331+
"type": "string",
332+
"description": "Device ID from config or IP address of the test equipment",
333+
},
334+
"scpi_command": {
335+
"type": "string",
336+
"description": "SCPI command to send (e.g., '*IDN?', 'MEAS:VOLT:DC?')",
337+
},
338+
},
339+
"required": ["device_id_or_ip", "scpi_command"],
340+
},
341+
),
294342
Tool(
295343
name="power_cycle_device",
296344
description="Power cycle a device by controlling its Tasmota power switch (turns off, waits, then turns on)",

0 commit comments

Comments
 (0)