NoMacSign in
← Blog

Give GitHub Copilot's cloud agent a Mac for iOS work

Copilot cloud agent runs on Ubuntu or Windows runners, not macOS. Add NoMac as an MCP server with an Agents secret, and the agent can build and test an iOS app on a cloud Mac.

· 5 min read

Need a Mac for this? NoMac gives your agent full macOS with Xcode for $0.80 an hour, billed by the minute. Start now →


GitHub Copilot cloud agent, which GitHub earlier called the coding agent, takes an issue or a task, works on it in its own GitHub Actions environment and pushes the changes to a branch. GitHub's environment docs say it “is only compatible with Ubuntu x64 Linux and Windows 64-bit runners. Runners with macOS or other operating systems are not supported.” So it cannot run Xcode, compile SwiftUI or boot the iOS Simulator by itself. With NoMac connected, it can do those steps on a cloud Mac.

Not tested end to end: we have not run this setup on Copilot cloud agent. The steps follow GitHub's documentation as of October 2026 and NoMac's own requirements. Copilot's firewall must let the requests through, as described below.

Step 1: make an API key

Sign in at nomac.app/keys and create a key. It starts with nmk_. Anyone holding it can start Macs on your credit, so keep it only in GitHub's secret settings.

Step 2: store it as an Agents secret

In the repository's Settings, open Secrets and variables, then Agents, and add a repository secret named COPILOT_MCP_NOMAC_API_KEY. GitHub's secrets docs say these are exposed to the agent as environment variables, “except secrets and variables prefixed with COPILOT_MCP_, which are only available to MCP servers.” The prefix keeps the key out of the agent's shell and hands it to the MCP server below.

To use the CLI from the agent's shell as well, add the same key a second time as NOMAC_API_KEY.

Step 3: add NoMac as an MCP server

In Settings, open Copilot, then MCP servers, and paste this into the MCP configuration section:

{
  "mcpServers": {
    "nomac": {
      "type": "local",
      "command": "npx",
      "args": ["-y", "@nomac/cli@latest", "mcp"],
      "env": { "NOMAC_API_KEY": "$COPILOT_MCP_NOMAC_API_KEY" },
      "tools": [
        "get_mac_credits", "start_mac", "get_mac_session", "list_mac_sessions",
        "exec_mac", "get_mac_job", "read_mac_output", "cancel_mac_job",
        "write_mac_file", "read_mac_file", "screenshot_mac", "stop_mac"
      ]
    }
  }
}

It follows the pattern of GitHub's own MCP examples: a server started with npx, with a COPILOT_MCP_ secret passed in env. The tools list is what the agent may call without asking you first; GitHub recommends naming tools rather than allowing *. This list covers starting a Mac, running commands, files, screenshots and stopping. It leaves out credit purchases and secret requests.

The server needs Node on the runner. If yours does not have it, install it in .github/workflows/copilot-setup-steps.yml. GitHub requires the job to be called copilot-setup-steps and the file to be on the default branch:

name: "Copilot Setup Steps"
on: workflow_dispatch
jobs:
  copilot-setup-steps:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v7
        with:
          node-version: "22"

The hosted server instead

NoMac also runs the same tools at https://mcp.nomac.app/mcp, with no Node needed on the runner:

{
  "mcpServers": {
    "nomac": {
      "type": "http",
      "url": "https://mcp.nomac.app/mcp",
      "headers": { "Authorization": "Bearer $COPILOT_MCP_NOMAC_API_KEY" },
      "tools": [
        "get_mac_credits", "start_mac", "get_mac_session", "list_mac_sessions",
        "exec_mac", "get_mac_job", "read_mac_output", "cancel_mac_job",
        "write_mac_file", "read_mac_file", "screenshot_mac", "stop_mac"
      ]
    }
  }
}

GitHub's docs allow a secret reference in every string field except tools and type, but none of their examples puts one inside a longer header value like Bearer $COPILOT_MCP_NOMAC_API_KEY. The local server above follows their examples exactly. Remote servers that use OAuth are not supported there, so the hosted server needs the header. The docs also do not say whether the firewall covers a remote server's requests, so with this option add nomac.app to the custom allowlist as well (step 4); the entry covers mcp.nomac.app.

Step 4: the firewall

GitHub's firewall docs say that “by default, Copilot's access to the internet is limited by a firewall”, and that it “only applies to processes started by the agent via its Bash tool. It does not apply directly to Model Context Protocol (MCP) server processes or processes started in configured Copilot setup steps.” By that description, the NoMac MCP server's requests are outside the firewall.

The CLI in the agent's shell is inside it. For npx -y @nomac/cli@latest, open Settings, Copilot, Internet access, Custom allowlist, and add nomac.app; a domain entry also allows its subdomains. The recommended allowlist already covers JavaScript package registries for npx. The CLI's exec, ssh, sync and pull also connect to NoMac's session gateway, over HTTPS on port 443. It is a separate host, not under nomac.app: the API returns it for each session, as the gateway field of POST /api/v1/mac/sessions/:id/access. Add it too, or use the MCP server alone.

Step 5: getting the code onto the Mac

Over MCP, the Mac gets the code from GitHub. GitHub's docs say Copilot handles branch creation, commit messages and pushing changes; the agent then clones or pulls its branch into ~/drive/src on the Mac with exec_mac.

For a private repository, the Mac needs read access. Make a fine-grained token that can read that one repository and save it as a NoMac secret named GH_TOKEN (at nomac.app/secrets, or nomac secrets set GH_TOKEN). Every Mac you start receives it, and the GitHub CLI on the Mac reads it, so gh repo clone OWNER/REPO works without a token in the saved remote URL.

Step 6: tell Copilot how to use the Mac

Copilot reads AGENTS.md files and .github/copilot-instructions.md. Add a section like this and adjust the scheme:

## iOS builds
- Xcode work (builds, tests, the Simulator) happens on a NoMac cloud Mac
  through the nomac MCP tools.
- Push your branch before each Mac build.
- start_mac once per task with a stable request_key; wait with
  get_mac_session until it is ready.
- Clone or pull the branch into ~/drive/src/REPO with exec_mac
  (gh repo clone works: GH_TOKEN is set on the Mac).
- Build with exec_mac and wait_seconds 50; for longer builds, poll
  get_mac_job, then read_mac_output:
  xcodebuild -scheme MyApp -destination 'generic/platform=iOS Simulator' build
- Read the full compiler output before changing code.
- Always call stop_mac before you finish.

Costs and limits

  • ·$0.80 an hour while the Mac is ready, billed by the minute. Queue and setup time are free. A five-minute build costs about 7 cents.
  • ·A session stops after two hours or $5 by default; start_mac takes other limits.
  • ·One Mac at a time by default. A start while a Mac runs answers with that Mac's ID.
  • ·Stopping deletes the VM and everything outside ~/drive. The 50 GB drive keeps the project and build caches, so the next task's build is incremental.

Why hosted agents need this at all is in why cloud coding agents can't build your iOS app. For the next step after a build, see give your agent TestFlight. The full agent guide is at nomac.app/llms.txt.

Give your agent a Mac in a minute.

Full macOS with Xcode and root, over MCP, CLI, API or SSH. $0.80 an hour, billed by the minute. The Mac is deleted at stop; your 50 GB drive is kept for the next one. No Apple account needed to start.

Get started from $10

7-day money-back guarantee on your first purchase. Credit never expires.

Connect your agent →