Skip to main content
Glama

windows98-mcp

CI npm license

Control a real Windows 98 VM or Windows 10 machine through explicit Model Context Protocol (MCP) tools. Agents can capture screens, use exact mouse and keyboard input, run and stream commands, manage windows and processes, use the clipboard, and transfer files and directories without ordinary Computer Use.

The same broker can manage local QEMU VMs: create/import qcow2 machines, control lifecycle and snapshots, inspect QMP, and capture/input the framebuffer before the Windows controller starts.

Download the Windows 98 guest · Windows x64 admin · Windows ARM64 admin · macOS Apple Silicon admin · All releases · npm package

Download the admin archive for the host computer: Windows x64 is Intel/AMD, Windows ARM64 is only for ARM Windows PCs, and macOS ARM64 is for Apple Silicon Macs. Windows needs the Microsoft Edge WebView2 Runtime. The macOS portable app is ad-hoc signed rather than Developer-ID notarized; if Gatekeeper blocks its first launch, move it to Applications and run xattr -dr com.apple.quarantine "/Applications/Windows 98 MCP Admin.app".

How it works

WIN98CTL.EXE is a C89 x86 guest agent that runs on Windows 98 SE through Windows 10 (x86 or WOW64). It opens and maintains an outbound TCP connection to the broker on the host. One broker listener accepts multiple named guests. MCP clients and the Windows admin app both use the same broker through a local endpoint selected by port. Parallel operation is the default: each VM has its own FIFO queue, and the broker sends one operation at a time to each single-threaded guest. The default port uses the shared endpoint; other ports are isolated broker instances.

The transport intentionally has no authentication or authorization. Keep it only on an isolated disposable VM network. The framing, sequence numbers, CRC32, and SHA-256 values remain to detect corrupted or malformed data; they do not provide security.

Related MCP server: windows-computer-use-mcp

Quick start

  1. Download and extract the guest ZIP on the host.

  2. Edit WIN98CTL.INI directly. Set host to the host-only adapter IPv4 address visible from Windows 98, choose a TCP port (default 9898), and give the guest a stable, unique [connection] name, such as name=win98-lab-a.

  3. Run INSTALL.BAT from the extracted folder or mounted ISO. It copies the package to C:\WIN98MCP and registers WIN98SUP.EXE for login. Restart Windows; the supervisor owns WIN98CTL.EXE and is the program installed to the current user's login Run key. A dedicated agent thread signals a PID-bound kernel heartbeat event every two seconds. The supervisor restarts its child only if that event is stale for eight seconds. Its heartbeat text file is diagnostic output only and is not used to decide whether to restart. Run C:\WIN98MCP\UNINSTALL.BAT to stop both processes and remove their current-user startup registration; it leaves logs and files in place.

  4. Download and run the Windows admin app. Set the same port in its connection panel. It starts the broker and shows guest status.

  5. Configure Codex to run the published MCP:

    [mcp_servers.win98]
    command = "npx"
    args = ["-y", "windows98-mcp@latest"]
    startup_timeout_sec = 20
    tool_timeout_sec = 1860
    required = false

The guest retries its outbound connection every two seconds. Guest-dependent MCP calls wait up to five seconds for it to reconnect, then return GUEST_CONNECT_TIMEOUT. Status and capability calls return immediately.

The MCP stdio server remains available if the VM is powered off or its guest agent disconnects. After a previously connected VM goes offline, guest tools return retryable VM_OFFLINE results immediately; start the VM again and the same Codex task resumes normal control when the guest reconnects. The adapter also resumes short broker connection losses using its original session ID. Interrupted tool calls are replayed automatically in order and may report recovery.replayed; this is at-least-once behavior, so a lost acknowledgement can duplicate a click, command, or write.

The verified development host-only setup uses host 192.168.60.1 and guest 192.168.60.128; edit the guest INI for your own adapter address.

Named multi-VM routing

A single broker listener can accept multiple Windows 98 guests at the same time. Each guest must have a distinct name in WIN98CTL.INI:

[connection]
host=10.0.2.2
port=9898
name=win98-lab-a

VM names are matched case-insensitively, so win98-lab-a and WIN98-LAB-A identify the same VM and cannot both be connected. If a second live guest uses an occupied name, the broker keeps the original connection and rejects the new one with VM_NAME_IN_USE. A disconnected guest may reconnect with its previous name.

Use vm_list to discover the VMs known to the broker and their current connection state. It is a broker-wide operation and therefore does not take a VM target:

npx windows98-mcp call vm_list --params '{}'

