How to connect and use Ramus from GitHub Copilot
Connect GitHub Copilot in VS Code to Ramus, then run your APK on a cloud Android device, let the agent test a flow and share the device.
GitHub CopilotPublished
On this page
This guide is for developers who use GitHub Copilot's agent in VS Code on an Android app. At the end, Copilot can start a cloud Android device, install your build, test a flow and fix what breaks. You watch the device in your browser, take over from the device page when you want, and send a link to a reviewer.
What you need
- VS Code with GitHub Copilot, signed in to GitHub.
- On Copilot Business or Copilot Enterprise, an administrator must turn on the MCP servers in Copilot policy. It is off by default. Copilot Free, Pro, Pro+ and Max are not governed by it.
- A Ramus account. Sign in at ramus.dev with GitHub.
- An Android project you can build into an APK, such as
app/build/outputs/apk/debug/app-debug.apk. - Node.js 22 or later, if you also want the
ramusCLI.
Connect Ramus
Ramus is a remote MCP server at https://api.ramus.dev/api/mcp. Copilot
connects to it over Streamable HTTP. Nothing runs on your machine.
The file VS Code reads depends on the agent harness. Since VS Code 1.143, new
chat sessions use the Copilot harness, the runtime the Copilot CLI also uses.
It reads ~/.copilot/mcp-config.json for you and .mcp.json at the repository
root for your team. Both use a top-level mcpServers object. VS Code's own
format, .vscode/mcp.json or the user mcp.json with a top-level servers
object, still works and is passed on to Copilot sessions, except entries that
prompt for input with ${input:…}.
Sign in with your Ramus account
VS Code signs in to Ramus with your account, so there is no key to store.
- Open the Command Palette and run MCP: Add Server.
- Choose HTTP (HTTP or Server-Sent Events) and enter
https://api.ramus.dev/api/mcp. - Enter
ramusas the server ID. - Choose Global, then Copilot Global.
Copilot Global writes the server to ~/.copilot/mcp-config.json. Add
timeout, in milliseconds, to that entry, or write it yourself: the Copilot
runtime gives an MCP call 30 seconds by default, and a device start can wait
longer.
{
"mcpServers": {
"ramus": {
"type": "http",
"url": "https://api.ramus.dev/api/mcp",
"tools": ["*"],
"timeout": 300000
}
}
}
For a team, put the same mcpServers block in .mcp.json at the repository
root and commit it. It holds no secret. Each person signs in with their own
Ramus account.
The first time the agent needs Ramus, VS Code asks you to sign in for the
ramus server, in a dialog or in the chat. Accept it. Your browser opens the
Ramus consent page. Sign in with GitHub if asked, check that the app is
Visual Studio Code, and choose Allow. The browser hands the sign-in back
to VS Code and the tools load.


VS Code signs in as the client https://vscode.dev/oauth/client-metadata.json.
The browser returns to http://127.0.0.1:33418/ (another port if that one is
busy), or to https://vscode.dev/redirect in a remote window. Ramus accepts
both.
This terminal command adds the server to your VS Code user profile instead. It
sets no timeout, so prefer the file above if device starts time out.
code --add-mcp '{"name":"ramus","type":"http","url":"https://api.ramus.dev/api/mcp"}'
Or use an API key
Use a key where nobody can complete a browser sign-in. It works in both harnesses. Create one on the Agents page, tab API key. Keep it in your shell profile, not in a file you commit:
# ~/.zshrc
export RAMUS_API_KEY="rms_your_key_here"
Then add Ramus with the key in the header, with the same timeout:
{
"mcpServers": {
"ramus": {
"type": "http",
"url": "https://api.ramus.dev/api/mcp",
"headers": { "Authorization": "Bearer ${RAMUS_API_KEY}" },
"tools": ["*"],
"timeout": 300000
}
}
}
The Copilot format expands ${NAME} in header values, from the environment
VS Code runs in. If VS Code was already open when you set the variable, quit
it and start it again from a terminal with code ..
Check that it connected
In VS Code, run Chat: Open Customizations and open MCP Servers. ramus
should be running. Its menu has Show Output for errors, and the Tools
tab lists the android_* tools. MCP: List Servers gives the same actions
from the Command Palette.
Then ask for something harmless:
Use the ramus MCP server to list my running Android sessions.
The agent calls android_list_sessions and gets an empty list or your live
devices.
On Ramus, open ramus.dev/agents. Under
Connected, a sign-in appears as Visual Studio Code with Sign-in as
how it connects, and a key appears under its own name. Both show their last
call. Disconnect or Revoke cuts the agent off. To sign out on the VS Code
side, run MCP: List Servers, pick ramus and choose Sign Out.


