A Rust-based Model Context Protocol server that gives AI agents the ability to open TCP and TLS connections, send/receive data across multiple interactions, and manage session lifecycle.
- Multi-turn sessions - Open a connection once, interact multiple times
- TCP and TLS support - Plain TCP or encrypted TLS with certificate validation
- Session management - Automatic TTL-based cleanup, max session limits
- Binary data support - Send/receive binary via hex encoding (
hex:DEADBEEF) - Human-readable session IDs - Easy to track sessions like
tcp_example_80_0 - Flexible response formats - Choose between concise (default) or detailed output
- Rust 1.85+ (2024 edition)
- Cargo
cargo install socket-tools-mcpThe binary will be installed to ~/.cargo/bin/socket-tools-mcp.
Add to your MCP client configuration:
Add to ~/.claude/settings.json (user scope) or .mcp.json (project scope):
{
"mcpServers": {
"socket-tools": {
"command": "~/.cargo/bin/socket-tools-mcp"
}
}
}With environment variables:
{
"mcpServers": {
"socket-tools": {
"command": "~/.cargo/bin/socket-tools-mcp",
"env": {
"RUST_LOG": "debug"
}
}
}
}Add to ~/.config/opencode/opencode.json (global) or opencode.json in your project:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"socket-tools": {
"type": "local",
"command": ["~/.cargo/bin/socket-tools-mcp"]
}
}
}With environment variables:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"socket-tools": {
"type": "local",
"command": ["~/.cargo/bin/socket-tools-mcp"],
"environment": {
"RUST_LOG": "debug"
}
}
}
}Note: OpenCode requires
"type": "local"and uses"command"as an array. Claude Code uses"mcpServers"with"command"as a string.
Use initial_data for simple request/response:
socket_open(
host="example.com",
port=80,
initial_data="GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
)
-> {session_id: "tcp_example_80_0", response: "HTTP/1.1 200 OK...", bytes_received: 1256}
socket_open(host="api.github.com", port=443, tls=true)
-> {session_id: "tls_api_443_0", tls_version: "TLSv1_3"}
For protocols requiring multiple exchanges:
1. socket_open(host="redis.local", port=6379)
-> {session_id: "tcp_redis_6379_0"}
2. socket_write(session_id="tcp_redis_6379_0", data="PING\r\n")
-> {bytes_sent: 6}
3. socket_read(session_id="tcp_redis_6379_0")
-> {data: "+PONG\r\n", bytes_received: 7}
4. socket_close(session_id="tcp_redis_6379_0")
socket_write(session_id="...", data="hex:2a310d0a24340d0a50494e470d0a")
socket_read(session_id="...")
Open a TCP or TLS connection. Returns a human-readable session_id for subsequent operations.
| Parameter | Type | Required | Description |
|---|---|---|---|
host |
string | yes | Hostname or IP (e.g., example.com, 192.168.1.1) |
port |
integer | yes | Port number (80=HTTP, 443=HTTPS, 6379=Redis) |
tls |
boolean | no | Use TLS encryption. Required for HTTPS (port 443) |
insecure |
boolean | no | Skip cert verification (dev only, self-signed certs) |
timeout |
integer | no | Connection timeout in ms (default: 10000) |
sni |
string | no | Override TLS server name (SNI). Use when connecting to IP addresses or load balancers |
alpn |
array | no | ALPN protocols to negotiate (e.g., ["h2", "http/1.1"] for HTTP/2) |
client_cert |
string | no | Path to PEM file with client certificate chain (for mTLS) |
client_key |
string | no | Path to PEM file with client private key (for mTLS) |
initial_data |
string | no | Data to send immediately and get response in one call |
response_format |
string | no | concise (default) or detailed (includes hex) |
When to use:
- Starting any network interaction (HTTP, databases, custom protocols)
- Use
initial_datato combine connect + send + receive in one call
Example (concise response):
// Request
{"host": "example.com", "port": 80, "initial_data": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"}
// Response
{"session_id": "tcp_example_80_0", "response": "HTTP/1.1 200 OK\r\n...", "bytes_received": 1256}Example (detailed response with TLS):
// Request
{"host": "api.github.com", "port": 443, "tls": true, "response_format": "detailed"}
// Response
{
"session_id": "tls_api_443_0",
"host": "api.github.com",
"port": 443,
"tls_info": {"protocol_version": "TLSv1_3", "cipher_suite": "TLS13_AES_256_GCM_SHA384"}
}Example (HTTP/2 with ALPN):
{"host": "api.github.com", "port": 443, "tls": true, "alpn": ["h2", "http/1.1"]}Example (connect to IP with SNI override):
{"host": "93.184.216.34", "port": 443, "tls": true, "sni": "example.com"}Example (mutual TLS / client certificate auth):
{"host": "secure.internal", "port": 443, "tls": true, "client_cert": "/path/to/cert.pem", "client_key": "/path/to/key.pem"}Send data to the socket. Returns immediately after sending (non-blocking).
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID from socket_open (e.g., tcp_example_80_0) |
data |
string | yes | Data to send. Prefix with hex: for binary |
When to use: Any multi-step interaction. Follow with socket_read to get response.
Data format:
- Text sent as-is. Include
\r\nfor protocols that need line endings. - Binary: prefix with
hex:(e.g.,hex:deadbeef)
Read and accumulate data from socket until idle or max timeout.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID from socket_open |
timeout |
integer | no | Idle timeout in ms (default: 1000). Returns when no new data for this duration. |
max_timeout |
integer | no | Max total time in ms (default: 30000). Safety limit for streaming servers. |
response_format |
string | no | concise (default) or detailed |
Behavior:
- Accumulates data as it arrives
- Returns when no new data for
timeoutms (response complete) - Returns early if
max_timeoutreached, withtruncated: true
Example response:
{"data": "HTTP/1.1 200 OK...", "bytes_received": 1256}With truncation (streaming server):
{"data": "...", "bytes_received": 65536, "truncated": true}Close a socket session and free resources. Safe to call multiple times.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID to close |
Notes: Sessions auto-close after 60s of inactivity. Max 100 concurrent sessions.
- Sessions automatically expire after 60 seconds of inactivity
- Maximum 100 concurrent sessions (configurable at compile time)
- Each operation (write, read) refreshes the session TTL
- Expired sessions are cleaned up every 10 seconds
Set the RUST_LOG environment variable for debug output:
RUST_LOG=debug ./socket-tools-mcp
RUST_LOG=socket_tools_mcp=trace ./socket-tools-mcpLogs are written to stderr to avoid interfering with the JSON-RPC stdio transport.
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a new branch:
git checkout -b feature-name - Make your changes
- Run checks:
cargo fmt cargo clippy -- -W clippy::all cargo build --release
- Push your branch:
git push origin feature-name - Create a pull request
- Follow the existing code style
- Add tests for new functionality
- Update documentation as needed
- Keep commits focused and atomic
This project is licensed under the Apache License 2.0.