Every operation directed at a guest requires its VM name, even when only one VM is connected. For CLI calls, pass --vm:

npx windows98-mcp call vm_status --vm win98-lab-a --params '{}'
npx windows98-mcp call screen_capture --vm win98-lab-b --params '{"include_cursor":true}' --image-out win98-lab-b.png
npx windows98-mcp call vm_status --vm win98-lab-a --broker-host 192.168.1.20 --broker-port 9899 --params '{}'

For MCP tools, pass vm_name with every guest-targeted call:

{"vm_name":"win98-lab-a","include_cursor":true}

For persistent JSON-lines RPC, put vm_name inside params for every guest-targeted request. The RPC adapter consumes it as broker routing metadata; it is not forwarded to Windows 98 as an operation parameter:

{"id":"list","method":"vm_list","params":{}}
{"id":"start-a","method":"shell_start","params":{"vm_name":"win98-lab-a","command":"COMMAND.COM"}}
{"id":"status-b","method":"vm_status","params":{"vm_name":"win98-lab-b"}}

Connections, capabilities, request queues, transfers, leases, heartbeat state, and cleanup are isolated per VM. Work targeting different VMs can proceed in parallel while operations within one VM retain their normal serialization and locking rules. If this broker relays guests to an upstream broker, it maintains one independent upstream bridge per guest connection and forwards each VM name; multiple named guests can therefore share the same downstream and upstream listeners.

Agent VM power policy

Agents may gracefully reboot or shut down a selected VM unless the user's request or more specific project/task documentation explicitly prohibits power operations. Use system_reboot or system_shutdown with an explicit named guest target. For a managed QEMU machine, use qemu_vm_restart or qemu_vm_shutdown with its explicit vm_id.

Close terminals and transfers and release held input before a power operation when practical. The selected VM will become unavailable; after a reboot, WIN98CTL.EXE should reconnect using the same name. This default permission does not authorize force-stopping or deleting a VM, or shutting down the broker host.

Windows admin app

The portable Windows x64/ARM64 and macOS Apple Silicon Tauri app is a small operator/test console for the same broker used by MCP. It provides:

  • Guest connection status and capabilities.

  • A Windows 98 message popup.

  • Streaming command output with terminate/close controls.

  • File and directory push/pull with progress.

  • Screenshot preview and native save.

Changing its port restarts that app's local broker after active terminal and transfer work is closed. The default port (9898) uses the shared MCP broker endpoint. Multiple uniquely named guests may use that same listener; a separate port is not required for each VM. Every non-default port still gets its own isolated broker endpoint. For headless MCP access to a non-default listener, use npx windows98-mcp --port <port>.

Chained broker proxy

The admin app can proxy upward to another normal broker. The Windows VM continues to connect to the local host, then the local broker connects outward to the remote broker using that remote broker's ordinary guest port. No extra proxy listener is opened locally:

WIN98CTL.EXE -> local admin/broker -> remote admin/broker

Start the remote broker or remote admin app on its chosen port. In the local admin app, enable Proxy upward to remote broker, enter the remote IP and port, and Apply. The local broker retries every two seconds. Once proxied, use MCP or the admin app on the remote machine for VM control; the local app keeps the transparent bridge exclusive so it cannot issue competing guest frames.

CLI

windows98-mcp [command] [options]

broker              Run the long-lived singleton broker
stdio               Run the stdio MCP adapter (the default)
doctor              Check the broker, guest, and capabilities
simulator           Run the deterministic simulated Windows 98 guest
smoke-test          Exercise a connected guest inside C:\MCPTEST
diagnostics [dir]   Collect sanitized diagnostics

--port <port>       VM guest listener port (default: 9898)
--broker-host <ip>  Broker control host for MCP (default: 127.0.0.1)
--broker-port <port> Broker control port for MCP (default: 9899)
--upstream <ip:port> Relay the connected VM to an upstream normal broker
--state-dir <dir>   Override local broker state storage

--port must match WIN98CTL.INI. The broker exposes MCP/admin control on TCP port 9899 by default; use --broker-host and --broker-port to attach an MCP session to a broker on another host, for example over Tailscale.

When MCP uses a TCP broker endpoint, file_push, file_pull, directory_push, and directory_pull operate on the filesystem of the machine running npx windows98-mcp—for example, the Mac client—not on the remote Windows broker. The transfer itself is sent through the broker-control connection in 64 KiB CRC32-checked chunks, with SHA-256 verification and resumable partial files.

CLI control without MCP

