--- created: '2026-04-15T05:37:59+00:00' id: 556bb313-29a5-4cd8-bd83-3213268262bf keywords: - MCP - SSH-TUI - interface contract - Linus - Model Context Protocol - TUI - Textual - AI copilot - ssh-tui - suggested commands - intent checklist - terminal context links: [] modified: '2026-04-15T05:37:59+00:00' summary: MCP interface contract defining the message types, data formats, and behavioral contracts between the SSH-TUI application and the Linus AI agent. tags: - aipa-plans - ssh-tui - mcp - interface-contract - linus - specification title: SSH-TUI MCP Interface Contract --- # SSH-TUI MCP Interface Contract **Status:** Draft — Pending review **Project:** AIPA SSH-TUI **Last updated:** 2025-07-10 **Author:** Linus (Systems Architect) ## Overview This document defines the MCP (Model Context Protocol) interface between the SSH-TUI application and the Linus AI agent. The SSH-TUI is a Textual-based terminal application that wraps SSH sessions and provides an AI copilot experience. The TUI acts as an MCP client; Linus is exposed via the MCP server. ## Design Principles 1. **TUI calls Linus, Linus responds with structured updates** — the TUI makes one call and receives everything it needs to render (chat response, intent, suggested commands). 2. **Linus never executes commands directly** — all commands must be explicitly sent by the user via the Send action. 3. **Intent is a living checklist** — not freeform text. Uses step status markers (✓ done, ▸ current, ○ pending). 4. **Commands are editable before sending** — the TUI must allow the user to modify any suggested command before execution. 5. **AI-sent commands are visually distinct** — in the SSH session panel, commands originating from suggested commands are dimmed or prefixed (e.g., `→`) so there is always a clear audit trail. 6. **Graceful degradation** — if the AI connection drops, SSH remains fully functional. Intent/Commands show "AI offline", Chat queues messages locally. ## Message Types ### TUI → Linus (via MCP) #### 1. `chat` — User typed a message in the Chat panel Sent when the user submits a message in the "Chat to Linus" panel. Includes the current terminal context so Linus has situational awareness. ```json { "type": "chat", "session_id": "uuid-string", "message": "hey linus, /var is full what's eating the space", "context": { "ssh_host": "root@10.250.50.70", "ssh_user": "root", "connected": true, "terminal_tail": "last ~100 lines of terminal output as string", "cwd": "/root", "last_command": "df -h", "last_exit_code": 0 } } ``` #### 2. `terminal_update` — New output in the SSH session Streamed to Linus on a debounced interval (~1 second) when new output appears in the SSH session while the session is active. Provides Linus with awareness of what's happening even when the user isn't chatting. ```json { "type": "terminal_update", "session_id": "uuid-string", "new_output": "only the new lines since last update", "terminal_tail": "last ~100 lines including new output", "context": { "ssh_host": "root@10.250.50.70", "ssh_user": "root", "cwd": "/root" } } ``` #### 3. `command_executed` — A command was sent through the SSH session Sent when any command is executed — whether it was a user-typed command, a sent suggested command (possibly user-edited), or a command Linus previously suggested. This gives Linus feedback on what happened. ```json { "type": "command_executed", "session_id": "uuid-string", "command": "du -ah /var | sort -rh | head -20", "source": "suggested", "suggestion_id": "cmd_001", "was_edited": false, "output": "4.2G /var/log/syslog\n2.1G /var/log/journal/...\n...", "exit_code": 0, "context": { "ssh_host": "root@10.250.50.70", "ssh_user": "root", "cwd": "/root" } } ``` `source` values: `"suggested"` (from suggested commands panel), `"user_typed"` (typed directly into SSH session). #### 4. `session_state` — Session lifecycle events Sent on connection, disconnection, and error events. ```json { "type": "session_state", "session_id": "uuid-string", "event": "connected", "context": { "ssh_host": "root@10.250.50.70", "ssh_user": "root" } } ``` `event` values: `"connected"`, `"disconnected"`, `"connection_error"`, `"authentication_failed"`. ### Linus → TUI (via MCP response) All responses use a unified envelope. A single MCP response can contain any combination of the following blocks. ```json { "chat_response": { ... }, "intent_update": { ... }, "suggested_commands": { ... }, "clear_suggestions": { ... } } ``` #### `chat_response` — Reply in the Chat panel ```json { "chat_response": { "message": "Looks like /var/log is the culprit at 4.2G. I've queued up some commands to identify the largest files.", "mentions": ["cmd_001", "cmd_003"] } } ``` `mentions` is optional — IDs of suggested commands that are particularly relevant to this response, which the TUI can highlight. #### `intent_update` — Living checklist in the Intent panel The intent is structured as a multi-step plan with status markers: ```json { "intent_update": { "summary": "Investigating /var disk usage", "confidence": 0.85, "steps": [ { "status": "done", "text": "Check overall disk usage with df -h" }, { "status": "done", "text": "Identify largest directories in /var" }, { "status": "current", "text": "List largest individual files in /var/log" }, { "status": "pending", "text": "Determine if logs can be rotated or cleaned" }, { "status": "pending", "text": "Free disk space safely" } ] } } ``` Status values: `"done"` (rendered as ✓), `"current"` (rendered as ▸), `"pending"` (rendered as ○). `confidence` is a float 0.0–1.0 indicating how certain Linus is about the approach. The TUI renders this as a visual indicator. #### `suggested_commands` — Commands in the Suggested Commands panel ```json { "suggested_commands": { "commands": [ { "id": "cmd_001", "command": "ls -lhS /var/log/*.log | head -10", "description": "List largest log files in /var/log", "risk": "low" }, { "id": "cmd_002", "command": "sudo journalctl --disk-usage", "description": "Check journald disk usage", "risk": "low" }, { "id": "cmd_003", "command": "sudo apt-get clean && sudo apt-get autoremove -y", "description": "Clean apt cache and remove unused packages (~500MB typical)", "risk": "medium" } ] } } ``` `risk` values: `"low"`, `"medium"`, `"high"`. The TUI renders risk indicators to help the user make informed decisions. The TUI MUST allow editing any command before sending. #### `clear_suggestions` — Remove stale commands ```json { "clear_suggestions": { "ids": ["cmd_001", "cmd_002"] } } ``` Optionally `"all": true` to clear all suggestions. ## MCP Tool Interface (Alternative Framing) If the MCP server exposes Linus as tools rather than a streaming message channel, the TUI would call: | Tool | Input | Output | |---|---|---| | `linus_chat` | `{ message, context }` | `{ chat_response, intent_update, suggested_commands }` | | `linus_terminal_update` | `{ new_output, terminal_tail, context }` | `{ intent_update, suggested_commands }` (optional — Linus may choose not to update) | | `linus_command_executed` | `{ command, output, source, exit_code, context }` | `{ chat_response, intent_update, suggested_commands, clear_suggestions }` | | `linus_session_state` | `{ event, context }` | `{ chat_response, intent_update }` | The response from `linus_chat` is always the full unified envelope — the TUI makes one call and gets everything it needs to render all panels. ## Terminal Context Format The `terminal_tail` field is a plain string of the last ~100 lines of terminal output. Format conventions: - Preserve ANSI escape codes if present (the TUI can strip them for context, but raw output is more useful for Linus to detect colors/formats) - Include the prompt line so Linus can see the current working directory and user - Trim trailing whitespace per line - Include a `--- snip ---` marker if lines were omitted from the middle (should be rare at 100 lines) ```json { "terminal_tail": "root@prod-web-03:~# df -h\nFilesystem Size Used Avail Use% Mounted on\n/dev/sda1 45G 42G 1.2G 98% /\nroot@prod-web-03:~# _" } ``` ## Debouncing and Throttling | Event | Debounce | Notes | |---|---|---| | `terminal_update` | 1 second | Only send if new output exists since last update. Buffer and send in batch. | | `command_executed` | Immediate | Send as soon as the command produces output (or after a 5s timeout for long-running commands, send what's available). | | `chat` | Immediate | User-initiated, no debounce. | | `session_state` | Immediate | Lifecycle events are infrequent. | ## Error Handling If Linus is unreachable or returns an error: 1. The TUI continues operating as a normal SSH client — no functionality is blocked. 2. The Intent panel shows: `AI offline — chat messages will be queued.` 3. The Suggested Commands panel shows its last state with a note: `(AI offline — commands may be stale)`. 4. Chat messages are queued locally and sent when connection is restored. 5. Terminal updates are discarded (not queued) — they're ephemeral context. ## Security Considerations - **No direct command execution** — Linus never sends commands to the SSH session. The TUI always presents commands to the user for explicit approval via the Send action. - **Risk labels** — every suggested command includes a risk level. The TUI should render high-risk commands with a warning. - **Command editing** — the TUI MUST allow the user to modify any suggested command before sending. The user is the final safety net. - **Audit trail** — commands sent from the suggested panel are visually distinct in the SSH session (dimmed or prefixed) so the user can always distinguish their own commands from AI-suggested ones. - **No credential exposure** — the TUI should never include SSH passwords, keys, or authentication material in MCP messages. The `context` object includes host and user but never credentials. ## Future Considerations - **Multiple concurrent sessions** — the `session_id` field is designed to support this. Not in scope for v1. - **Command history** — Linus could suggest commands based on the user's bash history. Requires `history` file access or session command log. - **File content inspection** — Linus may want to read specific files on the remote host. This would require a new tool (`linus_read_file`) that the TUI executes over SSH. Not in scope for v1. - **Notifications** — Linus could proactively notify the user of conditions detected in terminal output (e.g., "I see a kernel OOM in the dmesg output"). This would be a push mechanism. Not in scope for v1.