DeskVNC DeskVNC

Registering DeskVNC with Visual Studio Code

Visual Studio Code is the editor most teams already have open, and it speaks the Model Context Protocol. Pairing it with DeskVNC's dvv turns Copilot Chat (or any VS Code MCP client) into an agent that can see and click a real remote desktop. The protocol that connects to the machine is the same VNC, RDP, or SSH the remote already speaks, so nothing is installed on the remote target, and the user can take the wheel back with one click. The DeskVNC integration notes document the exact shape VS Code reads.

Prerequisite: the dvv binary

dvv is the executable that ships inside DeskVNCViewer. Install the viewer, open it once, and save a machine with its password so the agent has something concrete to reach. The binary lives next to the application:

The path you point VS Code at is the path the viewer installed.

The registration step

VS Code reads a workspace-scoped MCP file. Per the DeskVNC integration notes, the top-level key is servers (not mcpServers) and each entry takes a "type": "stdio" field. On macOS, drop the following into .vscode/mcp.json in the project root:

{
  "servers": {
    "deskvnc": {
      "type": "stdio",
      "command": "/Applications/DeskVNCViewer.app/Contents/MacOS/dvv",
      "args": ["mcp", "--stdio"]
    }
  }
}

On Linux, the same block with the system path:

{
  "servers": {
    "deskvnc": {
      "type": "stdio",
      "command": "/usr/bin/dvv",
      "args": ["mcp", "--stdio"]
    }
  }
}

On Windows, use a JSON-safe path. Forward slashes keep the file portable:

{
  "servers": {
    "deskvnc": {
      "type": "stdio",
      "command": "C:/Program Files/DeskVNCViewer/dvv.exe",
      "args": ["mcp", "--stdio"]
    }
  }
}

The DeskVNC integration notes call out that VS Code uses servers rather than mcpServers and takes "type": "stdio" on the entry. The exact key name and type field are worth a glance at the current VS Code MCP docs, in case the schema is renamed in a future release, but the shape above is the documented one today.

The shell form is dvv setup. It writes the same MCP entry, copies the skill into the skills directory VS Code reads, and points the agent at the right dvv. VS Code's MCP panel then shows deskvnc as connected.

For the HTTP transport on any platform, replace command and args with a url plus a headers block that carries the bearer token:

{
  "servers": {
    "deskvnc": {
      "type": "http",
      "url": "http://127.0.0.1:7333/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

A first agent session

Open the project, then ask the chat to do something on a saved machine:

You: Open "build-server" and list the open Visual Studio windows.

The agent drives the four-call loop. Behind the scenes, VS Code forwards each MCP call to the dvv subprocess:

dvv_hosts   {}
dvv_open    {"hostId": "build-server", "perceive": true}
dvv_control {"limbId": "limb-44d1", "action": "acquire"}
dvv_screen  {"limbId": "limb-44d1", "form": "full", "scale": 0.25}

The screenshot comes back with a geometry_generation of, say, 41. The agent reads the picture, finds the Window menu, and acts:

dvv_click   {"limbId": "limb-44d1", "x": 92, "y": 78, "generation": 41}
dvv_screen  {"limbId": "limb-44d1", "form": "damage-crop"}

The follow-up screenshot confirms the menu opened where the agent expected it, and the agent reads the list of open windows out loud. The whole observe-then-act cycle is short enough that the agent keeps up with a real desktop.

The coordinate generation fence

Every dvv_screen carries two fences: a geometry_generation and a content_generation. Clicks must echo the geometry generation they were computed against. A click computed against a screen that has since resized is refused rather than landing in the wrong place. Typing and keys are fenced by the content generation, and dvv_type plus dvv_key are refused with SCREEN_CHANGED when something window-sized has repainted since the last dvv_screen. The fence is the safety net that stops an agent from typing into a dialog that appeared over the editor it was aiming at. One dvv_screen clears the fence, dvv_status does not (it reads no pixels), and there is no override. Terminal limbs are not fenced, because a PTY echoes what it is sent into a stream the agent reads back.

Human takeover

The person at the remote machine can take control back at any moment. The viewer shows an "agent driving" badge while the agent holds the lease, and one click in the viewer hands the desktop back to the person. The plane releases every held key and every held button the moment a person takes over, so a half-finished drag cannot strand the desktop. The recipient can revoke the agent's control or end the session outright. This is attended automation by design: the agent never has a stronger position than the person at the keyboard.

Troubleshooting

Symptom Likely cause Try this
LIMB_GONE from any tool The viewer closed the connection or the last dvv_close detached the limb Run dvv limbs to list live limbs, then dvv open <host> again
SCREEN_CHANGED on dvv_type or dvv_key A window-sized region repainted since the last dvv_screen Call dvv_screen once, then retry the action
VS Code does not list deskvnc in the MCP panel JSON parse error, wrong file path, or wrong top-level key Validate the JSON, confirm the path is .vscode/mcp.json, and check the current VS Code MCP docs for the expected key name
dvv exits immediately on spawn The path in command is wrong or the file is not executable Run the command value in a shell and confirm dvv mcp --stdio starts
Click lands in the wrong place Stale geometry_generation after a resize Take a fresh dvv_screen, then send the new generation with the click