pms-infra-agent-socket
June 7, 2026 · View on GitHub
⚠️ Caution
Do not grant unrestricted control to AI.
Unsupervised use or misuse may lead to unintended consequences.
All AI systems must remain strictly under human oversight and control.
Use responsibly, with full awareness and at your own risk.
📘 Overview
pms-infra-agent-socket is a Haskell infrastructure library that provides AI agents with direct, low-level control over socket-based communication endpoints.
Unlike higher-level abstractions, this library exposes raw byte-stream access over both TCP/IP and Unix Domain Sockets, allowing agents to handle protocol-specific exchanges such as Telnet IAC negotiation, binary protocol framing, and real-time I/O monitoring with fine-grained control.
The library is a core component of the pty-mcp-server ecosystem and implements the agent-socket-* family of MCP tools.
🔧 Provided MCP Tools
agent-socket-open
Opens a socket connection for subsequent read/write operations.
Supports both TCP (host + port) and Unix Domain Socket (file) connections via a single tool.
host— TCP host name or IP addressport— TCP service name or port numberfile— Unix domain socket path (absolute path required on Windows)
Only one socket connection can be active at a time.
agent-socket-close
Closes the active socket connection and releases all associated resources.
agent-socket-read
Reads up to the specified number of bytes from the active socket connection and returns the data as a UTF-8 string.
Returns an empty string if no data is available before timeout.
length— Maximum number of bytes to read
⚠️ If the received data contains non-UTF-8 bytes (e.g., binary protocols, IAC bytes), use
agent-socket-read-byteinstead.
agent-socket-read-byte
Reads up to the specified number of bytes from the active socket connection and returns the data as an uppercase hex string (e.g., FF0A1B41).
Use this for binary protocols or when precise byte-level inspection is required.
length— Maximum number of bytes to read
agent-socket-write
Writes the specified UTF-8 string to the active socket connection.
data— Text data to write
⚠️ Escape sequences such as
\r\nin the string are sent as literal characters. To send exact byte sequences (e.g., CR+LF =0D0A), useagent-socket-write-byte.
agent-socket-write-byte
Decodes the specified hex string and writes the resulting bytes to the active socket connection.
Use this for binary protocols or when precise byte-level control is required.
data— Uppercase hex string to decode and write (e.g.,DEADBEEF0D0A)
💡 Usage Notes
AI-to-AI communication
Any two AI agents that each have a pty-mcp-server instance can communicate with each other directly over TCP — no shared infrastructure, message broker, or custom integration required.
One agent uses the agent-server-* tools to act as a TCP server; the other uses the agent-socket-* tools (this library) to act as a TCP client. The agents exchange messages using a lightweight text protocol, and each agent interprets and responds to the other's messages autonomously.
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ AI Agent A │ │ AI Agent B │
│ (e.g. Claude on Machine A) │ │ (e.g. GPT on Machine B) │
│ │ │ │
│ pty-mcp-server │ TCP │ pty-mcp-server │
│ agent-server-listen :19999 │◄───────►│ agent-socket-open │
│ agent-server-write │ │ agent-socket-read │
│ agent-server-events │ │ agent-socket-write │
└─────────────────────────────┘ └─────────────────────────────┘
Server role Client role
What this enables
- Collaborative task solving — Agent A breaks down a problem and delegates subtasks to Agent B, collecting results over the socket.
- Cross-model review — One model generates code or text; another model on a different machine reviews it and sends back comments.
- Heterogeneous agent pipelines — Chain agents of different models or specialisations (Claude, GPT, Gemini, …) into a processing pipeline across machines.
- Autonomous negotiation — Agents can exchange proposals, counter-proposals, and decisions without human involvement in each round-trip.
- Distributed tool use — Agent B may have access to tools (databases, sensors, local files) that Agent A does not. Agent A requests operations from Agent B over the socket.
Communication protocol
The pty-mcp-server ecosystem ships a lightweight handshake and messaging protocol for AI-to-AI sessions. Prompt skills (skill_agent_server.md / skill_agent_client.md) are provided so each agent knows exactly how to play its role.
Handshake sequence:
Server → Client : HELLO? name?\r\n
Server ← Client : NAME: <name>\r\n
Server → Client : RULES: MSG:<content>\r\n | REPLY:<content>\r\n | BYE\r\n | HEX:<hex>\r\n
Server ← Client : ACK\r\n
Conversation:
Server → Client : MSG: <content>\r\n
Server ← Client : REPLY: <content>\r\n
Graceful shutdown (server-initiated):
Server → Client : BYE\r\n
Server ← Client : ACK\r\n ← server waits for this before closing
Server : agent-server-close
Full session example
The following shows a complete exchange where Agent A (server role) delegates a task to Agent B (client role).
Agent A — server side
agent-server-listen host=172.16.0.43 port=19999
→ "listening."
--- Agent B connects ---
agent-server-events
→ [{ "tag": "ClientConnected" }]
agent-server-write-byte "48454C4C4F3F206E616D653F0D0A" ("HELLO? name?\r\n")
agent-server-events (poll until BytesReceived)
→ bytes: "4E414D453A20416765742D420D0A" ("NAME: Agent-B\r\n")
agent-server-write-byte "<hex of RULES: MSG:... | REPLY:... | BYE\r\n>"
agent-server-events (poll for ACK)
→ bytes: "41434B0D0A" ("ACK\r\n")
--- handshake complete ---
agent-server-write-byte "<hex of MSG: Please summarise this text: ...\r\n>"
agent-server-events (poll for REPLY)
→ bytes: "<hex of REPLY: Here is the summary: ...\r\n>"
agent-server-write-byte "<hex of BYE\r\n>"
agent-server-events (poll for ACK)
→ bytes: "41434B0D0A" ("ACK\r\n")
agent-server-close
Agent B — client side
agent-socket-open host=172.16.0.43 port=19999
→ socket connected to 172.16.0.43:19999
agent-socket-read length=256
→ "HELLO? name?\r\n"
agent-socket-write-byte "<hex of NAME: Agent-B\r\n>"
agent-socket-read length=256
→ "RULES: MSG:<content>\r\n | REPLY:<content>\r\n | BYE\r\n | HEX:<hex>\r\n"
agent-socket-write-byte "<hex of ACK\r\n>"
--- handshake complete ---
agent-socket-read length=1024
→ "MSG: Please summarise this text: ...\r\n"
--- Agent B processes the request autonomously ---
agent-socket-write-byte "<hex of REPLY: Here is the summary: ...\r\n>"
agent-socket-read length=256
→ "BYE\r\n"
agent-socket-write-byte "<hex of ACK\r\n>"
agent-socket-close
💡 Always use
agent-socket-write-byte(notagent-socket-write) to ensure\r\nis sent as correct CRLF bytes.
Generate hex strings with:python3 -c "print('your message\r\n'.encode().hex())"
IAC / Telnet negotiation
Telnet IAC processing is the responsibility of the agent, not the library.
Use agent-socket-read-byte and agent-socket-write-byte to handle IAC sequences at the byte level.
Example negotiation flow:
← FFFD18FFFD20FFFD23FFFD27 (Server: IAC DO TERMINAL-TYPE/SPEED/X-DISPLAY/NEW-ENVIRON)
→ FFFC18FFFC20FFFC23FFFC27 (Agent: IAC WONT x4)
← FFFB03FFFD01FFFD1FFFFB05 (Server: IAC WILL SGA / DO ECHO / DO NAWS / WILL STATUS)
→ FFFD03FFFB01FFFC1FFFFD05 (Agent: IAC DO SGA / WILL ECHO / WONT NAWS / DO STATUS)
← "localhost login: " (Login prompt — read as UTF-8 string)
→ "phoityne\r\n" (Username — send as bytes: 70686F6974796E650D0A)
← "Password: " (Password prompt)
Full login session example (confirmed with a real Linux Telnet server):
agent-socket-open host=172.16.0.171 port=23
→ socket connected to 172.16.0.171:23
← FFFD18FFFD20FFFD23FFFD27
(IAC DO TERMINAL-TYPE / DO TERMINAL-SPEED / DO X-DISPLAY / DO NEW-ENVIRON)
→ FFFC18FFFC20FFFC23FFFC27
(IAC WONT x4)
← FFFB03FFFD01FFFD1FFFFB05FFFD21
(IAC WILL SGA / DO ECHO / DO NAWS / WILL STATUS / DO REMOTE-FLOW-CONTROL)
→ FFFD03FFFB01FFFC1FFFFD05FFFC21
(IAC DO SGA / WILL ECHO / WONT NAWS / DO STATUS / WONT REMOTE-FLOW-CONTROL)
← FFFE01FFFB01 + "Kernel 6.12.0-...\r\nlocalhost login: "
→ 61692D6167656E740D0A ("ai-agent\r\n" — username as bytes)
← "ai-agent\r\nPassword: "
→ 61692D6167656E740D0A ("ai-agent\r\n" — password as bytes)
← "Last login: ...\r\n[ai-agent@localhost ~]$ "
→ 686F73746E616D650D0A ("hostname\r\n")
← "hostname\r\nlocalhost.localdomain\r\n[ai-agent@localhost ~]$ "
→ 657869740D0A ("exit\r\n")
← "exit\r\nlogout\r\n"
agent-socket-close
→ socket is closed.
Unix Domain Socket on Windows
Unix Domain Socket (file parameter) is supported on Windows 10 build 1803 and later at the OS level.
However, the socket server side must be implemented in a runtime that supports AF_UNIX on Windows.
- Python 3.13.7 (Windows):
socket.AF_UNIXis unavailable unless Developer Mode is enabled. - PowerShell / .NET:
System.Net.Sockets.UnixDomainSocketEndPointworks without Developer Mode. - pty-mcp-server (Haskell): Confirmed working on Windows 11 via
Network.SocketwithAF_UNIX.
🏗️ Architecture
Module Structure
PMS.Infra.Agent.Socket
├── DM.Type -- Data type definitions (SocketData, AppData, tool parameter types)
├── DM.Constant -- Constants
├── DS.Core -- Core domain service logic
├── DS.Utility -- Utility functions (TCP connect, Unix Domain Socket connect)
└── App.Control -- Application control: tool dispatch and socket lifecycle management
Key Design Points
- Single active connection: Only one socket can be open at a time per server instance. State is managed via
STM.TMVar. - Dual connection mode:
agent-socket-opensupports both TCP (host/port) and Unix Domain Socket (file) via a single unified interface. - Non-blocking reads: Read operations return immediately with available data, allowing the agent to poll at its own pace.
- Byte-level I/F: In addition to UTF-8 string I/F, hex string I/F is provided for binary protocol handling. IAC processing and protocol framing are delegated to the agent.
📦 Dependencies
📜 Credits & License
- Execution & Process Lead: Claude Sonnet 4.6, Gemini 3 Flash, GPT-5.5
- Direction & Policy: phoityne
- License: Apache-2.0 — see LICENSE