Packages

TCP MCP server for supervising child BEAM OS instances. Spawns Mix projects as child nodes via Port, connects through Erlang distribution for remote evaluation.

Current section

Files

Jump to
os_sup_mcp README.md
Raw

README.md

# Os Supervisor Mcp
TCP MCP server for supervising child BEAM OS instances. Each child runs a Mix project from a given path, spawned via `Port.open` and connected through Erlang distribution for remote evaluation.
## Installation
Add `os_sup_mcp` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:os_sup_mcp, "~> 0.1.0"}
]
end
```
## Architecture
```
OsSupMcp.Application
└── Supervisor (rest_for_one)
├── OsSupMcp.Node.Manager (GenServer, ETS registry)
├── OsSupMcp.Node.WorkerSupervisor (DynamicSupervisor)
│ ├── Worker (child1) -- wraps Port
│ ├── Worker (child2)
│ └── ...
└── OsSupMcp.MCP.Server (TCP listener, port 9100)
```
Workers use `restart: :transient` — if a child BEAM crashes, the DynamicSupervisor automatically restarts it with the same config. Clean stops don't trigger restart.
## MCP Tools
| Tool | Params | Description |
|------|--------|-------------|
| `status` | _(none)_ | List all managed nodes: name, connected, OS PID, uptime |
| `start` | `name`, `path`, `args?` | Start a child node from a Mix project directory |
| `stop` | `name` | Stop a running child node |
| `restart` | `name` | Stop + start with same config |
| `eval` | `name`, `code` | Evaluate Elixir expression on a child node via `:erpc` |
## Usage
```bash
# Start the server
cd os_sup_mcp
mix deps.get
mix run --no-halt
```
The MCP server listens on TCP port 9100 (configurable in `config/config.exs`).
### Manual testing with socat
```bash
# Initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | socat - TCP:localhost:9100
# List tools
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | socat - TCP:localhost:9100
# Start a child node
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"start","arguments":{"name":"myapp","path":"/path/to/mix/project"}}}' | socat - TCP:localhost:9100
# Eval on child
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"eval","arguments":{"name":"myapp","code":"1 + 1"}}}' | socat - TCP:localhost:9100
# Stop child
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"stop","arguments":{"name":"myapp"}}}' | socat - TCP:localhost:9100
```
### Claude Code MCP integration
Add to your MCP config:
```json
{
"mcpServers": {
"os_sup_mcp": {
"type": "stdio",
"command": "socat",
"args": ["STDIO", "TCP:localhost:9100"]
}
}
}
```
## Configuration
```elixir
# config/config.exs
config :os_sup_mcp,
mcp_port: 9100
```
## Programmatic API
```elixir
OsSupMcp.start_node("myapp", "/path/to/project")
OsSupMcp.eval_on_node("myapp", "Enum.sum(1..10)")
OsSupMcp.list_nodes()
OsSupMcp.restart_node("myapp")
OsSupMcp.stop_node("myapp")
```
## License
MIT — see [LICENSE](LICENSE) for details.