mcp-socket
by cinit
README.md
# mcp-socket
Stateful **outbound TCP/UDP MCP server** for LLMs.
Sockets stay open across tool calls until you close them or they hit the idle timeout. That makes multi-step protocols practical: HTTP/1.x, SMTP, Redis, DNS (UDP), custom text/binary protocols, and more.
See [DESIGN.md](DESIGN.md) for the full design.
## Install
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
## Run
```bash
# stdio (default) — typical for MCP clients
mcp-socket
# or
python -m mcp_socket
# HTTP transport
mcp-socket --transport streamable-http --host 127.0.0.1 --port 8000
```
### CLI options
| Option | Default | Description |
|--------|---------|-------------|
| `--transport` | `stdio` | `stdio`, `streamable-http`, or `sse` |
| `--host` | `127.0.0.1` | HTTP bind address |
| `--port` | `8000` | HTTP bind port |
| `--socket-idle-timeout` | `300` | Idle seconds before auto-close |
| `--cleanup-interval` | `5` | Cleanup scan interval |
| `--allow-private-network` | off | Allow RFC1918/loopback/ULA/etc. |
| `--max-sockets` | `128` | Max concurrent sockets |
| `--max-send-bytes` | `1048576` | Max send payload |
| `--max-recv-bytes` | `1048576` | Max recv payload |
| `--log-level` | `INFO` | Logging level |
## Tools
| Tool | Purpose |
|------|---------|
| `resolve_dns` | Hostname → A/AAAA |
| `tcp_connect` | Connect TCP to IP:port |
| `udp_open` | Create UDP socket |
| `tcp_send` / `udp_send` | Send (`utf8` or `base64`) |
| `tcp_recv` / `udp_recv` | Receive (base64 + optional text) |
| `socket_poll` | Check readability |
| `list_sockets` | Inspect open sockets |
| `close_socket` | Close (optional TCP RST) |
`tcp_connect` / `udp_send` require **IP literals**. Call `resolve_dns` first for hostnames.
Private and local destinations are blocked by default (`ADDRESS_BLOCKED`). Use `--allow-private-network` for local testing.
## Example (TCP HTTP/1.0)
```text
resolve_dns(hostname="example.com")
→ { "ipv4": ["93.184.216.34"], ... }
tcp_connect(address="93.184.216.34", port=80)
→ { "socket_id": "...", "state": "connected" }
tcp_send(socket_id="...", encoding="utf8",
data="GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
tcp_recv(socket_id="...", max_bytes=65536, timeout_seconds=5)
→ { "bytes_received": N, "data_base64": "...", "text": "HTTP/1.0 200 ..." }
close_socket(socket_id="...")
```
## Security
Before every `connect()` / `sendto()`:
- Destination must be a valid IP literal
- Private/local ranges are denied unless `--allow-private-network`
- Multicast / unspecified / reserved ranges are always denied
No TLS, no listening sockets, no proxy support — higher-level servers can layer those on top.
## Develop
```bash
pip install -e ".[dev]"
pytest
```
## License
MIT
TDQS
A3.9/5.0
Scored across 10 tools
Disambiguation5/5
Each tool targets a distinct operation (TCP connect/send/recv/close, UDP open/send/recv, DNS resolution, socket listing, polling). No overlap in functionality.
Naming Consistency5/5
All tools use consistent lowercase snake_case with a verb_noun pattern (e.g., tcp_connect, resolve_dns, close_socket). Adheres to a predictable naming convention.
Tool Count5/5
10 tools is appropriate for a socket utility server. It covers TCP and UDP client operations without being excessive or sparse.
Completeness4/5
Covers essential TCP/UDP client operations and DNS resolution. Missing server-side features (TCP listen, UDP bind) and advanced options, but the scope is clearly client-oriented.
Maintenance
ActivityStale
ResponsivenessNo issues