Llim.run

Per-instance MCP server

Every iOS and Android instance runs its own Model Context Protocol server. Connect an agent to it when the agent should drive one existing device through native tool calls instead of shelling out to the lim CLI.

Choose the CLI, MCP, or both

Aspectlim CLIPer-instance MCP server
Where it runsThe agent's shellThe agent's MCP client transport
AuthAPI key in the environment or config, or a single pinned instance with no keyThe instance token as Authorization: Bearer
ConnectionA background WebSocket that repeated commands reuse (--daemon, on by default), or one started explicitly with lim session startA long-lived MCP session
ScopeEverything Limrun does. See the CLI reference.Device control only: five tools on iOS and three on Android, listed below. No builds, no asset uploads.
Best forBuilds, instance lifecycle, asset managementTap, screenshot, and element-tree loops where round-trips matter

Most agents use both: the CLI for provisioning, builds, and assets, and MCP for native tool calls over device control.

Get the MCP URL and token

Read mcpUrl and token from the instance's status. Both come back on the same response, and you need both to talk to the server. The CLI example reads an instance you already have; the SDK examples create one, or reuse one with the same labels:

lim ios get --json | jq -r '.status.mcpUrl, .status.token'
import Limrun from '@limrun/api';

const lim = new Limrun({ apiKey: process.env['LIM_API_KEY'] });

const instance = await lim.iosInstances.create({
  wait: true,
  reuseIfExists: true,
  metadata: { labels: { name: 'agent-session' } },
});

console.log(instance.status.mcpUrl);
console.log(instance.status.token);   // bearer for the Authorization header
from limrun_api import Limrun

client = Limrun()
instance = client.ios_instances.create(
    wait=True,
    reuse_if_exists=True,
    metadata={"labels": {"name": "agent-session"}},
)
print(instance.status.mcp_url)
print(instance.status.token)   # bearer for the Authorization header
client := limrun.NewClient()
inst, _ := client.IosInstances.New(ctx, limrun.IosInstanceNewParams{
    Wait:          param.NewOpt(true),
    ReuseIfExists: param.NewOpt(true),
    Metadata: limrun.IosInstanceNewParamsMetadata{
        Labels: map[string]string{"name": "agent-session"},
    },
})
fmt.Println(inst.Status.McpURL)
fmt.Println(inst.Status.Token)   // bearer for the Authorization header

CLI only: lim ios get reads the last iOS instance the CLI created; pass an instance ID (lim ios get <id> --json) to read another one.

Android instances return mcpUrl the same way (not exposed in Go SDK v0.9.0).

The URL carries no credentials. Authenticate every MCP request with the instance token in an Authorization: Bearer header. The token is scoped to this one instance: it works only while the instance is running and cannot be used for anything outside it. Do not use your API key here; the API key is for creating, listing, and deleting instances.

For a running instance, the console at console.limrun.com gives copy-paste snippets for each supported agent. Open the instance and click the connect icon in the sidebar:

Connect modal on console.limrun.com with one-click Replit and Cursor installers, plus collapsible Claude Code and Custom sections

Connect your agent

Claude Code

Add the server with the two values from the create response:

claude mcp add simulator --transport http \
  '<mcpUrl>' \
  --header 'Authorization: Bearer <status.token>'

Verify it with claude mcp list. The console's connect modal renders the same command with your values filled in:

Connect modal with the Claude Code section expanded, showing the full claude mcp add command pre-populated with the instance URL and Authorization Bearer header

Claude Desktop

To use Limrun from Claude Desktop, add the remote MCP server as a custom connector in its settings. The remote server signs in with OAuth, so it needs no custom header. The per-instance server needs an Authorization header, so use it only from clients that let you set one.

Cursor

The console's Add to Cursor button opens Cursor with the server pre-filled. To add it by hand, create an MCP server in Cursor's settings with the URL and the Authorization: Bearer <status.token> header.

Other MCP clients

Any MCP client that speaks the HTTP transport works. Pass the URL as the endpoint and Authorization: Bearer <status.token> as a header. The connect modal's Custom section shows both values:

Connect modal with the Custom section expanded, showing the MCP server URL and the Authorization Bearer header to paste into any MCP client

Tools

The server's tools depend on the platform. An iOS simulator's server exposes five tools:

ToolWhat it does
ios-screenshot-and-element-treeReturns the current screenshot and the accessibility element tree in one call. Call it before every action to see the current state.
ios-usePerforms a batch of actions in order. Action kinds: tap, tapElement, setElementValue, incrementElement, decrementElement, type, pressKey, scroll, wait, toggleKeyboard, openUrl, setOrientation, touchDown, touchMove, touchUp, keyDown, keyUp, buttonDown, buttonUp, deviceInfo, startRecording, stopRecording, discoverStoreKitConfig, clearStoreKitConfig, softReset.
ios-open-urlOpens a URL or deep link in the simulator, including Safari URLs and custom schemes such as exp:// for Expo Go.
ios-appLists installed apps and launches or terminates them. It does not install apps; use the CLI or SDKs for installs.
ios-logsFetches the last N combined stdout and stderr log lines for a bundle ID.

An Android emulator's server exposes three:

ToolWhat it does
android-screenshot-and-element-treeReturns the current screenshot and the UIAutomator element tree in one call.
android-usePerforms a batch of actions on the emulator in order.
android-open-urlOpens a URL or deep link on the emulator.

The actions inside ios-use map onto methods of the TypeScript SDK's createInstanceClient. The server batches them into a few tools instead of one tool per action, so the agent can group related steps into one round-trip.

touchDown, touchMove, and touchUp accept optional x2 and y2 coordinates for a second finger. Supply both on every touch action of a two-finger gesture, or omit both for one finger. Both fingers share the optional screenWidth and screenHeight coordinate space.

A tapElement action whose selector matches nothing fails in about a second and aborts the batch. iOS creates list rows lazily, so a row below the fold is often absent from the tree. When you expect that, put scroll actions before the tapElement in the same batch.

App installs, Xcode builds, and asset uploads are not on the server. MCP gives a tool no access to the client's filesystem, so anything that sends bytes from your machine (an APK, a .app bundle, a build artifact) lives on the CLI and SDKs.

Next steps

smartphone

Run a simulator

The full device-control surface these tools call into.

terminal

Set up a coding agent

Instance lifecycle, builds, and assets through the CLI.