mcp-winaccess-win
Version 1.8.0 · Windows-only desktop automation MCP server. Built directly on the OS APIs —
ctypes (SendInput, ImageGrab, Win32 windows, clipboard) and UI Automation via
comtypes — with no pyautogui / pywinauto / pywin32.
Requirements
- Windows 10/11 (x64) — this package only runs on Windows.
- Python 3.10+.
- The server must run inside an interactive desktop session (a logged-in user), not as a
background service — otherwise
SendInput/UI Automation cannot reach the desktop. - No administrator rights are required for normal user applications (see Limitations).
- OCR auto-install needs network access and 7-Zip (or an existing Tesseract install; see Troubleshooting).
Install
pip install mcp-winaccess-win # OCR support (pytesseract) is included
pip install "mcp-winaccess-win[vision]" # optional: OpenCV template matching
The Tesseract binary (a system program, not a Python package) is downloaded and installed
automatically on first OCR use into %LOCALAPPDATA%\mcp-winaccess\tesseract (with eng + rus
language data). Use --tesseract_cmd <path> to point at an existing install, or
--no-auto-tesseract to disable the automatic install (see Troubleshooting).
Run
python -m mcp_winaccess_win.server
# or the console script
mcp-winaccess-win
Command-line arguments
| Argument | Default | Meaning |
|---|---|---|
--transport |
local |
local (stdio) or remote (streamable-http) |
--listen |
0.0.0.0 |
HTTP bind address (remote only) |
--port |
8765 |
HTTP port (remote only) |
--token |
(none) | Bearer token required for HTTP (remote only) |
--tesseract_cmd |
auto |
auto, or an explicit path to tesseract.exe |
--auto-tesseract |
on | automatic Tesseract install; --no-auto-tesseract disables it |
--no-shell |
off | disables the run_command tool (shell execution); enabled by default |
Local (stdio) is the default and needs no arguments. To serve over HTTP, protect the desktop
with a token — a token is required whenever --listen is not loopback:
mcp-winaccess-win --transport remote --listen 127.0.0.1 --port 8765 --token mysecret
OpenCode config (opencode.jsonc)
Local (stdio) — OpenCode launches the server itself:
{
"mcp": {
"winaccess": {
"type": "local",
"command": ["uvx", "mcp-winaccess-win", "--tesseract_cmd", "auto"],
"enabled": true
}
}
}
Remote (streamable-http) — the token goes in the Authorization header:
{
"mcp": {
"winaccess": {
"type": "remote",
"url": "http://127.0.0.1:8765/mcp",
"headers": { "Authorization": "Bearer mysecret" },
"enabled": true
}
}
}
Architecture
| Layer | Implementation |
|---|---|
| Mouse / keyboard | SendInput (ctypes); text via KEYEVENTF_UNICODE (Unicode without the clipboard) |
| Screenshots | Pillow ImageGrab (bbox, all_screens, window handle) |
| Windows | ctypes EnumWindows / MoveWindow / SetWindowPos / PostMessage |
| Clipboard | Win32 clipboard via ctypes |
| UI tree, menus, dialogs | UI Automation COM via comtypes |
| Vision / OCR | OpenCV template matching / pytesseract with an auto-installed Tesseract binary |
Modules: mcp_winaccess_win/server.py (tool wrappers), mcp_winaccess_win/adapter/windows.py
(adapter), mcp_winaccess_win/adapter/win32_input.py,
mcp_winaccess_win/adapter/win32_screen.py, mcp_winaccess_win/adapter/win32_window.py,
mcp_winaccess_win/adapter/win32_clipboard.py,
mcp_winaccess_win/adapter/win32_overlay.py (element highlight), mcp_winaccess_win/adapter/win32_notifications.py,
mcp_winaccess_win/adapter/win32_process.py (launch/kill/enumerate processes),
mcp_winaccess_win/adapter/tesseract_setup.py (auto-install OCR engine), mcp_winaccess_win/adapter/uia.py (UI Automation),
mcp_winaccess_win/adapter/base.py (interface + shared helpers).
Conventions
value(window identifier): a partial title/class (str), a window handle (int), or a prefixtitle:,class:,pid:N,exe:name.exe.control_identifier: theIDreturned byget_all_controls(element_N) or a controlName/AutoID.- All coordinates are absolute screen pixels (virtual-desktop space).
- Any failure returns a string starting with
ERROR:; success messages are human-readable. - Tool schemas carry per-parameter descriptions,
Literalenums for fixed choices, a human-readabletitle, and behavioural hints (readOnlyHint/destructiveHint/idempotentHint) so agents can tell observing tools from state-changing ones.
Tools
94 tools. They are registered only when the adapter advertises the matching capability; unsupported tools are hidden.
Screenshots and display — screenshot, screenshot_region, screenshot_monitor, screenshot_window, screenshot_element
screenshot(grid=False, include_cursor=False)— the whole virtual desktop (all monitors);grid=Trueoverlays labeled 100 px lines;include_cursor=Truedraws the mouse pointer.screenshot_jpg(path="")— save a JPEG (temp file whenpathis empty).screenshot_region(left, top, width, height, grid=False).screenshot_monitor(index=0, grid=False)— a single monitor.screenshot_window(value, grid=False)— capture a window (even if partially occluded).screenshot_element(value, control_identifier, grid=False)— capture a single control.compare_screenshots(image_a, image_b, save_diff="")— differing pixels/percentage between two image files.list_monitors()(includes DPIscale),image_to_screen_coords(x, y, monitor_index=0),get_pixel_color(x, y),wait_for_pixel_color(x, y, color, timeout=10, tolerance=0).
Mouse and keyboard — input
get_mouse_position(),move_mouse(x, y),mouse_move_relative(dx, dy).click(x=None, y=None, button="left", clicks=1)— omitx/yto click at the current position;clicks=2is a double-click,button="right"a right-click.mouse_down(x=0, y=0, button="left")/mouse_up(button="left")— hold/release for manual drags.drag(x_from, y_from, x_to, y_to, duration=0.5),scroll(direction="down", amount=3, x=0, y=0).type_text(text)(Unicode),hotkey(keys)(e.g."ctrl+shift+s").press_key(key)— a key (enter,tab,esc,f5, letters/digits) or a system key (win,volumeup,volumedown,volumemute,playpause,nexttrack,prevtrack,printscreen).key_down(key)/key_up(key)— hold/release keys (e.g. Shift range selection).sleep(seconds)— wait a fixed amount of time.
Clipboard — clipboard
clipboard_get(),clipboard_set(text),clipboard_clear().clipboard_set_files(paths)/clipboard_get_files()— file paths (CF_HDROP).clipboard_set_image(path)/clipboard_get_image(save_path="")— image (CF_DIB).
Vision / OCR — vision, ocr
locate_image_on_screen(image_path, confidence=0.9),wait_for_image(...),click_image(...)— require thevisionextra.ocr_screen(left, top, width, height, lang=""),find_text_on_screen(text, confidence, lang),click_text(text, confidence, lang)—lange.g."eng"or"rus+eng"; the Tesseract binary auto-installs on first use.wait_for_text(text, timeout, lang, confidence)— waits until OCR finds text (for canvas/custom UI).
Windows — window_list, window_activate, window_close, window_minimize, window_maximize, window_move, window_resize, window_snap, window_topmost
list_windows(process=""),find_window(value),get_active_window(),get_window_state(value)(rect, handle, pid, exe, state, monitor).switch_to_window(value),wait_for_window(value, timeout, require_ready=False)(require_ready=Truewaits until visible and responsive),wait_for_window_gone(value, timeout).minimize_window(value),maximize_window(value),restore_window(value),close_window(value).move_window(value, x, y),resize_window(value, x, y, width, height),snap_window(value, position).set_always_on_top(value, enabled).
value accepts a partial window title (str), a window handle (int), or a prefix: title:, class:, pid:N, exe:name.exe. list_windows(process=...) filters by exe name or PID.
Menus and dialogs — menus, dialogs, tray
menu_select(value, path)(e.g."File->Save As"),get_menu_items(value, menu="")(discover the menu bar / a menu's items),context_menu_click(x, y, item).list_dialogs(),handle_dialog(button_text, title="").file_dialog_set_path(path, title=""),file_dialog_confirm(title="").tray_icon_click(name, action="left").
UI tree (semantic controls) — ui_tree
get_all_controls(value, limit=150, query="", control_type="")— use the returnedID(element_N) orName/AutoIDascontrol_identifier; each row includesRectandCenter.click_element(value, control_identifier, clicks=1)(clicks=2= double-click),get_text,set_text(value, control_identifier, text, mode="value", clear=False)(mode="type"forces focus + typing;clear=Trueselects-all before typing),get_window_text(value)(flat text dump),select_item,toggle_checkbox,get_control_state,set_slider,get_selected_text,scroll_into_view,wait_for_element,drag_element.
Element inspection — ui_tree
get_element_at_point(x, y)— element under a screen point.get_active_element()— the currently focused control.highlight_element(value, control_identifier, duration=1.0, color="red", width=3)— temporary rectangle (visual confirmation).highlight_region(x, y, width, height, duration=1.0, color="red", border_width=3)— temporary rectangle over an arbitrary screen region.wait_for_element_gone(value, control_identifier, timeout=10)— wait until a control disappears.expand_element(value, control_identifier)/collapse_element(value, control_identifier)— tree/expander controls.get_control_state(value, control_identifier)— enabled/offscreen/checked/value (works for checkboxes, menu items, sliders).drag_element_to_element(from_value, from_control, to_value, to_control, duration=0.5)— drag-and-drop between controls.scroll_element(value, control_identifier, direction="down", amount=3).
Lists and tables — ui_tree
get_list_items(value, control_identifier, limit=200)— item names of a list/tree.get_table_data(value, control_identifier, limit=200)— table/grid rows (cells joined by|).
Notifications — notifications
list_notifications()— current Windows notifications via theUserNotificationListenerAPI (no UI opened).dismiss_notifications()— clears all notifications (UI clear-all button; the WinRT clear API is unavailable to desktop apps).
Virtual desktops — desktop
switch_desktop(direction="right")— switch to the adjacent desktop.move_window_to_desktop(value, direction="right")— move a window to the adjacent desktop.
Processes and shell — process, shell
run_app(path, args="", cwd="")— launch an application detached (returns its PID); pair withwait_for_window(require_ready=True).kill_process(pid_or_name)— force-kill a process tree (irreversible; preferclose_window).list_processes(filter="")— list running processes asPID N | name.exe.run_command(command, cwd="", timeout=30, shell="cmd")— run a console command and return its exit code and output (shell="powershell"for PowerShell). Disable with--no-shell.
Examples
# 12 + 34 in Calculator
click_element("Калькулятор", "clearButton")
click_element("Калькулятор", "num1Button")
click_element("Калькулятор", "num2Button")
click_element("Калькулятор", "plusButton")
click_element("Калькулятор", "num3Button")
click_element("Калькулятор", "num4Button")
click_element("Калькулятор", "equalButton")
get_text("Калькулятор", "CalculatorResults") # -> 46
# Screenshot with a coordinate grid
screenshot(grid=True)
Limitations
- UIPI:
SendInputcannot drive windows with higher integrity (elevated apps) from a non-elevated process. Run the server elevated to automate those. - Foreground activation:
switch_to_windowuses the Alt-unlock +SetForegroundWindowtechnique; some always-on-top/system windows may still refuse focus. - UWP apps (e.g. Calculator) can expose two
ApplicationFrameWindowinstances (one minimized); the adapter prefers the visible/largest frame. - DPI: the process is per-monitor-v2 DPI aware, so coordinates match physical pixels.
Troubleshooting
- OCR fails — the Tesseract binary is auto-installed on first use (downloaded via the UB-Mannheim
installer, extracted with 7-Zip, into
%LOCALAPPDATA%\mcp-winaccess\tesseract). If that fails (no network / no 7-Zip), install Tesseract manually and pass--tesseract_cmd <path>. Language dataengandrusare fetched automatically; add more by dropping*.traineddatainto the managedtessdata. - Vision tools missing — install the
visionextra (opencv-python). - UI tree tools missing —
comtypesis required (installed with the package).
Tests
The tests/ suite was removed; verification is done manually, function by function, against a
live desktop session.
Release files for mcp-winaccess-win 1.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_winaccess_win-1.8.0.tar.gz | 61.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_winaccess_win-1.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 117.4 kB
Release files / mcp_winaccess_win-1.8.0.tar.gz
| Download URL | mcp_winaccess_win-1.8.0.tar.gz |
|---|---|
| Size | 61.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4009df3e2b4c365fa12090524d6caae2eaa574985ed5f0312fc4a08f393e3cb9
|
|
BLAKE2b-256 checksum How to use checksums |
fadb58f5d9570b9a127fc95470a332def3e43600b1d5a6d81dcf9b02eeda5cd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.10
|
Release files / mcp_winaccess_win-1.8.0-py3-none-any.whl
| Download URL | mcp_winaccess_win-1.8.0-py3-none-any.whl |
|---|---|
| Size | 56.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ffc76d0ee349bf0884e832243a50413c01f9eef42ff789027122bebe5e7d8a47
|
|
BLAKE2b-256 checksum How to use checksums |
59c220c3be5f2d2e30ed1499249d082f25c879c4ef03732a33cca286cf0ce084
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.10
|