Agents that only have terminal access can invoke the same operations directly:

# Inspect all operations and their exact JSON parameter schemas.
npx windows98-mcp tools

# Run one self-contained operation. Output is one JSON result on stdout.
npx windows98-mcp call mouse_click --vm win98-lab-a --params '{"x":120,"y":80}'
npx windows98-mcp call screen_capture --vm win98-lab-a --params '{}' --image-out screen.png

For terminal sessions, held input, or a multi-step workflow, keep one session open with JSON Lines:

{"id":"1","method":"shell_start","params":{"vm_name":"win98-lab-a","command":"COMMAND.COM"}}
{"id":"2","method":"shell_write","params":{"vm_name":"win98-lab-a","session_id":"1","text":"dir\r\n"}}
{"id":"3","method":"shell_read","params":{"vm_name":"win98-lab-a","session_id":"1","after_cursor":0,"wait_ms":500}}

Pipe those lines into npx windows98-mcp rpc; each response has the same ID. call cleans up its temporary session automatically, while rpc cleans up when stdin closes. Files and directories use the CLI computer's filesystem, even when its broker is remote.

Managed QEMU VMs

Use qemu_doctor to check the QEMU executable, qemu_vm_create to import a broker-local disk, and qemu_vm_start to run it. --qemu-root changes the managed VM directory; --qemu-binary sets the default executable. Profiles are win98, winxp, win10, and generic; per-VM binary paths, structured device/network overrides, and extra arguments remain available through the QEMU schemas shown by npx windows98-mcp tools.

Every built-in profile explicitly starts with kernel-irqchip=off,hpet=off,usb=off. These compatibility flags are required by our Windows 98 profile on Windows, Linux, and macOS: removing them can cause a Windows 98 blue screen. The generated Windows 98 machine is -M pc,accel=<auto-plan>,hpet=off,kernel-irqchip=off,usb=off.

acceleration: "auto" always includes emulation fallback: Windows x64 uses whpx:tcg, Linux x64 uses kvm:tcg, Intel macOS uses hvf:tcg, and x86 guests on ARM hosts use tcg. QEMU tries the accelerators from left to right, so a missing or unusable hardware accelerator falls back to TCG instead of preventing a VM from starting. Use qemu_doctor to inspect the selected plan, or set acceleration to tcg, whpx, kvm, hvf, or auto explicitly.

The win98 profile is tuned for an unpatched Windows 98 SE guest: a Pentium II CPU, one vCPU, 256 MiB RAM, i440fx chipset, Cirrus VGA, local-time RTC, HPET disabled, IDE qcow2 disk, and an RTL8139 network adapter. Do not raise memory above 512 MiB without applying the relevant Windows 98 VCache workarounds.

profile_overrides replaces any named profile component, not only disk or network. Give a component an ordered argument array to replace it, or false to remove it. Built-in groups include display, machine, memory, cpu, audio, firmware, boot, devices, platform, disk, and network; custom names are also accepted and appended before broker-owned QMP setup.

# Replace the Win98 profile's audio and display configuration, and add USB.
npx windows98-mcp call qemu_vm_update --params '{"vm_id":"win98","profile_overrides":{"audio":["-audiodev","sdl,id=snd0","-device","ac97,audiodev=snd0"],"display":["-display","sdl"],"usb":["-usb"]}}'
npx windows98-mcp call qemu_doctor --params '{}'
npx windows98-mcp call qemu_vm_create --params '{"name":"Win98","disk_path":"C:\\VMs\\win98.qcow2","profile":"win98"}'
npx windows98-mcp call qemu_vm_start --params '{"vm_id":"win98"}'
npx windows98-mcp call qemu_screen_capture --params '{"vm_id":"win98"}' --image-out qemu.png
npx windows98-mcp call qemu_vm_force_stop --params '{"vm_id":"win98"}'
npx windows98-mcp call qemu_snapshot_create --params '{"vm_id":"win98","name":"clean-install"}'

qemu_screen_capture, qemu_keyboard_*, and qemu_mouse_* work through QMP before WIN98CTL.EXE is online. Deleted managed VMs go to broker trash; the newest three are recoverable with qemu_vm_restore. Each broker manages at most four live VMs; delete a VM before creating a fifth.

Managed ISO media is kept beneath each VM's media/ directory. Import an ISO from a path on the broker host, mount or eject it while QEMU is running, and set CD-ROM boot order while the VM is stopped. These operations are exposed identically through MCP, call, and rpc:

