Skip to main content
Glama
NasirSultan

desktop-control-mcp

by NasirSultan

desktop-control-mcp

An MCP server that lets an MCP client (Claude Code, Claude Desktop, or claude.ai via a custom connector) open and close applications, files, and folders on this Windows machine.

Tools exposed:

Tool

Does

open_app

Launch an app by friendly name (chrome, word, notepad, ...) or .exe name, optionally with an argument (URL/file)

close_app

Force-close a running app by name

list_running_apps

List processes that currently have a visible window

open_path

Open a file/folder path, or a friendly folder name (documents, desktop, downloads, pictures, music, videos, home)

close_folder_window

Close any open File Explorer window(s) showing a given folder

list_folder_contents

List the files/subfolders directly inside a folder (name, type, path, size)

open_path_with

Open a file/folder with a SPECIFIC app (e.g. a folder in VS Code) - app is required

find_duplicate_files

Recursively find duplicate files by content (name, all locations, count, wasted space)

list_open_folders

List every open File Explorer folder window (path, title, hwnd)

close_all_folder_windows

Close every open File Explorer folder window

focus_folder_window

Bring an open folder window to front (un-minimizes if needed)

minimize_folder_window

Minimize an open folder window

list_chrome_tabs

List every open Chrome tab (index + title)

open_chrome_tab

Open a new Chrome tab, optionally to a URL

close_chrome_tab

Close the open tab matching a title search

focus_chrome_tab

Switch to the open tab matching a title search

scroll_chrome_page

Maximize Chrome and scroll the active page up/down (simulated PageUp/PageDown)

list_chrome_profiles

List configured Chrome profiles (name + directory)

open_chrome_profile

