Mobile MCP
Drives iOS and Android simulators, emulators and real devices from an assistant
Inspect and drive a running React Native or Flutter app, simulator farms and Chrome from your editor
Official · Buoy TypeScript Local · stdio Developer toolsTesting
62 popularity score ★ 695 ↓ 1.5k/wk
Opens the app, which asks before it adds the server.
claude mcp add buoy -- npx -y @buoy-gg/mcp@latest{
"mcpServers": {
"buoy": {
"command": "npx",
"args": [
"-y",
"@buoy-gg/mcp@latest"
]
}
}
}{
"mcpServers": {
"buoy": {
"command": "npx",
"args": [
"-y",
"@buoy-gg/mcp@latest"
]
}
}
}{
"servers": {
"buoy": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@buoy-gg/mcp@latest"
]
}
}
}[mcp_servers.buoy]
command = "npx"
args = ["-y", "@buoy-gg/mcp@latest"]gemini mcp add --scope user buoy npx -- -y @buoy-gg/mcp@latest| Set together: sign-in | |
|---|---|
BUOY_KEY secret |
Optional: Backup account value when the computer is not signed in with buoy login. BUOY_LICENSE_KEY is checked first, then this name and its EXPO_PUBLIC_, VITE_, NEXT_PUBLIC_ or REACT_APP_ forms in the project's env files. |
BUOY_PROJECT_ROOT |
Optional: App project folder used for the env file lookup and .buoy files. |
BUOY_SECRET_NAME secret |
Optional: One per secret, with NAME replaced. Typed in place of {{secret:NAME}} and masked in what the tool returns. |
BUOY_CHROME_PATH |
Optional: Chrome binary to use instead of the chrome-headless-shell the farm downloads. |
BUOY_FARM_HOME |
Optional: Folder where the Sim Farm keeps its simulators and state. |
BUOY_TELEMETRY |
Optional: Set to 0, false or off to stop Buoy Web's daily usage ping. DO_NOT_TRACK=1 does the same. |
| Set together: broker | |
BUOY_BROKER_PORT |
Optional: Port of the local broker. |
Buoy is a set of in-app developer tools for React Native and Flutter apps, and @buoy-gg/mcp is the MCP server that ships with it. The in-app tools sync to a local broker. This server joins that broker as a dashboard client, the same role Buoy Desktop plays, or starts a broker of its own when Desktop isn't running. From there your editor's assistant can see which devices are connected and read the screen as a list of elements. It can tap, swipe and type, run multi-step flows, take screenshots or recordings, and read console output and captured requests.
Pro opens up the inside of the app: Zustand, Redux, Jotai and React Query state, storage values, request bodies and mocked responses, plus overrides for network speed, the clock, location and permissions. A free account keeps the basic set and Buoy Optimize, which covers the benchmark tools and the Sim Farm but leaves component names out of its results.
The bundle registers 112 tools, many more than the docs name. Two newer groups work outside your app. The Sim Farm (sim_farm_*) clones slim iOS simulators or Android emulators from a template build and leases them out, so an agent can try many fixes side by side. The Chrome Farm (chrome_farm_*) starts headless Chrome instances on a web app, each with its own storage and a memory cap. You can drive both from a shell too, with `npx -y @buoy-gg/mcp@latest farm`.
The same package also holds a second server called Buoy Web, set up with `init --web`. It works websites in Chrome with real clicks and key presses, and nothing has to be installed in an app. Its guide now names all 15 of its tools: open, read, click, type, key, wait, scroll, drag, hover, select, tabs, dialog and logs, plus upload and screenshot. With the Buoy Web extension it works in your own Chrome profile. Without the extension it opens a separate Chrome window that keeps its sign-ins in ~/.buoy/web-profile. It is free and needs no account.
| Runtime | Node.js 18+ |
|---|---|
| Runs on | macOS, Windows, Linux |
| Buoy | Free tierFree covers the basic tools, Optimize and Buoy Web. Pro adds app state, storage, request bodies and overrides. |
| Also |
|
Sign the computer in once by running `npx --package=@buoy-gg/core buoy login` in the app folder. The server uses that sign-in and needs nothing else, though it falls back to an account value in the project's env files. The app tools need `@buoy-gg/external-sync` in the app, running as a development build (React Native) or a debug build (Flutter). Buoy Web needs nothing in the app. Its Chrome extension is optional.
Most tools need Buoy Pro; on a free account a Pro tool answers that it needs Pro and nothing reaches the app. Buoy is proprietary software under Buoy's terms. Several features are React Native only (UI driving with describe_screen/tap_element, reload_app, network conditions, JS-thread profiling, buoy-optimize). native_pinch does not work on Android; native_inspect shows only the app's side on a physical iPhone. Recordings stop at 3 minutes. Network conditions reset on a JS reload, do not affect native transports outside fetch/XHR, and are a development preview. An MCP version older than the Desktop broker is refused, so both must be updated together.
Suits React Native or Flutter developers who use Buoy already, or can add it to their app, and want an editor assistant to reproduce bugs, look at state and network traffic, and check a fix on a device or simulator. The deeper tools sit behind the paid Pro plan. Performance work on a Mac gets the most out of the farms. Someone who only wants an assistant working in Chrome can use Buoy Web alone, free and without an account. It is a poor fit for apps that can't take Buoy's in-app packages, or for teams that need open-source tooling, since Buoy is proprietary.
28 only read, 29 change things, 3 can delete or overwrite. A ? marks an optional parameter.
list_devicesdetails?: booleanincludeDisconnected?: booleanlist_tool_actionstoolId?: stringtool?: stringdeviceId?: stringget_snapshottoolId?: stringtool?: stringdeviceId?: stringtimeoutMs?: numbercall_action changestoolId?: stringtool?: stringaction: stringparams?: anyargs?: anydeviceId?: stringtimeoutMs?: numberget_eventslimit?: numbersources?: arraystatus?: enumincludeData?: booleanformat?: enumpreset?: enumdeviceId?: stringget_triagedeviceId?: stringdescribe_screeninteractiveOnly?: booleanincludeBuoy?: booleanincludeHidden?: booleandeviceId?: stringtap_element changesnativeTag?: numbertestID?: stringquery?: stringvalue?: anytext?: stringlongPress?: booleanscrollIntoView?: booleanincludeBuoy?: booleanincludeHidden?: booleanobserve?: enumdeviceId?: stringnative_tap changeslabel?: stringquery?: stringtestID?: stringnativeTag?: numberx?: numbery?: numberholdMs?: numberallowBuoy?: booleanserial?: stringdeviceId?: stringnative_type changestext: stringserial?: stringdeviceId?: stringnative_swipe changesdirection?: enumfromX?: numberfromY?: numbertoX?: numbertoY?: numberdurationMs?: numberdrag?: booleanuntilEnd?: booleanallowBuoy?: booleanserial?: stringdeviceId?: stringnative_pinch changesx?: numbery?: numberscale?: numberrotate?: numberdurationMs?: numberallowBuoy?: booleandeviceId?: stringnative_inspectpointX?: numberpointY?: numberx?: numbery?: numberserial?: stringdeviceId?: stringrun_flow changesscreenshot_componentcompareTo?: stringquery?: stringnativeTag?: numberscrollIntoView?: booleanserial?: stringbaseline?: stringupdateBaseline?: booleansteady?: booleanthreshold?: numberignore?: arrayignoreAreas?: arraydeviceId?: stringscreen_recordingaction: enumname?: stringsteps?: arrayserial?: stringdeviceId?: stringdevice_control changesaction: enumorientation?: enumtext?: stringmatch?: booleanfingerId?: integerserial?: stringdeviceId?: stringlifecycle_action deletesaction: enumduration?: anyskipWait?: booleanurl?: stringscheme?: enummode?: enumlevel?: numberlowPowerMode?: booleanstate?: enumid?: stringshowChip?: booleanreportWindow?: anyreal?: booleanappPath?: stringkeepBuoySignIn?: booleansimulator?: stringudid?: stringserial?: stringdeviceId?: stringreload_app changesstrategy?: enumwait?: booleantimeoutMs?: numberdeviceId?: stringget_routesincludeSitemap?: booleandeviceId?: stringnavigate changespath: stringreplace?: booleanobserve?: enumdeviceId?: stringget_consolelevel?: enumlimit?: numberpattern?: stringdeviceId?: stringget_network_requestslimit?: numberpattern?: stringstatus?: enumflagged?: enumincludeBodies?: booleandeviceId?: stringget_network_requestid: stringmaxChars?: numberdeviceId?: stringnetwork_action changesaction: enumid?: stringkey?: stringdeviceId?: stringnetwork_conditions changesaction: enumprofile?: enumconnection?: enumdeviceId?: stringnetwork_override changesaction: enumurlPattern?: stringfromRequestId?: stringmethods?: arraykind?: enumstatus?: numberbody?: anybodyPatch?: objectstatusText?: stringheaders?: objectfailKind?: enumdelayMs?: numbertimes?: numberalternate?: booleanname?: stringenabled?: booleanid?: stringurl?: stringmethod?: stringdeviceId?: stringget_storagepattern?: stringincludeValues?: booleanlimit?: numberdeviceId?: stringget_redux_stateincludeValues?: booleandeviceId?: stringredux_dispatch changestype: stringpayload?: anydeviceId?: stringtime_machine_action changesaction: enumid?: stringname?: stringmode?: enumexcludeKeys?: arrayrestoreRoute?: booleansourceIds?: arraydeviceId?: stringclock_action changesaction: enumtime?: anyby?: anyfreeze?: booleanfireTimers?: booleanrate?: numberpersist?: booleanshowChip?: booleanfireTimersOnJump?: booleantoken?: stringleadMs?: numberstatus?: numbertimes?: numberdeviceId?: stringlocation_action changesaction: enumlatitude?: numberlongitude?: numberlabel?: stringquery?: stringplace?: stringpoints?: arrayroute?: stringto?: stringspeed?: numberheading?: numberloop?: booleanmeters?: numberfraction?: numberidentifier?: stringtask?: stringconditions?: enumon?: booleanaccuracy?: numberjitter?: numberpermission_action changesaction: enumpermission?: stringstate?: enumanswer?: enumnotifyApp?: booleaninterceptSettings?: booleanenforce?: booleanpersist?: booleanshowChip?: booleandeviceId?: stringrun_benchmark_batchtargetRoute: stringcases: arraybounceRoute?: stringrunsPerCase?: numberperCaseDurationMs?: numbersettleMs?: numbercoolDownMs?: numbernavTimeoutMs?: numberdiscardWarmupRuns?: numbershuffleCases?: booleanreloadBetweenCases?: booleancaptureRenders?: booleandeviceId?: stringmaxWaitMs?: numbermeasure_renderssteps?: arrayidleMs?: numberlabel?: stringcompareToPrevious?: booleantop?: numberdeviceId?: stringget_js_thread_topdeviceId?: stringdurationMs?: numberclearFirst?: booleanget_component_sourcequery?: stringnativeTag?: integerdeviceId?: stringnative_profilememory_checkdeviceId?: stringaction: enumbaselinePath?: stringtargetPath?: stringcycles?: integersettleMs?: integerrunId?: stringcamera_source changeskind: enumvalue?: stringformat?: enumsim_farm_statusoutside?: booleansim_farm_setup changesmode: enumplatform?: enumapkPath?: stringphone?: stringreverse?: arraytemplateId?: stringcount?: integerappPath?: stringseedDir?: stringlaunchUrl?: stringdeviceType?: stringruntime?: stringprofile?: enummetroPort?: integerdryRun?: booleansim_farm_acquire changescount: integergoal?: stringlabels?: arraykind?: enumrunId?: stringpurpose?: stringtemplateId?: stringplatform?: enumlaunch?: booleanallowPartial?: booleanwaitSeconds?: integerttlMinutes?: integersim_farm_action changesleaseId: stringepoch: integerudids: arrayaction: enumurl?: stringapkPath?: stringsim_farm_release deletesleaseId: stringepoch: integerreset?: enumkeepRun?: booleansim_farm_finish changesoutcome?: enumsummary?: stringchrome_farm_statuschrome_farm_up changesurl: stringcount?: integerready?: stringviewport?: enumcapMB?: integerlabel?: stringboost?: booleangpu?: booleanchrome_farm_down changeschrome_farm_screenshotid: stringrun_web_benchmarkurl: stringpath?: stringcases?: arrayrunsPerCase?: numberperCaseDurationMs?: numbersettleMs?: numbercpuSlowdown?: arrayviewport?: objectreadySelector?: stringsteps?: arraytraceDir?: stringheaded?: booleanallowPageErrors?: booleanprojectRoot?: stringoutFile?: stringextraRoundsWhenClose?: numbermaxBatchMs?: numberbudgets?: objectfind_web_ceilingurl: stringpath?: stringcases?: arrayparam: stringstart?: numbergrowth?: numbermax?: numbertargetFps?: numberprecisionPct?: numberrounds?: numbermaxBatchMs?: numbersettleMs?: numbermeasureMs?: numbercpuSlowdown?: numberviewport?: objectreadySelector?: stringheaded?: booleanprojectRoot?: stringget_native_profileget_memory_leaksdeviceId?: stringrunId?: stringkind?: enumlimit?: integersim_farm_lock changesleaseId: stringepoch: integername: stringhold: booleanwaitSeconds?: integersim_farm_report changesudid?: stringstate?: enumnote?: stringcounts?: objectresultSource?: enumsequence?: integersim_farm_extend changesminutes: integerchrome_farm_reset deleteschrome_farm_pause changes