MiMo Desktop MCP
Enables interaction with the Xiaomi MiMo AI Desktop application, providing tools for desktop automation (window observation, input, drag) and MiMo API workflows.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MiMo Desktop MCPlist the open windows and their titles"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MiMo Desktop MCP
See the window. Choose the action. Control the desktop.
A local MCP server for Windows desktop interaction and Xiaomi MiMo AI workflows.
Window screenshots · Unicode input · Smooth dragging · Cross-window drops · Live MiMo events
Quick start · Desktop workflows · Tool reference · Testing · Troubleshooting
MiMo Desktop MCP connects an MCP-compatible assistant to two useful surfaces: Windows application windows and the local Xiaomi MiMo AI Desktop API. It provides small, explicit actions rather than a single opaque automation script. An assistant observes a window, inspects the image, performs an action, and observes again to check the result.
This is an independent community project. It is not affiliated with or endorsed by Xiaomi, Microsoft, or the Model Context Protocol maintainers.
Why this project?
Capability | What it gives you |
28 focused tools | Desktop input and MiMo API operations in one stdio server |
Window-scoped images | Capture a chosen client area without a full-desktop screenshot fallback |
Unicode typing | Enter text such as Thai directly, without replacing clipboard contents |
Smooth mouse gestures | Left/right/middle drag, waypoints, and adjustable duration |
Cross-window interaction | Drag between two observed windows with optional Ctrl/Shift/Alt |
Checks before input | One-use observations, expiration, foreground and geometry validation |
Cleanup on failure | Attempt to release mouse buttons and modifiers even after an interrupted drag |
Bounded event streaming | SSE parsing with line, frame, and queue limits plus loss accounting |
Input delivery does not prove task success. The destination application decides whether it accepts a drop, a shortcut, or text. Inspect the result after each action.
Related MCP server: Desktop Commander MCP Server
Requirements
Windows 10/11 with an unlocked interactive desktop for live UI actions.
Python 3.11 or later. Windows CI is configured for 3.11, 3.12, and 3.13.
Pillow for PNG encoding and screenshot checks.
An MCP host supporting local stdio servers.
Xiaomi MiMo AI Desktop, running with its local Desktop API available, for
mimo_*API tools. The genericdesktop_*tools do not require MiMo to be running.
The implementation uses Python's standard library and Win32 via ctypes, plus
Pillow and pywinauto for UI Automation. No cloud service or separate automation daemon is started by this server.
Quick start
1. Clone and install
In PowerShell, choose a folder where you keep source projects:
git clone https://github.com/akaradje/mimo-desktop.git
cd mimo-desktop
py -3 -m venv .venv
& .\.venv\Scripts\python.exe -m pip install -r requirements.txtYou do not need to activate the virtual environment. The examples invoke its Python executable directly, so they do not require changing PowerShell policy.
2. Register in MiMo
Edit %USERPROFILE%\.config\mimocode\mimocode.jsonc and merge the following
entry into its existing mcp object. Replace both paths with absolute paths
to your clone and virtual environment. Preserve your other settings.
{
"mcp": {
"mimo-desktop": {
"type": "local",
"command": [
"C:\\Tools\\mimo-desktop\\.venv\\Scripts\\python.exe",
"C:\\Tools\\mimo-desktop\\server.py"
],
"enabled": true
}
}
}Reload the MCP server or restart the host engine after changing code or configuration. A process already running keeps its loaded code. Depending on the host, you may also need a new conversation to refresh tool discovery.
3. Register in another MCP host
Hosts using the common mcpServers configuration shape can use:
{
"mcpServers": {
"mimo-desktop": {
"command": "C:\\Tools\\mimo-desktop\\.venv\\Scripts\\python.exe",
"args": ["C:\\Tools\\mimo-desktop\\server.py"]
}
}
}The exact configuration location is host-specific. This server speaks
newline-delimited JSON-RPC over stdio; it is not an HTTP MCP endpoint and does
not use LSP Content-Length framing. Starting server.py manually and seeing no
output is normal: it is waiting for MCP requests on stdin.
4. Verify discovery
& .\.venv\Scripts\python.exe test_mcp_client.pyThe client initializes the server, discovers 28 tools, checks basic calls and errors, and verifies shutdown. Its MiMo screenshot check is explicitly skipped if the MiMo window is unavailable or minimized. A skipped check is not a capture pass.
Suggested first request to your assistant:
List my visible windows, observe the intended test window, and describe it. Do not type or submit anything yet.
Desktop workflows
Visible activity and smoother input (1.9.0)
A small MIMO DESKTOP badge now appears near the top-right of the primary
display while a desktop_* tool is running. It shows the operation name, elapsed
seconds, and a completion, error, or waiting-for-focus message. It is disabled and
non-activating, so it does not receive clicks or take foreground. Normal results
remain visible for about three seconds; a focus-wait message for about twelve.
It reports MCP tool activity, not the model's thinking between calls, and does not
claim task success. MiMo API-only operations do not use this desktop indicator.
The indicator is enabled by default. Set the MCP server environment variable
MIMO_DESKTOP_OVERLAY=0 before launch to disable it. Reload the MCP process after
updating: an old process will not display the new badge. The helper uses a bounded
background queue and cannot block desktop input if the visual channel fails. Its
messages contain only operation/state/timing, never typed text or window titles.
This is best-effort UI telemetry; a helper startup failure does not fail the action.
Pointer travel before clicks uses a short 180 ms eased movement. Drag interpolation uses smoothstep acceleration/deceleration on a monotonic deadline schedule, with approximately 60 planned frames per second. Slow validation skips overdue frames instead of adding a full extra delay each frame. The exact endpoint is retained; this is not a guarantee of a fixed frame rate under CPU/GPU or application load. Wheel requests are delivered one tick at a time, 30 ms apart, with foreground and Escape checks. App-specific scroll animation still depends on the application.
To test the badge without touching application content:
python test_activity_live.py --runDelivery is not verification (1.8.0)
See ARCHITECTURE.md for the layers, state transitions, Win32/COM choices, timeout scope, and known limitations.
Use desktop_paste_text for reliable mixed-script entry through the clipboard.
It deliberately replaces clipboard contents and sends Ctrl+V; select existing text
and observe again first if replacing an editor. Existing desktop_type_text keeps
its Unicode default for compatibility and now warns about app/IME conversion.
Input results now say outcome: input_delivered, verification: not_performed.
After entering text, call desktop_inspect, choose the actual editor element, then:
{
"observation_id": "<fresh editor observation>",
"element_index": 5,
"expected_text": "ทดสอบ mimo-desktop สำเร็จ"
}Send these arguments to desktop_verify_text. It reads ValuePattern or
TextPattern and returns verified, mismatch, or unavailable. It compares exact
characters, not just length; does not return actual document text; and does not
pretend that unsupported providers passed. Expected text is limited to 2,000
characters. A new inspection is required after each action.
For cross-window drag, optional pickup_ms (default 150) and drop_ms (default 300)
allow 50–2,000 ms of application processing time. Target/Escape checks continue
during these waits. A drop still needs an app-specific postcondition; longer dwell
does not prove that every destination accepts the data.
UI Automation and verified layout (1.7.0)
Update dependencies with python -m pip install -r requirements.txt, then reload
the MCP process. There are now 26 tools.
desktop_inspect takes hwnd and optional focus, returning a screenshot and
an elements array. Each row contains an element_index, UIA runtime identity,
name, control type, automation ID, enabled/visible flags, and screen rectangle.
Choose the intended element from this observation, then call
desktop_click_element with its observation_id and element_index.
Before clicking, the tool reads UIA again and rejects changed identity, name, control type, automation ID, or rectangle. It clicks the element's center using the existing foreground and occlusion checks. It is not an InvokePattern action and cannot operate invisible controls. Reinspect afterwards to verify the result.
desktop_verify_element compares a freshly inspected element's accessible name
with expected_name, returning matched. This is a narrow, explicit assertion:
it does not read or verify an entire editor document. Truncated names cannot pass
an exact match. The name limit is 500 characters; password controls are omitted.
UIA reads run in a separate process with an 8-second timeout, up to 200 visited nodes and depth 8. The tree can be incomplete; not every custom canvas or app provides useful accessibility data. Capture and UIA reads are sequential rather than atomic. Treat names and all other application content as untrusted data.
Use desktop_set_window_rect to arrange windows directly instead of dragging a
custom title/tab strip. Pass an observation ID and x, y, width, height in
physical screen pixels for the entire window including its frame. The tool
returns requested, actual, and matched. Applications can impose size limits;
ok: true with matched: false means Windows accepted the call but the geometry
differs. Capture again before using client coordinates.
Desktop results include elapsed_ms on normal completion. Common state/argument
and operation failures now return structured status, invalidate observations, and
set retry_automatically: false. These controls improve diagnosability; they do
not establish superiority over another computer-use system or remove OS limits.
Observe → act → verify
flowchart LR
A[List windows] --> B[Choose HWND]
B --> C[Observe and inspect image]
C --> D[One input action]
D --> E[Observe and verify]
E --> DCall
desktop_list_windowsand select the intended window by title, executable path, and HWND. Do not guess a handle.Call
desktop_observewith thathwndandfocus: true.Inspect the returned image and save its
observation_id.Perform one input using that ID.
Observe again before the next input, including after an error.
Coordinates are physical pixels in the returned client-area image. (0, 0)
is its top-left corner, not the screen or title bar. If your UI scales the preview,
map the point back to the image's original dimensions. The server uses per-thread
DPI awareness to keep capture and input coordinates consistent.
Observations expire after 60 seconds and are consumed by input. A new
observation normally clears the old one. retain_previous: true keeps up to eight
distinct window observations for a cross-window gesture. Observing the same window
replaces its earlier observation; a failed observation clears the cache.
Click and type
After observing, click the intended editor. Observe once more to check focus, then type using the new observation ID:
{
"observation_id": "<new observation ID>",
"text": "Hello — สวัสดี"
}desktop_type_text accepts 1–2000 printable characters. Use desktop_press_key
for control keys such as Enter or Tab; typing literal text does not submit it.
Supported chords include Ctrl+A, Ctrl+Shift+S, and Alt+F4. Their effects depend
on the focused application and keyboard layout.
Mixed-script text and IME recovery (1.6.1)
Some applications or active IMEs can transform Unicode input events. If the observed text is incorrect, select the incorrect text first, observe again, then request explicit clipboard mode:
{
"observation_id": "<fresh ID after selecting the incorrect text>",
"text": "ทดสอบ mimo-desktop สำเร็จ",
"method": "clipboard"
}This replaces the clipboard with the supplied Unicode text and sends Ctrl+V.
The text remains on the clipboard; previous contents are not restored because
applications may consume a paste asynchronously. Default method: unicode does
not modify the clipboard. There is no automatic fallback that could duplicate
already-entered text. Inspect the result; neither mode verifies editor contents.
Target is not foreground means no input should be retried until a fresh
desktop_observe with focus: true succeeds. Observation expired or already used means capture again and use the new ID. Each action consumes its ID,
including an attempted action that later fails validation. Do not reuse the ID
from a click to type, or the ID from Ctrl+A to paste.
Starting with 1.6.2, focus failures return a structured tool error:
{
"ok": false,
"status": "waiting_for_focus",
"hwnd": 12345,
"retry_automatically": false,
"observation_invalidated": true
}This is an immediate response, not a background wait. Select the target manually,
then observe again for a fresh ID. After Windows refuses an activation request,
repeated focus: true calls for that window do not call SetForegroundWindow again
until the server observes it already in foreground. This suppression is scoped
to the current MCP process. Errors do not undo earlier input or clipboard changes.
Drag inside a window
Use desktop_drag after inspecting the source image:
{
"observation_id": "<source observation ID>",
"from_x": 100,
"from_y": 100,
"to_x": 400,
"to_y": 300,
"via": [{"x": 250, "y": 120}],
"button": "left",
"modifiers": ["shift"],
"duration_ms": 1000
}Replace the example coordinates with points from your image. via is optional
and accepts up to 64 waypoints. The button can be left, right, or middle.
Modifiers can include unique ctrl, shift, and alt names. Duration is
100–10000 ms, plus validation overhead; movement targets roughly 60 updates
per second. All points must stay inside the source client area.
Hold Escape to cancel a running drag. Cancellation is not undo: a partial selection, drawing, or drop may remain. Cleanup attempts button/modifier release up to three times; it cannot guarantee delivery if Windows rejects input or the server is forcibly terminated.
Drag across windows
Use desktop_drag_between:
Arrange source and destination so both gesture endpoints are visible.
Observe the destination and inspect its image.
Observe the source with
focus: trueandretain_previous: true.Inspect the source image and pass both observation IDs:
{
"observation_id": "<source observation ID>",
"destination_observation_id": "<destination observation ID>",
"from_x": 100,
"from_y": 120,
"to_x": 250,
"to_y": 180,
"button": "left",
"modifiers": ["ctrl"],
"duration_ms": 1200
}from_x/y use source image coordinates; to_x/y use destination image coordinates.
Both tokens are consumed. The server checks both window identities and geometries,
destination visibility, and foreground ownership throughout the gesture. Its
straight screen path can hover over intermediate windows, which may react to it.
Inspect the destination afterwards. Ctrl often changes drag semantics, but the meaning is application-specific. These tools deliver input; they do not implement every application's drag-and-drop protocol or guarantee that a file was transferred.
Scroll
desktop_scroll requires an observation ID, client x/y, and nonzero ticks
between -20 and 20. Positive ticks scroll up vertically or right horizontally.
One tick is 120 Windows wheel units. Set axis to vertical or horizontal.
Tool reference
Windows desktop — 14 tools
Tool | Purpose |
| Visible titled windows, HWND, PID, executable path, and geometry |
| Client-area screenshot, optional focus, and one-use observation ID |
| Single/double left, right, or middle click |
| Literal Unicode text without clipboard replacement |
| Named keys, navigation, F1–F12, and Ctrl/Alt/Shift chords |
| Vertical or horizontal wheel input at a chosen point |
| Single-window drag with waypoints and optional modifiers |
| Drag between two observed windows |
| Screenshot and bounded UI Automation tree |
| Revalidate and click an observed UI element |
| Exact accessible-name comparison |
| Move/resize and report actual window geometry |
| Explicit clipboard text transport for mixed scripts |
| Exact editor text comparison through UIA patterns |
MiMo integration — 14 tools
Tool | Purpose |
| Process, shortcut, and Desktop API status |
| Resolve the Start Menu shortcut |
| Launch MiMo and wait for API readiness |
| Graceful close; optional force termination |
| Restore and focus MiMo |
| Local Desktop API health |
| API metadata without returning the full token |
| Session summaries |
| Summarized session messages |
| Submit a turn to a selected session |
| Subscribe, submit, collect events, optionally reconcile messages |
| Bounded SSE collection without submitting a turn |
| MiMo-only screenshot and optional file output |
| Allowlisted preference fields |
tools/list returns the full input schema for every tool. Calls that submit turns,
close apps, or send input have real side effects; use them within the user's intent.
MiMo API and event architecture
The app writes its current loopback port and bearer token to:
%APPDATA%\Xiaomi MiMo AI\desktop-api.jsonThe server reads this file at runtime. Do not copy it into this repository or hardcode its token. Ports can change when the app restarts.
mimo_send_and_watch opens SSE on one connection and submits the turn on another.
The event stream has no replay. Receiving its meta event is a practical readiness
signal, not a formal subscription barrier; optional message reconciliation helps
inspect the final state.
Bound | Default |
JSON HTTP body | 16 MiB; oversized responses raise an explicit error |
SSE line | 64 KiB |
SSE frame data | 256 KiB |
SSE queue | 200 events |
The SSE reader consumes decoded HTTP body bytes, not raw chunk headers. The ordered
queue drops older non-control events on overflow and reports loss counters.
Lifecycle control events are bounded. history_complete describes collection
accounting; it does not establish that the application replayed historical events.
The server advertises MCP protocol version 2024-11-05. Host compatibility is
tested at the stdio contract level; it is not a claim of certification across hosts.
Testing
Local tests without desktop input
& .\.venv\Scripts\python.exe -m unittest test_desktop_control test_api_body test_clipboard_text test_uia_reader test_result_contract test_motion test_activity
& .\.venv\Scripts\python.exe test_sse_stress.pyThe first command covers 64 cases, including stale observations, occlusion, Unicode input construction, drag cleanup, modifiers, and HTTP response bounds. The second covers 13 SSE scenarios using a local fixture server.
Opt-in real-input tests
& .\.venv\Scripts\python.exe test_desktop_live.py --run
& .\.venv\Scripts\python.exe test_cross_window_live.py --runThese open disposable Tk windows and move the pointer/type into those windows. Avoid interacting with the desktop during the short run. They cover eight single-window scenarios and two cross-window payload drops, including Ctrl. The cross-window test verifies real events and a Tk drop handler, not Windows OLE file transfer. They are not run in hosted CI.
Live MiMo checks
& .\.venv\Scripts\python.exe test_mcp_client.py
& .\.venv\Scripts\python.exe test_live_soak_readonly.pyThe soak requires a running MiMo API and an available session for full coverage.
It performs four read-only API checks; it does not submit messages or close MiMo.
Test output may include local session metadata, so sanitize logs before sharing.
_acl_test.py is an additional local diagnostic for screenshot-directory ACLs.
Test counts describe this release's suite. Passing these checks does not prove compatibility with every app, GPU state, display arrangement, or MCP host.
Troubleshooting
Symptom | What to check |
No tools appear | Verify absolute paths, install Pillow in the configured Python, reload the host |
Old tool count/version | Restart the MCP process; an existing process retains loaded code |
Server looks idle in a terminal | Expected: it waits for JSON-RPC on stdin |
Observation expired/already used | Capture a fresh image before the next action |
Target is not foreground | Observe with |
Point/destination is covered | Arrange the windows so the endpoint is visible, then observe both again |
Cannot send input to an app | Check whether it is elevated or running on a protected desktop |
Blank/failed screenshot | Restore the window; some protected or GPU surfaces reject PrintWindow |
Drop has no effect | Inspect app behavior; it may reject the data type, modifiers, or drop location |
MiMo API unavailable | Start MiMo and check that its |
Thai text works but a shortcut differs | Shortcut handling depends on the app and active keyboard layout |
There is no UAC bypass, secure-desktop automation, automatic elevation, or full-desktop screenshot fallback. UI Automation is available where the application exposes it. Window content can change without moving the window; validation cannot make input atomic with an observation. See SECURITY.md for the trust model.
Project layout
mimo-desktop/
├── server.py # MiMo tools, MCP transport, capture, SSE
├── desktop_control.py # Window-scoped Win32 input and drag tools
├── test_desktop_control.py # Mocked input and failure-path regression tests
├── test_api_body.py # HTTP response-bound regression tests
├── test_sse_stress.py # Local streaming fixtures
├── test_mcp_client.py # Independent stdio MCP client
├── test_desktop_live.py # Opt-in disposable single-window input test
├── test_cross_window_live.py # Opt-in two-window drop test
├── test_live_soak_readonly.py # Read-only running-MiMo checks
├── _acl_test.py # Local ACL diagnostics
├── requirements.txt
└── .github/workflows/tests.yml # Windows unit/SSE CIContributing and license
Bug reports with sanitized reproductions are welcome. Read CONTRIBUTING.md, review the changelog, and avoid committing credentials, screenshots, or session histories.
Released under the MIT License. Use, modify, and redistribute it with the license notice included.
This server cannot be deployed
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA standalone MCP server for Windows desktop control, enabling screenshots, mouse and keyboard input, app launch, window/display management, and clipboard access via natural language.2MIT
- AlicenseNot gradedqualityDmaintenanceA comprehensive MCP server that gives AI assistants full control over your desktop — monitor system resources, manage windows, capture screenshots, control the clipboard, launch applications, and more.MIT
- AlicenseNot gradedqualityBmaintenanceAn MCP server that gives any AI assistant eyes and hands on your desktop — screenshots, clicking, typing, OCR, window management, accessibility-tree queries, workflow recording.5Apache 2.0
- AlicenseNot gradedqualityAmaintenanceA Windows computer use agent — FastMCP server that gives AI assistants hands on the real desktop: windows, UI elements, mouse, keyboard, screenshots, OCR, shortcuts, dialogs, and outcome verification.36MIT