11 KiB
created, id, keywords, links, modified, summary, tags, title
| created | id | keywords | links | modified | summary | tags | title | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-04-15T05:37:59+00:00 | 556bb313-29a5-4cd8-bd83-3213268262bf |
|
2026-04-15T05:37:59+00:00 | MCP interface contract defining the message types, data formats, and behavioral contracts between the SSH-TUI application and the Linus AI agent. |
|
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
- 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).
- Linus never executes commands directly — all commands must be explicitly sent by the user via the Send action.
- Intent is a living checklist — not freeform text. Uses step status markers (✓ done, ▸ current, ○ pending).
- Commands are editable before sending — the TUI must allow the user to modify any suggested command before execution.
- 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. - 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.
{
"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.
{
"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.
{
"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.
{
"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.
{
"chat_response": { ... },
"intent_update": { ... },
"suggested_commands": { ... },
"clear_suggestions": { ... }
}
chat_response — Reply in the Chat panel
{
"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:
{
"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
{
"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
{
"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)
{
"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:
- The TUI continues operating as a normal SSH client — no functionality is blocked.
- The Intent panel shows:
AI offline — chat messages will be queued. - The Suggested Commands panel shows its last state with a note:
(AI offline — commands may be stale). - Chat messages are queued locally and sent when connection is restored.
- 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
contextobject includes host and user but never credentials.
Future Considerations
- Multiple concurrent sessions — the
session_idfield is designed to support this. Not in scope for v1. - Command history — Linus could suggest commands based on the user's bash history. Requires
historyfile 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.