Laz.Mcp
0.2.0
{ "inputs": [ { "type": "promptString", "id": "LAZ_DELAY_MS", "description": "Overrides Laz's default 50ms inter-event delay used between chained input actions." } ], "servers": { "Laz.Mcp": { "type": "stdio", "command": "dnx", "args": ["Laz.Mcp@0.2.0", "--yes"], "env": { "LAZ_DELAY_MS": "${input:LAZ_DELAY_MS}" } } } }
.vscode/mcp.json settings file.
dotnet tool install --global Laz.Mcp --version 0.2.0
dotnet new tool-manifest
dotnet tool install --local Laz.Mcp --version 0.2.0
#tool dotnet:?package=Laz.Mcp&version=0.2.0
nuke :add-package Laz.Mcp --version 0.2.0
Laz.Mcp
An MCP (Model Context Protocol) server that exposes the Laz library's mouse, keyboard, and screen-capture automation as tools an LLM client can call.
Laz simulates real OS-level input (mouse, keyboard) and reads real pixels off the screen on Windows, Linux (X11/XWayland), and macOS. This server just wraps that library's public API 1:1 (plus a couple of small ergonomic conveniences) as MCP tools — it does not add new automation capabilities beyond what Laz already does.
This grants a connected LLM control of your actual mouse and keyboard. Only run it in a session/user context you're comfortable handing that control to, and prefer running it in a disposable VM or sandboxed desktop session for anything you don't fully trust.
Why this one
There are several other MCP servers for desktop automation (RobotJS-, PyAutoGUI-, AutoHotkey-, or native-backed). Most converge on the same base — click/move/drag, keypress/type, screenshot — with window management, clipboard access, or OCR bolted on as extras, and most that claim "cross-platform" are really Windows- or macOS-first with the other platforms added on top.
Laz.Mcp stays narrow on purpose and differs on two things:
- Natural mouse movement.
mouse_move_smoothandmouse_drag_and_droptravel a linear or bezier path under a choice of 9 easing curves, rather than a flat duration parameter or an instant jump. Relevant if the target app (or a bot-detection layer) treats motion trajectory as a signal. - One implementation across Windows, Linux (X11/XWayland), and macOS, from Laz's native input handling on each platform, rather than a single-OS core with other platforms shimmed in.
It doesn't do window management, clipboard access, or OCR — this stays a thin, reliable primitives layer over mouse, keyboard, and screen, meant to be a building block for whatever agent logic you put on top of it, not a full computer-use framework.
Transport
Stdio only. The server is a console app launched by an MCP client (Claude Desktop, Claude Code, etc.) over stdin/stdout — no network listener.
Coordinates
All positions are integer (x, y) screen pixels in Laz's coordinate space (see platform notes
in the Laz README — DPI-awareness matters on
Windows, and Wayland/XWayland HiDPI setups can behave unexpectedly on Linux). Call screen_get_size
or screen_list_displays first to get valid bounds instead of guessing coordinates/regions.
Tools
Mouse
| Tool | Description | Parameters |
|---|---|---|
mouse_get_position |
Returns the current cursor position. | — |
mouse_jump_to |
Instantly moves the cursor to a position (teleport, no intermediate motion). | x, y |
mouse_move_smooth |
Moves the cursor from its current position (or an explicit startX/startY) to a target over time, along a linear or bezier path with an easing curve — looks like natural human movement instead of a teleport. |
targetX, targetY, startX?, startY?, durationMs? (default 1500), path? (Linear|Bezier, default Linear), easing? (Linear, EaseInOutCubic, EaseOutCubic, EaseOutQuartic, EaseOutExpo, EaseInQuad, EaseInOutQuad, EaseInOutSine, EaseOutCircular, EaseOutElastic, EaseOutBounce; default Linear) |
mouse_press |
Presses and holds a button down until mouse_release. |
button? (Primary|Middle|Secondary, default Primary) |
mouse_release |
Releases a previously pressed button. | button? |
mouse_click |
Presses and releases a button once. | button? |
mouse_double_click |
Two clicks in quick succession. | button? |
mouse_scroll |
Spins the scroll wheel. Positive scrolls up, negative scrolls down. | notches |
mouse_drag_and_drop |
Presses at start, moves naturally to target, releases. Optional dragPreamble adds a short downward nudge first, which some apps need to recognize a drag gesture. |
startX, startY, targetX, targetY, durationMs?, path?, easing?, dragPreamble? (default false) |
mouse_move_smooth and mouse_drag_and_drop are synchronous and block for the full
durationMs (default 1.5s) while they play out the motion — that's inherent to Laz's move
implementation, not an artifact of the server.
Keyboard
| Tool | Description | Parameters |
|---|---|---|
keyboard_key_down |
Presses and holds a key until keyboard_key_up. Used to build modifier-held sequences. |
key |
keyboard_key_up |
Releases a previously held key. | key |
keyboard_stroke |
Presses and releases a single key. | key |
keyboard_combo |
Convenience helper (not a direct Laz method): holds down a list of keys in order, then releases them in reverse order — e.g. ["Control", "Shift", "Esc"] for a shortcut chord. |
keys (array of key names, 1+) |
keyboard_type |
Types arbitrary text as a sequence of keystrokes, handling dead keys and shifted characters automatically. Characters that can't be produced by the active keyboard layout fail unless clipboardFallback is set. |
text, clipboardFallback? (default false, Windows/macOS only), useCtrlInsert? (default false, Windows only — uses Ctrl/Shift+Insert instead of Ctrl+C/V for the clipboard fallback) |
key accepts the case-insensitive name of a Laz.Key enum member, e.g. A-Z, Zero-Nine,
F1-F24, Enter, Tab, Esc, Space, Backspace, Delete, Insert, Left/Right/Up/Down,
Home, End, PageUp, PageDown, Shift, Control, Alt, LeftShift/RightShift/
LeftControl/RightControl/LeftAlt/RightAlt, LeftWin/RightWin, CapsLock, NumLock,
ScrollLock, Numpad0-Numpad9 and NumpadPlus/NumpadMinus/NumpadMultiply/NumpadDivide/
NumpadDecimal/NumpadEquals/NumpadSeparator, punctuation (Semicolon, Equal, Comma,
Minus, Dot, Slash, Grave, OpenBracket, Backslash, CloseBracket, Apostrophe), and
media/browser/volume keys. An invalid name returns a tool error listing this guidance rather than
throwing a raw exception.
Screen
| Tool | Description | Parameters |
|---|---|---|
screen_capture |
Captures a rectangular region and returns it as a PNG image content block (viewable inline by the client). | x, y, width, height |
screen_get_color_at |
Reads the color of a single pixel. | x, y → { r, g, b, a } |
screen_get_size |
Returns the bounding box of the full virtual screen spanning all monitors. | — → { x, y, width, height } |
screen_list_displays |
Lists each connected monitor's bounds, primary flag, and DPI scale factor. | — → [{ index, x, y, width, height, isPrimary, scaleFactor }] |
macOS requires the Screen Recording permission to be granted to the host process for both
screen_capture and screen_get_color_at; the OS prompts on first use. macOS and Linux also
require Accessibility / an active X11-or-XWayland session respectively for mouse and keyboard
tools — see the Laz README's per-platform remarks for each method.
screen_get_size/screen_list_displays are implemented outside of Laz (which has no such API —
see Implementation notes below) via direct OS calls, so they have their own platform caveats:
Linux requires xrandr on an X11/XWayland session (no Wayland-native support) and always reports
scaleFactor: 1.0 since xrandr --query doesn't expose per-monitor DPI. Windows' scaleFactor
reflects real per-monitor DPI only once the process is DPI-aware; an unaware process reports
1.0 for every monitor.
Configuration
LAZ_DELAY_MSenv var — overrides Laz's default 50ms inter-event delay (used between chained actions likekeyboard_strokeand between characters inkeyboard_type). Set before the server process starts.
Implementation notes (for the build)
- .NET 10,
ModelContextProtocol+Microsoft.Extensions.Hostingfor the stdio server host. - A single
Laz.Lazbotinstance is held for the process lifetime and all calls into it are serialized behind one lock, since it manipulates global OS input/cursor state and two tool calls interleaving mid-gesture (e.g. a click landing in the middle of a drag) would be a real bug, not just a theoretical race. screen_capture's raw BGRA bytes are encoded to PNG (via SixLabors.ImageSharp, for cross-platform support —System.Drawingis Windows-only) before being returned as anImageContentBlock.- Enum-like parameters (
key,button,path,easing) are accepted as strings and parsed withEnum.TryParse(ignoreCase: true), throwingMcpExceptionwith a specific message on failure, rather than relying on the default JSON-schema enum-as-integer serialization — this keeps error messages legible to the model instead of a generic "invocation failed". screen_get_size/screen_list_displaysare the one deliberate exception to "thin wrapper over Laz": since Laz exposes no screen-size or monitor-enumeration API,ScreenInterop.csgoes straight to the OS instead — Win32 (EnumDisplayMonitors/GetMonitorInfo/Shcore.dll!GetDpiForMonitor) on Windows, CoreGraphics (CGGetActiveDisplayList/CGDisplayBounds/CGDisplayCopyDisplayMode) on macOS, and anxrandr --queryshell-out on Linux. It deliberately never touches process DPI awareness (e.g.SetProcessDpiAwarenessContext) since Laz's own native code already establishes whatever awareness context its mouse coordinate mapping relies on, and overriding that independently could silently breakmouse_jump_to/mouse_move_smoothaccuracy.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.0 | 39 | 10/3/2026 |
| 0.2.0-beta | 145 | 8/1/2026 |
| 0.1.0-beta.1 | 119 | 8/1/2026 |
| 0.1.0-beta | 126 | 8/1/2026 |