In modern software development, agentic workflows (like Claude Code and Cline) are redefining how we write, test, and debug code. To protect host systems from runaway bash execution or malicious packages, the gold standard is running these agents inside isolated ephemeral Docker containers.
However, containerization introduces a severe networking roadblock for the Model Context Protocol (MCP).
When you run Claude Code inside a locked-down container sandbox, it expects to communicate with local MCP servers (such as a long-term database like Segnog) to fetch memory graphs, classify facts, or query local APIs. But because the sandbox has zero network permissions, it cannot connect to host ports directly, nor can it launch host processes.
To bridge this boundary, we must establish a translation layer. This article details how to build a high-performance Standard I/O to Server-Sent Events (SSE) Proxy to seamlessly connect sandboxed CLI agents to host-level MCP servers.
๐๏ธ The Networking Challenge: Stdio vs. SSE
The Model Context Protocol supports two primary transport layers:
- Standard I/O (
stdio): The client spawns the server as a child process and communicates viastdin(standard input) andstdout(standard output). This is standard for local command-line tools. - Server-Sent Events (
SSE): The client connects to a server over HTTP, holding an open SSE stream (text/event-stream) to receive asynchronous notifications, and dispatches JSON-RPC payloads back to the server using standard HTTPPOSTrequests.
Inside an isolated Docker container:
- Claude Code can only launch child processes within the container itself.
- It cannot spawn processes on the host.
- Mounting host sockets or standard utilities directly into the sandbox exposes the host system, completely defeating the purpose of the security boundary.
Our solution is to write an elegant, lightweight Node.js Proxy that runs inside the container, posing as a local stdio MCP server to Claude Code while translating all commands into HTTP-based SSE calls to the host system.
๐ ๏ธ Implementing the Node.js stdio-to-SSE Proxy
The proxy's job is simple but requires meticulous stream handling:
- Initialize standard input/output channels: Read raw standard input JSON payloads dispatched by Claude Code.
- Open the SSE Endpoint: Trigger an HTTP request to the host-level SSE endpoint (
http://host.docker.internal:9000/mcp/sse) to retrieve the EventSource endpoint and the unique session ID. - Piping streams:
- When Claude Code writes a JSON-RPC message to the proxy's
stdin, the proxy dispatches a standard HTTPPOSTto the host's active session endpoint. - When the host-level SSE server pushes a notification over the
text/event-streamchannel, the proxy translates it into standardstdoutlines, writing directly to Claude's memory context.
Below is the production-grade, highly resilient Node.js implementation:
// index.js (Piped stdio-to-SSE MCP Proxy)
import EventSource from 'eventsource';
import fetch from 'node-fetch';
import readline from 'readline';
const HOST_MCP_URL = 'http://host.docker.internal:9000/mcp/sse';
let eventSource = null;
let uploadUrl = null;
// Initialize standard input line reader to catch Claude's commands
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
/**
* Initializes the Server-Sent Events (SSE) connection to the Host Server.
*/
function initSseConnection() {
eventSource = new EventSource(HOST_MCP_URL);
// 1. Listen for the initial endpoint registration
eventSource.addEventListener('endpoint', (event) => {
try {
const urlParam = new URL(event.data, HOST_MCP_URL);
uploadUrl = urlParam.toString();
// Start processing queued input once the channel is ready
process.stderr.write(`[Proxy] Channel established. Endpoint: ${uploadUrl}\n`);
} catch (err) {
process.stderr.write(`[Proxy] Error parsing endpoint registration: ${err.message}\n`);
}
});
// 2. Relay incoming messages from Host SSE to Claude's stdout
eventSource.onmessage = (event) => {
// Write directly to stdout so Claude Code parses it natively
process.stdout.write(event.data + '\n');
};
eventSource.onerror = (err) => {
process.stderr.write(`[Proxy] EventSource critical error: ${err.message || 'Connection lost.'}\n`);
};
}
/**
* Relay standard input JSON commands from Claude to Host HTTP POST.
*/
rl.on('line', async (line) => {
if (!line.trim()) return;
// If the upload route hasn't registered yet, wait momentarily
while (!uploadUrl) {
await new Promise(resolve => setTimeout(resolve, 50));
}
try {
// Send command to the active session URL on the host
const res = await fetch(uploadUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: line
});
if (res.status !== 202 && res.status !== 200) {
process.stderr.write(`[Proxy] Post command failed. HTTP Status: ${res.status}\n`);
}
} catch (err) {
process.stderr.write(`[Proxy] Error posting to host: ${err.message}\n`);
}
});
// Start the bridge connection immediately on launch
process.stderr.write('[Proxy] Initiating SSE connection to host...\n');
initSseConnection();
๐ฆ Integrating the Proxy into Claude Code's Client Config
With the proxy script compiled, you can map it directly inside the Claude Code configuration file inside the container sandbox.
Configure Claude's local .claude.json configuration file:
{
"mcpServers": {
"segnog-memory-bridge": {
"command": "node",
"args": ["/mnt/segnog/mcp_servers/index.js"]
}
}
}
When Claude Code starts up, it executes node /mnt/segnog/mcp_servers/index.js as a child process. From Claude's perspective, it is executing standard standard I/O calls to a local service.
Behind the scenes, the proxy translates every single graph insertion, embedding request, and fact search into HTTP SSE streams going out to your hostโs high-performance memory database.
๐ Summary of Benefits
Bridging isolated sandboxes to host-level APIs using this pattern provides massive operational benefits:
- Perfect Isolation: Claude Code remains confined to its dynamic Docker container, retaining zero access to your primary host network interfaces or standard terminal sessions.
- Unified Transport Layer: Solves standard I/O process execution constraints inside container environments.
- High Performance: Reuses persistent, HTTP connection channels. Commands are relayed with sub-millisecond latency.
- Resiliency: If the container sandboxes are rapidly destroyed and recreated, the SSE server manages session persistence, keeping state records alive across sandboxes.
By implementing this proxy architecture, you can safely deploy highly autonomous coding agents inside locked-down sandbox environments while preserving their ability to query complex long-term knowledge graphs.