MCP server

Brief

Terminal Delight is an MCP server. An agent running in one of its panes can ask about the rest of the window: which panes exist and what each is running, what they printed, what tool another agent is calling right now.

It starts locked down. Nothing is readable until you turn the server on, in the MCP control panel (Ctrl+Shift+A in a pane). Even then only agent panes are visible unless you choose all panes. Writing is a second switch, and a write only ever restyles a pane, leaves a note, declares a deliverable, opens a document or puts work on a workbench. No tool can type into a terminal.

To connect an agent, register the relay as a stdio MCP server:

claude mcp add --scope user terminal-delight -- terminal-delight mcp

The relay finds the window it is running in by itself. Every answer ends with the window it came from, because several Terminal Delight windows can run on one machine.

Technical lists all twelve tools with their arguments, the switches, and the errors.

Technical

The server

The server speaks newline-delimited JSON-RPC 2.0, advertises MCP protocol 2025-06-18, names itself terminal-delight, and offers tools and logging. It answers for the panes of one window.1

Connecting#

There are three ways in:

the relay
terminal-delight mcp, registered as a stdio server. It forwards each request to a running window over that window's control socket. It finds its own window by walking up its parent processes to the pane it was started in, so it needs no environment variable; --pid <N> picks a window explicitly. If the window is replaced mid-session, the relay reconnects to the same session once and says so on stderr. Each call waits up to ten seconds.
in-process
An MCP client that launches terminal-delight itself with TD_MCP set gets the server on the window's own stdio. This is the only way that receives pushed notifications.
one call from a script
terminal-delight ctl mcp rpc '<json>' hands one JSON-RPC line to a window.

The registration this machine uses, in ~/.claude.json:

"terminal-delight": { "type": "stdio", "command": "terminal-delight", "args": ["mcp"] }

A relay that located itself names its session and pane with every call. If that session isn't the window's, the call is refused with -32001, wrong window: this is terminal-delight session "1" (window 31337), and you asked for session "2". Nothing was read or written., so a relay pointed at the wrong window gets an error instead of someone else's panes.

The switches#

SwitchDefaultMeans
server enabledoffNothing is readable until this is on.
expose: agents only · all panesagents onlyWhich panes the server can see. An agent pane runs Claude Code or Codex.
stream tool-call eventsonWhether pane_events and the push feed work.
writes on · agents can restyleoffWhether any tool that changes something is allowed.

They live in the MCP control panel: Ctrl+Shift+A in a pane, or AGENTS · MCP in the footer's … menu. From a script: ctl mcp on|off, ctl mcp writes on|off, ctl mcp expose agents|all. Each change is saved with the session. TD_MCP starts the in-process transport but does not turn the server on, and TD_MCP_WRITE turns writes on only alongside TD_MCP.

Tools#

ToolNeedsArgumentsDoes
list_panesonnoneEvery visible pane: tab, title, mode, pid, pane_id, cwd, session (the resume command), the tool in flight, and its sticky note.
greponquery, scrollback (default 2000 lines)An exact, case-insensitive search across every visible pane's scrollback, up to 50 matches per pane.
pane_eventson, eventspid, limit (default 20, up to 200)An agent's recent tool calls, from its own transcript.
get_pane_configontargets: pids and/or "outer"Each pane's appearance, as percentages.
set_pane_configon, writesupdates: [{target, config}]Restyle panes or the window.
leave_noteon, writespid, title, text, pin, clearPut a sticky note on a pane's glass.
declare_deliverableon, writespid, label (48 characters), href, clearName the thing this pane produced, on its row in the attention rail.
present_surfaceon, writespid, surfacePut a work object on a pane's workbench. It is saved to disk first.
surface_cataloguenothingnoneWhat the running build can draw: the surface kinds, actions and weights.
open_documenton, writespath, placement: beside or hereOpen a Markdown, HTML or image file next to your pane, or over it.
document_notesonnoneThe notes a person left on the document open beside you.
engineering_stateonnoneEvery project's git state as the top bar sees it. A missing number means not measured, never zero.

Where a tool takes a pid, leaving it out means your own pane, which only works through the relay because only the relay says who is calling. Without it you get no `pid`, and this connection did not say who is calling — pass a pid from list_panes. A write to a pane the policy hides is refused.

Appearance#

get_pane_config and set_pane_config use 0 to 100 percent for brightness, contrast, colour, text, background, gamma, menu_bar, text_size, bench_size, warp, crawl_angle and crawl_depth, plus crawl as true or false, and logo as an image path for a pane. An update names only what changes; a misspelled channel is an error. The values are absolute, so "20 % lower" is yours to compute from a read. On a pane, only the channels you set become its own; outer changes every pane that follows the window.

Every answer says where it came from#

Each tool result, errors included, ends with a line like — terminal-delight · session 1 · window 31337 · td-81ec545-rows-where-drawn and carries the same in structuredContent.instance. To find your own pane in list_panes, match its pane <n> against $TD_PANE_ID; titles and directories are not unique.

Pushed notifications#

Over the in-process transport, after initialize and with events on, the server pushes notifications/message with data.event set to agent_appeared, agent_vanished or tool_call, about once a second. logging/setLevel to warning or above silences it. The relay carries no pushes.

Errors#

CodeWhen
-32000terminal-delight UI not ready: the window didn't answer within five seconds.
-32001The relay named a different session from this window's.
-32601An unknown method.
-32602A tool call with no name, or an unknown tool.

What would prove this wrong#

Any tool call that puts bytes into a pane's terminal breaks the server's first rule. So does any answer that describes another window's panes without saying which window it came from.

Sources

  1. The server, its tools and the policy: mcp.rs; the transports: mcp_transport.rs; the relay: ctl.rs.