Skip to content

Make Mobile Bash the default mobile MCP surface - #38

Open
Miyamura80 wants to merge 4 commits into
mainfrom
feature/mobile-bash-default
Open

Make Mobile Bash the default mobile MCP surface#38
Miyamura80 wants to merge 4 commits into
mainfrom
feature/mobile-bash-default

Conversation

@Miyamura80

@Miyamura80 Miyamura80 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • expose one Mobile Bash MCP server with a single run tool instead of five separate mobile servers
  • embed a pinned, restricted just-bash runtime in QuickJS with a run-scoped in-memory filesystem
  • bridge device, battery, Wi-Fi, Bluetooth, and USB capabilities through composable CLI commands
  • add BLE GATT sequencing, short UUIDs, MTU-aware validation, notification helpers, and truthful queued versus confirmed write results
  • remove the legacy mode toggle and migrate Mobile Bash to the only/default surface
  • add pull-to-refresh reconnect, lifecycle cleanup, documentation, licenses, and a connected-device smoke harness

Verification

  • Gradle testDebugUnitTest: 75 tests passed
  • Gradle assembleDebug: passed
  • Gradle lintDebug: passed
  • Pixel 6 install and Mobile Bash UI verification: passed
  • LED_BLE hardware sequence: 9 frames and 45 confirmed writes
  • SealGate gateway E2E through mobilebash_run: 4 frames and 20 confirmed writes
  • final gateway catalog contains mobilebash_run and no legacy mobile module prefixes

Dashboard registration

Display name: Mobile Bash
MCP prefix: mobilebash
Command: mobile-builtin
Arguments: none


Summary by cubic

Makes Mobile Bash the default and only MCP surface on Android. The app now exposes one mobilebash server with a single run tool instead of the five separate mobile modules, executing scripts in a pinned just-bash runtime inside QuickJS with an in-memory filesystem.

What changed

  • Routes device, battery, Wi-Fi, Bluetooth, and USB capabilities through composable CLI commands in run.
  • Adds BLE GATT sequencing, short UUIDs, MTU-aware validation, notification helpers, and separates queued from confirmed write results.
  • Removes the legacy mode toggle; releasing the tunnel closes GATT/USB connections, and stop returns immediately while module teardown finishes in the background.
  • Hardens the sandbox with filesystem size caps, a 30-second sleep limit, and compression/network commands disabled.
  • Adds pull-to-refresh reconnect, which resets cleanly on shutdown, and a connected-device smoke harness.

Migration

  • The old module prefixes are gone; existing agents must call mobilebash CLI commands.
  • Register the dashboard server with display name Mobile Bash, prefix mobilebash, and command mobile-builtin.

Written for commit 9549738. Summary will update on new commits.

Review in cubic

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 37 files

Not reviewed (too large): app/src/main/assets/mobile-bash-runtime.js (~1,656 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/ai/sealgate/stdiod/mcp/BluetoothModule.kt">

<violation number="1" location="app/src/main/java/ai/sealgate/stdiod/mcp/BluetoothModule.kt:1200">
P3: The 16/32-bit BLE UUID alias expansion is implemented twice: `canonicalGattUuid` in this module and `expandBluetoothUuid` in AndroidBluetoothSource.kt are the same `0x`-strip, pad-16-bit, expand-32-bit algorithm. The module canonicalizes every service/characteristic before calling the source, so the source copy is redundant on these paths, and the two can drift. Consolidate into one shared helper (e.g. a top-level utility) so alias handling stays in sync.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/AndroidUsbSource.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/AndroidBluetoothSource.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/MobileBashRuntime.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/MobileCommandRouter.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/BluetoothModule.kt Outdated
Comment thread tools/bash-runtime/package.json Outdated
Comment thread app/src/test/java/ai/sealgate/stdiod/mcp/MobileBashRuntimeTest.kt Outdated
isError = true,
)

