- New shell_escape() utility for safe command interpolation
- Applied across all MCP tools, docker, scanner, network commands
- MCP server generates random bearer token at startup
- Token written to mcp-token file with 0600 permissions
- All MCP HTTP requests require Authorization header
- Bridge binary reads token and sends on every request
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was only setting the remote clipboard without pasting. Now sends
clipboard content then simulates Ctrl+V (scancode 0x001D + 0x002F)
with 50ms delay for clipboard propagation. Works for any text
including special characters and multi-line content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The AI can now open its own SSH sessions without the Commander
pre-opening them:
- ssh_connect(hostname, username, password?, private_key_path?, port?)
Returns session_id for use with all other tools
Supports password auth and SSH key file auth
Also added app_handle and error_watcher to MCP server state so
new sessions get full scrollback, monitoring, and CWD tracking.
This completes the autonomy loop: the AI discovers what's available
(list_sessions), connects to what it needs (ssh_connect), operates
(terminal_execute, docker_ps, sftp_read), and disconnects when done.
Total MCP tools: 31.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3 new MCP tools completing the RDP interaction loop:
- rdp_click — click at x,y coordinates (left/right/middle button)
Use terminal_screenshot first to identify coordinates
- rdp_type — type text into RDP session via clipboard paste
- rdp_clipboard — set clipboard content on remote desktop
The AI can now screenshot an RDP session, analyze it visually,
click buttons, type text, and read clipboard content. Full GUI
automation through the MCP bridge.
Total MCP tools: 30.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8 new MCP tools exposed through the bridge:
Docker:
- docker_ps — list all containers with status/image/ports
- docker_action — start/stop/restart/remove/logs/builder-prune/system-prune
- docker_exec — execute command inside a running container
System:
- service_status — check systemd service status
- process_list — ps aux with optional name filter
Git (remote repos):
- git_status — branch, dirty files, ahead/behind
- git_pull — pull latest changes
- git_log — recent 20 commits
Total MCP tools: 27. All accessible through the wraith-mcp-bridge.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RDP performance overhaul:
- Switched from polling (rAF loop calling rdp_get_frame every tick)
to event-driven rendering (backend emits rdp:frame:{id} when
frame buffer updates, frontend fetches on demand)
- Eliminates thousands of empty IPC round-trips per second when
the screen is idle
- Backend passes AppHandle into run_active_session for event emission
- Frontend uses listen() instead of requestAnimationFrame polling
MCP terminal fix:
- terminal_type and terminal_execute now send \r (carriage return)
instead of \n (newline) — PTY terminals expect CR to submit
- Fixes commands not auto-sending, requiring manual Enter press
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
terminal_type MCP tool (19 tools total):
- Fire-and-forget text input to any session
- Optional press_enter flag (default: true)
- No marker wrapping, no output capture
- Use case: AI sends messages/commands without needing output back
Tab resize fix:
- Double requestAnimationFrame before fitAddon.fit() on tab switch
- Container has real dimensions after browser layout pass
- Also sends ssh_resize/pty_resize to backend with correct cols/rows
- Fixes 6-8 char wide terminals after switching tabs
Close confirmation:
- beforeunload event shows browser "Leave page?" dialog
- Only triggers if sessions are active
- Synchronous — cannot hang the close like onCloseRequested did
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DashMap::clone() deep-copies all entries into a new map. The MCP
server's cloned SshService/SftpService/RdpService/ScrollbackRegistry
were snapshots from startup that never saw new sessions.
Fix: wrap all DashMap fields in Arc<DashMap<...>> so clones share
the same underlying map. Sessions added after MCP startup are now
visible to MCP tools.
Affected: SshService, SftpService, RdpService, ScrollbackRegistry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On startup, Wraith checks if wraith-mcp-bridge exists in the data
directory. If missing or version mismatch, downloads the correct
version from Gitea packages automatically. No installer changes needed.
Flow:
1. Check data_dir/wraith-mcp-bridge.exe exists
2. Check data_dir/mcp-bridge-version matches app version
3. If not, download from packages/vstockwell/generic/wraith/{ver}/
4. Set execute permissions on Unix
5. Write version marker
Also exposes mcp_bridge_path command so the frontend can show the
path in settings for users to add to PATH or configure Claude Code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same root cause as the PTY crash (v1.2.6): tokio::spawn called from
Tauri setup hook without a tokio runtime guard. Switched error watcher
to std:🧵:spawn. Also wrapped both error watcher and MCP server
spawn in individual catch_unwind blocks so neither can crash the app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every tool in Wraith is now callable by the AI through MCP:
| MCP Tool | AI Use Case |
|-------------------|------------------------------------------|
| network_scan | "What devices are on this subnet?" |
| port_scan | "Which servers have SSH open?" |
| ping | "Is this host responding?" |
| traceroute | "Show me the route to this server" |
| dns_lookup | "What's the MX record for this domain?" |
| whois | "Who owns this IP?" |
| wake_on_lan | "Wake up the backup server" |
| bandwidth_test | "How fast is this server's internet?" |
| subnet_calc | "How many hosts in a /22?" |
| generate_ssh_key | "Generate an ed25519 key pair" |
| generate_password | "Generate a 32-char password" |
| terminal_read | "What's on screen right now?" |
| terminal_execute | "Run df -h on this server" |
| terminal_screenshot| "What's that RDP error?" |
| sftp_list/read/write| "Read the nginx config" |
| list_sessions | "What sessions are active?" |
11 new HTTP endpoints on the MCP server. 11 new tool definitions
in the bridge binary. The AI doesn't just chat — it scans, discovers,
analyzes, and connects.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resizable panel:
- Drag handle on left border of copilot panel
- Pointer events for smooth resize (320px–1200px range)
SFTP MCP tools:
- sftp_list: list remote directories
- sftp_read: read remote files
- sftp_write: write remote files
- Full HTTP endpoints + bridge tool definitions
Active session context:
- mcp_get_session_context command returns last 20 lines of scrollback
- Frontend can call on tab switch to keep AI informed
Error watcher:
- Background scanner runs every 2 seconds across all sessions
- 20+ error patterns (permission denied, OOM, segfault, disk full, etc.)
- Emits mcp:error events to frontend with session ID and matched line
- Sessions auto-registered with watcher on connect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-inject CLAUDE_MCP_SERVERS env var when copilot PTY spawns,
so Claude Code auto-discovers wraith-mcp-bridge without manual config
- RDP screenshot_png_base64() encodes frame buffer as PNG via png crate
- Bridge binary exposes terminal_screenshot tool returning MCP image
content (base64 PNG with mimeType) for multimodal AI analysis
- MCP session list now includes RDP sessions with dimensions
- /mcp/screenshot HTTP endpoint on the internal server
"Screenshot that RDP session, what's the error?" now works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Complete MCP communication pipeline:
Backend HTTP server (axum on localhost:0):
- POST /mcp/sessions — list active sessions
- POST /mcp/terminal/read — read scrollback (ANSI stripped)
- POST /mcp/terminal/execute — send command + marker, capture output
- Port written to data_dir/mcp-port at startup
- Shares SshService and ScrollbackRegistry with AppState via Clone
Bridge binary (wraith-mcp-bridge):
- Speaks JSON-RPC 2.0 over stdio (MCP protocol)
- Translates tool calls to HTTP requests against running Wraith
- Implements initialize, tools/list, tools/call
- Exposes: terminal_read, terminal_execute, list_sessions
- Reads MCP port from data_dir/mcp-port
Auto-config:
- PTY spawn injects WRAITH_MCP_BRIDGE env var
- SshService and ScrollbackRegistry derive Clone for sharing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Infrastructure for the Wraith Terminal MCP server:
- ScrollbackBuffer: 64KB circular buffer per session with ANSI stripping
- ScrollbackRegistry: DashMap registry shared between output loops and MCP
- SSH output loop feeds scrollback in addition to emitting events
- PTY output loop feeds scrollback in addition to emitting events
- mcp_terminal_read: read last N lines from any session (ANSI stripped)
- mcp_terminal_execute: send command + marker, capture output until marker
- mcp_list_sessions: enumerate all active SSH sessions with metadata
8 new scrollback tests (ring buffer, ANSI strip, line limiting).
95 total tests, zero warnings.
Bridge binary and auto-config injection to follow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>