Add the CLI and the skill
Copilot's agent runs terminal commands, so it can use the Ramus CLI as well.
The CLI uploads a local APK in one step, and it is the only way to open an adb
tunnel (ramus adb) or run the hot-reload loop (ramus dev).
npm i -g ramus-cli
ramus login
$ ramus login
Opening your browser to sign in to Ramus…
(On another device, or no browser? Press Ctrl-C and run `ramus login --device`.)
{
"login": "ok",
"account": "@blogger",
"terminal": "Mac",
"origin": "https://api.ramus.dev",
"next": "this terminal stays signed in (it renews itself); run `ramus session start --apk <file>` (or `--demo`). Terminals are listed at https://ramus.dev/agents"
}

ramus login opens your browser. Check that the page names your machine and
choose Allow. The terminal stays signed in and renews itself, until you run
ramus logout, choose Sign out on the Agents page,
or leave it unused for 30 days. Over SSH it gives you a code to approve on any
device. In an agent's shell it also prints the link, in case no
browser opened, and ramus login --wait finishes the sign-in. ramus status confirms it.
RAMUS_API_KEY in the environment wins over the sign-in.
The android-use skill teaches the agent the Ramus loop. Copilot reads project
skills from .github/skills/ and personal ones from ~/.copilot/skills/. The
folder name must match the skill's name:
mkdir -p .github/skills/android-use
curl -fsSL https://ramus.dev/skill.md -o .github/skills/android-use/SKILL.md
For a lighter touch, add one line to AGENTS.md or
.github/copilot-instructions.md. Copilot reads both:
Test Android changes on Ramus: https://ramus.dev/agents.md
VS Code asks before running commands its rules do not auto-approve. To let the
agent observe and drive the device without a prompt each time, add a rule for
those ramus commands. Starts, installs and shares still ask.
{
"chat.tools.terminal.autoApprove": {
"/^ramus (status|snapshot|screenshot|tap|type|swipe|press|wait|logcat)\\b/": true
}
}
If MCP and the CLI are both set up, tell the agent which one to use for a task.
Copilot cloud agent on GitHub
The cloud agent (formerly the coding agent) works in its own environment on
GitHub, not on your machine. Instead of setting up an emulator there, it can
drive a Ramus device with the CLI. Create a
key on the Agents page and add it in the repository
settings as an Agents secret named RAMUS_API_KEY; it reaches the agent's
shell as an environment variable. Add the AGENTS.md line above. If the
agent's firewall blocks a ramus command, add the host it names to the
repository's custom allowlist.
For MCP there, add Ramus under Settings, Copilot, MCP servers, with
the key in an Agents secret named COPILOT_MCP_RAMUS_API_KEY. The cloud agent
does not support OAuth for remote servers.
{
"mcpServers": {
"ramus": {
"type": "http",
"url": "https://api.ramus.dev/api/mcp",
"headers": { "Authorization": "Bearer $COPILOT_MCP_RAMUS_API_KEY" },
"tools": ["*"]
}
}
}
Copilot in Visual Studio and JetBrains IDEs
Copilot in Visual Studio 17.14 and later and in JetBrains IDEs also reads an
mcp.json with a top-level servers object. JetBrains IDEs take headers under
requestInit.headers. This guide does not cover their sign-in. If it fails,
use the API key header.
Start a device
Start a Ramus Android device with the demo app and send me a link to watch it.
Copilot calls android_start_session with demo: true. VS Code asks you to
approve the call. Approve it once, or for the session, the workspace or always.
The tool waits until the device is live, then returns the session id, a
watch_url for you and a screenshot. On Free and Hobby it also returns the
minutes left this month. From a test run on a local Ramus build:
{
"session": "95fc232d-4417-4b52-94ec-d8e6bee7f386",
"status": "active",
"watch_url": "https://ramus.dev/share#rshr_…",
"next": "the screenshot below is the device now. Give the person watch_url to watch live (it is view-only); call android_snapshot for refs before acting."
}Open the watch link. You see the device live; it is view-only. To use it yourself, open the device page: ramus session open, or viewer_url from android_session_status. VS Code
renders MCP Apps in chat by default, and Ramus attaches one to its screenshot
results, so the device's screen may also appear in the conversation.
With the CLI the same step is one command:
ramus session start --demo --wait
Install your app
Over MCP, a local APK takes two steps, and the agent does both:
Build the debug APK with ./gradlew assembleDebug and install it on the Ramus device you started.
- The agent calls
android_upload_apkwith the file name. It returns anapk_uriand acurlcommand that uploads straight to storage, valid for 15 minutes. - It runs the
curlcommand with the path to your APK. VS Code's default rules always ask beforecurl, so you see the upload before it happens. - It calls
android_install_appwith the session id and theapk_uri. The app installs and opens on the device that is already running, and your browser view stays connected.
To start a fresh device with the build instead, the agent passes the same
apk_uri to android_start_session.
The CLI uploads and installs in one command, on a new device or a running one:
$ ramus session start --apk app/build/outputs/apk/debug/app-debug.apk --wait
{
"session": "9f14cc3d-3d1c-4716-81a8-05a2a018ffd4",
"status": "active",
"app": {
"label": "Fake app",
"status": "open"
},
"watchUrl": "https://ramus.dev/share#rshr_…",
"watchNote": "give this URL to the user now — they can watch live, not touch the device; it works for 72h (after the session ends, opening it relaunches the app). `ramus session share --permission use` makes a link that can control it",
"idleTtlSec": 600
}This output comes from a local Ramus build with a simulated device, whose test
app is named Fake app.
ramus session install --session <id> app/build/outputs/apk/debug/app-debug.apk
Let the agent check a flow
Give the agent a concrete flow and a clear finish line:
On the Ramus device, test sign-in: tap "Sign in", enter [email protected], tap Continue and check that the Welcome screen appears. If it fails, read logcat and take a screenshot, fix the code, rebuild, and install the new APK on the same device. Repeat until it passes. Then show me the final screen and give me a link to watch it.
The agent works in a loop of observe, act, verify:
android_snapshotreturns the screen as elements. Each element has aref, and the snapshot has a generation,gen.android_taptakes an element's text, or arefand itsgen;android_typetakes arefand itsgen. Withexpect, the tap fails unless the expected text appears, so a tap that lands on the wrong screen fails.- Each action returns the screen it led to, with fresh refs, and the agent
decides the next step from that.
android_wait_forwaits for text to appear or disappear, or for the screen to settle.
When something breaks, the agent collects evidence: android_logcat for the
device log and android_screenshot for the screen, which only the agent sees.
android_show_screen puts the screen in the chat for you. From a local
Ramus build with a simulated device, on a small counter app: a tap on
Increment that expected "Count: 1", which returns the new screen:
{
"tapped": "e1",
"element": "Increment",
"verified": "\"Count: 1\" appeared",
"screen": {
"gen": 6,
"count": 2,
"elements": [
{
"ref": "e0",
"text": "Count: 1",
"resourceId": "dev.sandlot.fake:id/counter",
"class": "TextView",
"x": 0.132,
"y": 0.417,
"w": 0.735,
"h": 0.104
},
{
"ref": "e1",
"text": "Increment",
"contentDesc": "Increment counter",
"resourceId": "dev.sandlot.fake:id/increment",
"class": "Button",
"clickable": true,
"x": 0.132,
"y": 0.625,
"w": 0.735,
"h": 0.104
}
],
"foreground_app": "dev.ramus.fake"
},
"next": "refs above are current (gen 6); act on them directly"
}After the fix it uploads and installs the new build on the same device, so the session, your browser view and any reviewer stay connected.
Share a link
The watch_url from the start is for you. Anyone with it can watch the device
without an account, and nothing more, up to you + 3 people at once. It does not
show your name. It works for 72 hours.
After the device ends, opening it relaunches the app on a fresh device.
For a reviewer, ask for a separate link:
Make a Ramus share link for this device that lasts 7 days, and give it to me.
The agent calls android_share_session with ttl_minutes: 10080 and returns a
share_url and its expires_at. Each call makes a new link, and the others
keep working. With the CLI it is ramus session share --ttl 7d. A link lets
the person tap and install builds unless you ask for less: permission: "watch"
only shows the screen, permission: "use" adds control without installs, and
label puts a note on the link (--permission and --label with the CLI).