npx windows98-mcp call qemu_media_push --params '{"vm_id":"win98","source_path":"C:\\ISO\\win98-mcp-guest.iso","media_id":"guest-tools"}'
npx windows98-mcp call qemu_media_mount --params '{"vm_id":"win98","media_id":"guest-tools"}'
npx windows98-mcp call qemu_media_list --params '{"vm_id":"win98"}'
# Stop first, then make the mounted CD bootable on the next start.
npx windows98-mcp call qemu_media_set_boot --params '{"vm_id":"win98","device":"cdrom"}'
npx windows98-mcp call qemu_media_eject --params '{"vm_id":"win98"}'

qemu_media_push intentionally does not interpret a path from a remote MCP or CLI client. Copy the ISO to the broker host first; remote resumable media upload is a separate future transport feature. Likewise, disk_path is currently resolved on the broker host, not uploaded from a remote MCP/CLI client.

QEMU prerequisites and portable guest networking

Install QEMU on the machine that runs the broker; qemu_doctor reports the resolved executable and accelerator plan before a VM is created. The managed profile uses QEMU user networking. In that network the host is always 10.0.2.2 from inside the guest, so a QEMU Windows image can retain this guest configuration when moved to a different host:

[connection]
host=10.0.2.2
port=9898
name=win98-lab-a

127.0.0.1 is not correct here: it is the Windows guest itself. Start the broker listener on the same port (9898 by default) and allow that private listener port through the host firewall. For VMware, bridged networking, or a physical Windows installation, replace 10.0.2.2 with the broker host's reachable IPv4 address.

  • Windows: Install a current QEMU build and enable Windows Hypervisor Platform in Windows Features (or with DISM /Online /Enable-Feature /FeatureName:HypervisorPlatform /All). WHPX requires that Windows feature; on systems where it is unavailable, the default plan automatically uses TCG. QEMU documents the supported Windows versions and ARM64 requirements in its WHPX documentation.

  • Linux: Install the distribution's QEMU package. Hardware acceleration additionally requires KVM support (/dev/kvm) and permission to use it, commonly membership of the kvm group. If KVM is absent or unavailable, auto uses TCG.

  • macOS: Install QEMU (for example, brew install qemu). Intel Macs use Hypervisor.framework through HVF when available. Apple Silicon hosts run an i386/x86 Windows 98 guest with TCG emulation, so it is compatible but slower.

SMB, SMB1, shared-folder setup, and Windows' SMB 1.0/CIFS File Sharing Support feature are not used by this release and must not be enabled for windows98-mcp. The prior SMB mailbox transport was removed; guest control is outbound TCP only.

CLI operational reference

All commands below use the exact MCP method name and JSON schema shown by npx windows98-mcp tools. Use call <method> --params '<JSON>' for a single operation, or send the same method/params through rpc for a persistent workflow.

Group

Methods

Status, recovery, lease

vm_status, vm_capabilities, agent_diagnostics, vm_lock, vm_wait, vm_unlock

Message and screen

show_message, screen_capture, window_capture

Mouse

mouse_move, mouse_click, mouse_down, mouse_up, mouse_drag, mouse_scroll, mouse_position, mouse_release_all

Keyboard

keyboard_type, keyboard_key, keyboard_hotkey, keyboard_keycode, keyboard_release_all, input_batch

Clipboard and windows

clipboard_get, clipboard_set, window_list, window_focus, window_close

Shell and terminal

shell_exec, shell_start, shell_read, shell_write, shell_terminate, shell_close

Processes

process_list, process_wait, process_kill

Filesystem

fs_drives, fs_stat, fs_list, fs_mkdir, fs_move, fs_delete

Transfers

file_push, file_pull, directory_push, directory_pull

System

system_info, system_reboot, system_shutdown

Common one-shot calls:

npx windows98-mcp call vm_status --vm win98-lab-a --params '{}'
npx windows98-mcp call mouse_move --vm win98-lab-a --params '{"x":320,"y":200,"duration_ms":150}'
npx windows98-mcp call keyboard_hotkey --vm win98-lab-a --params '{"keys":["CTRL","S"]}'
npx windows98-mcp call shell_exec --vm win98-lab-a --params '{"command":"dir C:\\","timeout_ms":30000}'
npx windows98-mcp call fs_list --vm win98-lab-a --params '{"path":"C:\\MCPTEST","recursive":false}'
npx windows98-mcp call file_push --vm win98-lab-a --params '{"host_path":"C:\\work\\input.txt","guest_path":"C:\\MCPTEST\\input.txt"}'
npx windows98-mcp call directory_pull --vm win98-lab-a --params '{"guest_path":"C:\\MCPTEST","host_path":"C:\\work\\mcp-test"}'
npx windows98-mcp call system_reboot --vm win98-lab-a --params '{"force":false,"delay_seconds":0}'
npx windows98-mcp call system_shutdown --vm win98-lab-b --params '{"force":false,"delay_seconds":0}'

