Skill is guidance, not a connection
The Skill teaches an agent to discover or install the App, pair and operate it. Installing a Skill does not configure MCP. The App runs on the computer whose windows you want to control
User guide
Start with the installation prompt, or follow the separate CLI, MCP and remote connection steps below. Both macOS and Windows use the same pairing and safety controls
The Skill explains what to do; CLI and MCP provide ways to call the local service
The Skill teaches an agent to discover or install the App, pair and operate it. Installing a Skill does not configure MCP. The App runs on the computer whose windows you want to control
macOS and Windows both provide CLI, stdio MCP and optional loopback HTTP MCP. CLI saves screenshots as local files for the agent to open; MCP returns images directly to the agent
Your model can run in the cloud while its command tools run on your computer. That still uses a local connection; a cloud-only agent with no access to your computer needs a reachable remote connection
For an agent that can execute local commands, start with the App’s installation prompt and CLI. Keep an existing working MCP connection. For another computer, use HTTP MCP over an SSH tunnel
These are setup recommendations, not an automatic selection mechanism. Computer Use does not choose an interface for your agent or retry an uncertain action through another one
Use this flow unless you specifically need manual configuration or another computer
Install the correct package from the download page, then open Computer Use. In “Connect”, choose “Copy Installation Prompt” and paste it into your agent. The App includes its own CLI runtime; you do not need global Node or a repository clone
The agent follows the Skill installation mechanism it supports. Keep existing Skill customizations and use the same profile throughout; examples in this guide use default
On macOS, grant Accessibility and Screen Recording to Computer Use in system settings. On Windows, keep the App in your signed-in interactive desktop and review any system launch warning yourself. Approve the client in the local App when the first pairing request appears
Reuse an existing authorized profile. Pairing, operating-system permission and the agent’s own tool approvals are separate controls. A new window or app does not require another pairing when the client already has all-app access
Open a harmless test window and copy the read-only task below to your agent. Ask it to check the connection, list windows, open a background session, show a screenshot and close the session without clicking, typing or changing anything
Success means the agent actually opens and shows the image, not just that a command exits successfully. Screenshots are sent to the agent you chose; avoid a window containing information you do not want it to receive
Use computer-use to check the connection, list authorized windows, open a session for the test window, capture and describe its screenshot, then close the session. Do not click or type during this taskRun commands on the computer with Computer Use installed. CLI does not require MCP configuration
Use the local path hint in the App’s installation prompt, or discover standard installation locations with the example below. It sets cu; if it finds multiple copies, select the intended complete installation instead of guessing. Keep this terminal open for the following commands
Read --help and instructions at the start of each new agent conversation, then run preflight --profile default. These commands do not require pairing or start the service. An offline credential marked unverified is not proof that access is valid
cuApp=''
for candidate in '/Applications/Computer Use.app' "$HOME/Applications/Computer Use.app"; do
if [ -d "$candidate" ]; then
if [ -n "$cuApp" ]; then
printf '%s\n' 'Multiple installations: choose the intended App path' >&2
cuApp=''
break
fi
cuApp="$candidate"
fi
done
# For multiple or custom installations, set cuApp to the intended absolute path
cu() {
[ -n "$cuApp" ] || { printf '%s\n' 'Set cuApp first' >&2; return 1; }
cuResources="$cuApp/Contents/Resources"
[ "$(/usr/bin/plutil -extract CFBundleIdentifier raw -o - "$cuApp/Contents/Info.plist")" = com.starroy.computeruse ] || return 1
for file in "$cuApp/Contents/MacOS/ComputerUseHost" "$cuResources/bin/node" "$cuResources/bin/computer-use" "$cuResources/bin/cua-driver"; do
[ -x "$file" ] || { printf 'Missing executable: %s\n' "$file" >&2; return 1; }
done
for file in runtime/cli.js runtime/host.js package.json build-receipt.json skills/computer-use/SKILL.md; do
[ -f "$cuResources/$file" ] || { printf 'Missing file: %s\n' "$file" >&2; return 1; }
done
[ -d "$cuResources/node_modules" ] || return 1
"$cuResources/bin/computer-use" "$@"
}
cu --help && cu instructions && cu preflight --profile defaultOpen PowerShell as the desktop user. Use the local path hint in the App’s installation prompt, or discover the current-user installation as below; for a portable package, use its complete extracted directory. The example sets cuNode and cuCli; keep this PowerShell window open
Read --help and instructions, then inspect preflight --profile default. Do not copy cli.js out of its package or substitute a global Node installation
$ErrorActionPreference = 'Stop'
$cuRoot = Join-Path $env:LOCALAPPDATA 'Programs\Computer Use'
# For a portable/custom installation, replace cuRoot with its complete package directory
foreach ($file in @('ComputerUse.WindowsHost.exe', 'bin\node.exe', 'bin\cua-driver.exe', 'runtime\cli.js', 'runtime\host.js', 'package.json', 'build-receipt.json', 'skills\computer-use\SKILL.md')) {
if (-not (Test-Path -LiteralPath (Join-Path $cuRoot $file) -PathType Leaf)) {
throw "Incomplete package: $file"
}
}
if (-not (Test-Path -LiteralPath (Join-Path $cuRoot 'node_modules') -PathType Container)) {
throw 'Incomplete package: node_modules'
}
$cuNode = Join-Path $cuRoot 'bin\node.exe'
$cuCli = Join-Path $cuRoot 'runtime\cli.js'
& $cuNode $cuCli --help
if ($LASTEXITCODE -ne 0) { throw 'CLI help failed' }
& $cuNode $cuCli instructions
if ($LASTEXITCODE -ne 0) { throw 'Read the installed version compatibility instructions' }
& $cuNode $cuCli preflight --profile defaultIf preflight reports missing and no known revocation explains it, request first pairing and approve it in the local App. If the profile already exists, reuse it; invalid, unauthorized or an offline unverified state calls for diagnosis, not deleting credentials and pairing again
The examples request the default all-desktop-app scope. Review that scope before approving it; isolated-browser access is separate. Replace default consistently if you use another profile
# Only when preflight reports missing credentials and there is no known revocation
cu pair --profile default --name 'My Agent'# Only when preflight reports missing credentials and there is no known revocation
& $cuNode $cuCli pair --profile default --name 'My Agent'Run doctor and targets, choose the returned target ID for your test window, then call session_open in background mode. Use its returned session ID for observe and session_close; replace every placeholder with the actual returned value
Open the screenshot file returned by observe with the agent’s image-reading tool before closing the session. No click or typing is required for this check. Use schema for the installed version’s exact method parameters
# Run each command separately, inspect its result, then replace the next placeholder
cu doctor --profile default
cu targets --profile default
cu session_open --profile default --json '{"targetId":"TARGET_ID","mode":"background"}'
cu observe --profile default --json '{"sessionId":"SESSION_ID"}'
# Read the screenshot file returned by observe, then close this session
cu session_close --profile default --json '{"sessionId":"SESSION_ID"}'# Run each step separately and inspect the result
& $cuNode $cuCli doctor --profile default
& $cuNode $cuCli targets --profile default
# File input avoids native-command JSON quoting differences in PowerShell 5.1 and 7
$cuRequest = Join-Path ([IO.Path]::GetTempPath()) ("cu-observe-" + [Guid]::NewGuid().ToString() + '.json')
$utf8 = New-Object Text.UTF8Encoding($false)
[IO.File]::WriteAllText($cuRequest, '{"targetId":"TARGET_ID","mode":"background"}', $utf8)
& $cuNode $cuCli session_open --profile default --input $cuRequest
# Replace SESSION_ID with the returned sessionId
[IO.File]::WriteAllText($cuRequest, '{"sessionId":"SESSION_ID"}', $utf8)
& $cuNode $cuCli observe --profile default --input $cuRequest
# Read the screenshot file returned by observe, then close this session
& $cuNode $cuCli session_close --profile default --input $cuRequest
Remove-Item -LiteralPath $cuRequestUse this when your agent supports MCP and can launch a process on the same computer
First complete the CLI discovery and profile checks above. In the App, open “Connect” → “Advanced Connection”, select the same profile, and copy the configuration for your agent. HTTP does not need to be enabled for stdio MCP
Alternatively use config stdio for generic JSON or config codex for Codex configuration. Generated stdio settings contain absolute launch paths and the profile name, not the pairing token
Run these in the terminal where cu was set. Add the generated server entry to the format supported by your agent, preserving its other entries
cu config stdio --profile default
# For an Agent that uses Codex TOML, run this instead:
# cu config codex --profile defaultRun these in the PowerShell window where cuNode and cuCli were set. Keep the generated absolute paths and argument boundaries; do not paste a shell command into a field that expects an executable path
& $cuNode $cuCli config stdio --profile default
# For an Agent that uses Codex TOML, run this instead:
# & $cuNode $cuCli config codex --profile defaultReload the agent’s MCP configuration or restart the agent, then check that the server exposes tools. Ask it to run doctor → targets → session_open → observe → session_close on the test window. MCP returns the screenshot as an image
preflight, instructions and recover are CLI helpers, not MCP tools. An agent using MCP may still need local command access for maintenance; a pure MCP client cannot assume these helpers are available
The target computer runs the App and its windows; the controller computer runs your agent and the SSH tunnel
Keep the desktop signed in and unlocked, run Computer Use, approve permissions and pairing, prepare SSH and enable HTTP MCP
Prepare the SSH client and key, verify the target, open the tunnel, import the private HTTP configuration and check a screenshot
Use the same LAN or an existing trusted network where SSH is reachable. This guide does not set up public port forwarding, tunnelling services or unattended access. Use the same target account for SSH and the App so its profile and private files match. Keep that user signed in to an unlocked interactive desktop, with the App running and its system permissions approved
Both platforms expose HTTP MCP, but interface availability is not an acceptance-test claim: the documented cross-computer test controls Windows from a Mac; remote control of a Mac has not received the same desktop validation
Open System Settings → General → Sharing → Remote Login, turn it on and allow only the account you intend to use. Note the displayed login name and address. Do not enable full disk access for remote users for this setup; SSH permission does not grant Computer Use access
Follow Apple’s Remote Login instructions if your system settings differ
In an administrator PowerShell, inspect the optional OpenSSH Server component, install it only if absent, and start sshd. Check the existing inbound SSH rule rather than adding duplicate rules; restrict its source addresses to the controller or trusted network. Do not open the MCP port in the firewall
Automatic service startup is optional and is a separate persistent change. See Microsoft’s OpenSSH setup; the second example enables automatic startup only if you choose it
$ErrorActionPreference = 'Stop'
$cuSsh = Get-WindowsCapability -Online -Name 'OpenSSH.Server~~~~0.0.1.0'
if ($cuSsh.State -ne 'Installed') {
Add-WindowsCapability -Online -Name 'OpenSSH.Server~~~~0.0.1.0'
Set-Service -Name sshd -StartupType Manual
}
Start-Service sshd
Get-Service sshd
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' |
Select-Object Name, Enabled, Direction, Action, Profile
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' | Get-NetFirewallPortFilterSet-Service -Name sshd -StartupType AutomaticmacOS includes an SSH client. On Windows, check ssh -V; if missing, add the OpenSSH Client optional feature in Windows settings. Generate a dedicated passphrase-protected key, or reuse an appropriate existing key without overwriting it
Only transfer the .pub public key to the target through a trusted channel. The private key stays on the controller. The examples use a dedicated key path; cancel if a key already exists there rather than replacing it
command -v ssh ssh-keygen sftp
cuKey="$HOME/.ssh/id_ed25519_computer_use"
if [ -e "$cuKey" ] || [ -e "$cuKey.pub" ]; then
printf '%s\n' 'Key already exists: reuse the intended pair; do not overwrite it'
else
install -d -m 700 "$HOME/.ssh"
ssh-keygen -t ed25519 -f "$cuKey" -C 'computer-use'
fi
# Copy only this public key to the target computer
cat "$cuKey.pub"$ErrorActionPreference = 'Stop'
Get-Command ssh.exe, ssh-keygen.exe, sftp.exe -ErrorAction Stop
$cuKey = Join-Path $env:USERPROFILE '.ssh\id_ed25519_computer_use'
if ((Test-Path -LiteralPath $cuKey) -or (Test-Path -LiteralPath "$cuKey.pub")) {
Write-Output 'Key already exists: reuse the intended pair; do not overwrite it'
} else {
New-Item -ItemType Directory -Path (Split-Path $cuKey) -Force | Out-Null
ssh-keygen.exe -t ed25519 -f $cuKey -C computer-use
if ($LASTEXITCODE -ne 0) { throw 'Key generation failed' }
}
# Copy only this public key to the target computer
Get-Content -LiteralPath "$cuKey.pub"Sign in locally as the target SSH user. Add the controller’s public key as a new line in ~/.ssh/authorized_keys, preserving existing keys. The directory belongs to that user with permission 700; the file uses 600. Do not paste the private key
cuPublicKey='<PUBLIC_KEY_LINE>'
case "$cuPublicKey" in
'ssh-ed25519 '*)
install -d -m 700 "$HOME/.ssh"
cuAuthorized="$HOME/.ssh/authorized_keys"
if [ -L "$cuAuthorized" ]; then
printf '%s\n' 'Review the existing authorized_keys symlink before continuing' >&2
else
(umask 077; touch "$cuAuthorized")
grep -Fqx -- "$cuPublicKey" "$cuAuthorized" || printf '\n%s\n' "$cuPublicKey" >> "$cuAuthorized"
chmod 600 "$cuAuthorized"
fi
;;
*) printf '%s\n' 'Replace PUBLIC_KEY_LINE with the complete public key' >&2 ;;
esacFor a standard account, add the public key to that user’s %USERPROFILE%\.ssh\authorized_keys; the example restricts the file to that account, Administrators and SYSTEM. Check that its directory belongs to the user and cannot be written by other standard accounts. For an administrator account, default OpenSSH instead uses %ProgramData%\ssh\administrators_authorized_keys; manage it from administrator PowerShell
Append without replacing existing keys. The administrator key file is shared across administrator accounts and must be accessible only to Administrators and SYSTEM. To limit a key to one administrator, review a deliberate server configuration instead of treating this shared file as per-user authorization. Use the matching example and Microsoft’s key-management instructions; a customized sshd_config can change the expected location
$ErrorActionPreference = 'Stop'
$cuPublicKey = '<PUBLIC_KEY_LINE>'
if (-not $cuPublicKey.StartsWith('ssh-ed25519 ')) { throw 'Replace PUBLIC_KEY_LINE with the complete public key' }
$cuAuthorized = Join-Path $env:USERPROFILE '.ssh\authorized_keys'
New-Item -ItemType Directory -Path (Split-Path $cuAuthorized) -Force | Out-Null
if ((Test-Path -LiteralPath $cuAuthorized) -and ((Get-Item -LiteralPath $cuAuthorized).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw 'Review the existing authorized_keys link before continuing'
}
if (-not (Test-Path -LiteralPath $cuAuthorized) -or -not (Select-String -LiteralPath $cuAuthorized -Pattern $cuPublicKey -SimpleMatch -Quiet)) {
Add-Content -LiteralPath $cuAuthorized -Value ("`r`n" + $cuPublicKey) -Encoding ascii
}
$cuSid = [Security.Principal.WindowsIdentity]::GetCurrent().User
$cuAcl = New-Object Security.AccessControl.FileSecurity
$cuAcl.SetOwner($cuSid)
$cuAcl.SetAccessRuleProtection($true, $false)
foreach ($sid in @($cuSid, [Security.Principal.SecurityIdentifier]'S-1-5-18', [Security.Principal.SecurityIdentifier]'S-1-5-32-544')) {
$cuAcl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($sid, 'FullControl', 'Allow')))
}
Set-Acl -LiteralPath $cuAuthorized -AclObject $cuAcl$ErrorActionPreference = 'Stop'
$cuPublicKey = '<PUBLIC_KEY_LINE>'
if (-not $cuPublicKey.StartsWith('ssh-ed25519 ')) { throw 'Replace PUBLIC_KEY_LINE with the complete public key' }
$cuAuthorized = Join-Path $env:ProgramData 'ssh\administrators_authorized_keys'
if ((Test-Path -LiteralPath $cuAuthorized) -and ((Get-Item -LiteralPath $cuAuthorized).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw 'Review the existing administrators_authorized_keys link before continuing'
}
if (-not (Test-Path -LiteralPath $cuAuthorized) -or -not (Select-String -LiteralPath $cuAuthorized -Pattern $cuPublicKey -SimpleMatch -Quiet)) {
Add-Content -LiteralPath $cuAuthorized -Value ("`r`n" + $cuPublicKey) -Encoding ascii
}
$cuAdmins = [Security.Principal.SecurityIdentifier]'S-1-5-32-544'
$cuAcl = New-Object Security.AccessControl.FileSecurity
$cuAcl.SetOwner($cuAdmins)
$cuAcl.SetAccessRuleProtection($true, $false)
foreach ($sid in @($cuAdmins, [Security.Principal.SecurityIdentifier]'S-1-5-18')) {
$cuAcl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($sid, 'FullControl', 'Allow')))
}
Set-Acl -LiteralPath $cuAuthorized -AclObject $cuAclRead the target’s host-key fingerprint on the target computer itself and record it through a trusted channel. Compare it with the fingerprint shown on the controller’s first SSH connection; accept only after it matches. A changed fingerprint needs investigation, not disabling host-key checking
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubssh-keygen.exe -lf "$env:ProgramData\ssh\ssh_host_ed25519_key.pub"Replace the user and address placeholders with the target’s actual login. Use the dedicated key, verify the fingerprint and confirm you reach the intended account. Exit that remote shell before starting the tunnel; a successful SSH login does not start Computer Use or approve pairing
ssh -i "$HOME/.ssh/id_ed25519_computer_use" -o IdentitiesOnly=yes -o HostKeyAlgorithms=ssh-ed25519 '<REMOTE_USER>@<REMOTE_HOST>'
# Compare the offered SHA256 fingerprint with the target computer before accepting
# After verifying the login, type exit to return to the Agent computerssh.exe -i "$env:USERPROFILE\.ssh\id_ed25519_computer_use" -o IdentitiesOnly=yes -o HostKeyAlgorithms=ssh-ed25519 '<REMOTE_USER>@<REMOTE_HOST>'
# Compare the offered SHA256 fingerprint with the target computer before accepting
# After verifying the login, type exit to return to the Agent computerKeep this command running in a separate terminal. Bind only 127.0.0.1:47631 and forward it to the target’s same port. The Host validates that address and port, so changing only the local port is not a supported workaround
If the port is busy, identify and stop your old tunnel or disable the controller’s local HTTP MCP before retrying. Do not kill an unrelated process, use -g, bind 0.0.0.0 or expose the MCP port directly
ssh -i "$HOME/.ssh/id_ed25519_computer_use" \
-o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
-o HostKeyAlgorithms=ssh-ed25519 -o ExitOnForwardFailure=yes \
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 -N \
-L 127.0.0.1:47631:127.0.0.1:47631 '<REMOTE_USER>@<REMOTE_HOST>'ssh.exe -i "$env:USERPROFILE\.ssh\id_ed25519_computer_use" `
-o IdentitiesOnly=yes -o StrictHostKeyChecking=yes `
-o HostKeyAlgorithms=ssh-ed25519 -o ExitOnForwardFailure=yes `
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 -N `
-L 127.0.0.1:47631:127.0.0.1:47631 '<REMOTE_USER>@<REMOTE_HOST>'On the target, reuse the CLI discovery variables and the intended existing profile, or complete first local pairing only if missing and not known to be revoked. Open “Connect” → “Advanced Connection” in the App and enable local HTTP MCP. It defaults to off each time the App or service restarts
Export a new HTTP configuration file using the matching command. Unlike stdio settings, this JSON contains a Bearer credential. Windows requires the App’s private data directory. The exporter refuses to overwrite an existing file; review that file or choose a new filename
install -d -m 700 "$HOME/.config/computer-use"
cu config http --profile default --out "$HOME/.config/computer-use/remote-http.json"
# The CLI refuses to overwrite an existing file; do not print its contents& $cuNode $cuCli config http --profile default --out "$env:LOCALAPPDATA\Computer Use\remote-http.json"
# Export only into the Host private data directory; existing files are not overwritten
# Do not print the file contentsUse SSH/SFTP to retrieve the exported JSON into a new private local directory. Replace the remote-path placeholder with the absolute path returned by the export command, using forward slashes for a Windows target and keeping the whole remote argument quoted. The examples restrict the downloaded file to your account
Import its URL and authorization header into an agent that supports HTTP MCP and private credential storage. Keep the URL http://127.0.0.1:47631/mcp; the tunnel reaches the target. Do not paste the credential into an agent conversation, a web page, a repository or a shared folder. No global Node installation is required for this direct HTTP connection
Reload the agent’s MCP connection. Keep the private configuration while it is needed; after confirming the transfer, remove only the extra exported copy on the target if desired, not the App’s pairing credentials
cuRemoteDir="$(mktemp -d "$HOME/.computer-use-remote.XXXXXX")"
# Replace REMOTE_CONFIG_PATH with the absolute path returned by config http
# The exported filename is remote-http.json; keep the entire remote argument quoted
(
umask 077
cd "$cuRemoteDir" &&
sftp -i "$HOME/.ssh/id_ed25519_computer_use" \
-o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
-o HostKeyAlgorithms=ssh-ed25519 \
'<REMOTE_USER>@<REMOTE_HOST>:<REMOTE_CONFIG_PATH>' &&
chmod 600 remote-http.json
)
printf 'Private configuration directory: %s\n' "$cuRemoteDir"$ErrorActionPreference = 'Stop'
$cuRemoteDir = Join-Path $env:USERPROFILE ('.computer-use-remote-' + [Guid]::NewGuid().ToString())
New-Item -ItemType Directory -Path $cuRemoteDir | Out-Null
$cuSid = [Security.Principal.WindowsIdentity]::GetCurrent().User
$cuAcl = New-Object Security.AccessControl.DirectorySecurity
$cuAcl.SetOwner($cuSid)
$cuAcl.SetAccessRuleProtection($true, $false)
$cuAcl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($cuSid, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow')))
Set-Acl -LiteralPath $cuRemoteDir -AclObject $cuAcl
# Replace REMOTE_CONFIG_PATH with the absolute exported path, using / separators
Push-Location -LiteralPath $cuRemoteDir
try {
sftp.exe -i "$env:USERPROFILE\.ssh\id_ed25519_computer_use" `
-o IdentitiesOnly=yes -o StrictHostKeyChecking=yes `
-o HostKeyAlgorithms=ssh-ed25519 `
'<REMOTE_USER>@<REMOTE_HOST>:<REMOTE_CONFIG_PATH>'
if ($LASTEXITCODE -ne 0) { throw 'SFTP failed; do not use the partial file' }
} finally {
Pop-Location
}
Write-Output "Private configuration directory: $cuRemoteDir"Run the same read-only sequence: doctor → targets → session_open → observe → session_close. Confirm the window and screenshot belong to the target computer, not the controller
Remote HTTP cannot start the Host or invoke local recover. If the service is unavailable, the target user must check the App and its state; do not bypass a pause, emergency stop or revoked grant by starting another copy
If the tunnel disconnects, preserve any action’s original requestId. Reconnect, query action_status and observe again; do not resend an action whose result is uncertain. If the App or service restarted, the target user must enable HTTP again
When finished, close sessions and press Ctrl+C in the tunnel terminal. Disable HTTP in the target App. To stop SSH access too, turn off Remote Login on macOS or stop sshd on Windows; if you enabled automatic startup, disable it deliberately. Remove only the dedicated public-key entry if you no longer want that key authorized
Stop-Service sshd
Set-Service -Name sshd -StartupType ManualKeep the exact error and the existing profile. Changing the connection does not change its authorization
Check the complete installation and the local path hint in the App’s installation prompt. After moving the App or portable directory, regenerate stdio configuration because its paths are absolute. If an older App lacks instructions or preflight, use the installed Skill’s compatibility guidance and review an upgrade; a missing command does not mean the App is absent
Use the same profile in CLI commands, MCP configuration and diagnostics. Inspect doctor.authorization, capabilities.authorization or online preflight.profile.authorization; an absent field means the scope is unknown. targets omits windows outside the client’s grant
For an existing desktop client, the user can choose “Clients” → “Allow all apps…” in the App and confirm locally. This preserves the token, profile and MCP configuration and leaves isolated-browser permission unchanged. Browser-only clients need separate local review; an older App without this control needs an upgrade or local review, not automatic re-pairing
Also check that the app has a visible window in the signed-in desktop and that system permissions are granted. New windows do not need individual approval under an existing all-app grant
For SSH, check the target address, allowed account, SSH service, firewall rule, key-file location and ACL. Never dismiss a changed host fingerprint without checking the target. For HTTP, check that the target App is running, its HTTP switch is enabled and the tunnel owns the controller’s port 47631
A 401 response calls for checking the selected profile and whether the client was revoked. Missing system permissions and a locked or non-interactive desktop need attention on the target. Do not expose MCP through the firewall to work around the tunnel
Read the installed instructions and preflight first. For a failed Host, or a connection lost after an unknown desktop action with no user stop, an agent may make one recover attempt using the same complete package and existing profile. The examples are local CLI commands, not remote MCP tools
Recovery cannot clear pause or emergency stop, restore revoked access, supply system permissions or re-pair. Those need local user action. On success, query any original action, open a new background session and observe; do not reuse old sessions, snapshots or elements. If recovery fails or the next step faults again, report it rather than looping
cu preflight --profile default
# Only for a recoverable service fault; inspect preflight before running once
cu recover --profile default
# If an action is uncertain, preserve its original requestId and query it after recovery
cu action_status --profile default --json '{"requestId":"ORIGINAL_REQUEST_ID"}'
# Open a new session and observe; never replay the uncertain action& $cuNode $cuCli preflight --profile default
# Only for a recoverable service fault; inspect preflight before running once
& $cuNode $cuCli recover --profile default
# If an action is uncertain, preserve its original requestId and query it after recovery
$cuStatusInput = Join-Path ([IO.Path]::GetTempPath()) ("cu-status-" + [Guid]::NewGuid().ToString() + '.json')
[IO.File]::WriteAllText($cuStatusInput, '{"requestId":"ORIGINAL_REQUEST_ID"}', (New-Object Text.UTF8Encoding($false)))
& $cuNode $cuCli action_status --profile default --input $cuStatusInput
Remove-Item -LiteralPath $cuStatusInput
# Open a new session and observe; never replay the uncertain actionunknown means input delivery is uncertain. Keep the original requestId, query action_status and inspect a fresh observation after reconnection. Do not retry through CLI instead of MCP, invent a new request ID, or repeat an equivalent click or keystroke
executed with an unconfirmed effect needs observation, not a service restart. An unchanged screen does not prove input was never delivered; if you cannot establish whether a consequential action happened, ask the user to resolve it