VMware Workstation Pro MCP Server
Enables controlling VMware Workstation Pro virtual machines, including listing, power management, snapshots, cloning, guest operations, networking, and screenshots.
README
VMware Workstation Pro MCP Server
A local MCP server (stdio) that lets Claude drive VMware Workstation Pro 26 on Windows: list VMs, read configuration, power, snapshots, clone, guest operations, networking, and screenshots.
Built against Workstation 26.0.0, Python 3.14, mcp 2.0.
Install
git clone <this repo>
cd vmware-mcp-server
uv sync
Claude Code (with uv)
claude mcp add vmware -s user -- `
C:\Users\<you>\.local\bin\uv.exe `
--directory C:\path\to\vmware-mcp-server `
run -m vmware_mcp
Two details matter:
- Use the absolute path to
uv.exe. The client spawns the server directly and does not guarantee your shell'sPATH. - Pass
--directorywith an absolute path. A stdio server's working directory is chosen by the client and can be anywhere.
Then /mcp in Claude Code to check the connection.
Claude Code (manual install, no uv)
uv is not required — this is an ordinary Python package (requires-python = ">=3.14").
Any Python environment with the dependencies installed works:
git clone <this repo>
cd vmware-mcp-server
python -m venv .venv
.venv\Scripts\pip install -e .
Then register the venv's interpreter instead of uv.exe:
claude mcp add vmware -s user -- `
C:\path\to\vmware-mcp-server\.venv\Scripts\python.exe `
-m vmware_mcp
claude mcp add is itself just a convenience that writes the server entry into Claude
Code's config (~/.claude.json for -s user, or .mcp.json for -s project). Editing
that JSON by hand under mcpServers.vmware — command, args, env — has the identical
effect; claude mcp add is not required either.
Claude Desktop
This is a standard stdio MCP server, so any MCP-compatible client can run it — including Claude Desktop. Add an entry to its config file:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"vmware": {
"command": "C:\\Users\\<you>\\.local\\bin\\uv.exe",
"args": [
"--directory", "C:\\path\\to\\vmware-mcp-server",
"run", "-m", "vmware_mcp"
],
"env": {}
}
}
}
Swap command/args for the venv's python.exe -m vmware_mcp if installing without uv,
same as above. Restart Claude Desktop after editing the file so it reloads the server list.
Configuration
All optional; the defaults suit a standard install. These are plain environment variables
read once at server startup (config.py:load_settings) — there is no separate config file
of the server's own, so they must be set wherever the MCP client launches the server
process, then the server (and the client) restarted for a change to take effect:
- Claude Code, user scope (
claude mcp add ... -s user): edit theenvobject undermcpServers.vmwarein~/.claude.json(C:\Users\<you>\.claude.json), e.g."env": { "VMWARE_MCP_ALLOW_DELETE_VM": "1" }. Equivalently, pass-e VAR=valueflags when runningclaude mcp add. - Claude Code, project scope (
-s project): sameenvobject, in the project's.mcp.jsoninstead. - Claude Desktop: the
envobject undermcpServers.vmwarein%APPDATA%\Claude\claude_desktop_config.json. - Manual/other clients: set the variable in whatever environment spawns the process
(a wrapper script, the OS-level user/system environment variables, etc.) — the server
just reads
os.environ.
| Variable | Default | Purpose |
|---|---|---|
VMWARE_MCP_VMWARE_DIR |
C:\Program Files\VMware\VMware Workstation |
Where vmcli.exe and vmrun.exe live |
VMWARE_MCP_INVENTORY |
%APPDATA%\VMware\inventory.vmls |
Workstation's VM library file |
VMWARE_MCP_VM_ROOTS |
common ancestor of registered VMs | ;-separated allowlist of directories the server may touch |
VMWARE_MCP_TIMEOUT |
120 |
Seconds before a VMware command is killed |
VMWARE_MCP_MAX_OUTPUT |
100000 |
Byte cap on guest output |
VMWARE_MCP_ALLOW_DELETE_VM |
unset | Set to 1 to enable delete_vm |
VMWARE_MCP_CREDENTIALS |
%APPDATA%\vmware-mcp\credentials.toml |
Guest credentials file |
VMWARE_MCP_GUEST_USER / _PASS |
unset | Fallback guest credentials |
Guest credentials
Guest username and password are never tool arguments, so they never enter the model's
transcript. Put them in %APPDATA%\vmware-mcp\credentials.toml:
[default]
username = "user"
password = "secret"
[vm.ubuntu-server-26-04-lts]
username = "ubuntu"
password = "ubuntu"
Keys under [vm.*] are the vm_id values from list_vms.
Tools
31 tools, grouped by risk. Annotations are per-tool, which is why operations of different
destructiveness are separate tools rather than one tool with an action switch.
Refer to VMs by the vm_id from list_vms; display names and absolute .vmx paths also
work. Paths outside the allowlist are rejected with a JSON-RPC -32602.
Read-only
| Tool | What it does |
|---|---|
list_vms |
List every VM registered in VMware Workstation's inventory, running or stopped, plus any unregistered VM that happens to be running |
get_vm_info |
Full configuration of one VM: CPU, memory, disks, NICs, shared folders, display, USB/sound/floppy, guest isolation, tools, power state |
list_snapshots |
List a VM's snapshots with the uid needed to revert or delete them |
get_vm_ip |
Read the IP address a running VM's guest has been assigned |
capture_screenshot |
Capture what is currently on a running VM's screen |
guest_inspect |
Read directory contents, running processes, or environment inside a guest |
Write
| Tool | What it does |
|---|---|
vm_power |
Start, stop, reset, suspend, pause, or unpause a VM |
create_snapshot |
Take a snapshot of a VM |
clone_vm |
Copy a VM to a new .vmx path — linked (fast, shares parent disks) or full (independent copy) |
create_vm |
Create a new VM, either blank or deployed from a .vmtx template |
register_vm |
Add an existing .vmx to the Workstation library, so list_vms sees it — Workstation must be closed |
unregister_vm |
Remove a VM from the library without deleting any files — Workstation must be closed |
set_vm_hardware |
Change a VM's vCPU count, cores per socket, and memory size |
manage_disk |
Create a standalone .vmdk file, or extend a disk already attached |
attach_disk / detach_disk |
Wire a .vmdk into a VM as a SATA or NVMe device, or unwire it |
set_network_adapter |
Change a NIC's connection type and plug or unplug its virtual cable |
set_display |
3D acceleration, monitor count, video memory, guest resolution |
set_vm_option |
Toggle USB / sound / floppy / serial / parallel and guest-isolation settings |
manage_shared_folder |
Add or remove a share, and turn shared-folder sync on and off (read them from get_vm_info) |
set_device_connection |
Connect or disconnect a device, live and at power on |
send_keystrokes |
Type into a VM's console as if at the keyboard — needs no VMware Tools or credentials, but does need host privileges |
guest_run |
Run a program or a script inside a guest OS |
guest_copy_file |
Copy a single file between the host and a guest OS |
install_tools |
Mount the VMware Tools installer in a running VM (install still finishes inside the guest) |
manage_port_forwarding |
Inspect host virtual networks and manage NAT port forwarding rules |
Destructive
| Tool | What it does |
|---|---|
revert_snapshot |
Restore a VM to a snapshot, discarding all changes made since it was taken |
delete_snapshot |
Remove a snapshot (VM must be powered off or suspended) |
guest_modify_path |
Create a directory, rename a file, or delete a file/directory inside a guest |
guest_kill_process |
Stop a process inside a guest OS by PID |
delete_vm |
Permanently delete a VM and all of its files from disk, sweeping up what vmrun leaves behind — cannot be undone; disabled unless VMWARE_MCP_ALLOW_DELETE_VM=1 |
To take a VM out of the library but keep its files, use unregister_vm; that is Workstation's
Remove from Library, where delete_vm is Delete from Disk.
Everything under Write and Destructive needing guest access additionally requires
VMware Tools running in the guest and credentials configured in credentials.toml (see
above) — except send_keystrokes, which needs neither.
Things worth knowing
These were all found by testing against a real Workstation 26 install, and each one is a silent failure if you get it wrong.
Snapshots are addressed by UID, not name. vmcli Snapshot Take takes a name, but
Revert and Delete take a uid. -n on Take/Revert is the boolean --native flag,
not "name". list_snapshots therefore always returns uid; the tools accept a name and
resolve it, refusing ambiguous ones.
PowerState: off is not a boolean. PyYAML implements YAML 1.1, where off/on/
yes/no parse as booleans — so a stock yaml.safe_load silently turns the power state
into False. yamlfix.py restricts the bool resolver to true/false.
vmcli output is not always valid YAML. HGFS query prints a plain sentence before the
mapping. The parser splits that preamble off and keeps it.
vmcli can fail while exiting 0. vmcli Power Start requires administrator rights or
__vmware__ group membership; without them it prints a refusal to stdout and exits 0.
All power actions therefore run through vmrun. Control commands on both CLIs are sniffed
for known failure phrasing — guest output is exempt, since a guest may legitimately print
the word "error".
Host-level operations need Administrator. Elevation is not only a vmcli Power Start
problem, and it is never reported as one. Run the server as Administrator, or as a member of
the __vmware__ group, if you need:
| Operation | How it fails without privileges |
|---|---|
send_keystrokes |
Insufficient permissions in the host operating system |
manage_port_forwarding (set/delete) |
Failed to refresh NAT configuration — even with VMware NAT Service running |
vm_power on some hosts |
User must be a member of the __vmware__ group |
Reading is unaffected; list_networks, list, and every query tool work unprivileged.
Failures matching these patterns come back with an explanation appended, rather than as the
CLI's original wording alone.
vmcli Ethernet ConnectionControl crashes vmcli.exe — 0xC0000409, for every argument
arrangement, on Workstation 26. It is not wrapped. set_network_adapter unplugs a cable
through Ethernet SetStartConnected plus vmrun connectNamedDevice instead.
A device has two connection states. connectionStatus is live and startConnected is
what the .vmx says; get_vm_info reports them as connected and start_connected. A
stopped VM shows everything as not connected, which is not a failed write — check
start_connected there.
vmcli VM Create makes an unusable VM. It writes scsi0:0.present into the .vmx but
never creates the scsi0 controller, so the disk it just made is not attached, and it adds
no network adapter. vmcli has no way to create a SCSI controller — use attach_disk, which
puts the disk on SATA or NVMe.
Neither CLI can register a VM. vmrun has no register on Workstation and vmcli VM
only has Create, so clone_vm and create_vm produce VMs the library knows nothing about.
register_vm edits inventory.vmls directly, which is why it refuses while Workstation is
running: Workstation keeps the library in memory and rewrites it on exit.
install_tools is Windows-only now. Workstation 26 ships no linux.iso. Linux guests
install open-vm-tools from their own package manager.
The two CLIs report errors on different streams. vmcli writes to stderr, vmrun to stdout. Both are captured.
vmcli flags come before positional arguments, and it consumes single-letter flags such
as -c itself, so Guest run /bin/sh -c "..." does not work. Use guest_run in script
mode for shell syntax.
guest_run does not return the command's output. VMware's guest API never pipes guest
stdout back to the host: program mode returns a PID, script mode returns an empty string.
To read output, redirect it to a file in the guest and fetch it with guest_copy_file.
Guest passwords are visible in the host process list while a guest command runs. Neither vmcli nor vmrun accepts a password on stdin, so this cannot be fixed here.
send_keystrokes needs neither VMware Tools nor credentials, which makes it the only
way to drive a VM sitting at an installer, bootloader, or login prompt. It does need host
privileges (see above), and it cannot type a newline: vmrun rejects an embedded \n as an
invalid parameter. Send the text, then call again with mode="sequence" and keys="enter",
which goes through vmcli MKS sendKeySequence — also the way to send tab, esc, arrow
keys, or ctrl-alt-delete.
Development
uv run pytest # parser and policy tests, no VM needed
uv run mcp dev src/vmware_mcp/__main__.py # MCP Inspector
Fixtures under tests/fixtures/ are real vmcli ... query output captured from
Workstation 26. When adding a wrapper, read vmcli <Module> <Command> --help on the
installed build first — the flags changed between 17.x and 26, and stale flags fail in
ways that look like something else.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.