Persistent RPC rules:

  • Every input line must contain id, method, and an object params.

  • Responses use {"kind":"response","id":...,"result":...}. Transfers additionally emit {"kind":"progress","vmName":"<name>",...} lines.

  • Use RPC for shell_start/shell_read/shell_write/shell_close, mouse_down, and low-level keyboard action:"down"; call deliberately rejects these stateful operations to prevent stranded input or terminals.

  • End with vm_unlock; closing stdin also performs forced cleanup.

Target a remote broker without a proxy:

npx windows98-mcp call vm_status --vm win98-lab-a --params '{}' --broker-host 100.79.57.62 --broker-port 9899

MCP tools

The tool groups are:

  • VM discovery, lease, and status: vm_list, vm_status, vm_capabilities, vm_lock, vm_wait, vm_unlock.

  • Screen and input: screenshot, mouse, keyboard, and input batch tools.

  • Desktop: clipboard and window control.

  • Commands: one-shot shell execution and cursor-based interactive terminals.

  • Message: show_message displays a Windows 98 popup.

  • Recovery: agent_diagnostics reports the guest's persisted crash context and supervisor state.

  • System and files: processes, filesystem primitives, resumable file transfer, and merging directory transfer.

Parallel operation is the default. Multiple agents may submit work, while the broker's per-VM FIFO queues serialize protocol requests within each guest and allow different VMs to run concurrently. This is safe for independent shell, file, and inspection work, but it cannot make one Windows guest have separate mice, keyboards, focus, clipboard, or screens: agents targeting the same VM must coordinate interactive UI work themselves. vm_unlock cleans up the calling session's terminals, transfers, and held input for the selected VM.

Enable Exclusive lock agents in the Admin app only when one agent must own all VM work. In that opt-in mode, the first VM-affecting call acquires the lease; VM_BUSY responses include a FIFO ticket for vm_wait, and inactivity expires the lease after 30 minutes. Disconnect cleanup releases held keys, buttons, terminals, and transfers in either mode.

Development

npm ci
npm run typecheck
npm test
npm run build
npm audit --audit-level=moderate

# Build the real Windows 98 guest with pinned Open Watcom 1.9
powershell -File scripts/bootstrap-openwatcom.ps1 -Install
powershell -File scripts/build-guest.ps1 -Clean
powershell -File scripts/stage-release.ps1

The guest build audits the PE32 GUI subsystem and permits imports only from Windows 98 system DLLs. The admin app has its own Tauri build instructions in admin/README.md.

Limitations

Windows 98 has no ConPTY, so terminals use redirected pipes rather than a true full-screen console. DOS/TUI screens, boot failures, BSODs, kernel hangs, and exclusive graphics surfaces remain outside the guest agent. File transfers are limited to 2 GiB minus one byte, and unrepresentable ANSI/keyboard characters are rejected instead of silently substituted.

License

MIT

Available Tools

85 tools
agent_diagnosticsA
Read-onlyIdempotent

Read the guest crash context and supervisor recovery status without acquiring the VM lease.

Inputs: vm_name (required).

clipboard_getA
Read-onlyIdempotent

Read text from the Windows 98 clipboard. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), format.

clipboard_setA

Replace Windows 98 clipboard text. VM remains locked by this session; call vm_unlock when finished.

Inputs: text (required), vm_name (required).

directory_pullA
Destructive

Merge-copy a guest directory to an allowed host path without deleting unrelated host files. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), host_path (required), guest_path (required), overwrite.

directory_pushA
Destructive

Merge-copy a host directory into the guest without deleting unrelated guest files. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), host_path (required), guest_path (required), overwrite.

file_pullA
Destructive

Copy a guest file to an allowed host path through a verified temporary-file commit. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), host_path (required), guest_path (required), overwrite.

file_pushA
Destructive

Copy a host file into the guest through a verified temporary-file commit. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), host_path (required), guest_path (required), overwrite.

fs_deleteA
Destructive

Delete a guest file or directory. VM remains locked by this session; call vm_unlock when finished.

Inputs: path (required), vm_name (required), recursive.

fs_drivesA
Read-onlyIdempotent

