Problem
The initial configuration using nc to bridge the MCP stdio transport to the CogServer's TCP port (18888) failed with invalid request errors.
This was caused by two issues:
- Buffering: Standard
nc or shell pipes can buffer input/output, breaking the strict line-based JSON-RPC expectation of the CogServer.
- Protocol Violation: The CogServer sends a non-compliant
{"jsonrpc":"2.0","result":{}} response to the initialized notification (which should not have a response). This caused strict MCP clients to reject the connection.
Temporary Solution
We created a custom Python adapter script to replace nc.
stdio_tcp_client.py
#!/usr/bin/env python3
import socket
import sys
import threading
import argparse
import time
BUFFER_SIZE = 65536
# LOG_FILE = "/tmp/mcp_debug.log"
# def log(msg):
# with open(LOG_FILE, "a") as f:
# timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
# f.write(f"[{timestamp}] {msg}\n")
def stdin_to_socket(sock):
"""Reads from stdin and writes to the socket."""
# log("Starting stdin_to_socket thread")
try:
while True:
# Read from stdin
try:
# Use read1 to get available bytes immediately
chunk = sys.stdin.buffer.read1(4096)
except AttributeError:
chunk = sys.stdin.buffer.read(4096)
if not chunk:
# log("Stdin EOF received")
break
# log(f"Stdin -> Socket ({len(chunk)} bytes): {chunk}")
try:
sock.sendall(chunk)
except Exception as e:
# log(f"Socket send error: {e}")
break
except Exception as e:
pass # log(f"Stdin loop error: {e}")
finally:
# log("Shutting down socket WR")
try:
sock.shutdown(socket.SHUT_WR)
except:
pass
def socket_to_stdout(sock):
"""Reads from the socket and writes to stdout, filtering bad protocol messages."""
# log("Starting socket_to_stdout thread")
buffer = b""
try:
while True:
data = sock.recv(BUFFER_SIZE)
if not data:
# log("Socket EOF received")
break
# log(f"Socket -> Buffer ({len(data)} bytes): {data}")
buffer += data
while b"\n" in buffer:
line_end = buffer.find(b"\n") + 1
line = buffer[:line_end]
buffer = buffer[line_end:]
# Check for the specific malformed response to 'notifications/initialized'
# CogServer sends: {"jsonrpc":"2.0","result":{}}
# This response has no 'id', which violates JSON-RPC 2.0 for a Response object,
# and it shouldn't exist because 'initialized' is a Notification.
if b'"result":{}' in line and b'"id"' not in line:
# log(f"DROPPING MALFORMED LINE: {line}")
continue
# log(f"Forwarding Line: {line}")
sys.stdout.buffer.write(line)
sys.stdout.buffer.flush()
except Exception as e:
sys.stderr.write(f"Socket loop error: {e}\n")
def main():
parser = argparse.ArgumentParser(description="Bridge Stdio to TCP for MCP")
parser.add_argument("host", help="Hostname", nargs="?", default="localhost")
parser.add_argument("port", help="Port", type=int, nargs="?", default=18888)
args = parser.parse_args()
# log(f"=== Starting Session connecting to {args.host}:{args.port} ===")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((args.host, args.port))
# log("Socket connected successfully")
except Exception as e:
# log(f"Failed to connect: {e}")
sys.stderr.write(f"Failed to connect: {e}\n")
sys.exit(1)
t = threading.Thread(target=socket_to_stdout, args=(sock,), daemon=True)
t.start()
stdin_to_socket(sock)
t.join(timeout=2.0)
# log("=== Session Ended ===")
if __name__ == "__main__":
main()
Key Features:
- Unbuffered I/O: Reads directly from
sys.stdin.buffer and flushes sys.stdout.buffer immediately after every message.
- Protocol Filtering: Intercepts and drops the malformed
{"jsonrpc":"2.0","result":{}} message from CogServer, preventing client errors.
- Robustness: Handles socket closures and thread synchronization cleanly.
Configuration
The mcp_config.json was updated to use this adapter:
{
"mcpServers": {
"atomese": {
"command": "path/to/cogserver/examples/mcp/stdio_tcp_client.py",
"args": [
"localhost",
"18888"
],
"env": {}
}
}
}
Verification
- Connectivity: Verified via manual
nc tests and the Python script.
- Functionality: Successfully executed
atomese/version and atomese/echo tools.
- Result:
- CogServer Version: 5.2.0
- Echo Test: Passed
While temporary solutions exist, modifying the server to satisfy more demanding clients might be a better option.
Problem
The initial configuration using
ncto bridge the MCPstdiotransport to the CogServer's TCP port (18888) failed withinvalid requesterrors.This was caused by two issues:
ncor shell pipes can buffer input/output, breaking the strict line-based JSON-RPC expectation of the CogServer.{"jsonrpc":"2.0","result":{}}response to theinitializednotification (which should not have a response). This caused strict MCP clients to reject the connection.Temporary Solution
We created a custom Python adapter script to replace
nc.stdio_tcp_client.py
Key Features:
sys.stdin.bufferand flushessys.stdout.bufferimmediately after every message.{"jsonrpc":"2.0","result":{}}message from CogServer, preventing client errors.Configuration
The
mcp_config.jsonwas updated to use this adapter:{ "mcpServers": { "atomese": { "command": "path/to/cogserver/examples/mcp/stdio_tcp_client.py", "args": [ "localhost", "18888" ], "env": {} } } }Verification
nctests and the Python script.atomese/versionandatomese/echotools.While temporary solutions exist, modifying the server to satisfy more demanding clients might be a better option.