mouse_drag
Click and drag with the left mouse button from a start to an end coordinate to move sliders, drop items, draw on canvases, or resize windows, with guards that block accidental cross-window drags.
Instructions
Click and drag from (startX, startY) to (endX, endY) holding the left mouse button — for sliders, drag-and-drop, canvas drawing, and window resizing. Pass windowTitle so the server auto-guards the start coordinate and returns post.perception. Examples: mouse_drag({windowTitle:'Notepad', startX:50, startY:50, endX:200, endY:200}). lensId is optional and only for advanced pinned-target workflows. Caveats: Left button only. Both start and endpoint are guarded. Cross-window and desktop drags are blocked by default — pass allowCrossWindowDrag:true to confirm intent; that refusal is code:'CrossWindowDragBlocked'. A drag starting in a tabbed application's tab strip returns code:'TabDragBlocked' — pass allowTabDrag:true when tearing off or rearranging a tab is intended. hints.verifyDelivery:{status:'delivered'|'focus_only'|'unverifiable', reason} reports the post-drop observation in the same 3-value shape as mouse_click. MouseDragNotDelivered is SUGGESTS-registered but reserved-only (not emitted) — degradation is expressed via the 'unverifiable' status rather than a typed code. Win11 foreground refusal (UIPI cross-elevation / admin-only target / call from a background process or service) returns code:'ForegroundRestricted' ok:false from the homing path. A window on another virtual desktop returns WindowOnOtherDesktop and nothing is sent — the user's desktop is not switched.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| endX | Yes | ||
| endY | Yes | ||
| hwnd | No | Direct window handle ID (takes precedence over windowTitle). Obtain from desktop_discover response (windows[].hwnd). String type to avoid 64-bit precision issues. | |
| speed | No | Cursor movement speed in px/sec. 0 = instant (teleport, no animation). Omit to use the configured default (DESKTOP_TOUCH_MOUSE_SPEED env var, default 3000). | |
| homing | No | Enable homing correction (default true). When enabled, the MCP server corrects stale coordinates if the target window moved since the last screenshot. Set false to disable all correction (like traction control OFF). | |
| lensId | No | Optional perception lens ID. Guards and envelope same as mouse_click. | |
| startX | Yes | ||
| startY | Yes | ||
| include | No | Optional response-shape opt-in. `['envelope']` returns the self-documenting envelope (`_version` / `data` / `as_of` / `confidence`). `['raw']` forces raw shape (overrides DESKTOP_TOUCH_ENVELOPE=1 server default). Default behaviour is raw shape (compat with existing clients). | |
| narrate | No | Narration level. "rich": include UIA diff in post.rich (appeared/disappeared/valueDeltas, and nameDeltas when an element's name changed, such as a calculator display) — usually removes the need for a verification screenshot. It is withheld, with post.rich.diffDegraded saying why, when the diff cannot be shown to describe the window that was acted on. On click_element and keyboard (and set_element_value where the server registers it), which resolve the target window before acting: another open window's title contains the text this call resolved to, whether you named the hwnd or the server did — "@active" and the dialog rescue both resolve one ("ambiguous_title"); or the target moved between the snapshot and the action ("target_changed"). On those and on mouse_click, retrying with a fixId also withholds it, because the stored fix names a window this cannot see ("fix_target_unknown") — browser tools keep their diff on a fixId retry, because theirs is a tab diff and does not depend on a window title. mouse_click and mouse_drag accept an hwnd and still take their snapshots by windowTitle, so nothing else is withheld for them: verify those with a screenshot. A window too large to read whole is withheld too ("tree_truncated"). The action itself is unaffected in every case; only the diff is. Default: "minimal". | minimal |
| windowTitle | No | Hint: partial title of the window being clicked. Enables window-delta correction and auto-focus if the window went behind another. Use '@active' for the current foreground window. Example: "メモ帳", "Google Chrome" | |
| allowTabDrag | No | When true, allow drags that start in the title-bar / tab-strip area of a tabbed app (Notepad, Terminal, Edge, Chrome, etc.). Default false — such drags are blocked because they detach the tab into a new window rather than moving the window. Pass true only when you intentionally want to rearrange or detach a tab. Note: active only when auto-guard is enabled (same scope as allowCrossWindowDrag). | |
| verifyDelivery | No | When true (default), capture pre/post snapshots of element-under-cursor + focusedElement + foregroundWindow + scrollPos to populate hints.verifyDelivery with status='delivered' | 'focus_only' | 'unverifiable' (issue #178). Set false to skip the extra UIA work when the caller will read post state itself. | |
| allowCrossWindowDrag | No | When true, allow dragging the endpoint into a different window or the desktop background. Default false — cross-window drags (including desktop/wallpaper) are blocked to prevent accidents. Pass true to confirm intent for deliberate cross-window or desktop-area drags. |