Skip to main content
Glama
KevinBuettner

docent-terminal-mcp

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
DOCENT_TERMINAL_MCP_HOMENoState directory. Default `~/.local/state/docent-terminal-mcp`.
DOCENT_TERMINAL_MCP_SOCKETNotmux socket name, default `docent-terminal-mcp`.
DOCENT_TERMINAL_MCP_SSH_ENVNoA list of variable names (set in the session via session_create's env) to also set on the far side of `docent-terminal-mcp ssh` and `docent-terminal-mcp into`.
DOCENT_TERMINAL_MCP_SUMMARYNoSet to 0 to turn off reply summaries, for an A/B.
DOCENT_TERMINAL_MCP_SOCKET_PATHNoThe shared server's Unix socket path, default `$XDG_RUNTIME_DIR/docent-terminal-mcp/server.sock`.
DOCENT_TERMINAL_MCP_ATTACH_PREFIXNoWords put before the attach command in replies and `/api/sessions`, for a server that runs where a person cannot run tmux directly: `openshell sandbox exec -n NAME --tty --`, `podman exec -it NAME`, `ssh -t HOST`.
DOCENT_TERMINAL_MCP_KEEP_CLOSED_DAYSNoDays to keep a closed session's logs; default 3, 0 keeps everything. Also set with `docent-terminal-mcp serve --keep-closed-days`.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
guideA

Usage guidance, worth one call before the first real use. Topics: patterns (one-shot shell habits -- pipes, redirects, -batch, sleep-and- poll, nohup -- and their interactive form, plus the gotchas), programs (gdb, python, REPLs, prompts, questions), fullscreen (vim, less, send order, screen view), output (timeouts, large output, views, the log files), sharing (working alongside a human or another agent).

session_createA

Start a terminal session: a tmux pane a human can watch or type into, whose output is logged in full and kept as numbered regions. Use one instead of a one-shot shell call for anything that runs a program with a prompt (gdb, python, ssh, any REPL), takes more than a few seconds (a build, a testsuite), prints more than a reply holds, may ask a question (y/n), or that the user may want to watch or take over; a one-shot call stays right for reading and editing files and for quick commands whose whole output you want. Open one at the start of a task and do the task's shell work in it with the run tool: sessions are cheap, keep running between calls and across your own restarts (session_list finds them), and keep their cwd, environment and running programs -- cd once, start gdb once.

With no command (or "bash"), the session is bash with shell integration: exact command boundaries and exit statuses, and programs are started from it with the run tool (make, gdb, python, ssh, ...). command runs another program as the session itself instead, e.g. "gdb -q -ex 'break main' -ex run ./prog" or "ssh host"; when it exits the session is over. One session per job is the usual shape: a shell for the build and the tests, a second one for gdb while the first is busy.

Tell the user the session's name and attach command (in the reply) on a line of its own, so they can watch or step in. First time here: load the terminal-sessions skill if one is listed, else guide.

By default the pane follows the window of a human who attaches, so cols/rows apply only until then; fixed_size keeps them (the human then sees the pane clipped or padded). session_resize changes either later.

session_splitA

Split a session's window: a new pane beside it, shown together to a human attached to that window, and a session of its own -- logged from its first byte, with shell integration (exact exit statuses) by default. Use it instead of typing tmux split-window, whose pane has neither until the server adopts it. For two things to watch at once: a testsuite running in one pane, gdb in the other. Both panes are addressed by session name; typing never follows the active pane.

session_listA

List terminal sessions: state, what is running, size, who started each (you, a human, another agent), humans attached, the attach command, and presence: how old each session is, its last output, which agents typed into it and when, a human terminal's last input, a typing call in progress -- to judge whether a session you find is in use. Sessions started by earlier servers or by others are used by name like your own; a closed session's logs stay on disk for a few days (the listing says until when; session_logs keeps them). Worth a call at the start of a conversation: a session from an earlier one may still be running, its log intact.

session_resizeB

Set the pane size and pin it (fixed, the default: attaching humans no longer resize it), or with fixed=false let it follow the attached human's window again.

session_closeA

Kill a session and whatever runs in it. Its logs and region files are kept on disk for a few days (session_logs keeps them for good, or deletes them). Refused for a session a person is attached to, and for another's while a command runs there: leave those to their owners, or ask the user to close it. Close what you are done with; a session another agent or a human started is theirs to close. A session that shares a window with others (a split) closes its own pane only; window closes them all.

session_logsA

Keep or delete a session's logs (its log directory: the full output, regions, raw bytes). The usual rule: a closed session's logs are deleted once they have been neither written nor read for a few days (DOCENT_TERMINAL_MCP_KEEP_CLOSED_DAYS, default 3). Reading a closed session's logs needs none of this -- and counts as use: the read, search and regions tools work on them as they are. Change how a session's logs are kept only when the user asks: "keep" exempts a session they want to refer back to; "delete_on_close" and "delete" are for logs that showed something sensitive. Deleting cannot be undone: ask the user first, and never delete another agent's or a human's logs unasked.

runA

Type a line into the session, press Enter, and wait for the result: the session's form of a shell tool call, and of a line typed at gdb's or python's prompt.

At a bash prompt (shell integration) it waits for the command to exit and returns its output with the exit status (pipestatus for a pipeline; no ; echo $? needed); for a build or a testsuite give timeout_s the whole run (up to 1500 s) and get the exit status in one reply. Inside a program (gdb, python, psql, ...) it waits for the program's next prompt; starting one from bash returns at its first prompt, or its first screen (vim, less; continue with send). The session persists: cwd, variables and a running program stay between calls.

Output longer than max_lines keeps its first and last lines with a marker naming what was left out; nothing is lost: read pages it, search finds lines in it. So no | tail, | head, 2>&1 > log -- and never a pipe or redirect on an interactive program (gdb without -batch, python): it then waits at a prompt you cannot see. To watch for particular lines as they come, show=REGEX replies with the matching lines and the last few while the command runs unfiltered, exit status its own.

At timeout_s -- a short one gives your turn back soon -- the command keeps running and its region stays open: wait keeps waiting, send keys=["ctrl+c"] interrupts, send signal="TERM" if it survives. until=REGEX returns as soon as the output matches.

Several lines go one at a time, each once the previous is back at the prompt; a line that asks a question or times out stops the rest. Into Python or IPython they go as one paste (an exception drops the lines after it). Predictable questions: expect. Keystrokes (ctrl+c, tab, arrows) are send's keys, not an argument here.

prompt_pattern is rarely needed: never pass one to start a program (shell, gdb, pdb, lldb, python and any prompt ending in $ # % > are known); only after a reply came back "waiting" at a prompt it did not know, which then offers the pattern.

shell_integrateA

Add shell integration to the bash now waiting at the prompt: exact command boundaries and exit statuses for run there.

Sessions started without a command have it already, and so does any bash started inside them. A shell that could not inherit it -- one reached through ssh or su - -- falls back to prompt matching, with no exit statuses; call this at its prompt, typically right after run ssh host came back at the remote prompt. Types one short line that reads the integration file: this server's own on this host; on another host the copy the user installed there with docent-terminal-mcp install HOST (without it the reply says so; docent-terminal-mcp ssh HOST needs none). For bash and zsh, and only at a prompt.

expectA

Script predictable interactions in one call: optionally type input (+ Enter), then answer each prompt that matches a respond rule, in whatever order the prompts appear. The interactive form of yes |, echo y |, gdb's -batch and an expect script: the program gets a real terminal, and only the questions you foresaw are answered. Rules that never match are fine -- use them for questions only sometimes asked.

Ends when the command finishes (bash), the program is back at its prompt (prompt_pattern, default as for run), until (a regex) matches, a stop rule matches, or -- the important case -- output stops at a question no rule answers: that returns at once as "unanswered" instead of waiting for the timeout, so a surprise comes back to you rather than being guessed at.

Example, gdb's optional questions: input="gdb -q -ex 'break lib_fn' -ex run ./prog", respond=[{"pattern": "Make breakpoint pending", "line": "y"}, {"pattern": "Enable debuginfod", "line": "n"}] Example, ssh, handing any password prompt to the human: input="ssh host", respond=[{"pattern": "continue connecting", "line": "yes"}, {"pattern": "[Pp]assword:", "stop": true}] Without input, the rules apply to a question already waiting at the cursor (one a run came back "waiting" at).

Returns a transcript (what matched, what was sent), rules that never fired, and the resulting region(s) as run does.

sendA

Send keystrokes without waiting for a command's result (that is run). ORDER: all of text is typed first (literally; a newline in it is Enter), THEN the keys are pressed in list order. To press a key before typing (escape, then an ex command), make two calls.

For: interrupting (ctrl+c; ctrl+d ends input, or gdb/python at their prompt; q leaves a pager), answering a one-character prompt, tab completion, history and arrows in a REPL, and driving full-screen programs (vim, less, top). Command lines go through run, which waits for their result; send only waits until output pauses for settle_ms (at most wait_ms) and returns what appeared -- or, while a full-screen program runs, the rendered screen with the cursor position: screen= "full" (every row), "changes" (only rows changed since the screen last returned: cheapest for editing), or "cursor" (the rows around the cursor). With nothing to send, it just reads what is new.

Keys are names such as ctrl+c, ctrl+d, enter, tab, escape, backspace, up, down, left, right, home, end, pageup, pagedown, f1-f12, alt+x, or any single character. Shell commands that finish during the call are reported with their exit status. Refuses, like run, to type over a human's unsubmitted line unless force. When nothing new appears, or a program is still in the foreground after ctrl+c, the reply names what is running there.

signal ("TERM", "KILL", "INT", "HUP", "QUIT"), instead of text and keys, sends that signal to the terminal's foreground job -- never the session's own shell or program: for a job that ignores ctrl+c and ctrl+d. TERM first; KILL if it survives. Prefer it to pkill from outside, which can hit the session's own shell.

waitA

Keep waiting for what is running in the session -- what your last call left running (a run that timed out, settled, or returned at until), or else a command a human or another agent started -- and return its region: only the lines not shown before. The interactive form of sleep 30; tail log: call it as often as needed, with timeout_s up to the client's patience; each reply is new output only, and the command's exit status when it ends. Commands of others that finished since your last call are reported at once (regions lists the session without waiting). When a human's (or another agent's) unsubmitted text holds the prompt, waits for it to be erased or submitted, and says which. After a run into a program (gdb, python), waits for the program's prompt; after a shell command, for it to finish. show filters the lines as for run; until returns at a pattern, last_lines and save_to work as for run.

readA

Read session output: the log or one region, by line number -- what tail -n, sed -n or head would do on a log file you had redirected to, except that nothing had to be redirected. A reply's "[... N lines omitted (lines A-B) ...]" marker gives the range to read.

view="cooked" (default): the whole-session log as plain text with line numbers, real line breaks only. With region, reads that region; start is a line number (1-based, as shown) to page from. Without start, shows the last limit lines. view="screen": what the terminal shows right now, row by row as tmux renders it (a long line wraps onto several rows), with the size and cursor position. start/limit select screen rows. The view to use for full-screen programs. Note that such programs clip long lines at the window edge; check file contents another way. view="raw": the bytes the program wrote, escape codes included, with control characters spelled out (\e, \r, \xNN). For debugging odd rendering. start is a byte offset; max_bytes bounds the result. With region, reads that region's bytes (bounds may include a little output from either side).

searchA

Search session output (regex by default) without reading it all: what grep would do on a log file you had redirected to. Use it for a build's errors, a testsuite's FAIL lines, a value in a long trace -- after the command, or while it still runs.

Reports the total number of matching lines (so you know whether you saw them all), then up to max_results of them (after skipping skip), each with context lines around it, its line number (the number read start= takes) and the region it belongs to. Restrict to one region with region.

regionsA

List the most recent regions: each command or program input with its status (running, done, waiting at a question, ...), exit status, line range and file. The session's history at a glance: to find a region id for read/search, to check on a command left running without waiting for it, or to see what a human or another agent ran.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.1/5.0

Scored across 15 tools

Disambiguation4/5

Each tool has a distinct role: session lifecycle tools (session_create, session_split, session_list, session_resize, session_close, session_logs) are clearly separated, and interactive tools (run, send, wait, expect) are differentiated by whether they wait for completion, type keystrokes, or script prompts. Minor conceptual overlap between run/send/wait exists, but the detailed descriptions resolve it.

Naming Consistency4/5

All tools use lower_snake_case, and session management tools share a consistent session_ prefix (session_create, session_split, session_list, etc.). However, non-session tools are a mix of plain verbs (run, send, wait, read, search, expect) and noun_verb (shell_integrate), and 'regions' is a bare noun, so the pattern is not uniformly verb_noun.

Tool Count5/5

15 tools map cleanly to the domain's needs: 6 session lifecycle operations, 5 interaction tools, 3 output inspection tools, plus a guide. Each tool earns its place and no tool appears redundant or trivial for terminal session management.

Completeness5/5

The surface covers the full terminal session lifecycle: creating, splitting, listing, resizing, closing, and retaining logs, plus rich interaction (run, send, expect, wait, shell_integrate) and output analysis (read, search, regions). No obvious gaps for the stated purpose of managing and interacting with terminal sessions.

Maintenance

ActivityMaintained
ResponsivenessNo issues