Name the layer first, then retry on purpose.
Keep the original result and decide whether the problem is the connection, a tool call, one terminal, the command's own outcome or the way you observed it. Each layer has its own success signal: a delivered input is not a finished command, and a returned result is not a zero exit code.
Before you repeat anything, ask whether the first attempt could already have taken effect. A timeout, a lost response or a missing event does not show that nothing happened. Use a harmless read or a list where you can, and keep retries of work that changes things deliberate.
| Layer | What failed | Section |
|---|---|---|
| Connection | Tools are missing, or the terminal set looks different | Connection |
| Tool call | A create or change was rejected | Tool call |
| Terminal | A terminal is missing, detached or exited, or does not close | Terminal |
| Command | It timed out or has no exit value | Command |
| Observation | Output is cut, empty or missing, a watch is silent, or browser access fails | Observation |
Tools are missing or the terminals look different.
| Symptom | Likely cause | What to do |
|---|---|---|
| The eight tools are not listed | The service is not the one you meant, or the client did not initialize it | Confirm the selected service and environment, then initialize the intended connection and list the tools again |
| A terminal you opened earlier is not listed | A new connection can be given a different identity, and a terminal id from another identity is not necessarily visible to you | Reconnect the same way as before. Do not switch the service to shared mode as a fix: that changes who can operate every terminal and belongs to the service owner |
| The command-line tool shows a different set than your client | It connects to the socket named by MCP_SERVER_URL, and runs in a short-lived local instance when it cannot connect | Read its --json output, or use the client you originally initialized |
A create or change was rejected.
| Reported problem | Useful next action |
|---|---|
| Invalid or too large a size | Use positive sizes within 500 columns and 200 rows |
| The name already exists | Look at the terminal you meant; use a different name only for genuinely new work |
| The terminal limit is reached | Review the terminals you own and close only those no longer needed; ask the service owner about capacity if the work needs more |
| Invalid tags | Use non-empty tags, at most 20, each at most 50 bytes |
| A send, watch or stats target is missing | Give the terminal id or the group you meant |
| A region read needs a rectangle | Give all four of x, y, w and h through the tool; the command-line tool cannot pass that object |
| A throttled call | Read the retry interval in the error and poll less often. If the call changed something and its outcome is unclear, look at the state before you retry |
A failed creation can leave a listed terminal behind, and a change of several fields can be partly applied before a later one fails. Look at the current state before you repeat the whole request. Coordinate concurrent creation with the service owner. A change can add tags but cannot remove one that is stored.
A terminal is missing, detached, exited or will not close.
The terminal is missing, detached or exited. Use the id you saved to see what state is left. If the process exited, persistence does not restart it: decide whether a new terminal is right for the application's state. Giving terminal_open a new command for a terminal you already own changes that terminal and does not restart the program.
A terminal can disappear or detach after its connection ends, an idle threshold passes, retention expires, the service stops, or reload recovery fails. Use the intended maintained connection and the exact saved terminal identifier. For a deliberate handoff, request attachment only to the persistent terminal agreed with its owner. After a reload, history and browser links need to be established again. If attachment fails, report the sanitized identifier and exact error before recreating valuable work; ask the service owner to reconcile any remaining workload.
Close reports success but a process seems to remain. The exit code of a close is synthetic and does not independently confirm that the workload stopped. A missing record or a returned count does not prove that every child process stopped. Keep the exact target and result, use the workload's own shutdown signal, and involve the service owner if it stays active. Close the one terminal you mean and not all: in shared mode others can have work there. A group close returns the terminals it ended and can leave out those that failed, which stay listed, so look at what remains before you widen the request.
It timed out, or no exit value came back.
terminal_run waits up to its timeout, 120 seconds by default, and can return what it has with timedOut: true. The command can still be running, especially in a named terminal. Read the screen and the terminal's state before you decide, and do not repeat work that changes things. For a longer job, choose a larger timeout in advance, or run it in the background and watch it; a background run is followed for 24 hours at most. Neither option kills a command on timeout.
A command that replaces the shell, changes its prompt integration or involves another controller can interfere with the exit-code framing; if it repeats with a harmless first command, ask the service owner to look at the failure.
| Symptom | What it means |
|---|---|
An exit code of -1 in the history | No exit code was collected. It is not a measured result |
| The output is cut | The inline output is a head and a tail; see Observation to read the rest |
| The wait ended but the prompt never appeared | A send waits ten seconds at most and cannot tell a prompt from a quiet screen. The input may already have taken effect. Read the screen and check that the pattern matches what the program really prints before you send it again |
Output is cut, empty or missing, or an event never arrives.
Inline output is cut or a capture cannot be found. The inline preview shows a head and a tail, 2 KiB each by default. For a foreground run in a throwaway terminal, read the whole capture with terminal_read in run_output mode and the returned runId, from the same connection and while the store still holds it. A named terminal's run, and a background run, have no stored capture: read the terminal's screen or scrollback instead, which is approximate history and not an exact archive. One supported execution mode keeps at most 8 MiB of a run before previewing; installed modes can differ, and a larger maxOutputBytes only widens the preview: it cannot bring back bytes that were never kept. The store holds at most 500 entries and 64 MiB and is lost on a restart; an eviction error means the output was removed, and a not-found error can mean the id, the owner, the kind of run or the retention differs from what you assumed. Do not rerun a build or a deployment only to get its output back; use the workload's own reports.
An incremental read is empty or seems to skip lines. Incremental reads use one cursor shared by every reader of the terminal and return only finished lines. Another reader can have moved it, an unfinished prompt is held back, and filtering and cutting happen after the lines are consumed, so an empty answer does not show a blank screen or a finished command. Use screen for what is visible now and scrollback with a range for earlier lines. tail is the bottom of the viewport and does not search older history. For an explicit result when nothing is there, ask for text. A bad regular expression is an error after the output was already fetched, so an incremental cursor may already have moved. Region and frame reads ignore the filter, so never use it to hide confidential text.
A watch is acknowledged but no events arrive. Setting up the watch, producing output, delivery, forwarding and the client consuming it are separate steps, and small output can stay below the sampling thresholds. Idle means periodic statistics here, and the complete, pattern and exit labels do not give separate detection. Use explicit screen or stats reads, or start a frame watch and pull mode: frames with the cursor you hold. A watch acknowledgement does not prove that notifications/terminal/event reaches your client, and subscribing again does not fix a forwarding limit: use explicit reads while the service owner checks delivery. End a watch with off: true; a later watch without resource does not stop a resource watcher that is already running.
Resource values look stale or too small. Quick repeated resource reads can return the same measurement, and a process seen for the first time has no earlier CPU interval. CPU is a share of the whole machine, so one busy core is only part of 100%. A thread count of zero can mean a platform that does not report it. Detailed process lists include command lines that can show credentials or private paths, so start with the totals.
Browser access fails, or an old tab stays open after you disabled the link.
| Observation | Next check |
|---|---|
No attachUrl | The bridge configuration, and whether this terminal was opted in with web: true |
| The page says not found | The latest address you were given privately: a stale link and a missing terminal look the same |
| The page loads but shows no live screen | The connection status and the per-terminal connection limit; the page can load while the live connection is refused |
| The address works on one machine only | Ask the service owner to check the bind address, the advertised address and the route |
| An old tab is still open after you disabled the link | Disable the link with web: false. To end browser access at once, close the terminal with terminal_close. |
| A tab is cut off while someone is typing | Plan for idle cleanup even while someone is typing; keep the terminal active from your side |
Route and configuration problems go to the service owner: do not widen a listener yourself. The settings are on Settings, and the steps for a controlled handoff are in Let a person watch or type.