List available Windows drive roots for filesystem browsing. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

fs_listA
Read-onlyIdempotent

List a guest directory, optionally recursively. VM remains locked by this session; call vm_unlock when finished.

Inputs: path (required), vm_name (required), recursive.

fs_mkdirB
Idempotent

Create a guest directory. VM remains locked by this session; call vm_unlock when finished.

Inputs: path (required), vm_name (required), recursive.

fs_moveA
Destructive

Move or rename a guest file or directory. VM remains locked by this session; call vm_unlock when finished.

Inputs: source (required), vm_name (required), destination (required), overwrite.

fs_statA
Read-onlyIdempotent

Read metadata for a guest filesystem path. VM remains locked by this session; call vm_unlock when finished.

Inputs: path (required), vm_name (required).

input_batchA

Execute a validated mouse, keyboard, delay, clipboard, and focus sequence in one guest round trip. VM remains locked by this session; call vm_unlock when finished.

Inputs: actions (required), vm_name (required), stop_on_error, screenshot_after.

keyboard_hotkeyA

Press named keys in order and release them in reverse order. VM remains locked by this session; call vm_unlock when finished.

Inputs: keys (required), vm_name (required).

keyboard_keyA

Press, hold, or release a named key such as ENTER, CTRL, LEFT, or F1. VM remains locked by this session; call vm_unlock when finished.

Inputs: key (required), vm_name (required), action.

keyboard_keycodeB

Send a low-level Win32 virtual-key or scan-code input event. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), action, extended, scan_code, +1 more.

keyboard_release_allA
Idempotent

Release every keyboard key tracked as held by this session. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

keyboard_typeA

Type text with the active Windows 98 keyboard layout; fails rather than substituting unrepresentable characters. VM remains locked by this session; call vm_unlock when finished.

Inputs: text (required), vm_name (required), interval_ms.

mouse_clickA

Click at the supplied coordinates, or at the current pointer position when omitted. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), x, y, button, +2 more.

mouse_downA

Hold a mouse button down, optionally moving to coordinates first. Always release it later. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), x, y, button.

mouse_dragA

Drag between exact pixel coordinates while holding the selected mouse button. VM remains locked by this session; call vm_unlock when finished.

Inputs: to_x (required), to_y (required), from_x (required), from_y (required), +4 more.

mouse_moveB
Idempotent

Move the mouse to an exact zero-based physical pixel coordinate. VM remains locked by this session; call vm_unlock when finished.

Inputs: x (required), y (required), vm_name (required), duration_ms.

mouse_positionA
Read-onlyIdempotent

Read the current mouse pointer position. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

mouse_release_allA
Idempotent

Release every mouse button tracked as held by this session. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

mouse_scrollA

Send a mouse-wheel delta at optional coordinates. Requires guest wheel support. VM remains locked by this session; call vm_unlock when finished.

Inputs: delta (required), vm_name (required), x, y.

mouse_upA
Idempotent

Release a held mouse button, optionally moving to coordinates first. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), x, y, button.

process_killA
Destructive

Terminate a process and, by default, its discovered child tree. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), process_id (required), tree.

process_listA
Read-onlyIdempotent

List Windows 98 processes. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

process_waitA
Read-onlyIdempotent

Wait for a process to exit for a bounded period. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), process_id (required), timeout_ms.

qemu_doctorB
Read-onlyIdempotent

Check the local QEMU host, configured binary, managed VM root, accelerator policy, and stable guest-to-host TCP route.

Inputs: profile, qemu_binary, acceleration.

qemu_hmp_commandC

Run an advanced HMP command through QMP human-monitor-command.

Inputs: vm_id (required), command (required).

qemu_keyboard_keyA

Send a QMP qcode key event before or after guest-agent startup.

Inputs: key (required), vm_id (required), action.

qemu_keyboard_typeB

Type basic QEMU monitor-compatible text into the active QEMU display.

Inputs: text (required), vm_id (required).

qemu_media_deleteA
Destructive

Delete an unmounted managed ISO. force=true ejects it first when it is mounted.

Inputs: vm_id (required), media_id (required), force.

qemu_media_ejectA

Eject the managed CD-ROM now when running and persist an empty drive for future starts.

Inputs: vm_id (required).

qemu_media_listA
Read-onlyIdempotent

List ISO images stored in this managed VM's media directory and report which ISO is configured as mounted.

Inputs: vm_id (required).

qemu_media_mountA

Mount a managed ISO now when the VM is running and persist it for future starts.

Inputs: vm_id (required), media_id (required).

