Add a USB host control MCP module - #34
Merged
Merged
Conversation
Add an in-process `usb` MCP module so an agent, through the SealGate gateway, can enumerate and drive devices plugged into the phone over the Android USB Host API (USB-OTG) - the USB analogue of the bluetooth/battery/wifi modules. Tools: usb_list_devices, usb_request_permission, usb_open, usb_bulk_transfer, usb_control_transfer, usb_close. Transfers are protocol-agnostic raw bulk/ control with hex payloads (direction inferred from the endpoint address / request_type top bit), so CDC-ACM/FTDI/HID/vendor protocols layer on top. Design mirrors BluetoothModule: all hardware access sits behind a `UsbSource` interface (production impl `AndroidUsbSource` over `UsbManager`) so the module is JVM-testable with a fake; every precondition (no host support, no permission, unknown device/endpoint, bad hex, not-open, transfer failure/ timeout) is returned as an in-band `isError` tool result, never a JSON-RPC error or crash. Open `UsbDeviceConnection`s + claimed interfaces are held by device_name across calls. Permission model differs from a manifest permission: USB host needs no `<uses-permission>` but per-device runtime permission granted via a system dialog (`UsbManager.requestPermission`), so usb_request_permission triggers it and every I/O tool reports an in-band error when permission is missing. The manifest declares `<uses-feature android:name="android.hardware.usb.host" android:required="false" />` so the app still installs without OTG. A USB-OTG adapter is required to attach devices. Registered in TunnelService.connect() so the gateway can bind a `usb` server by name. JVM test (UsbModuleTest, 10 cases) covers the tool set, device JSON shaping, permission-missing, not-open, bad-hex, bulk IN, and control round-trip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NgN7YdfLT41kWnWqe1MPZa
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
…trol # Conflicts: # CLAUDE.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an in-process
usbMCP module so an agent, through the SealGate gateway, can enumerate and drive devices plugged into the phone over the Android USB Host API (USB-OTG) — the USB analogue of the existingbluetooth/battery/wifimodules.Tools
usb_list_devices[{device_name, vendor_id, product_id, manufacturer?, product?, serial?, device_class, interface_count, has_permission}]usb_request_permissiondevice_name{requested:true}(async grant) or{granted:true}if already permittedusb_opendevice_name,interface_index?endpoints[{address, direction, type, max_packet_size}]usb_bulk_transferdevice_name,endpoint_address,value_hex?,length?,timeout_ms?{bytes_transferred}; IN:{value_hex, bytes_transferred}usb_control_transferdevice_name,request_type,request,value,index,value_hex?,length?,timeout_ms?{bytes_transferred}; IN:{value_hex, bytes_transferred}usb_closedevice_name{closed:true}(idempotent)Transfers are protocol-agnostic raw bulk/control with hex payloads; direction is inferred from the endpoint address /
request_typetop bit (0x80= IN). CDC-ACM/FTDI/HID/vendor protocols layer on top — no serial specifics baked in.Design
Mirrors
BluetoothModule: all hardware access sits behind aUsbSourceinterface (production implAndroidUsbSourceoverandroid.hardware.usb.UsbManager), so the module is JVM-testable with a fake. OpenUsbDeviceConnections plus the claimedUsbInterfaceare held bydevice_namein aConcurrentHashMapacross calls, sousb_open→ transfers →usb_closereference one session. Every precondition (no host support, no permission, unknown device/endpoint, bad hex, not-open, transfer failure/timeout) is returned as an in-bandisErrortool result — never a JSON-RPC error, never a crash.Permission model
Different from a manifest permission: USB host access needs no
<uses-permission>, but requires per-device runtime permission granted via a system dialog (UsbManager.requestPermission+ aRECEIVER_NOT_EXPORTEDbroadcast receiver).usb_request_permissiontriggers the dialog and returns immediately; every I/O tool reports an in-band error (permission not granted for device <id>: call usb_request_permission and approve the on-device dialog) whenhasPermissionis false. The manifest declares<uses-feature android:name="android.hardware.usb.host" android:required="false" />so the app still installs on phones without OTG (devices simply never enumerate). A USB-OTG adapter is required to attach devices.Registered in
TunnelService.connect()so the gateway binds ausbstdio server by name.Verification
UsbModuleTestcases pass): tools/list advertises the full ordered tool set;usb_list_devicesJSON shaping incl.has_permission; I/O with no open connection → in-band error; bulk OUT bad hex → in-band error; bulk IN returnsvalue_hex; permission-missing on open → in-band error;usb_control_transferround-trips its args to the source and returns the payload; unknown tool → in-band error.AndroidUsbSource.ktand theTunnelServicewiring referenceandroid.*and compile only under the Android toolchain;assembleDebug+lintDebug+testDebugUnitTestare the authoritative check. SecurityException/exceptions are handled in the same function as eachUsbManager/connection call per the lint rule.🤖 Generated with Claude Code
https://claude.ai/code/session_01NgN7YdfLT41kWnWqe1MPZa
Generated by Claude Code
Summary by cubic
Adds a
usbMCP module so an agent can enumerate and drive USB devices plugged into the phone over the Android USB Host API (USB-OTG), the USB analogue of the existingbluetooth/wifi/batterymodules. Hardware access sits behind aUsbSourceinterface, so module logic is JVM-testable with a fake;AndroidUsbSourceis the production implementation overUsbManager.New Features
usb_list_devices,usb_request_permission,usb_open,usb_bulk_transfer,usb_control_transfer,usb_close.request_typetop bit.usb_open→ transfers →usb_closereference one session.isErrortool result — never a JSON-RPC error or crash.Migration
usb_request_permissionfires it, and every I/O tool reports an in-band error until granted.<uses-feature android:name="android.hardware.usb.host" android:required="false" />so the app still installs on phones without OTG; a USB-OTG adapter is required to attach devices.Written for commit b794586. Summary will update on new commits.