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.
Metadata
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 | Provenance | Actions |
|---|---|---|---|---|
| mcp_winaccess_win-1.8.0.tar.gz | 61.4 kB | Without provenance | Details for mcp_winaccess_win-1.8.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mcp_winaccess_win-1.8.0-py3-none-any.whl | Python 3 | none | any | Details for mcp_winaccess_win-1.8.0-py3-none-any.whl |
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
|
Security for mcp-winaccess-win 1.8.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.