qemu_media_pushA
Destructive

Copy a broker-local .iso image into this VM's managed media directory. source_path is resolved on the broker host; remote media upload is not available yet.

Inputs: vm_id (required), source_path (required), media_id.

qemu_media_set_bootA
Destructive

Set persistent QEMU boot order to disk, cdrom, or network. The VM must be stopped.

Inputs: vm_id (required), device (required).

qemu_mouse_clickA

Move then click through QMP before the Windows controller is available.

Inputs: x (required), y (required), vm_id (required), button.

qemu_mouse_moveA

Send absolute QMP mouse coordinates to a running QEMU VM.

Inputs: x (required), y (required), vm_id (required).

qemu_qmp_executeC

Run an advanced QMP command against a managed VM's local broker-owned QMP endpoint.

Inputs: vm_id (required), command (required), arguments.

qemu_screen_captureA
Read-onlyIdempotent

Capture the QEMU framebuffer before the Windows controller has started.

Inputs: vm_id (required).

qemu_snapshot_createA
Destructive

Create a named qcow2 internal disk snapshot while the VM is stopped.

Inputs: name (required), vm_id (required).

qemu_snapshot_deleteA
Destructive

Delete a named qcow2 internal disk snapshot while the VM is stopped.

Inputs: name (required), vm_id (required).

qemu_snapshot_listA
Read-onlyIdempotent

List stopped-VM qcow2 internal snapshots.

Inputs: vm_id (required).

qemu_snapshot_restoreA
Destructive

Restore a named qcow2 internal disk snapshot while the VM is stopped.

Inputs: name (required), vm_id (required).

qemu_vm_command_previewB
Read-onlyIdempotent

Preview the exact managed QEMU command without changing VM state.

Inputs: cpus, name, vm_id, memory, +8 more.

qemu_vm_createA
Destructive

Import a broker-local disk into a new managed qcow2 QEMU VM. disk_path currently belongs to the broker host; remote-media upload is not available yet.

Inputs: name (required), cpus, vm_id, memory, +9 more.

qemu_vm_deleteB
Destructive

Move a managed QEMU VM to recoverable broker trash; only the newest three entries are retained.

Inputs: vm_id (required), force.

qemu_vm_force_stopA
Destructive

Immediately stop a managed QEMU VM when graceful shutdown is not possible.

Inputs: vm_id (required).

qemu_vm_listA
Read-onlyIdempotent

List broker-managed QEMU VMs and their lifecycle state.

Inputs: no named parameters.

qemu_vm_metricsB
Read-onlyIdempotent

Read managed QEMU process and QMP metrics.

Inputs: vm_id (required).

qemu_vm_restartA
Destructive

Gracefully stop then restart a managed QEMU VM.

Inputs: vm_id (required).

qemu_vm_restoreC
Destructive

Restore a managed VM from broker trash.

Inputs: vm_id (required).

qemu_vm_selectA

Record the managed QEMU VM selected in this MCP/Admin session's QEMU panel. In-guest MCP control remains the agent's outbound TCP connection.

Inputs: vm_id (required).

qemu_vm_shutdownA
Destructive

Request graceful guest shutdown, wait 40 seconds, then stop only this QEMU process if needed.

Inputs: vm_id (required).

qemu_vm_startB

Start a managed QEMU VM with QMP and the profile's guest TCP network.

Inputs: vm_id (required).

qemu_vm_statusB
Read-onlyIdempotent

Read one managed QEMU VM's process, QMP, and guest TCP transport state.

Inputs: vm_id (required).

qemu_vm_trash_emptyA
Destructive

Permanently delete every retained QEMU trash entry.

Inputs: no named parameters.

qemu_vm_trash_listA
Read-onlyIdempotent

List recoverable deleted managed VMs.

Inputs: no named parameters.

qemu_vm_unselectA

Clear this session's managed QEMU VM selection.

Inputs: no named parameters.

qemu_vm_updateA
Destructive

Update a stopped managed QEMU VM definition, including accelerator policy and any profile component.

Inputs: vm_id (required), cpus, name, memory, +8 more.

screen_captureA
Read-onlyIdempotent

Capture the primary display or a pixel region as native MCP PNG image content. Acquires the VM lease. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), region, include_cursor.

shell_closeA
Idempotent

Release broker resources for a completed interactive shell session. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), session_id (required).

shell_execA
Destructive

Run a command to completion with captured ordered stdout+stderr output; error results may include a screenshot. VM remains locked by this session; call vm_unlock when finished.

