Fix get_mgr() to use ctx.lifespan_context (works in both request
and standalone Client mode). Add autouse fixture to reset
event-loop-bound singleton state per test, preventing cross-test
asyncio.Event contamination.
21 new tests exercise all 14 tools through FastMCP's in-memory
transport. New shortcuts: network_status (NetworkManager),
battery_status (UPower), bluetooth_devices (bluez),
kwin_windows (KRunner WindowsRunner). 53 tests pass.
- Add asyncio.wait_for timeout (30s) to all D-Bus calls
- Add asyncio.Lock to BusManager.get_bus to prevent race conditions
- Convert recursive tree walk to bounded BFS with visited set, max depth (20), max nodes (500)
- Add input validation for D-Bus names and object paths at tool boundary
- Standardize error handling (RuntimeError, TimeoutError) across all tools
- Catch JSONDecodeError in deserialize_args and set_property
- Check arg count matches signature in deserialize_args
- Add explicit variant wrapping via {"signature": "ai", "value": [1,2,3]}
- Narrow resource exception handling from Exception to (RuntimeError, OSError)
- Guard disconnect_all per-bus to avoid partial cleanup on error
- Audit log system bus calls and all set_property calls to stderr
- Consolidate _get_mgr into get_mgr in _bus.py
- Sort MPRIS players for deterministic auto-discovery
- Fix progress reporting (pass None as total when unknown)
- Add 7 new tests for validation, arg count, and JSON error paths (32 total)
Bridge Linux D-Bus IPC into MCP with tools for service discovery
(list_services, introspect, list_objects), method calls and property
access, plus convenience shortcuts for notifications, systemd units,
and MPRIS media player control. All 25 tests passing.