startLABSCO SUMMARY
It survives the VM going away, which is the whole problem with serial consoles.
A disconnect triggers an automatic restart with exponential backoff — starting at 1 second, capped at 60, tracked per VM and reset on a successful connection — so a rebooting guest does not turn into a reconnection storm. The ring buffer holds the last 1000 lines within a 10MB cap per VM, and a newly attached client is sent 60 lines of history, which is what makes joining midway through useful rather than confusing.
What it is
A Perl bridge between an MCP client and a virtual machine's serial console. It holds a pseudo-terminal open against the VM's console port and exposes two Unix sockets, one for input and one for output, so an agent and a human can both be attached at once.
What you get
startopens the bridge for a named VM on a port, and spawns a graphical terminal window attached to the same session so you can watch what the agent is doingwritesends a command to the console, andreadreturns whatever the console has producedstatusreports whether the bridge is running and how much is buffered;stoptears down the pseudo-terminal, child processes and sockets- Live output arrives as MCP resource notifications on a
vm://<vm_name>/outputURI once the client subscribes, so you are not obliged to poll - Terminal detection covers Ghostty, WezTerm, iTerm, Terminal.app, kitty, alacritty, foot, konsole, gnome-terminal, tilix, terminator, xfce4-terminal, xterm and urxvt, with an override if you want a specific one
- Binary output from the VM is converted to UTF-8 safely, with non-printable characters escaped rather than breaking the transport
Requirements
A Unix-like system — Linux, macOS or BSD; Windows is not supported except through WSL. Perl with the IO::Pty module. A VM whose serial console is bound to a TCP port, with the default starting at 4555, and a guest configured to run a getty on that serial line. No root permissions needed. The client launches it as perl serencp.pl; an experimental variant serves the same five tools over streamable HTTP on port 8080 instead.
Setup effort
Build from source — Install the non-core Perl module IO::Pty, e.g. cpan IO::Pty
USE CASES
Debugging a VM that has no network
Reach it over the serial console when SSH is not an option, and still have the agent read the output.
Watching what the agent is typing
The terminal window opens against the same session, so you see the console live rather than after the fact.
Following a boot sequence
Subscribe to the output resource and receive lines as they appear instead of polling for them.
Working across several VMs
Each gets its own port, its own sockets and its own buffer, addressed by name.
5 tools
Listed in project docs. Your client may show a different list.
statusreadwritestopBEFORE YOU INSTALL
What to know first
Tools you get
5 tools named in the project's documentation.
Requires
- A Unix-like system (Linux, macOS or BSD); Windows only through WSL
- The Perl module IO::Pty (for example cpan IO::Pty)
- A VM with its serial console on a TCP port (default from 4555), and the guest OS configured to use the serial console
- A supported terminal emulator, for the automatic console window
- /tmp writable by the user running the MCP server
Where it runs
The documented client runs the server on your machine.
INSTALLATION
Connect your client
Server setup
Install the non-core Perl module IO::Pty, e.g. cpan IO::Pty
Clone the repository (git clone https://github.com/abda11ah/serencp) to get serencp.pl, and note its absolute path (perl -c serencp.pl verifies it loads)
Configure the VM's serial console on a TCP port (default 4555) — e.g. the QEMU/KVM <serial type="tcp"> XML block — and enable a serial getty in the guest
Add the "mcp" block shown in the OpenCode tab below to opencode.jsonc, where <YOUR_PATH_TO_SERENCP> is the absolute path you noted
MCP Clients
OpenCode — local
{
"mcp": {
"serencp": {
"type": "local",
"command": [
"perl",
"<YOUR_PATH_TO_SERENCP>"
],
"enabled": true
}
}
}