private fun canonicalGattUuid(raw: String): String? {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The 16/32-bit BLE UUID alias expansion is implemented twice: canonicalGattUuid in this module and expandBluetoothUuid in AndroidBluetoothSource.kt are the same 0x-strip, pad-16-bit, expand-32-bit algorithm. The module canonicalizes every service/characteristic before calling the source, so the source copy is redundant on these paths, and the two can drift. Consolidate into one shared helper (e.g. a top-level utility) so alias handling stays in sync.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/ai/sealgate/stdiod/mcp/BluetoothModule.kt, line 1200:

<comment>The 16/32-bit BLE UUID alias expansion is implemented twice: `canonicalGattUuid` in this module and `expandBluetoothUuid` in AndroidBluetoothSource.kt are the same `0x`-strip, pad-16-bit, expand-32-bit algorithm. The module canonicalizes every service/characteristic before calling the source, so the source copy is redundant on these paths, and the two can drift. Consolidate into one shared helper (e.g. a top-level utility) so alias handling stays in sync.</comment>

<file context>
@@ -916,6 +1096,135 @@ class BluetoothModule(private val source: BluetoothControlSource) : BaseMcpModul
+        isError = true,
+    )
+
+    private fun canonicalGattUuid(raw: String): String? {
+        val compact = raw.trim().removePrefix("0x").lowercase()
+        val canonical = when {
</file context>

Comment thread tools/e2e/bash-tunnel-server.mjs Outdated
Comment thread app/src/androidTest/java/ai/sealgate/stdiod/mcp/MobileBashDeviceTest.kt Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 16 files (changes from recent commits).

Not reviewed (too large): app/src/main/assets/mobile-bash-runtime.js (~302 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/ai/sealgate/stdiod/tunnel/TunnelClient.kt">

<violation number="1" location="app/src/main/java/ai/sealgate/stdiod/tunnel/TunnelClient.kt:84">
P1: When the service restarts while a Mobile Bash call is executing, `stop()` returns before the old module and capability resources are closed. `TunnelService.connect()` then creates a replacement tunnel, allowing the old script and new tunnel to operate concurrently. Coordinate stop completion with replacement creation, or cancel in-flight module work before starting the new tunnel.</violation>
</file>

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.

Re-trigger cubic

if (modulesClosed.compareAndSet(false, true)) {
// A QuickJS evaluation may hold its runtime lock until the 60-second
// execution limit. Never make the service/main thread wait for it.
thread(start = true, isDaemon = true, name = "mobile-mcp-close") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When the service restarts while a Mobile Bash call is executing, stop() returns before the old module and capability resources are closed. TunnelService.connect() then creates a replacement tunnel, allowing the old script and new tunnel to operate concurrently. Coordinate stop completion with replacement creation, or cancel in-flight module work before starting the new tunnel.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/ai/sealgate/stdiod/tunnel/TunnelClient.kt, line 84:

<comment>When the service restarts while a Mobile Bash call is executing, `stop()` returns before the old module and capability resources are closed. `TunnelService.connect()` then creates a replacement tunnel, allowing the old script and new tunnel to operate concurrently. Coordinate stop completion with replacement creation, or cancel in-flight module work before starting the new tunnel.</comment>

<file context>
@@ -76,10 +78,15 @@ class TunnelClient(
+        if (modulesClosed.compareAndSet(false, true)) {
+            // A QuickJS evaluation may hold its runtime lock until the 60-second
+            // execution limit. Never make the service/main thread wait for it.
+            thread(start = true, isDaemon = true, name = "mobile-mcp-close") {
+                modulesByName.values.filterIsInstance<AutoCloseable>().forEach { module ->
+                    runCatching(module::close).onFailure {
</file context>

Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/MobileBashRuntime.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/AndroidUsbSource.kt
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/BluetoothModule.kt Outdated
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/AndroidBluetoothSource.kt
Comment thread app/src/main/java/ai/sealgate/stdiod/tunnel/TunnelClient.kt
Comment thread tools/e2e/bash-tunnel-server.mjs
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/MobileBashRuntime.kt
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/MobileBashRuntime.kt Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files (changes from recent commits).

Not reviewed (too large): app/src/main/assets/mobile-bash-runtime.js (~359 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread app/src/main/java/ai/sealgate/stdiod/TunnelService.kt
Comment thread app/src/main/java/ai/sealgate/stdiod/mcp/AndroidBluetoothSource.kt
@Miyamura80

Copy link
Copy Markdown
Contributor Author

Babysit complete at head 9549738.

  • Addressed all actionable Cubic findings across the follow-up passes.
  • Local verification: Mobile Bash bundle rebuilt, npm audit reports 0 vulnerabilities, 81 unit tests pass, assembleDebug passes, and lintDebug passes.
  • GitHub Android CI passes.
  • Cubic final review: all reported issues were addressed.
  • PR is CLEAN and MERGEABLE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant