Complete Feature Reference¶
🎯 The Approach: Semantic First, Fallback When Needed¶
Windows MCP uses the Windows UI Automation API as the primary interaction method. This gives AI agents semantic understanding of applications — finding elements by name, type, and state rather than parsing screenshots.
Token Optimization¶
All tool responses are designed for LLM efficiency, minimizing token usage while preserving information:
| Optimization | Description | Token Savings |
|---|---|---|
| Short Property Names | ok instead of success, h instead of handle, ec instead of errorCode | ~40% |
| Omitted Null Values | Null/empty fields are not included in responses | ~15% |
| Compact Element Data | UI elements use n (name), t (type), id (elementId), c (coordinates) | ~30% |
| JPEG Screenshots | Default JPEG at 60% quality instead of PNG | ~70% smaller |
| Auto-Scaling | Screenshots auto-scale to 1568px width (vision model native limit) | ~50% smaller |
Example response comparison:
// Standard JSON (~180 tokens)
{ "success": true, "errorCode": "success", "message": "Clicked element", "element": { "name": "Save", "controlType": "Button", "handle": "123" } }
// Optimized JSON (~60 tokens)
{ "ok": true, "ec": "success", "msg": "Clicked", "el": { "n": "Save", "t": "Button", "h": "123" } }
This reduces LLM costs by ~60% and improves response times when processing tool results.
LLM Testing & Validation¶
Every tool is tested with a real AI model (GPT-5.5 via GitHub Copilot) using pytest-skill-engineering to ensure LLMs understand tool descriptions and use them correctly.
| Test Suite | Focus | Pass Rate |
|---|---|---|
| Window Management | Find, activate, move, resize, close windows | 100% |
| Notepad UI Operations | Semantic click, type, and read | 100% |
| Paint UI Operations | Ribbon UI and canvas drawing | 100% |
| File Dialog Handling | Save As dialog handling | 100% |
| Screenshot Capture | Capture with annotations and regions | 100% |
| Keyboard & Mouse | Keyboard and mouse control | 100% |
| Run Dialog & App Launch | Launching classic and UWP apps | 100% |
| Real-World Workflows | Multi-step, end-to-end scenarios | 100% |
130+ LLM tests run against GPT-5.5 through the dedicated manual LLM Integration Tests workflow.
Why LLM testing matters:
- Tool descriptions must be LLM-friendly — If the AI misunderstands a parameter, it fails silently
- Response formats affect reasoning — Structured hints guide the LLM to correct next steps
- Edge cases surface quickly — Real models find ambiguities that unit tests miss
LLM tests are intentionally manual-only and never run as part of PR, CI, or release workflows. See CONTRIBUTING.md for how to run them.
When to Use Each Tool¶
| Scenario | Tool | Why |
|---|---|---|
| Discover UI elements | ui_find | Find elements by name, type, or ID (with timeout/retry) |
| Click a button by name | ui_click | Semantic, works at any DPI/theme |
| Type text into a field | ui_type | Direct text input with clear option |
| Read text from elements | ui_read | Get text via UIA or OCR |
| Extract a table/grid to structured rows | ui_read_table | Rows + headers as JSON, no OCR/screenshot parsing |
| Wait for windows | window_management | Use wait_for action for new windows |
| Save files | file_save | Handle Save As dialogs automatically |
| Open an existing file | file_open | Handle Open dialogs automatically |
| Move bulk text in/out of an app | clipboard | Fastest text IO; pair with copy/paste hotkeys |
| Record & replay a workflow | ui_macro | Save a ui_batch sequence by name, replay it later |
| List or kill running processes | process | Task-manager style: find hung apps, free resources |
| Discover UI visually | screenshot_control | Annotated screenshots with element data |
| Press hotkeys (Ctrl+S) | keyboard_control | Direct keyboard input |
| Custom controls / games | mouse_control | Coordinate-based fallback |
| Draw on a canvas | ui_batch | Batch mouse/polyline steps; one call per figure, not one per stroke |
| Find/move windows | window_management | Window lifecycle control |
Browser Automation¶
- Edge, Chrome, and other Chromium apps are auto-detected and searched with the deeper Chromium strategy.
- Launch with
app(programPath='msedge.exe', arguments='https://example.com')or find an existing browser window first. - Page links, buttons, and form fields usually surface visible text or ARIA labels as the UIA
name, so start withui_find,ui_click, andui_type. - For authenticated or SSO-only sites, prefer reusing an already-open signed-in Edge/Chrome window first. A Chromium launcher helper exiting immediately is often normal existing-session behavior, so check the browser window before retrying the launch.
- Keep discovery compact:
screenshot_controlalready returns annotated element metadata without image bytes unless you opt in. - For browser chrome like the address bar or tab switching, prefer shortcuts such as
Ctrl+L,Ctrl+R, andCtrl+Tab. - Treat browser chrome and non-Chromium browsers as best-effort until dedicated browser coverage expands beyond the Electron/Chromium harnesses.
- The Chromium smoke slice now runs by default: deterministic local Edge/Chrome test pages plus a required public-web smoke check against
https://demo.playwright.dev/todomvc/. - Chromium browser coverage stays on the same semantic-first model as Electron: deep Chromium tree search, ARIA/visible-text discovery, and no separate browser-only tool family.
- The deterministic Chromium smoke harness launches Edge and Chrome app windows with isolated browser state (
--user-data-dir), forces renderer accessibility, waits for page-owned readiness signals, and only uses narrow popup dismissal as a fallback so browser-owned UI does not mask real page interaction results.
Tools Overview¶
| Tool | Description |
|---|---|
app | Launch applications |
ui_snapshot | Capture a compact element tree; optionally return only changes after the first view |
ui_find | Find UI elements by name, type, or ID (with timeout/retry via timeoutMs) |
ui_click | Click buttons, tabs, checkboxes |
ui_type | Type text into edit controls |
ui_select | Select a value in a combo box, list, or tab |
ui_read | Read text from elements (UIA + OCR) |
ui_read_table | Extract a grid/table/list-view into structured rows + headers |
ui_wait | Wait for an element to appear, disappear, or reach a state |
ui_batch | Run several UI steps (find/click/type/select/wait/read/snapshot/key/mouse/polyline) in one call |
ui_macro | Record & replay a ui_batch sequence by name (save/run/list/get/delete) |
file_save | Save files via Save As dialog (English Windows only) |
file_open | Open an existing file via the Open dialog (English Windows only) |
clipboard | Read/write the Windows text clipboard (get/set/clear) |
process | List or kill running processes, task-manager style (list/kill) |
screenshot_control | Annotated screenshots for discovery + fallback |
keyboard_control | Keyboard input and hotkeys |
mouse_control | Coordinate-based mouse input (fallback) |
window_management | Window control and management |
Two ways to call these tools¶
Every tool listed above is available through two equal entry points that share one implementation:
- MCP server — the tool schemas documented in this file (for MCP hosts).
wincliCLI — the same tools as shell commands (for coding agents with terminal access). The CLI calls the exact same tool methods, so its JSON output is byte-for-byte identical to the MCP tools. It is the token-efficient path: discover everything viawincli --help/wincli tools/wincli guidanceinstead of loading every MCP schema. Command mapping mirrors the tool names, e.g.ui_click→wincli ui click,window_management→wincli window <action>,screenshot_control→wincli screenshot. Seesrc/Sbroenne.WindowsMcp.Cli/README.mdfor the full command reference.
� App (app)¶
Launch applications and get their window handles for subsequent operations.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
programPath | Program to launch (e.g., 'notepad.exe', 'C:\Program Files\...\app.exe') | Yes |
arguments | Command-line arguments | No |
workingDirectory | Working directory for the process | No |
waitForWindow | Wait for window to appear (default: true) | No |
Capabilities¶
- Launch applications by name or full path
- Automatic window detection after launch
- Returns window handle for use with other tools
- Configurable startup parameters
Example¶
�🔍 UI Find (ui_find)¶
Find and discover UI elements by name, type, or automation ID.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | Yes |
name | Exact element name | No |
nameContains | Partial name match | No |
namePattern | Regex pattern for name | No |
automationId | Automation ID (most reliable) | No |
controlType | Control type (Button, Edit, CheckBox, etc.) | No |
foundIndex | Return the Nth match (1-based) | No |
timeoutMs | Bounded search timeout in milliseconds | No |
sortByProminence | Sort by bounding box area | No |
Capabilities¶
- Find elements by name, control type, or automation ID
- Partial name matching with
nameContains - Regex pattern matching with
namePattern - Sort results by prominence (largest first) for disambiguation
- Returns element IDs for use with other ui_* tools
- Electron app support (VS Code, Teams, Slack)
🖱️ UI Click (ui_click)¶
Click buttons, tabs, checkboxes, and other interactive elements.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | Yes |
name / nameContains | Element name/partial match | No* |
namePattern | Regex pattern for element name | No* |
automationId | Automation ID | No* |
controlType | Control type filter | No |
foundIndex | Click the Nth match (1-based) | No |
doubleClick | Double-click instead of single-click | No |
*Selectors are optional; without one, the first actionable match in the target window is used.
Capabilities¶
- Click buttons, tabs, menu items
- Toggle checkboxes and toggle buttons
- Handles various control patterns automatically
- Falls back to coordinate-based click if pattern fails
doubleClick=truedouble-clicks an element by name/id - no coordinates needed for list/grid items that open on double-click. UI Automation has no double-click pattern, so this is always a physical double-click at the element's clickable point.
⌨️ UI Type (ui_type)¶
Type text into edit controls and text fields.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | Yes |
text | Text to type | Yes |
name / nameContains | Element name/partial match | No* |
namePattern | Regex pattern for element name | No* |
automationId | Automation ID | No* |
controlType | Control type (default: Edit) | No |
clearFirst | Clear existing text before typing | No (default: false) |
Capabilities¶
- Type text into any editable control
- Clear existing content before typing with
clearFirst=true - Append text to existing content
- Unicode support for any language
📖 UI Read (ui_read)¶
Read text from elements using UI Automation or OCR.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | Yes |
name / nameContains | Element name/partial match | No |
automationId | Automation ID | No |
controlType | Control type filter | No |
includeChildren | Include child element text | No (default: false) |
language | OCR language code (e.g., 'en-US') | No |
format | raw (default) or article for clean web-page text | No |
Capabilities¶
- Extract text from any UI element
- Automatic OCR fallback for custom-rendered text
- Windows.Media.Ocr for local text recognition
- Language support for international text
- Article mode (
format: "article") for web pages in Edge/Chrome: returns the main content only — navigation chrome, breadcrumbs, and "in this article" rails are dropped, inline link URLs are stripped (visible link text is kept), and headings/lists are emitted as lightweight markdown. Because it reads the live signed-in browser window via UI Automation, it also works for authenticated/internal pages that an HTTP fetch cannot reach.
🧮 UI Read Table (ui_read_table)¶
Extract a grid, table, or details-view list into structured rows — no OCR, screenshot parsing, or cell-by-cell ui_read loops. Uses the native UIA Grid/Table patterns, so WinForms DataGridView, WPF DataGrid, and Win32 ListView (Details view) all return clean row/column data.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | No |
name / nameContains / namePattern | Locate the grid by name | No |
automationId | Locate the grid by automation id | No |
controlType / className | Additional selectors | No |
elementId | Grid element id from a prior snapshot/find | No |
foundIndex | Nth match when selectors are ambiguous (1-based) | No (default: 1) |
maxRows | Cap rows returned (protects token budget) | No (default: 200) |
maxColumns | Cap columns returned | No (default: 50) |
includeDiagnostics | Include timing/framework diagnostics | No (default: false) |
If no selector matches an element that exposes the Grid pattern, the first grid-capable descendant of the target (or window root) is used automatically.
Response shape¶
{
"success": true,
"table": {
"rowCount": 5,
"columnCount": 5,
"headers": ["ID", "Product Name", "Price", "Stock", "Available"],
"rows": [["P001", "Laptop Pro 15", "1299.99", "12", "True"]],
"truncated": true
}
}
headers is omitted when the grid exposes no Table pattern; truncated is present only when rowCount exceeds the returned rows (raise maxRows to fetch the rest).
Capabilities¶
- One call instead of N×M
ui_readcalls to scrape a grid - Column headers via the UIA Table pattern when available
- Row/column caps keep large grids within an agent's token budget
- Fails cleanly with a recovery hint when the target isn't a grid
🌳 UI Snapshot (ui_snapshot)¶
Capture a compact tree ("snapshot") of a window. This is the orient primitive: call it first on an unfamiliar window instead of guessing selectors or relying on screenshots. The response is hierarchical, depth-bounded, and token-optimized.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle (foreground window if omitted) | No |
parentElementId | Revisit a known subtree using an id from an earlier snapshot/find | No |
maxDepth | Max tree depth (default framework-aware; capped at 20) | No (default: 5) |
controlTypeFilter | Comma-separated control types to keep (e.g. 'Button,Edit') | No |
mode | full for one complete view, auto for repeated checks of the same target, or reset to start a new comparison | No (default: full) |
includeDiagnostics | Include timing/framework diagnostics | No (default: false) |
Capabilities¶
- One call to see what's on screen with ids, names, types, click coordinates, and available value/toggle state
- Revisit a known part of a large window via
parentElementId - Prune noise with
controlTypeFilter - Feed returned ids straight into
ui_click,ui_type,ui_read,ui_wait - Use
mode=fullfor a one-time inspection. - Use
mode=autofrom the first check when the task will inspect the same window or known subtree again.fullis not remembered. The first automatic response is complete; later responses contain only changes when that is clearly smaller. - Use
mode=resetwhen starting a new comparison. Separatewinclicommands start fresh and safely return a complete view.
Savings depend on how stable an application's accessibility tree is. The four-workload benchmark measured 84-96% median byte/token savings for Electron, Word, and Excel changes. A Playwright-style semantic view improved realistic Chrome navigation to 13.1% fewer bytes and 13.4% fewer approximate tokens even though 18 of 20 responses were complete simplified views. Short live regressions still cover both Chrome and Edge because their Windows accessibility output is not identical. A later strict Chrome run measured the additional conservative display cleanup separately: 10.6% fewer bytes and 13.6% fewer tokens.
Snapshot response compatibility: Complete snapshots still return the compact
tree, but no longer serialize the redundant full-detailelementscopy. Consumers that read that former duplicate should migrate totree, or callui_findwhen they need a flat result.
Response examples¶
The first automatic view and a reset both return a complete tree:
{"success":true,"kind":"full","tree":[{"id":"1","name":"Window","type":"Window","click":[400,300,0],"enabled":true}]}
A useful update returns only the change:
{"success":true,"kind":"diff","changes":[{"op":"add","key":"root/Menu:File#0","node":{"id":"7","name":"File","type":"Menu","click":[50,20,0],"enabled":true}}]}
No change is explicit and very small:
If a change list would be close to the complete response size, the server safely returns kind="full" instead.
🎚️ UI Select (ui_select)¶
Select a value in a combo box, drop-down, list box, or tab control using the proper UI Automation selection patterns (SelectionItem/ExpandCollapse) for cross-framework reliability.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle | Yes |
value | Visible text of the option to select | Yes |
name / nameContains | Name/partial match of the selection control | No |
automationId | Automation ID of the control | No |
controlType | Control type (ComboBox, List, Tab) | No |
foundIndex | Nth matching control (1-based) | No (default: 1) |
Capabilities¶
- Reliable selection without click-then-click guesswork
- Auto-expands drop-downs when needed
- Works across Win32, WinForms, WPF, WinUI, and browser controls
⏳ UI Wait (ui_wait)¶
Wait until a UI condition is met before continuing - no blind sleeps or screenshot polling. Uses efficient exponential-backoff polling internally.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
mode | appear (default), disappear, or state | No |
windowHandle | Target window handle for appear/disappear | No |
name / nameContains | Selector for appear/disappear | No |
automationId | Automation ID selector | No |
controlType | Control type selector | No |
elementId | Element id for mode='state' | No |
desiredState | Target state for mode='state' (enabled, disabled, on, off, indeterminate, visible, offscreen) | No |
timeoutMs | Max wait in milliseconds | No (default: 5000) |
Capabilities¶
- Wait for dialogs/controls to appear before acting
- Wait for spinners/progress dialogs to disappear
- Wait for a specific element to become enabled/visible/toggled
🧩 UI Batch (ui_batch)¶
Run a sequence of UI automation steps against a window in a single call. Built for coding agents: a multi-field form fill + submit that would otherwise take many ui_type/ui_click round-trips becomes one request.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle. Used for every step unless a step overrides it. | Yes |
steps | JSON array of step objects (see below). | Yes |
stopOnError | Stop at the first failing step (default: true). | No |
withSnapshot | Attach the window element tree after the batch completes. | No |
snapshotMode | full (default), auto, or reset for the attached view. | No |
Step actions¶
Each step is a JSON object with an action plus the fields that action needs:
find- selectors; resolves an element and exposes its id to the next step as$prevclick- selectors orelementId, optionaldoubleClicktype- selectors orelementId, plustext(optionalclearFirst)select- selectors, plusvalue(visible option text)wait-mode(appear/disappear/state), selectors orelementId+desiredState, optionaltimeoutMsread- selectors orelementId(or neither, to read the whole window), optionalincludeChildrensnapshot- capture the window element tree (optionalmaxDepth)key-key(e.g.enter,tab,f5) with optionalmodifiers(ctrl,shift,alt,win) andrepeatmouse-mouseAction(move/click/double_click/right_click/middle_click/drag/polyline/scroll/get_position) plusx,y(andendX,endYfor drag), optionalbutton,modifiers,direction,amountpolyline-pointsas[[x1,y1],[x2,y2],...], drawn as ONE continuous stroke; optionalbutton
Mouse steps¶
Mouse coordinates are window-relative by default (they inherit the batch windowHandle). Set target (primary_screen/secondary_screen) or monitorIndex on a step for screen-relative coordinates instead.
The target window is activated before each mouse step, so a batch cannot fail with "Could not retrieve foreground window information". Setting expectedProcessName or expectedWindowTitle on a step suppresses that auto-activation and verifies the foreground window instead - the step fails cleanly if it doesn't match, and stopOnError halts the batch. Set activate explicitly to force either behavior.
polyline presses once at the first point, traces every vertex, and releases at the last - a single continuous stroke. This is better than N segment-drags, which lift the pen at every vertex, and costs one round-trip instead of N.
[{"action":"click","name":"Pencil"},
{"action":"polyline","points":[[300,200],[500,200],[500,400],[300,200]]},
{"action":"mouse","mouseAction":"drag","x":600,"y":200,"endX":700,"endY":400}]
Capabilities¶
- One round-trip for multi-step workflows (fill username + password + submit) and for multi-stroke drawing
- Per-step results:
{ index, action, success, summary, error?, elementId?, text? } - Chain steps by referencing the prior step's element with
elementId: "$prev" stopOnError=falseruns every step and reports each outcome- Mouse steps delegate to the same engine as
mouse_control, so monitor resolution, foreground guards, secure-desktop and elevation checks behave identically
Perceive/act fusion (withSnapshot)¶
ui_click, ui_type, ui_select, ui_batch, and ui_macro accept withSnapshot=true. By default they attach the complete window tree as postActionTree, preserving existing behavior. Set snapshotMode=auto to receive postActionChanges when a remembered update is clearly smaller.
💾 File Save (file_save)¶
Save files via Save As dialog. Handles the entire save workflow: triggers save, waits for dialog, fills path, confirms. English Windows only (detects English dialog titles and button text).
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle (the app window, not a dialog) | Yes |
filePath | File path to save to (e.g., 'C:\Users\User\file.txt') | No |
Capabilities¶
- Trigger Ctrl+S to save
- Auto-detect Save As dialog appearance
- Fill in filename automatically
- Handle overwrite confirmation dialogs
- Works with Office apps, Notepad, and more
📂 File Open (file_open)¶
Open an existing file via the standard Windows Open dialog — the counterpart to file_save. Sends Ctrl+O, waits for the Open dialog, types the path into the File name field, and clicks Open. English Windows only; the file must already exist so the operation is deterministic and never hangs on a "file not found" prompt.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
windowHandle | Target window handle (the app window, not a dialog) | Yes |
filePath | Absolute path of an existing file to open (forward/back slashes both work) | Yes |
includeDiagnostics | Include timing/diagnostic details in the response (default: false) | No |
Capabilities¶
- Trigger Ctrl+O to open
- Auto-detect Open dialog appearance (shares the Save-As dialog engine)
- Fill in the file path and click Open
- Validates the file exists up front for deterministic behavior
📋 Clipboard (clipboard)¶
Read and write the Windows text clipboard — often the fastest way to move bulk text in and out of desktop apps, far cheaper than typing character-by-character or OCR.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
action | get (read text), set (write text), or clear | Yes |
text | Text to place on the clipboard. Required for set; an empty string clears | For set |
Capabilities¶
- Pull text OUT of an app: focus it,
keyboard_control(key='c', modifiers='ctrl'), thenclipboard(action='get') - Push text INTO an app:
clipboard(action='set', text='...')thenkeyboard_control(key='v', modifiers='ctrl') getreturnstext,length, andhasText- Uses the raw Win32 clipboard API on a dedicated STA thread (no message-pump dependency)
🔁 UI Macro (ui_macro)¶
Record and replay reusable UI workflows. A macro is a saved ui_batch steps array; running one replays it through the identical batch engine, so a macro run behaves exactly like the equivalent inline ui_batch call. Macros persist on disk across sessions.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
action | save, run, get, list, or delete | Yes |
name | Macro name (letters, digits, -, _, .) | For save/run/get/delete |
steps | A ui_batch steps JSON array | For save |
windowHandle | Target window handle for replay | For run |
stopOnError | For run: stop at the first failing step (default: true) | No |
withSnapshot | For run: attach the window's element tree after replay (default: false) | No |
includeDiagnostics | Reserved for parity (default: false) | No |
Capabilities¶
save: build and verify a sequence withui_batch, then persist it under a namerun: replay a saved macro against any window (same$prevchaining andstopOnErrorsemantics asui_batch)list/get/delete: manage saved macros- Turns a repeated multi-step task (open a form, fill fields, submit) into a single named call
⚙️ Process Management (process)¶
List and terminate running processes, task-manager style — useful for finding a hung application before automating it, or freeing resources after a workflow.
Parameters¶
| Parameter | Description | Required |
|---|---|---|
action | list (enumerate) or kill (terminate) | Yes |
name | For list: case-insensitive substring filter. For kill: terminate all processes with this name | For kill (or pid) |
pid | For kill: the process id to terminate (takes precedence over name) | For kill (or name) |
sortBy | For list: memory (default), name, or pid | No |
limit | For list: max rows to return (1–500, default 20) | No |
force | For kill: also terminate the entire child process tree | No |
Capabilities¶
listreturnspid,name, andmemoryMbper process, ordered for token economykillbypid(precise) or byname(all matches)- Critical Windows processes (System, csrss, wininit, winlogon, services, lsass, …) and the automation server's own process are protected — the tool refuses to terminate them
- CPU usage is intentionally not reported (an accurate percentage requires sampling over time, which would add latency)
🖱️ Mouse Control (mouse_control)¶
Control mouse input on Windows with full multi-monitor and DPI awareness.
Actions¶
| Action | Description | Required Parameters |
|---|---|---|
move | Move cursor to coordinates | x, y, target or monitorIndex |
click | Left-click at coordinates | optional: x, y |
double_click | Double-click at coordinates | optional: x, y |
right_click | Right-click at coordinates | optional: x, y |
middle_click | Middle-click at coordinates | optional: x, y |
drag | Drag from current position to coordinates | x, y, endX, endY |
polyline | One continuous stroke through every vertex | points |
scroll | Scroll at coordinates | direction, optional: x, y, amount |
get_position | Get current cursor position with monitor context | none |
Parameters¶
| Parameter | Description | Required |
|---|---|---|
action | The mouse action to perform | Yes |
x / y | Coordinates, relative to the monitor (or the window when windowHandle is set) | Per action |
endX / endY | Drag end position | For drag |
points | JSON array of [x,y] pairs, e.g. [[650,430],[750,480],[750,620]] (at least 2) | For polyline |
button | left, right, or middle for drag/polyline | No |
modifiers | ctrl, shift, alt (comma-separated) | No |
direction / amount | Scroll direction and click count | For scroll |
target / monitorIndex | Monitor targeting | With coordinates |
windowHandle | Window-relative coordinate mode | No |
expectedWindowTitle / expectedProcessName | Abort unless the foreground window matches | No |
Capabilities¶
- Click, double-click, right-click, middle-click
- Move cursor to absolute coordinates
- Drag operations with hold/release
- Continuous multi-point strokes via
polyline- press once, trace every vertex, release once. Unlike N separate drags there is no pen lift at the vertices, so freehand shapes render as one stroke. - Scroll up/down/left/right
- Multi-monitor support with DPI awareness
- Easy targeting with
target='primary_screen'or'secondary_screen' - Modifier key support (Ctrl+click, Shift+click, etc.)
- Wrong window detection with
expectedWindowTitle/expectedProcessName
⌨️ Keyboard Control (keyboard_control)¶
Control keyboard input on Windows with Unicode support.
Actions¶
| Action | Description | Required Parameters |
|---|---|---|
type | Type text using Unicode input | text |
press | Press and release a key (with optional modifiers) | key, optional modifiers |
key_down | Hold a key down | key |
key_up | Release a held key | key |
sequence | Multiple keys in order | sequence |
release_all | Release all held keys | none |
get_keyboard_layout | Query current layout | none |
wait_for_idle | Wait for keyboard input to be processed | none |
Supported Keys¶
Function Keys¶
f1 through f24
Navigation¶
up, down, left, right, home, end, pageup, pagedown, insert, delete
Control¶
enter, tab, escape, space, backspace
Modifiers¶
ctrl, shift, alt, win
Media¶
volumemute, volumedown, volumeup, mediaplaypause, medianexttrack, mediaprevtrack, mediastop
Special¶
copilot (Windows 11 Copilot+ PCs)
Browser¶
browserback, browserforward, browserrefresh, browserstop, browsersearch, browserfavorites, browserhome
Capabilities¶
- Unicode text typing (layout-independent) - type any character in any language
- Virtual key presses - Enter, Tab, Escape, F1-F24, navigation keys
- Key combinations - Use
presswithmodifiersparameter:press(key='s', modifiers='ctrl')for Ctrl+S - Key sequences - multi-key macros with configurable timing
- Hold/release keys - for Shift-select and other hold operations
- Special keys - Copilot key (Windows 11), media controls, browser keys
- Layout detection - query current keyboard layout (BCP-47 format)
- Clear before typing - use
clearFirstto select all (Ctrl+A) before typing new text - Wait for idle - wait for keyboard input to be processed before continuing
🪟 Window Management (window_management)¶
Control windows on the Windows desktop. Use app tool to launch applications, then use this tool to manage the windows.
Actions¶
| Action | Description | Required Parameters |
|---|---|---|
list | List all visible windows | none |
find | Find windows by title or process name | title or processName |
activate | Bring window to foreground | handle |
get_foreground | Get current foreground window | none |
get_state | Get current window state (normal, minimized, maximized, hidden) | handle |
minimize | Minimize window | handle |
maximize | Maximize window | handle |
restore | Restore window from min/max | handle |
close | Close window (sends WM_CLOSE) | handle, optional discardChanges |
move | Move window to position | handle, x, y |
resize | Resize window | handle, width, height |
set_bounds | Move and resize atomically | handle, x, y, width, height |
wait_for | Wait for window to appear | title |
wait_for_state | Wait for window to reach a specific state | handle, state, timeoutMs |
move_to_monitor | Move window to a specific monitor | handle, target or monitorIndex |
move_and_activate | Move to position and activate atomically | handle, optional x, y |
ensure_visible | Ensure window is visible (restore if minimized, activate) | handle |
Close with discardChanges¶
Use discardChanges=true to automatically dismiss "Save?" dialogs when closing:
English Windows only — detects English button text like "Don't Save".
Capabilities¶
- List all visible top-level windows with titles, handles, process info, and bounds
- Locate windows by title (substring or regex matching)
- Bring windows to foreground with focus
- Minimize, maximize, restore, and close windows
- Position and size windows with move, resize, or set_bounds
- Wait for a window to appear with configurable timeout
- Move windows between monitors
- Full multi-monitor support with DPI awareness
- Proper UWP/Store app detection and handling
- Cloaking detection to filter out virtual desktop and shell-managed windows
📸 Screenshot Capture (screenshot_control)¶
Capture screenshots on Windows with LLM-optimized defaults. By default, screenshots include annotated element overlays with numbered labels and structured element data — perfect for UI discovery.
Actions¶
| Action | Description | Required Parameters |
|---|---|---|
capture | Capture screenshot (with element annotations by default) | optional target |
list_monitors | List all connected monitors (with DPI, scale, orientation, and work area) | none |
Each list_monitors entry includes displayNumber, width/height, x/y, isPrimary, effectiveDpi, scale (e.g. 1.5 = 150%), orientation (landscape/portrait), and workArea (the desktop rectangle minus the taskbar — handy for placing windows where the taskbar won't cover them).
Capture Targets¶
| Target | Description | Additional Parameters |
|---|---|---|
primary_screen | Capture primary monitor (default) | none |
secondary_screen | Capture secondary monitor (2-monitor setups) | none |
monitor | Capture specific monitor | monitorIndex |
window | Capture specific window by handle | windowHandle |
region | Capture rectangular region | regionX, regionY, regionWidth, regionHeight |
all_monitors | Composite of all displays | none |
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
action | string | "capture" | capture or list_monitors |
target | string | "primary_screen" | Screen, monitor, window, region, or all-monitors target |
monitorIndex | integer | null | Monitor index when target is monitor |
windowHandle | string | null | Window handle when target is window |
annotate | boolean | true | Include numbered element overlays and structured element data |
includeCursor | boolean | false | Include mouse cursor in capture |
imageFormat | string | "jpeg" | Output format: "jpeg", "png" |
quality | integer | 60 | Compression quality for JPEG (1-100) |
outputMode | string | "inline" | "inline" (base64) or "file" (save to disk) |
outputPath | string | null | Custom file path when using file output mode |
Annotated Screenshot Response¶
When annotate=true (default), the response includes structured element data. Image is omitted by default (includeImage=false) to save ~100K+ tokens:
{
"success": true,
"annotated_elements": [
{ "index": 1, "element_id": "...", "name": "File", "control_type": "MenuItem", "clickable_point": { "x": 50, "y": 30 } },
{ "index": 2, "element_id": "...", "name": "Edit", "control_type": "MenuItem", "clickable_point": { "x": 100, "y": 30 } }
],
"element_count": 25
}
Use case: When you don't know element names, capture an annotated screenshot first. The numbered labels in the image correspond to the structured element data, making it easy to identify what to click.
Plain Screenshot (No Annotations)¶
For simple screenshots without element discovery:
Capabilities¶
- Annotated by Default - Screenshots include numbered element overlays and structured data for UI discovery
- LLM-Optimized - JPEG format, auto-scaling to 1568px, quality 60 for minimal token usage
- Easy targeting - Use
window_management(action='find', title='...')to get a handle, then pass toscreenshot_control - Capture any monitor - Screenshot any connected display by index
- Capture windows - Screenshot a specific window (even if partially obscured)
- Capture regions - Screenshot an arbitrary rectangular area
- Capture all monitors - Composite screenshot of entire virtual desktop
- Format options - JPEG (default) or PNG with configurable quality (1-100)
- Auto-scaling - Large captures are scaled to the model-friendly output size
- Output modes - Inline base64 (default) or file path for zero-overhead file workflows
- Cursor inclusion - Optionally include mouse cursor in captures
- Multi-monitor aware - Supports extended desktop configurations
- DPI aware - Correct pixel dimensions on high-DPI displays
Error Handling¶
The server handles common Windows security scenarios:
| Error Code | Description |
|---|---|
ElevatedWindowActive | Target window is running as Administrator |
SecureDesktopActive | UAC prompt or lock screen is active |
InvalidKey | Unrecognized key name |
InputBlocked | Input was blocked by UIPI |
Timeout | Operation timed out |
OperationTimeout | Operation timed out (with configured timeout duration) |
InvalidMonitorIndex | Monitor index out of range |
InvalidWindowHandle | Window handle is invalid or window no longer exists |
MissingRequiredParameter | A required parameter was not provided |
CoordinatesOutOfBounds | Coordinates are outside monitor boundaries |
WindowMinimized | Cannot capture minimized window |
WindowNotVisible | Window is not visible |
InvalidRegion | Capture region has invalid dimensions |
CaptureFailed | Screenshot capture operation failed |
SizeLimitExceeded | Requested capture exceeds maximum allowed size |
WrongTargetWindow | Foreground window doesn't match expected title/process (use expectedWindowTitle/expectedProcessName) |
Configuration¶
Environment Variables¶
| Variable | Default | Description |
|---|---|---|
MCP_WINDOWS_KEYBOARD_CHUNK_DELAY_MS | 10 | Delay between text chunks |
MCP_WINDOWS_KEYBOARD_KEY_DELAY_MS | 10 | Delay between key presses |
MCP_WINDOWS_KEYBOARD_SEQUENCE_DELAY_MS | 50 | Delay between sequence keys |
MCP_WINDOWS_MOUSE_MOVE_DELAY_MS | 10 | Delay after mouse move |
MCP_WINDOWS_MOUSE_CLICK_DELAY_MS | 50 | Delay after mouse click |
MCP_WINDOWS_WINDOW_TIMEOUT_MS | 5000 | Default window operation timeout |
MCP_WINDOWS_WINDOW_WAITFOR_TIMEOUT_MS | 30000 | Default wait_for timeout |
MCP_WINDOWS_WINDOW_PROPERTY_TIMEOUT_MS | 100 | Timeout for querying window properties |
MCP_WINDOWS_WINDOW_POLLING_INTERVAL_MS | 250 | Polling interval for wait_for |
MCP_WINDOWS_WINDOW_ACTIVATION_MAX_RETRIES | 3 | Max retries for window activation |
MCP_WINDOWS_SCREENSHOT_TIMEOUT_MS | 5000 | Screenshot operation timeout |
MCP_WINDOWS_SCREENSHOT_MAX_PIXELS | 33177600 | Maximum capture size (default 8K) |
Known Limitations¶
UAC & Elevated Processes¶
Windows security prevents any non-elevated process from interacting with UAC prompts or elevated (Administrator) windows. This is a fundamental Windows security boundary that no MCP server can bypass.
| Scenario | Behavior | Workaround |
|---|---|---|
winget install (or similar) triggers UAC prompt | Command may report success, but UAC blocks the installer until user approves | Run terminal as Administrator before invoking winget |
| Target app is running as Administrator | ui_click, ui_type, keyboard_control return ElevatedWindowActive error | Run the MCP server elevated, or launch the app without elevation |
| UAC prompt appears mid-workflow | AI cannot see or interact with the secure desktop | User must manually approve the UAC prompt |
| Secure desktop (lock screen, Ctrl+Alt+Del) | All input methods blocked | User must unlock manually |
Why This Matters¶
Many common operations trigger elevation: - Installing software (winget, choco, MSI installers) - Modifying system settings - Apps that "Run as Administrator" - Antivirus, device manager, service management tools
When building automation workflows, plan for elevation boundaries: 1. Pre-install required software before running AI workflows 2. Use per-user installers when available (e.g., VS Code user installer) 3. Run the MCP server elevated if you need to automate admin tasks (with appropriate caution)
Security Considerations¶
- UIPI: Windows User Interface Privilege Isolation blocks input to elevated windows from non-elevated processes
- Secure Desktop: Input cannot be sent during UAC prompts or lock screen
- Input Simulation: The server uses
SendInputwhich is the standard Windows API for simulating input