Terminal GPT Experimental MCP
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., "@Terminal GPT Experimental MCPrungit statusin the project directory"
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 GPT Experimental MCP
An isolated experimental copy of the Terminal Linux MCP that bootstraps every model thread with GPT-specific instructions, skills, tool manifests, downstream MCP discovery, and persistent token-usage accounting.
The server can run locally over stdio, SSE, or Streamable HTTP. start.sh starts the Streamable HTTP server and an ngrok tunnel together, prints the final MCP endpoint, and shuts both processes down cleanly.
This server can execute shell commands and modify files on the host. Treat it like remote shell access. Run it as a dedicated low-privilege user, require authentication, keep tool approvals enabled, and never expose it anonymously on the public internet.
Highlights
Native command execution with per-session working directories and environment variables.
Foreground and background process management.
Direct file read/write/edit/copy/move operations.
Native local image inspection through
watch_image, returning MCPImageContentinstead of a text path or JSON-wrapped base64 blob.Optional persistent per-thread goals with fixed finish conditions, evidence-gated completion, and 15-minute reminder injection.
Mandatory per-thread bootstrap gate using
~/.GPT/AGENTS.mdand project.GPT/AGENTS.mdfiles; Codex~/.codex/AGENTS.mdis intentionally ignored.MCP initialization instructions include the GPT rules, every discoverable skill, every public Terminal tool, and configured nested MCP server names.
SQLite tracking for host-reported model input/output/cached-input tokens plus separately labeled server estimates for returned bootstrap context.
A mobile-first live usage ledger at
/dashboard, mounted in the same HTTP process and updated through Server-Sent Events.Discovery of local
SKILL.mdfiles.Discovery and proxying of configured MCP servers.
Persistent downstream MCP connections keyed by
(session_id, server_name).Per-server serialization, one reconnect attempt after a crashed downstream server, idle cleanup, and explicit reset actions.
Exclusive ownership for configured browser profile directories, preventing two owners from opening the same profile concurrently.
Optional bearer authentication for HTTP transports.
Safe launcher that refuses occupied ports and refuses an unauthenticated public tunnel unless explicitly overridden.
Related MCP server: llm-gateway
Thread bootstrap architecture
This branch is designed to run beside the normal Terminal MCP rather than replace it. Its defaults are isolated:
Normal Terminal MCP Experimental Terminal GPT MCP
port 8000 port 8011
~/.codex/AGENTS.md ~/.GPT/AGENTS.md
normal server process separate worktree/processOn MCP initialization, the server sends a startup instruction document containing:
The full global
~/.GPT/AGENTS.mdinstruction content.Every discovered
SKILL.mdname, description, source, and path.Every public Terminal GPT tool and description.
Every configured nested MCP server name and public endpoint summary.
The recovery and token-accounting tools.
Project-specific .GPT/AGENTS.md files are intentionally not injected until bootstrap_thread receives the target cwd, preventing one project’s rules from leaking into another project’s initialization. The global startup payload is rebuilt for every MCP initialization, so changes to global rules or discovered skills are visible to newly initialized clients without restarting the server.
A model thread must then call:
{
"thread_id": "a-unique-stable-id-for-this-model-thread",
"cwd": "/absolute/project/path"
}through bootstrap_thread. The same value must be reused as session_id for later tools. The shared value default is rejected for gated execution or modification, preventing one chat from inheriting another chat's loaded-context fingerprint.
If the model loses context after compaction or a long conversation, it calls get_thread_context. If any applicable .GPT/AGENTS.md changes, the fingerprint gate blocks further gated work until the thread reloads its context.
GPT instruction hierarchy
The experimental server never reads Codex's instruction tree. It resolves GPT instructions in this order:
~/.GPT/AGENTS.override.md # overrides ~/.GPT/AGENTS.md
~/.GPT/AGENTS.md
<repo>/.GPT/AGENTS.override.md # overrides that directory's AGENTS.md
<repo>/.GPT/AGENTS.md
<repo>/<subdir>/.GPT/AGENTS.md
...MCP_GPT_HOME changes the global GPT directory. The default is ~/.GPT.
Persistent thread goals
thread_goal stores one optional goal per bootstrapped thread. A goal contains an objective and fixed finish conditions; it remains active until complete receives exactly one non-empty evidence entry per condition, or technical_error records a genuine blocking failure. resume reactivates a technical-error goal and clear removes it.
When the goal has not been returned to the model for MCP_GOAL_REMINDER_SECONDS (15 minutes by default), the first later tool result atomically receives a compact <goal_context> block. The reminder is appended without flattening native image content or changing an existing MCP error flag. bootstrap_thread, get_thread_context, and thread_goal(action="get") also return the goal and reset the reminder timer.
thread_goal(
action="set",
session_id="the-bootstrapped-thread-id",
objective="Finish and verify the requested implementation",
finish_conditions=[
"The requested behavior exists",
"Relevant success and failure tests pass",
],
)The server cannot start a new model turn by itself. It persists and re-injects the goal so a compatible host or the next user/model turn can continue from the full objective instead of treating partial progress as completion.
Native image inspection
watch_image accepts an absolute or working-directory-relative local path and returns the original image bytes as native MCP ImageContent. This lets an MCP-capable model receive the image as visual input instead of receiving only the filename or a JSON string.
Supported formats are PNG, JPEG, WEBP, and non-animated GIF. The server validates the file signature rather than trusting the extension, rejects malformed or animated GIFs, and reads at most MCP_WATCH_IMAGE_MAX_BYTES bytes. The default limit is 20 MiB before base64 expansion.
watch_image(
path="/absolute/path/to/screenshot.png",
session_id="the-bootstrapped-thread-id",
cwd="/absolute/project/path",
)The MCP image content carries base64 data plus its MIME type. It preserves the original file bytes; image-detail selection remains a responsibility of the MCP host when it maps the content into a model request.
Token usage database
The database is stored at:
~/.GPT/thread_usage.dbIt stores a thread record and an append-only usage event stream with:
input tokens
output tokens
cached input tokens
model and provider request ID
exact-versus-estimated classification
context fingerprints and bootstrap counts
record_token_usage is for exact usage reported by the model host/provider. An MCP server cannot independently observe the ChatGPT host's complete model prompt or response, so exact accounting requires the wrapper/runtime to report those values.
The proxy additionally records a clearly separate proxy_estimate event for every non-default thread tool call. It uses tiktoken's o200k_base encoding: the tool-call name and JSON arguments are estimated model output, while the textual tool result is estimated model input available on the next turn. It deliberately excludes image/audio payloads and cannot calculate provider prompt-cache hits. Bootstrap text remains a server_estimate input event. These estimates must not be added to exact provider totals, because they describe overlapping portions of the same model turns.
get_token_usage returns global or per-thread totals, grouped thread summaries, and recent events. Reusing the same non-empty provider request ID is idempotent and does not double-count a retried report.
Live usage dashboard
For SSE or Streamable HTTP transports, the same server process exposes:
/dashboard interactive usage ledger
/dashboard/api current JSON snapshot
/dashboard/events live Server-Sent Events streamThe dashboard shows exact provider-reported tokens, proxy-estimated MCP text, tool-call counts and ranking, active/recent threads, time-window charts, and the newest accounting events. Exact and estimated figures stay visually and numerically separate because they can overlap.
Set MCP_DASHBOARD_TOKEN to require the dashboard login form. The MCP bearer middleware deliberately leaves /dashboard to this cookie-based browser flow; /mcp continues to use MCP_BEARER_TOKEN independently. When the dashboard token is unset, the dashboard inherits the reachability of the HTTP server and any tunnel in front of it, so do not expose it publicly without another access policy.
Requirements
Linux
Optional agent CLIs used by delegated tools: Codex and/or Antigravity
store.sh installs the remaining prerequisites. It supports Debian/Ubuntu,
Fedora/RHEL, Arch, openSUSE, and Alpine package managers. When the operating
system does not provide Python 3.11 or newer, it installs uv in user space and
uses a managed Python instead.
Quick start
git clone https://github.com/ru-aish/terminal-linux-mcp.git
cd terminal-linux-mcp
./store.sh --with-ngrok
cp .env.example .envinstall.sh is a conventional alias for the same installer:
./install.sh --with-ngrokUseful installer modes:
./store.sh # runtime dependencies only
./store.sh --dev --test # development dependencies and test suite
./store.sh --skip-system-packages # user-space setup without sudo/doas
./store.sh --check # readiness report without modificationsFor a local-only server, ngrok is not required:
./store.sh
./start.sh --local-onlysetup.sh is the lower-level, idempotent Python environment installer. It can
repair an existing .venv, or rebuild it with backup-and-rollback protection:
./setup.sh
./setup.sh --recreate
./setup.sh --dev --testGenerate a strong bearer token:
openssl rand -hex 32Put the generated value in .env:
MCP_BEARER_TOKEN=replace-with-the-generated-valueAuthenticate ngrok once:
ngrok config add-authtoken YOUR_NGROK_AUTHTOKENStart the MCP server and tunnel:
./start.shThe launcher prints both endpoints:
Local MCP endpoint: http://127.0.0.1:8011/mcp
Public MCP endpoint: https://example.ngrok.app/mcp
Authentication: Authorization: Bearer <MCP_BEARER_TOKEN>Ctrl+C stops the server and the tunnel.
Local-only mode
./start.sh --local-only
# Equivalent: MCP_SKIP_NGROK=1 ./start.shVerify the endpoint
MCP_BEARER_TOKEN='your-token' \
python scripts/smoke_test.py https://example.ngrok.app/mcpOpenAI setup
OpenAI products connect to a remote MCP URL; ChatGPT does not connect directly to a local MCP process. The ngrok URL printed by start.sh is a remote Streamable HTTP endpoint. OpenAI also provides a Secure MCP Tunnel for private or on-premises servers.
Official references:
ChatGPT developer mode and MCP apps: https://help.openai.com/en/articles/12584461-developer-mode-and-full-mcp-connectors-in-chatgpt-beta
MCP and Connectors in the Responses API: https://developers.openai.com/api/docs/guides/tools-connectors-mcp
Secure MCP Tunnel: https://developers.openai.com/api/docs/guides/secure-mcp-tunnels
ChatGPT custom app
Plan availability and the UI can change. Follow the current OpenAI documentation for your workspace. As of July 2026, OpenAI documents full MCP support in ChatGPT for Business, Enterprise, and Edu workspaces, while Pro developer mode is limited to read/fetch capabilities. The current setup flow is:
Enable developer mode for your account or workspace.
Open Settings → Apps → Create, or the equivalent workspace-admin path.
Enter the public endpoint printed by
start.sh, including/mcp.Configure authentication.
Select Scan Tools and review every discovered tool.
Create the draft app and test it in a new chat.
This repository supports a static bearer token. The Responses API can pass that token directly. ChatGPT custom apps commonly use OAuth for authenticated servers; place this MCP behind an OAuth-capable gateway or use OpenAI's Secure MCP Tunnel when the ChatGPT setup does not offer a static bearer-token option.
Do not select unauthenticated access for a public terminal endpoint. The launcher requires one of these before starting ngrok:
MCP_BEARER_TOKENNGROK_TRAFFIC_POLICY_FILEthe explicit and dangerous
MCP_ALLOW_UNAUTHENTICATED_PUBLIC=1override
Responses API
The Responses API supports remote MCP servers over Streamable HTTP or HTTP/SSE. Pass the MCP URL as server_url and the terminal bearer token as authorization.
import os
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model=os.environ.get("OPENAI_MODEL", "gpt-5.6"),
input="List the files in the configured workspace.",
tools=[
{
"type": "mcp",
"server_label": "terminal_linux",
"server_description": "A controlled Linux development terminal.",
"server_url": os.environ["TERMINAL_MCP_URL"],
"authorization": os.environ["MCP_BEARER_TOKEN"],
"require_approval": "always",
"allowed_tools": [
"bootstrap_thread",
"get_thread_context",
"context_manifest",
"thread_goal",
"record_token_usage",
"get_token_usage",
"list_dir",
"stat_path",
"read_file",
"watch_image",
],
}
],
)
print(response.output_text)OpenAI does not store the MCP authorization value in the Response object, so provide it on every Responses API request that uses the server.
Public tools
Area | Tools |
Thread bootstrap and recovery |
|
Persistent goal |
|
Token accounting |
|
Skills and MCP discovery |
|
Commands |
|
Session environment |
|
Files and images |
|
Delegated agents |
|
ChatGPT agent orchestration |
|
Persistent downstream MCP proxy
local_mcp keeps downstream MCP transports alive instead of spawning one child process per tool call. This is essential for stateful servers such as browsers.
A connection is identified by:
(session_id, server_name)Use the same session_id for a sequence that must share state:
local_mcp(action="call", server="stealth-browser", tool="browser_navigate", session_id="research")
local_mcp(action="call", server="stealth-browser", tool="browser_type", session_id="research")Supported actions:
list: list configured servers and showconnectedfor the current terminal session.tools: inspect a downstream server's tool schemas.call: invoke a downstream tool.reset: close one cached downstream server for the currentsession_id.reset-all: close every cached downstream server for the currentsession_id.
Behavior:
Calls to the same cached server are serialized.
A failed child connection is discarded and reconnected once.
Changed MCP configuration causes a fresh connection.
Idle connections close after
MCP_PROXY_IDLE_TIMEOUTseconds;0disables idle cleanup.Environment values such as
SAB_USER_DATA_DIR,BROWSER_PROFILE_DIR, and similar profile-path settings are treated as exclusive resources. Anothersession_idcannot claim the same profile while it is active.Server shutdown closes cached downstream clients and their child processes.
The persistent proxy preserves live tabs, DOM state, JavaScript state, and aria references while the downstream browser process stays alive. Cookie persistence across a process restart still depends on whether the downstream browser MCP genuinely uses a persistent browser context.
Downstream MCP configuration
The server discovers MCP configuration from:
~/.codex/config.toml~/.gemini/config/mcp_config.json~/.config/Claude/claude_desktop_config.json<project>/.codex/config.toml<project>/.mcp.json<project>/mcp.json<project>/.vscode/mcp.json
Example project .mcp.json:
{
"mcpServers": {
"stealth-browser": {
"command": "node",
"args": ["/absolute/path/to/stealth-agent-browser-mcp/dist/index.js"],
"env": {
"SAB_HEADLESS": "1",
"SAB_USER_DATA_DIR": "/absolute/path/to/browser-profile"
}
}
}
}Secrets in downstream MCP configuration are used to launch the child but are not included in local_mcp(action="list") output.
Configuration
Copy .env.example to .env. Important values:
Variable | Default | Purpose |
|
| HTTP listener address |
|
| HTTP listener port |
|
|
|
|
| Default terminal workspace |
|
| Runtime logs |
| empty | Required bearer token for HTTP requests |
|
| Downstream MCP idle timeout in seconds |
|
| Set |
|
| Run |
|
| Let |
|
| Override the virtual-environment directory |
| random URL | Reserved ngrok URL/domain |
| empty | Optional ngrok Traffic Policy |
|
| Dangerous public-tunnel override |
|
| Enable the five-minute ChatGPT task watchdog for SSE/Streamable HTTP |
|
| Use the Codex desktop app's internal normal-chat client; no UI fallback is enabled |
|
| Editable one-active-task-URL-per-line input queue; task state is reconciled into the durable ledger |
|
| Compatibility mirror and one-time import source for watchdog task state |
|
| Append-only task completion history |
|
| Selected Project allowlist plus baselined/seen conversation IDs for new-thread discovery |
|
| Codex desktop CDP endpoint |
|
| Scheduled scan interval |
|
| Duplicate-send cooldown |
|
| Inspect and report without sending |
|
| Start the desktop host when offline, or reopen its primary renderer when CDP is up but the internal client is not ready |
|
| Installed Codex desktop launch command |
|
| Maximum time to wait for a usable primary renderer after starting or reopening the desktop host |
|
| Timeout for CDP attachment and internal reads |
|
| Refuse to silently lower the requested reasoning level |
| empty | Preferred live model slug; otherwise reuse the thread model or live default |
|
| Requested live reasoning effort |
| falls back to watchdog effort | Reasoning effort attached to every durable agent create/continue request |
| falls back to watchdog requirement | Accept only high or extended effort for durable agent requests |
|
| Maximum time to wait for a watchdog-owned completion stream |
|
| Age after which unchanged in-progress canonical state is reported as stale; running recovery applies at the limits below |
|
| Stop and continue a watched generation still working after twenty minutes |
|
| Stop and continue after this many consecutive scans observe the same generation working, even if it makes progress |
|
| Hard per-task continuation-attempt ceiling |
|
| Delay before the canonical pre-send refetch |
|
| Enable the restart-safe parent/child orchestration sync loop for SSE/Streamable HTTP |
|
| Shared SQLite ledger for watchdog task generations plus agent registry, tasks, commands, events, subscriptions, and cursors |
|
| Background orchestration sync interval |
|
| Maximum compact execution events returned or journaled per delta |
|
| Maximum serialized compact execution context |
|
| Default recent visible/tool-summary lines |
|
| Maximum recent-tail text size |
|
| Hard ceiling for automatic child-task continuation attempts |
|
| Unchanged canonical-node age before an active/waiting child is marked stale and its parent is notified |
The launcher refuses to start when the selected port is already occupied. It never kills or replaces an existing service.
ChatGPT task watchdog
When enabled, the SSE and Streamable HTTP app scans every five minutes. Each URL line is one active task instance in an ordinary saved ChatGPT conversation, not a permanent thread watch or Work task. Completion removes that task URL; adding the same URL again creates a fresh task ID and increments its task generation, resetting hashes, cooldowns, attempts, completion state, and user-turn baseline. Direct file removal and later reappearance are reconciled the same way.
The default codex-internal adapter attaches to the installed desktop host at 127.0.0.1:9222 and calls its app-owned client for ordinary saved ChatGPT conversations directly. It does not launch Chrome, navigate conversations, read rendered transcript DOM, focus controls, type, or click, and there is no UI fallback. The desktop host must already be signed in once with the ChatGPT account that owns the queued conversations. If it is closed, the watchdog may start /usr/bin/codex-desktop. If CDP is up but no usable primary renderer exists, the watchdog sends the launcher's supported --new-chat warm-start action and waits for the internal runtime to become ready; failure remains non-destructive and sends nothing. The current build's mcpAppSandboxDevtools=1 primary renderer is supported.
Task completion is turn-bounded. A re-added task uses the prior generation's recorded completion turn as its boundary and waits for a later user turn, so an old DONE_I_HAVE_COMPLETED_ALL_THE_STEPS marker cannot complete a new task. Completion is accepted only when the latest meaningful turn is an assistant turn after the current task's user baseline and contains the marker as an exact standalone line. The durable completion record includes task ID, generation, baseline turn, and completion turn before the URL is removed.
A stopped incomplete task receives the configured continuation only after a second canonical get immediately before sending. A new completion marker, a changed transcript or current_node, an active stream, an existing continuation as the latest user turn, a duplicate parent node, cooldown, or the attempt ceiling cancels the send. The app's live model catalogue merges duplicate picker entries by backend slug. It uses an explicitly configured model strictly, otherwise reuses the thread model only when it satisfies the requested effort, and falls back to another verified high-reasoning model rather than silently downgrading. Watchdog operations share one global scan lock and one endpoint-wide internal-client lock, so only one watchdog operation or completion stream is initiated at a time while normal app use remains independent.
A watched generation that remains working for twenty minutes or two consecutive watchdog scans is selected for stop-and-continue recovery. The timer uses the current generation's recorded start when available, otherwise its first working observation. Scan counts persist across restarts and reset when the generation changes or a recovery message is submitted. Transcript progress does not reset this limit. The watchdog rechecks the target, stops it through the same adapter, and verifies the resulting state before submitting the usual continuation. A completion marker removes the task; a failed stop, an unreadable state, a new user turn, or a draft defers recovery. Scheduling retains one selected continuation per scan. Watchdog sends return after dispatch so a long completion stream cannot hold the scan lock and prevent later timeout checks. Existing project discovery, managed-agent exclusions, identity/bootstrap behavior, and ordinary stopped-task handling are unchanged.
The authenticated dashboard exposes /dashboard/watchdog plus task edit/add/remove and manual-scan controls. It also has a Project discovery section: Find projects performs an explicit Project catalogue read, and the user can add only chosen Projects to the persistent allowlist. Adding a Project baselines all currently listed conversations without enqueueing them. On each later watchdog timer, each selected Project normally costs one conversation-list request; unseen non-archived conversation IDs are added to the ordinary watchdog queue before task inspection. If a full page contains only unseen IDs, discovery follows the cursor until it reaches a previously seen ID so bursts larger than one page are not truncated. General chats and unselected Projects are never auto-added. The textarea edits the same threads.txt file used by the daemon, and active rows show their task generation. Saves include an optimistic file version, so a browser tab cannot overwrite URLs changed directly on disk. Mutating requests require same-origin context and the x-mcp-dashboard-csrf: chat-watchdog header; the existing dashboard token/cookie boundary still applies.
Persistent ChatGPT sub-agent orchestration
Terminal MCP exposes the existing agent_* tools while using two durable layers internally. durable_ledger.py stores parent/child identity, tasks, ordered mailboxes, subscriptions, events, working directories, and delivery cursors. The vendored chat_gateway package exclusively schedules automatic managed-agent provider work: creation, canonical inspection, continuation, cancellation, deletion, verification, request claims, rate windows, and circuit recovery. gateway_agent_orchestrator.py maps those layers without changing public tool schemas.
One agent_sync or background scheduler tick performs arbitrary local SQLite work and zero or one physical ChatGPT backend request. Create and continue are staged: the mutation uses one tick and canonical verification happens in a later tick. There are no same-tick retries, immediate readback, or per-agent polling loops. More agents increase queue latency rather than request rate. The default managed-child limit is five.
Default request limits are conservative: global and canonical reads use a 20-second minimum, 15 requests per five minutes, and 120 per hour; heavy generation operations use a 60-second minimum, five per ten minutes, and 20 per hour; metadata and cleanup have separate lanes. A 429 opens a durable shared circuit. Recovery starts after 120 seconds, then uses 6/12/24/48/60-minute failed-probe delays, half-open probes, and a paced recovery window. The gateway database survives restarts and serializes claims across processes.
Canonical completion is fail-closed. running=false, elapsed time, or an expired renderer stream record does not complete an agent. The gateway reports UNKNOWN until a canonical assistant terminal turn contains the configured completion marker, or verified failure/cancellation evidence exists. This prevents long-running agents from flipping through false terminal states.
agent_register_parent is a one-time, user-invoked canonical registration read used to discover the parent’s existing project. Project discovery tools are also explicit user calls. Automatic synchronization, creation, continuation, steering, verification, and cancellation are all routed through the gateway scheduler and accounted as physical request operations.
Every child receives exact orchestration IDs, project and working-directory placement, the Terminal MCP bootstrap/session contract, its assigned task, and an exact completion marker. Sub-agent operating guidance is provided by the machine skill terminal-mcp-subagents; it is discovered in startup metadata and loaded only when delegation work requires it. Nested delegation remains disabled by default unless the parent explicitly authorizes it.
The Claude-style core behavior prompt is stored at prompts/terminal_mcp_core_behavior.md and is inserted before global/project .GPT/AGENTS.md content for startup, bootstrap, and context reload. It contains no sub-agent policy or proprietary Claude prompt text. UI tasks are instructed to load the frontend-design and user-html-ui-preference skills.
The authenticated agent control room is available at /dashboard/agents. Its API at /dashboard/agents/api exposes the durable parent/child tree, synchronization state, reasoning configuration, wake timers, exact-marker completion gates, managed capacity, mailboxes, queued gateway operations, request history, circuits, errors, and next request eligibility. The page is mobile-first and linked from the existing /dashboard usage ledger.
Wake timers and completion-triggered prompts are local durable automations. When activated, they materialize one ordinary ordered command and use the same one-request gateway, rate limits, circuits, and staged verification as agent_send. See docs/AGENT_AUTOMATION_AND_CONTROL_TOWER.md for the exact completion contract, timing model, tools, and verification map.
Operational migration and rollback instructions are in docs/AGENT_GATEWAY_CUTOVER.md. Existing orchestration records are preserved in the domain database and mapped to gateway records on startup. Always back up the domain database before first deployment; the gateway database may start clean.
Security guidance
Run under a dedicated, unprivileged Linux user.
Limit
MCP_WORKSPACEand filesystem permissions to only the directories the agent needs.Set
MCP_BEARER_TOKENto a unique random value and rotate it if exposed.Keep OpenAI tool approvals set to
alwaysuntil the workflow is thoroughly reviewed.Use
allowed_toolsto expose the smallest possible tool set.Do not place
.env, browser profiles, logs, SSH keys, or MCP config files containing secrets in Git.Prefer a private network or OpenAI Secure MCP Tunnel over a public endpoint.
Review downstream MCP servers: they run with the same operating-system privileges as this process.
Bearer authentication protects the endpoint from anonymous requests, but it does not sandbox commands. The bearer token grants the holder the capabilities exposed by this server.
Development
Install development dependencies:
./store.sh --dev
# Or, when Linux prerequisites are already installed:
./setup.sh --devRun checks:
bash -n start.sh setup.sh store.sh install.sh
.venv/bin/python -m py_compile terminal_mcp.py scripts/smoke_test.py
.venv/bin/pytestThe regression suite verifies:
exact public tool discovery
project-context gating
skill discovery
persistent downstream MCP process reuse
reconnect after a child crash
explicit reset behavior
exclusive browser-profile ownership
filesystem and background-process lifecycle
bearer authentication
Dedicated ChatGPT runtime
For multi-day subagent workloads, run ChatGPT Desktop under its own supervised
user service rather than as a child of Terminal MCP. The runtime circuit, MCP
control tools, installation order, fault-injection tests, and rollback procedure
are documented in docs/chat-runtime-supervisor.md.
Troubleshooting
Fresh Linux machine or missing venv/pip
Run the full bootstrap installer:
./store.shIf sudo access is unavailable, use the user-space path:
./store.sh --skip-system-packagesThe installer downloads uv only when no usable Python 3.11+ interpreter is
available. Downloads use HTTPS, retry transient failures, and support optional
UV_INSTALLER_SHA256 and NGROK_SHA256 verification overrides.
Repair a broken environment
./setup.sh --recreate
./start.sh --check --local-onlyPort ... is already in use
Choose another port:
MCP_PORT=8010 ./start.shThe launcher intentionally does not stop the existing process.
401 unauthorized
Pass the same token configured as MCP_BEARER_TOKEN:
Authorization: Bearer your-tokenBrowser returns Stale aria-ref or resets to about:blank
Use the same
session_idfor all calls in the sequence.Check
local_mcp(action="list", session_id="..."); the server should showconnected.Reset a broken owner with
local_mcp(action="reset", server="stealth-browser", session_id="...").Ensure another session is not trying to use the same browser profile.
Confirm the downstream browser MCP itself uses a persistent context if cookies must survive process restarts.
ngrok starts but no public URL is printed
Check the ngrok log path printed by the launcher. Verify the ngrok account is authenticated and the requested reserved URL is available.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
Scoped agent execution. Server-side credentials, policy, budgets and verifiable receipts.
Hosted runtime for persistent agent teams, durable workflows, memory, schedules, and goals.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables an AI agent to run local tools on the user's own machine via stdio, including command execution, workspace file read/write, and system status checks.52MIT
- AlicenseNot gradedqualityDmaintenanceEnables users to run shell commands with compressed output, extract information from large files, drive local opencode and Codex agents, perform browser-automation tasks, and monitor runs via a live dashboard.MIT
- AlicenseAqualityBmaintenanceEnables an AI agent to take full control of a machine — running shell commands, editing files, managing git, packages and processes, and reaching the network — with batched execution, server-side variables and selectable tool profiles that keep token usage low. It also speaks HTTP so the same agent can operate a remote build box, NAS or VPS.262MIT
- AlicenseAqualityCmaintenanceEnables AI clients to perform sandboxed filesystem, directory, Ubuntu system, network, git, and code/text operations through 38 typed tools confined to a workspace. Ships with a browser-based web console that provides an interactive Linux terminal, a live tool playground, and real-time CPU, memory, and disk monitoring.382MIT