visible-terminal-mcp
This server lets you spawn, drive, inspect, and close visible PowerShell terminal windows on Windows.
Spawn a new visible PowerShell console window, optionally in a specified working directory, and get its pid.
Send literal text, Enter, and special keys (
UP,DOWN,LEFT,RIGHT,ESC,TAB) to a terminal by pid; delivery depends on that window having focus.Read the terminal's current on-screen text via the Windows Console API.
Close a terminal window by terminating its process.
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., "@visible-terminal-mcpOpen a terminal, run npm init -y, then read what's on screen"
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.
terminal-fleet-mcp
An MCP server that lets one controlling AI agent session spawn and independently drive a fleet of genuinely visible Windows terminal windows — each can run its own program (including a second claude session), take its own instructions, and get read back independently — while a human watches every real window the whole time.
The problem this solves
Most ways an AI agent can drive a terminal are headless: the agent spawns a process behind a pseudo-terminal (ConPTY / node-pty), types into it, and reports back what happened. That's fast and works well for scripted automation — but it gives a human nothing to look at. You're asked to trust that the agent did what it says it did, with no independent way to verify it in real time. See docs/motivation.md for the original incident that motivated not hiding the terminal.
This project started from that idea and grew into its real purpose: orchestrating several terminal/Claude Code sessions from one controlling session, instead of a human manually opening a terminal, typing claude, enabling remote control, and repeating that per task. One session can spawn several labeled workers, give each its own task, and read each one's output independently to decide what to do next.
The fix: don't hide the terminal, and don't rely on window focus to control it. Spawn real, classic Windows console windows — the same kind you'd open yourself — and drive each one directly by process id, immune to whatever else is happening on screen.
Related MCP server: com-use-mcp
What it actually gives you
Capability | Mechanism | Why it matters |
Spawn a real terminal window |
| An actual OS window, not a virtual buffer — the user can see it exists |
Send keystrokes |
| Writes directly into that specific console's own input buffer — never touches window focus or the shared system input queue, so it can't be misdelivered to whatever window the user happens to be using at the time |
Read what's on screen | Win32 Console API ( | Reads the actual character buffer the window is displaying — not a screenshot, not a guess, the same content the human sees. Can optionally annotate color (errors vs normal output) |
See it, as an image |
| Fallback for garbled text or layout-dependent TUIs |
Wait for output | Polls the buffer for text or quiet | No more guessing sleep durations between send and read |
Track a fleet | In-memory registry + labels | Every tool accepts a friendly label instead of a raw pid; |
Close it |
| Clean teardown when done |
Because reading goes through the real console buffer, the agent and the human are looking at the same ground truth — there's no second, hidden copy of "what happened" that only the agent has access to.
Why not SendKeys/SetForegroundWindow?
An earlier version of this project drove input by stealing window focus and simulating keystrokes via Windows Forms SendKeys. That turned out to be fundamentally unsafe for the actual use case: it injects into the shared, system-wide input queue, routed by whichever window currently has OS focus — which races with anything else the user is doing (clicking another window, typing in a different terminal) and can silently misdeliver keystrokes to the wrong place. WriteConsoleInput writes directly into one specific console's own buffer, by pid, bypassing focus and that shared queue entirely — the target doesn't need to be visible, foreground, or even unminimized.
Use cases
Orchestrating several Claude Code (or any CLI) sessions at once — spawn N labeled terminals, give each its own task, read each independently, follow up based on what each one actually produced. The motivating case for this project.
Supervised automation of interactive CLIs — anything that only shows its full behavior when it detects a real terminal (confirmation prompts, TUI pickers), with a human able to watch it happen.
Reproducing and debugging terminal-dependent bugs that don't manifest the same way under a headless PTY, with a human verifying each step.
Teaching or demoing what an agent is doing step by step, rather than presenting only a final summary.
Requirements
Windows (uses the Win32 Console API — this is not cross-platform)
Node.js >= 18
PowerShell available on
PATH
Installation
git clone https://github.com/Sanjay-dev22/terminal-fleet-mcp.git
cd terminal-fleet-mcp
npm installUsing it as an MCP server
Register it with your MCP-compatible client. For Claude Code, add this to your mcpServers config (e.g. ~/.claude.json):
{
"mcpServers": {
"terminal-fleet": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/terminal-fleet-mcp/src/server.js"],
"env": {}
}
}
}Restart your MCP client, and seven tools become available. The server also declares MCP instructions — a usage guide (workflow, pacing, key syntax) that a compliant client surfaces to the agent automatically on connect, the same way tool descriptions are surfaced. You don't need to paste anything from this README into a prompt for the agent to know how to use the server correctly.
term_spawn
Opens a new, visible terminal window, optionally running a command immediately and/or tagged with a friendly label.
Param | Type | Required | Description |
|
| no | Which shell hosts the window. Default |
| string | no | Run immediately after the shell starts, e.g. |
| string | no | Working directory |
| string | no | A friendly name to use instead of the pid in later calls |
| object | no | Extra environment variables for the spawned shell |
Returns { pid, label }.
term_send
Sends input directly into a terminal's own console input buffer, by pid — not by simulating a keyboard.
Param | Type | Required | Description |
| string | yes | Pid or label |
| string | no | Literal text, delivered as one atomic block regardless of length/content |
| boolean | no | Press Enter after text/keys |
| string[] | no | Key combos in order, e.g. |
term_read
Reads exactly what's currently rendered in the window via the real Windows Console API.
Param | Type | Required | Description |
| string | yes | Pid or label |
| boolean | no | Annotate colored text runs inline as |
| number | no | Also read this many lines of buffer history above the visible window |
term_wait
Blocks until a terminal's output contains specific text, goes idle, or times out — instead of guessing a sleep duration.
Param | Type | Required | Description |
| string | yes | Pid or label |
| string | no | Substring, or |
| number | no | Stop once unchanged for this long. Default 1500ms if |
| number | no | Default 30000 |
term_screenshot
Captures an actual PNG of the window via PrintWindow, for when term_read's text doesn't make sense.
term_list
Lists every terminal this server is tracking: pid, label, shell, command, cwd, alive/dead.
term_close
Terminates a terminal's process.
Examples
npm run example:basic # spawn -> send -> read -> list -> close
npm run example:menu-navigation # key combos: history recall via UP/UP, CTRL+C
npm run example:fleet # the actual headline use case: two labeled workers, driven independentlyKnown limitations
Windows only. The console-reading/writing mechanism is Win32-specific.
Reads text, not pixels (by default).
term_readreturns the character buffer; useterm_screenshotfor a true image.Can't reach an IDE's own integrated terminal panel (e.g. VS Code's) directly — this controls independent OS-level console windows, not IDE panels.
SHIFT+ENTER doesn't insert a newline. Once injected via
WriteConsoleInput, it's indistinguishable from plain ENTER and submits early — confirmed empirically while testing multi-line input into Claude Code's own TUI. For a real multi-line message, put a literal\ninsidetextitself instead of sending aSHIFT+ENTERkey combo; that's delivered as an actual newline character and the target renders it as one multi-line input, same as a human pressing shift+enter.CTRL+C doesn't reliably abort a program mid-blocking-call. It's delivered as a real keystroke (the console visibly echoes
^C, confirming it arrived), which reliably interrupts most interactive programs reading it from their input stream. It does not reliably raise the OS-level break signal a program like a bare PowerShellRead-Hostspecifically waits for — Windows has no supported way to raise that signal targeted at an unrelated, already-running process from the outside. If a worker is truly stuck there,term_closeand respawn rather than expectingCTRL+Cto free it.
License
Available Tools
4 toolsvterm_closeA
Close a visible terminal window (terminates the process).
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | Process id returned by vterm_spawn |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden, and it does earn credit for disclosing the key consequence: the underlying process is terminated, not merely detached or hidden. It still omits failure modes — what happens with an invalid or already-dead pid, whether the call is idempotent, and whether in-flight work is lost.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no waste; the most important fact, that the process dies, is included. It is arguably under-specified rather than bloated, but nothing in it is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lifecycle tool with full schema coverage and no output schema, the essential facts — action and side effect — are present. What is missing, error behavior on stale pids, is minor at this complexity level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the sole parameter is documented as the process id returned by vterm_spawn, which even cross-references the sibling that produces it. The description adds nothing beyond that, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (close) and resource (a visible terminal window), with a parenthetical that disambiguates what closing means: the process is terminated. That distinguishes it cleanly from vterm_spawn, vterm_send and vterm_read, which create, write to, and read terminals.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the verb-resource pair and the sibling set, but there is no explicit when-to-use or when-not-to-use statement, no mention of cleanup duties, and no declaration that this is the counterpart to vterm_spawn. An agent must infer that from tool names alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vterm_readB
Read exactly what is currently rendered on screen in a visible terminal window, via the real Windows Console API (not a screenshot) — the same thing the user sees if they look at that window.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | Process id returned by vterm_spawn |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden, and it does valuable work by clarifying this reads the console buffer rather than capturing pixels. However, it omits key behavior an agent needs: whether the window must be foregrounded/visible for the read to succeed, what happens for an invalid or closed pid, and whether only the viewport (not scrollback) is returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence with the core action front-loaded ('Read exactly what is currently rendered') and the parenthetical qualifiers each eliminating a plausible misinterpretation (screenshot, other windows). Nothing is padded or repeated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool, the description covers what is read and from where, but with no output schema it should say more about the returned shape (plain rendered text? whitespace/ANSI preserved? viewport-only vs scrollback) and about failure modes. It is minimally sufficient rather than complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single pid parameter is already documented as 'Process id returned by vterm_spawn', so the schema does the heavy lifting. The description adds no further parameter meaning, which is exactly the baseline 3 case for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource ('read exactly what is currently rendered on screen') plus the mechanism ('real Windows Console API, not a screenshot'), which makes the operation unmistakable. It never names vterm_spawn/vterm_send/vterm_close, so routing is inferred from the operation described rather than explicitly stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to call this versus waiting, re-sending input, or checking a different window; only the phrase 'in a visible terminal window' hints at a precondition. An agent must derive the usage pattern (e.g. read after vterm_send to verify output) entirely on its own.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vterm_sendA
Send keystrokes to a visible terminal window, exactly as if typed on a keyboard. Relies on the window having focus (true right after vterm_spawn, or after the user last interacted with it — does not forcibly steal focus from other windows). Does not wait for a response — call vterm_read afterward.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | Process id returned by vterm_spawn | |
| text | No | Literal text to type (e.g. a command or a chat message). | |
| enter | No | Press Enter after the text. | |
| special | No | Special keys to send in order, e.g. ["UP","UP"] to navigate a menu, before any text/enter. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose key behavior: focus dependency, no focus stealing, and non-blocking execution. However, it does not explain what happens if the window lacks focus or what the immediate return value is, leaving some failure-mode and response behavior unspecified.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three tight sentences, front-loads the core action, then gives focus constraints and the required follow-up. There is no redundant or filler text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given full parameter schema coverage and no output schema, the description provides the essential operational context: focus requirements and the need to call vterm_read afterward. It is complete enough for correct invocation, though failure behavior when unfocused is not fully specified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents pid, text, enter, and special keys in detail. The description adds only general context about keystrokes and does not supplement parameter semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: send keystrokes to a visible terminal window. It clarifies the action as equivalent to typing on a keyboard, which clearly distinguishes it from sibling tools like vterm_spawn, vterm_read, and vterm_close.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states the focus prerequisite (true right after vterm_spawn or after user interaction), warns that it does not forcibly steal focus, and directs the agent to call vterm_read afterward. This gives clear when-to-use context and sequencing relative to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vterm_spawnA
Open a brand-new, genuinely visible PowerShell console window the user can watch on their own screen. Returns the process id (pid) to use with vterm_send / vterm_read / vterm_close.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Working directory to start in. Defaults to the current directory. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key behavioral fact: this creates a real, user-visible window on their screen — an observable side effect an agent must not trigger casually. It also implies a lifecycle requiring vterm_close. It does not cover failure modes (e.g., headless/no interactive session) or whether the window steals focus, keeping it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: the first defines the action and its visible-window nature, the second gives the return value and the follow-up tools. No filler, and the most decision-relevant fact (a visible window appears) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-optional-parameter spawn tool with no output schema, the description supplies the birth-to-death lifecycle (spawn → send/read → close) and explicitly states the pid return, which substitutes for the missing output schema. Minor gap: no note on environment prerequisites or whether multiple windows are permitted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single optional cwd parameter is fully documented in the schema, so baseline 3 applies. The description adds no information about cwd semantics (e.g., whether it must exist or how paths are resolved) beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (open/spawn) and resource (a PowerShell console window) plus the distinguishing trait that it is 'genuinely visible' to the user, which separates it from any hypothetical headless execution. It also declares the return value (pid) and maps it to the sibling tools that consume it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly establishes the workflow: spawn first, then use the returned pid with vterm_send / vterm_read / vterm_close, naming all three siblings. It stops short of explicit when-not guidance (e.g., when to reuse an existing session rather than spawn a new window), so it is clear context without exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v1.0.0- First observed
vterm_close - First observed
vterm_read - First observed
vterm_send - First observed
vterm_spawn
TDQS
Scored across 4 tools
Each tool maps to a distinct lifecycle action on a visible terminal: spawn, send, read, and close. There is no overlap in purpose, and the descriptions make the boundaries between input, output, and process management clear.
All tools use a consistent vterm_verb pattern: vterm_spawn, vterm_send, vterm_read, vterm_close. The shared prefix and short action verbs are predictable and readable.
Four tools are well-scoped for a focused visible-terminal controller. Each tool earns its place in the create/send/read/close lifecycle, with no redundant operations.
The core lifecycle for a visible terminal is covered: opening, typing into, reading from, and closing a window. Minor gaps exist, such as explicit waiting for command completion or listing active terminal windows, but agents can work around them with repeated reads.
Maintenance
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Connect ChatGPT, Claude, Cursor or VS Code to your Windows PC: files, terminal, browser, apps.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides AI agents with fully interactive terminal sessions, including TUI support, keyboard control, and screen capture across Windows, Linux, and Mac.MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to see and operate a Windows PC through mouse, keyboard, screenshots, OCR, window control, and shell commands.-
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to drive native Windows apps and headed browsers inside a hidden child desktop session with its own screen, pointer and keyboard focus. Provides tools for screenshots, mouse/keyboard input, accessibility inspection, UI waits, display changes, Android emulators, application launches and cancellable command jobs, so the user's own desktop stays free.4MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI models to control a local Windows desktop by moving the cursor, clicking, scrolling, typing Unicode text, sending key chords, and capturing screenshots. Runs natively on Windows with minimal latency and no heavy dependencies such as Python, PyAutoGUI, or Docker.90 npm1MIT