Read on the hub → deskvnc-hub.pages.dev/story-helpdesk-3am
title: "The helpdesk at 3am, and the moment the agent had to stop" description: "A long form story about an overnight incident handled by an MCP equipped agent driving DeskVNC, the four-call loop, the generation fence, and the moment a person at the remote machine took the wheel back." date: 2026-10-09 tags: ["story", "incident-response", "mcp", "lease", "safety", "operations"]
The first page that came through the on-call rotation at Northwood Logistics that night was the kind that pretends to be one thing and is another. It said reporting service slow, which on the runbook page pointed at one machine and one machine only. By the time Priya had reached her kitchen counter with her laptop open, the dashboard had turned red across three regions and the reporting service had stopped answering health checks outright. She sat down to drive the remediation through dvv, the MCP server that ships inside DeskVNC, and what happened next is the reason this story exists.
The setting
Northwood runs the routing software that decides which of their forty thousand packages end up on which truck. Three of those machines back the reporting service that proves to the regulators how many trucks ran where, and how long each one took. The service eats routing events as they happen and writes one row a minute for the downstream accounting. When the trio goes quiet, the dashboards grey out, the loaders in the depot still load, and the regulators get a phone call by nine in the morning local time.
Priya is on the operations side of the floor, not the development side. Her job is to put the service back where it belongs before the phone call is owed. Three months earlier her team had started running the recoverable half of incident response through an MCP-equipped agent that lives on her laptop and talks to the reporting machines over the same RDP session she would have opened by hand. The loop reads a frame, decides what to click, fences the click to the frame's generation, and lands the next action. Each pass fits in the low tens of milliseconds on a LAN, which means a minute of careful clicking compresses to a few seconds of clicking under her eye.
The pager kept buzzing against her wrist. Priya opened the runbook page for the reporting service and let the agent have the wheel.
The first approach: the four-call loop and the fence
Every interaction starts with the same two calls. dvv_hosts enumerates the saved host library on Priya's DeskVNC client and the agent picks the reporting service's primary machine by name. dvv_open attaches the mirror with perceive: true, so the agent can read pixels at all. Without that flag the call refuses rather than handing back a blank picture, and an agent cannot tell a blank screen from a picture that was never taken. The call returns a limb id, the screen size, and a state of connected. Around 4 ms on a warm connection.
Once a limb is open, the per-machine lease model takes over. The agent takes an exclusive input lease with dvv_control and an acquire action so that nothing else in the world can race into the same keyboard. That call runs in under a millisecond. With the lease held, the agent reads a frame with dvv_screen, scales it to fit its context window, and reasons about the layout of the reporting service's UI. The screen call doubles as the typing fence reset, because the only thing that clears the typing fence is a call that returned pixels. Around 25 ms at scale 0.25 on a 1920 by 1080 desktop.
The first click computed its coordinates against the frame the agent had just read and stamped them with generation pulled from that frame. A click with a stale generation is rejected as GEOMETRY_CHANGED with nothing delivered, and that refusal is what saved Priya about forty seconds later. The reporting service's UI had been mid-resize when the agent first sampled it. The next dvv_screen reported geometry.generation = 2, the agent's click for the second screen element computed against the new size, fenced against the new generation, and clicked into the right place. The stale click the fence caught would have landed in empty space at the old coordinates.
That whole cycle fits in 19 ms end to end on the local LAN, around 52 actions a second is the steady state once a machine is warm, and every screen read returns the dimensions, the region, and the geometry generation so the next click never lands on stale coordinates. Two minutes in, Priya had a terminal window open on the reporting service and the agent was already past the runbook step that names the relevant log lines.
The complication: passing the wheel mid-incident
The runbook step at the end of the diagnostic half is the one where a human needs to make a call. The reporting service's journal was pointing at a deadlock between two scheduler tasks, and the recovery is to bounce the affected task pool without touching the input queues. Priya could do the bounce through dvv_type and dvv_key, but the bounce has to happen at a specific moment in the queue's rotation, which means watching two windows at once. Her laptop screen only has space for one.
She sent a message to Noah, the day-shift engineer whose shift started at six. The handoff is the part of the loop the per-machine lease model was built for. Priya's agent dropped the lease on the limb it was holding with dvv_control and the matching release action, and the limb went back to a state where any other acquisition attempt could win the race.
Noah opened his laptop, ran dvv_limbs against the same DeskVNC client, and saw the reporting service's limb sitting there waiting. dvv_open re-attached the mirror with perceive: true so Noah's agent would read pixels rather than guess. dvv_control acquire took the lease again, this time by Noah's process, and dvv_screen returned the same frame Priya's agent had last reasoned about, with a current geometry.generation and a state of connected. The handoff was a few seconds of wall clock and zero seconds of downtime to the machine.
Loops like this are why the limb model is per-machine rather than per-session. Ten machines are ten independent loops. One engineer stepping aside for another is one limb moving from one lease holder to another with the geometry and the screen state already on the wire. The reporting service never saw a disconnect.
The twist: the keystroke that ended the loop
The bounce ran on the first try, and the journal started producing the lines the runbook wanted. The dashboards began repopulating, the loaders were still loading, and the regulator would not need a phone call. Priya was about to close the limb when the agent's next call came back as a refusal.
The agent had typed notepad into the run box on the reporting service's admin UI. The call returned the structured refusal LEASE_REVOKED, with the reason string human_took_over, the limb id, and the new geometry generation that the press had triggered. Nothing had been typed. The lease had been invalidated by the same code path that delivers a keystroke to a window. Someone at the remote end had focused a window and pressed a key.
// The refusal the agent received mid-loop.
dvv_type {"limbId": "LR-7d12", "text": "notepad", "wpm": 3000}
// -> { "ok": false,
// "error": "LEASE_REVOKED",
// "lease": "LR-7d12",
// "reason": "human_took_over",
// "new_generation": 4 }
// Recovery call: reads no pixels, needs no lease.
dvv_status {"limbId": "LR-7d12"}
// -> { "state": "connected",
// "lease": { "holder": "none",
// "human_took_over": true },
// "geometry": { "width": 1920,
// "height": 1080,
// "generation": 4 } }
// Then close the limb and step aside.
dvv_close {"limbId": "LR-7d12"}The reporting service has a small desktop instance at the client site for the on-site operator who runs the loading dock floor. The on-site operator had walked past the workstation, seen a cursor move on its own, and tapped the Enter key to take the screen back. The lease model treats that exactly the same as a formal revoke control on a Boundary session. The person wins. The agent waits.
The right next call from the agent was dvv_status, which reads no pixels and needs no lease. It returns the full dvv.observation.v1 object for the limb, including the lease holder and the lease flags. The reply came back with lease.human_took_over set to true and lease.holder set to none. The flag told the agent everything it needed to know. The on-site operator was driving the machine now, and the right move was to stop.
No input was retried. No fallback path was forced. The screenshots already in the runbook ticket documented what the agent had found before the takeover, which was enough for the morning postmortem. The limb was released, and the same structured response would have come back if the formal revoke control had been pressed instead of the Enter key.
The after: the runbook, the metrics, the limb model
Northwood had been writing the runbook for that service on paper for years. Priya's team turned it into a workflow that runs the same way every time, with one change in shape: the part where a person is faster than an agent is now a hand-off the lease model knows how to express.
The numbers the team tracks after that morning are simple. Mean time to first dashboard recovery on the reporting service dropped from forty three minutes to seven. Pages per month that escalate after the first hour dropped from a handful to none. Journal dumps cut and pasted into tickets by hand dropped to zero. The agent held at around 52 actions a minute, the design speed of the MCP tool cycle on a healthy connection.
The per-machine limb model is the part the team keeps coming back to. Each reporting machine is its own limb, its own lease, its own loop, and the runbook for the service is three loops running together rather than one engineer with three remote desktop windows. When a person needs to take over, the lease falls to no holder and the next acquisition wins. When the agent needs to step aside because a person is driving, the lease refusal carries the same shape every time, the same flag every time, and the same right move every time.
The page from that morning is now a test fixture. The team re-runs the runbook against a staging copy of the reporting service with a synthetic remote operator standing by, presses Enter at the same point in the loop, and confirms the agent stops. The check passes on every run. That is the load-bearing property: not that the agent can drive the machine, but that the agent knows when to stop, and that the moment the person wins is structured the same way every time.
The safety is the feature. An agent that could be relied on to act but not to stop would not earn its keep on a regulated fleet at three in the morning, and the lease model is the part of DeskVNC that closes the gap. The loop is fast, the loop is fenced, and the loop ends the moment a person reaches for the keyboard.
Read more
- The DeskVNC repository carries the client, the MCP server source, and the release page with the signed and notarized macOS build, the signed Windows installer, and the Linux x86_64 tarball.
- The official DeskVNC project page walks the lease model, the refusal codes, and the per-machine limb model from the project's side.
- The installable dvv skill documents the full MCP surface and the four-call loop, and it ships with the repository so an agent can discover the tools on its own.