Open a new Chrome window under a specific profile (most reliable when Chrome isn't already running)

focus_app

Bring an app's window to front / switch to it (un-minimizes if needed)

maximize_app

Maximize an app's window

minimize_app

Minimize an app's window

system_info

Report OS, CPU, RAM (total/used/free/%), and disk usage per drive

restart_graphics_driver

Send Ctrl+Shift+Win+B to restart the graphics driver - fixes a frozen/stuck/black/glitched screen without closing apps or losing work

shutdown_pc

Schedule a full shutdown after a delay. Requires confirm: true.

restart_pc

Schedule a restart after a delay. Requires confirm: true.

cancel_shutdown

Abort a pending shutdown_pc/restart_pc before it fires

Known app aliases live in src/appMap.js — add more there as needed. Any other name is tried as a literal .exe.

open_path_with's app field is required on purpose: if a request doesn't say which app to use, the calling model should ask you rather than guess — making the field required enforces that at the schema level instead of relying on prompt wording. Use plain open_path for "just open it with whatever's default" requests.

focus_app / maximize_app / minimize_app take an optional pid. If more than one window of the requested app is open, they refuse to guess — the error lists each candidate's PID and window title so you (or Claude) can retry with the right pid.

find_duplicate_files matches by content (SHA-256), not filename — two files named differently but byte-identical count as duplicates; two files with the same name but different content don't. It groups by file size first and only hashes within a group that has more than one file, so a folder with mostly unique-sized files is fast. It stops after 20000 files on a very large tree and sets truncated: true rather than hanging.

Chrome tabs

close_chrome_tab / focus_chrome_tab match by a case-insensitive substring against tab titles (not URLs) and take an optional index the same way the window tools take pid - if the query matches more than one tab, they list the candidates instead of guessing. Built on Chrome's own UI Automation tree (the same mechanism screen readers use), not taskkill/Win32 windows, since individual tabs aren't OS-level windows at all.

Two things worth knowing:

  • Only the first Chrome window is used if you have more than one open — tabs in a second Chrome window aren't visible to these tools.

  • The first Chrome tab call after Chrome starts (or after it's been idle a while) can return an empty list while Chrome's accessibility tree activates. If you get [] from list_chrome_tabs when you know tabs are open, just call it again.

⚠️ Security model — read before exposing this to the internet

This server can launch and kill processes on your laptop. Anyone who can send it a request has meaningful control of your machine. It is not a toy:

  • The HTTP transport (src/http.js) refuses to start without MCP_AUTH_TOKEN set and requires Authorization: Bearer <token> on every request. There is no bypass for this — don't add one.

  • It binds to 127.0.0.1 only, never 0.0.0.0. The only way it becomes reachable from outside this machine is if you deliberately point ngrok (or something else) at it.

  • Every request is logged to stdout with timestamp and source IP, including rejected (unauthenticated) ones — keep an eye on that console while a tunnel is open.

  • A small denylist (PROCESS_DENYLIST in src/appMap.js) blocks closing core OS processes (lsass.exe, winlogon.exe, services.exe, ...) so a bad request can't easily crash the whole session.

  • All dynamic input (app names, paths) is passed to child processes via environment variables, never string-concatenated into a shell/PowerShell command line — this is what prevents a crafted tool argument from smuggling in extra commands.

shutdown_pc / restart_pc — the two tools that can strand you

These are the most destructive tools in this server, so they have three independent safety nets:

  1. confirm: true is required. Omit it and the tool refuses before touching shutdown.exe — a guard against an accidental or ambiguous call.

  2. A countdown delay (default 60s, min 15s, max 3600s) before anything happens.

  3. cancel_shutdown aborts a pending shutdown/restart during that countdown.

Two things worth knowing that aren't obvious from the tool names:

  • Unsaved work is not protected. Windows' shutdown.exe automatically implies force-close (/f) whenever the delay is greater than 0 seconds — every default call here has a delay, so once the countdown reaches zero, open apps are closed without a save prompt. The delay is your only window to react, not a "Windows will ask first" safety net.

  • restart_pc currently ends remote control, same as shutdown_pc. This server doesn't auto-start on boot, so after either one fires you'll need to be physically at the machine to get remote control back (auto-start-on-login is a possible follow-up, not set up here).

If you ever need to cancel by hand instead of through an MCP tool call, run shutdown /a from a normal cmd.exe or PowerShell window — not Git Bash. Git Bash's path auto-conversion rewrites leading-slash flags like /a into a bogus Windows path before shutdown.exe ever sees it, so the command silently does nothing (prints usage/help, exit code 1) instead of cancelling. This bit us during testing of this feature.

What this does not do: there is no arbitrary shell-command tool here on purpose. "Open/close apps and files" is a large enough attack surface already; a generic run_command tool would turn this into an unrestricted remote shell. If you extend this server, keep that boundary in mind.

Practical rules for running this safely:

  1. Treat MCP_AUTH_TOKEN like a root password. Generate a long random one (see .env.example), never commit it, never post the ngrok URL anywhere public.

  2. Only run the tunnel while you're actively using it. Stop ngrok (and the server, if you want to be extra safe) when you're done for the day.

  3. Prefer ngrok's own auth on top of yours. ngrok http 3939 --oauth=google --oauth-allow-email=you@example.com (requires a paid ngrok plan) or at least ngrok http 3939 --basic-auth "user:longpassword" adds a second lock on the door.

  4. Watch the console. Every open/close call this server executes is printed. If you see activity you didn't trigger, kill the ngrok tunnel immediately (Ctrl+C) and rotate MCP_AUTH_TOKEN.

  5. A free ngrok URL changes every time you restart the tunnel — that's a feature, not a bug, since a stale forgotten URL still needs your (rotatable) token to do anything.

  6. Try shutdown_pc/restart_pc locally over stdio first, with a generous delaySeconds and cancel_shutdown ready to go, before ever calling them through the ngrok tunnel where a dropped connection could keep you from cancelling in time.

Related MCP server: Windows-MCP

Setup

npm install
copy .env.example .env

Edit .env and set MCP_AUTH_TOKEN to a long random value:

node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"

Running locally (stdio) — for Claude Code / Claude Desktop on this machine

No token needed for stdio; the client launches the process directly, so there's no network exposure.

Claude Code:

claude mcp add desktop-control -- node "C:\Users\Al-Fateh\Documents\agentic-system\desktop-control-mcp\src\stdio.js"

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "desktop-control": {
      "command": "node",
      "args": ["C:\\Users\\Al-Fateh\\Documents\\agentic-system\\desktop-control-mcp\\src\\stdio.js"]
    }
  }
}

Running remotely (HTTP + ngrok) — for claude.ai custom connectors

  1. Start the server:

    npm run start:http

    It listens on http://127.0.0.1:3939/mcp and will refuse to start if MCP_AUTH_TOKEN isn't set.

  2. In a separate terminal, tunnel it:

    ngrok http 3939

    Note the https://<random>.ngrok-free.app URL ngrok prints.

  3. Connect a client to https://<random>.ngrok-free.app/mcp with header Authorization: Bearer <your MCP_AUTH_TOKEN>:

    • Claude Code: claude mcp add --transport http desktop-control https://<random>.ngrok-free.app/mcp --header "Authorization: Bearer <token>"

    • claude.ai (Settings → Connectors → Add custom connector): paste the URL. If the UI doesn't offer a header field for your account type, you'll need OAuth-based auth instead of a static bearer token to use claude.ai's hosted connector flow — the bearer-token approach above is guaranteed to work with Claude Code today.

  4. When you're done, Ctrl+C both the ngrok tunnel and the server.

Files

src/appMap.js     friendly-name -> exe/process map, and the process denylist
src/winControl.js the actual open/close logic (PowerShell + taskkill, injection-safe)
src/server.js     MCP tool definitions, shared by both transports
src/stdio.js      entry point for local stdio transport
src/http.js       entry point for remote HTTP transport (auth required)
F
license - not found
A
quality
C
maintenance

Maintenance

0Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to perform extensive Windows system administration, file operations, process management, network configuration, registry editing, GUI automation, and more through a comprehensive set of MCP tools.
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    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.

View all related MCP servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/NasirSultan/desktop-control-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server