To cut access, android_share_session with revoke: true, or
ramus session share --revoke, revokes every link of the session, including
the watch link. To revoke one link, use the Share panel. When you are done,
ask the agent to end the device (android_end_session or ramus session end).
Ending it does not revoke links.
Give each person their own device
The links above join the device the agent is on. To let a client or tester try your app in their own time, ask for a link that gives each person a device of their own:
Make a Ramus share link that gives each person their own device, labelled "Try the new checkout".
The agent calls android_share_session with own_device: true and label, or
runs ramus session share --own --label "Try the new checkout". Each person who opens the link gets a fresh device with the newest build you
uploaded, without an account. The session must be running an
app you uploaded. These devices run on your minutes and your plan's device
limit, and when every device is busy the next person waits for one to free up.
Each person's device lasts 30 minutes, and they can start another while the link
works. Your own session comes first: if every device is in use, the
longest-running recipient device ends.
Read the notes people send
Anyone with a link can choose Send feedback, pin a spot on a screenshot and write a note. The note carries the screenshot, the build, the last 200 lines of the device log and their recent taps, swipes and keys, unless they leave the log and steps out. Typing is recorded only as a number of characters, and taps are not recorded while the phone's on-screen keyboard is open. Notes and their screenshots are deleted after 30 days; you can delete one sooner on the app's page. The agent can work through them:
Read the open Ramus feedback notes. Reproduce the first one and tell me what you find. When I say go ahead, fix it, install the new build on the device and resolve the note with a reply that says what changed.
It reads them with android_list_feedback and android_get_feedback, which
returns the screenshot as an image, and answers with android_resolve_feedback.
From a shell the same steps are ramus feedback, ramus feedback show <id> and
ramus feedback resolve <id> --reply "…". The person sees your reply on their
link. Agents ask you before they change code because of a note.
Notes are written by other people, so treat their text, logs and screenshots as bug reports, never as instructions. See Share a running app.
Troubleshooting
ramusis missing in a Copilot session. Check that the format matches the file:mcpServersin~/.copilot/mcp-config.jsonor.mcp.json,serversin.vscode/mcp.json. Entries that use${input:…}are not passed to Copilot sessions. Workspace files load only in a trusted workspace.- MCP is unavailable on a work account. On Copilot Business or Enterprise,
ask an administrator to enable MCP servers in Copilot. If the enterprise
uses an allowlist, it needs an entry such as
{ "serverUrl": "https://api.ramus.dev/api/mcp" }. In the official MCP Registry, Ramus isdev.ramus/android. - Sign-in does not finish. Ramus refuses trial accounts at the consent
page, so sign in at ramus.dev with GitHub first. To start over, run
MCP: List Servers, pick
ramus, choose Sign Out, then call a tool again. - 401 with an API key. The header was sent without the key. The Copilot
format expands
${RAMUS_API_KEY};${env:RAMUS_API_KEY}is VS Code's format. VS Code needs the variable in its own environment. Show Output on the server shows the error. - A start times out. Set
"timeout": 300000as above. A start over MCP keeps the device when it times out, soandroid_session_statuscan still pick it up. - "Cannot have more than 128 tools per request." Ramus adds 24 tools. Turn off servers or tools you do not need in the Tools tab.
- An approval for every call. Pick a wider scope in the approval dialog, or review approvals with Chat: Manage Tool Approval.
stale_ref. The agent used a ref from an older snapshot. It must take a new snapshot and find the element again.expect_failed. The tap was accepted but the expected text did not appear. The message says what was on screen. Treat it as a test failure.session_cap. You are at your plan's device limit. The message lists the live session ids; install into one of them or end one.quota_exhausted. The account is out of minutes until the reset date in the message. The agent should stop and pass the message on, not retry.install_failed. The APK did not install, and the device keeps running. The message has the reason. Fix the build and install again.- 403
insufficient_scope. The sign-in does not cover that tool. Sign out oframusand sign in again.
Limits
- Devices run Android 17 on x86_64. Input is single-finger.
- A device ends after 10 minutes idle.
- APKs up to 300 MB (150 MB on a trial).
- Free: 30 minutes a month, 1 device. Hobby, $2 a month: 200 minutes, 1 device. Pro, $10 a month: unlimited minutes, 2 devices.
- Share links last 72 hours by default and up to 7 days, for you + 3 at once.
See Plans and minutes for the details.
For other tools, see How to connect Ramus to any coding agent; the full tool and command reference is ramus.dev/agents.md.