Inputs: command (required), vm_name (required), cwd, timeout_ms, +1 more.

shell_readA
Read-onlyIdempotent

Read bounded output after a cursor from an interactive shell, optionally long-polling. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), session_id (required), wait_ms, max_bytes, +1 more.

shell_startA
Destructive

Start an interactive redirected-pipe shell session and return its session ID. VM remains locked by this session; call vm_unlock when finished.

Inputs: command (required), vm_name (required), cwd.

shell_terminateA
Destructive

Terminate a running interactive shell session. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), session_id (required).

shell_writeA

Write UTF-8 text or base64 bytes to an interactive shell and optionally close stdin. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), session_id (required), eof, text, +1 more.

show_messageA

Display a Windows 98 message dialog titled Windows 98 Remote Control. Acquires the VM lease. VM remains locked by this session; call vm_unlock when finished.

Inputs: message (required), vm_name (required).

system_infoA
Read-onlyIdempotent

Read detailed guest operating-system, code-page, display, and build information. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

system_rebootA
Destructive

Reboot Windows 98. This disconnects the guest and requires configured autostart for recovery. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), force, delay_seconds.

system_shutdownA
Destructive

Shut down Windows 98. The guest cannot reconnect until the VM is started externally. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), force, delay_seconds.

vm_capabilitiesA
Read-onlyIdempotent

Read the connected Windows 98 guest capabilities without acquiring the VM lease.

Inputs: vm_name (required).

vm_listA
Read-onlyIdempotent

List every named VM known to this broker with its current connection, build, address, capabilities, and lease state.

Inputs: no named parameters.

vm_lockA
Idempotent

Explicitly acquire the exclusive VM lease. Most operational tools acquire it automatically. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required).

vm_statusA
Read-onlyIdempotent

Inspect guest connection and lease state without acquiring the VM lease.

Inputs: vm_name (required).

vm_unlockA
Idempotent

Release this session's VM lease. Normal unlock refuses while terminals or transfers remain open.

Inputs: vm_name (required), force.

vm_waitA

Wait in the FIFO lease queue for at most ten minutes. Use after VM_BUSY. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), wait_seconds (required).

window_captureA
Read-onlyIdempotent

Capture a selected window as native MCP PNG image content. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), window_id (required).

window_closeA
Destructive

Request that a selected window close. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), window_id (required).

window_focusA

Bring a window returned by window_list to the foreground. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), window_id (required).

window_listA
Read-onlyIdempotent

List windows with handle, title, class, process, visibility, enabled state, and screen rectangle. VM remains locked by this session; call vm_unlock when finished.

Inputs: vm_name (required), visible_only.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 85 tools

    Disambiguation2/5

    Several tool pairs have heavily overlapping purposes: qemu_keyboard_type/keyboard_type, qemu_mouse_click/mouse_click, qemu_screen_capture/screen_capture, and vm_list/qemu_vm_list. The QMP vs guest-agent distinction is documented, but with 85 tools an agent can easily select the wrong one, especially when both versions of an action exist for the same nominal target.

    Naming Consistency4/5

    The overwhelming majority of tools follow a clear object-prefix + action pattern using snake_case, such as qemu_vm_*, qemu_media_*, shell_*, mouse_*, window_*, and fs_*. A few outliers like show_message, agent_diagnostics, input_batch, and qemu_doctor break the pattern, but naming is generally predictable and category-scoped.

    Tool Count1/5

    85 tools is far beyond what an agent can cleanly reason about, and the rubric explicitly treats 50+ as an extreme mismatch. The server tries to cover VM lifecycle, media, snapshots, files, processes, shells, input, clipboard, windows, and transfers all in one namespace, resulting in severe tool-surface bloat.

    Completeness5/5

    The tool set covers the Windows 98/QEMU domain unusually well: full VM lifecycle with trash/recovery, media and snapshot management, filesystem and process access, interactive shell handling, input and clipboard control, window management, file transfer, and diagnostics. There are no obvious dead ends or critical missing operations for the stated purpose.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      An MCP server that allows AI agents to remotely control Windows, Linux, and macOS systems via VNC. It provides tools for mouse and keyboard interaction, text input, and screen capturing.
      6
      307 npm
      62
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      A local, dependency-free MCP server that gives AI agents controlled access to the active Windows desktop, enabling automated interaction with applications through screenshots, clicks, typing, and window management.
      151 npm
      1
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to seamlessly integrate with the Windows operating system, performing tasks such as file navigation, application control, UI interaction, and QA testing via the MCP protocol.
      -