Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions docs/content/docs/how-to-guides/driver/windows-ssh.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ pipe and accepts `--socket` when you want to make the endpoint explicit. The
SSH process only moves protocol messages; the daemon performs the actual GUI
work from a session with a desktop attached.

<Callout type="warn">
Sign in through SSH with the same Windows account that owns the interactive
daemon. The named pipe is private to that account; a different local or domain
account can detect the pipe but receives `Access is denied` when it tries to
connect. Run `whoami /user` in both sessions and compare the SIDs, which must
match exactly.
</Callout>

```
┌───────────────────────────────────────────────────────────────┐
│ Session 1+ (RDP / console, has interactive desktop) │
Expand Down Expand Up @@ -87,9 +95,12 @@ cua-driver status
# Cua Driver daemon is running
# socket: \\.\pipe\cua-driver
# pid: 12345
# session: 2 ← daemon is in your interactive session
```

`status` opens the pipe and requests daemon state. If the endpoint exists but
belongs to another Windows account, it reports that the endpoint is not
reachable and tells you to compare the two account SIDs.

**3. Call tools from SSH:**

```powershell
Expand All @@ -113,15 +124,16 @@ that process as a protocol proxy to the interactive daemon. Bare `cua-driver
mcp` owns a direct runtime on Windows and therefore fails closed in Session 0;
it never silently falls back to another session.

## Diagnose empty results
## Diagnose connection or empty results

Check these items before opening an issue:

1. Confirm that `cua-driver --version` on the SSH side reports the same current install you expect. Upgrade if needed with `irm https://cua.ai/driver/install.ps1 | iex`.
2. Run `cua-driver status` from SSH and confirm it reports a running daemon. If it does not, use `cua-driver autostart status` to see whether the Scheduled Task is registered.
3. Run `query session` and confirm your user has a row in `Active` or `Disc` state.
4. Run `cua-driver doctor` from RDP and confirm it reports `[ok] interactive session: session N has an attached interactive desktop`.
5. Confirm that the MCP command includes `--socket \\.\pipe\cua-driver`, or the
2. Run `whoami /user` over SSH and in the interactive desktop. The SIDs must match; the pipe does not permit cross-account desktop control.
3. Run `cua-driver status` from SSH and confirm it reports a reachable daemon. If the daemon is absent, use `cua-driver autostart status` to see whether the Scheduled Task is registered. If the endpoint exists but access is denied, fix the account mismatch.
4. Run `query session` and confirm your user has a row in `Active` or `Disc` state.
5. Run `cua-driver doctor` from RDP and confirm it reports `[ok] interactive session: session N has an attached interactive desktop`.
6. Confirm that the MCP command includes `--socket \\.\pipe\cua-driver`, or the
exact endpoint reported by `cua-driver status`.

If the explicitly selected interactive-session daemon is unavailable, MCP
Expand Down
28 changes: 20 additions & 8 deletions libs/cua-driver/rust/crates/cua-driver/src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2308,13 +2308,6 @@ pub fn run_stop_cmd(socket_path: &str) {
/// `cua-driver status` implementation.
pub fn run_status_cmd(socket_path: &str, pid_file_path: &str) {
if is_daemon_listening(socket_path) {
println!("Cua Driver daemon is running");
println!(" socket: {socket_path}");
if let Some(pid) = read_pid_file(pid_file_path) {
println!(" pid: {pid}");
} else {
println!(" pid: unknown (no pid file)");
}
let request = DaemonRequest {
method: "authorization_status".to_owned(),
name: None,
Expand All @@ -2323,7 +2316,26 @@ pub fn run_status_cmd(socket_path: &str, pid_file_path: &str) {
observation_origin: Some(ToolObservationOrigin::Direct),
client_kind: None,
};
if let Ok(response) = send_request(socket_path, &request) {
let response = send_request(socket_path, &request);
if let Err(error) = &response {
eprintln!("Cua Driver daemon endpoint exists but is not reachable");
eprintln!(" socket: {socket_path}");
eprintln!(" error: {error}");
#[cfg(target_os = "windows")]
eprintln!(
" hint: the named pipe accepts only the Windows account that owns the daemon. \
Run `whoami /user` in this shell and in the interactive desktop; the SIDs must match."
);
std::process::exit(1);
}
println!("Cua Driver daemon is running");
println!(" socket: {socket_path}");
if let Some(pid) = read_pid_file(pid_file_path) {
println!(" pid: {pid}");
} else {
println!(" pid: unknown (no pid file)");
}
if let Ok(response) = response {
if let Some(status) = response.result {
println!(
" permission mode: {} ({})",
Expand Down
Loading