Files
agent-coordinator/scripts/mcp_launcher_multi.sh
Ra 101e1e5c81
Some checks failed
build-container / build (push) Has been cancelled
pwd issues
2025-09-21 18:45:30 -07:00

239 lines
7.2 KiB
Bash
Executable File

#!/bin/bash
# AgentCoordinator Multi-Interface MCP Server Launcher
# This script starts the unified MCP server with support for multiple interface modes:
# - stdio: Traditional MCP over stdio (default for VSCode)
# - http: HTTP REST API for remote clients
# - websocket: WebSocket interface for real-time web clients
# - remote: Both HTTP and WebSocket
# - all: All interface modes
set -e
CALLER_PWD="${PWD}"
WORKSPACE_DIR="${MCP_WORKSPACE_DIR:-$CALLER_PWD}"
export PATH="$HOME/.asdf/shims:$PATH"
# Change to the project directory
cd "$(dirname "$0")/.."
export MCP_WORKSPACE_DIR="$WORKSPACE_DIR"
# Parse command line arguments
INTERFACE_MODE="${1:-stdio}"
HTTP_PORT="${2:-8080}"
WS_PORT="${3:-8081}"
# Set environment variables
export MIX_ENV="${MIX_ENV:-dev}"
export NATS_HOST="${NATS_HOST:-localhost}"
export NATS_PORT="${NATS_PORT:-4222}"
export MCP_INTERFACE_MODE="$INTERFACE_MODE"
export MCP_HTTP_PORT="$HTTP_PORT"
export MCP_WS_PORT="$WS_PORT"
# Validate interface mode
case "$INTERFACE_MODE" in
stdio|http|websocket|remote|all)
;;
*)
echo "Invalid interface mode: $INTERFACE_MODE"
echo "Valid modes: stdio, http, websocket, remote, all"
exit 1
;;
esac
# Log startup
echo "Starting AgentCoordinator Multi-Interface MCP Server..." >&2
echo "Interface Mode: $INTERFACE_MODE" >&2
echo "Environment: $MIX_ENV" >&2
echo "NATS: $NATS_HOST:$NATS_PORT" >&2
if [[ "$INTERFACE_MODE" != "stdio" ]]; then
echo "HTTP Port: $HTTP_PORT" >&2
echo "WebSocket Port: $WS_PORT" >&2
fi
# Install dependencies if needed
if [[ ! -d "deps" ]] || [[ ! -d "_build" ]]; then
echo "Installing dependencies..." >&2
mix deps.get
mix compile
fi
# Start the appropriate interface mode
case "$INTERFACE_MODE" in
stdio)
# Traditional stdio mode for VSCode and local clients
exec mix run --no-halt -e "
# Ensure all applications are started
{:ok, _} = Application.ensure_all_started(:agent_coordinator)
# Configure interface manager for stdio only
Application.put_env(:agent_coordinator, :interfaces, %{
enabled_interfaces: [:stdio],
stdio: %{enabled: true, handle_stdio: true},
http: %{enabled: false},
websocket: %{enabled: false}
})
# MCPServer and InterfaceManager are started by the application supervisor automatically
IO.puts(:stderr, \"STDIO MCP server ready with tool filtering\")
# Handle MCP JSON-RPC messages through the unified server
defmodule StdioMCPHandler do
def start do
spawn_link(fn -> message_loop() end)
Process.sleep(:infinity)
end
defp message_loop do
case IO.read(:stdio, :line) do
:eof ->
IO.puts(:stderr, \"MCP server shutting down\")
System.halt(0)
{:error, reason} ->
IO.puts(:stderr, \"IO Error: #{inspect(reason)}\")
System.halt(1)
line ->
handle_message(String.trim(line))
message_loop()
end
end
defp handle_message(\"\"), do: :ok
defp handle_message(json_line) do
try do
request = Jason.decode!(json_line)
# Route through unified MCP server with local context (full tool access)
response = AgentCoordinator.MCPServer.handle_mcp_request(request)
IO.puts(Jason.encode!(response))
rescue
e in Jason.DecodeError ->
error_response = %{
\"jsonrpc\" => \"2.0\",
\"id\" => nil,
\"error\" => %{
\"code\" => -32700,
\"message\" => \"Parse error: #{Exception.message(e)}\"
}
}
IO.puts(Jason.encode!(error_response))
e ->
id = try do
partial = Jason.decode!(json_line)
Map.get(partial, \"id\")
rescue
_ -> nil
end
error_response = %{
\"jsonrpc\" => \"2.0\",
\"id\" => id,
\"error\" => %{
\"code\" => -32603,
\"message\" => \"Internal error: #{Exception.message(e)}\"
}
}
IO.puts(Jason.encode!(error_response))
end
end
end
StdioMCPHandler.start()
"
;;
http)
# HTTP-only mode for REST API clients
exec mix run --no-halt -e "
# Ensure all applications are started
{:ok, _} = Application.ensure_all_started(:agent_coordinator)
# Configure interface manager for HTTP only
Application.put_env(:agent_coordinator, :interfaces, %{
enabled_interfaces: [:http],
stdio: %{enabled: false},
http: %{enabled: true, port: $HTTP_PORT, host: \"0.0.0.0\"},
websocket: %{enabled: false}
})
IO.puts(:stderr, \"HTTP MCP server ready on port $HTTP_PORT with tool filtering\")
IO.puts(:stderr, \"Available endpoints:\")
IO.puts(:stderr, \" GET /health - Health check\")
IO.puts(:stderr, \" GET /mcp/capabilities - Server capabilities\")
IO.puts(:stderr, \" GET /mcp/tools - Available tools (filtered)\")
IO.puts(:stderr, \" POST /mcp/tools/:tool_name - Execute tool\")
IO.puts(:stderr, \" POST /mcp/request - Full MCP request\")
IO.puts(:stderr, \" GET /agents - Agent status\")
Process.sleep(:infinity)
"
;;
websocket)
# WebSocket-only mode
exec mix run --no-halt -e "
# Ensure all applications are started
{:ok, _} = Application.ensure_all_started(:agent_coordinator)
# Configure interface manager for WebSocket only
Application.put_env(:agent_coordinator, :interfaces, %{
enabled_interfaces: [:websocket],
stdio: %{enabled: false},
http: %{enabled: true, port: $WS_PORT, host: \"0.0.0.0\"},
websocket: %{enabled: true, port: $WS_PORT}
})
IO.puts(:stderr, \"WebSocket MCP server ready on port $WS_PORT with tool filtering\")
IO.puts(:stderr, \"WebSocket endpoint: ws://localhost:$WS_PORT/mcp/ws\")
Process.sleep(:infinity)
"
;;
remote)
# Both HTTP and WebSocket for remote clients
exec mix run --no-halt -e "
# Ensure all applications are started
{:ok, _} = Application.ensure_all_started(:agent_coordinator)
# Configure interface manager for remote access
Application.put_env(:agent_coordinator, :interfaces, %{
enabled_interfaces: [:http, :websocket],
stdio: %{enabled: false},
http: %{enabled: true, port: $HTTP_PORT, host: \"0.0.0.0\"},
websocket: %{enabled: true, port: $HTTP_PORT}
})
IO.puts(:stderr, \"Remote MCP server ready on port $HTTP_PORT with tool filtering\")
IO.puts(:stderr, \"HTTP endpoints available at http://localhost:$HTTP_PORT/\")
IO.puts(:stderr, \"WebSocket endpoint: ws://localhost:$HTTP_PORT/mcp/ws\")
Process.sleep(:infinity)
"
;;
all)
# All interface modes
exec mix run --no-halt -e "
# Ensure all applications are started
{:ok, _} = Application.ensure_all_started(:agent_coordinator)
# Configure interface manager for all interfaces
Application.put_env(:agent_coordinator, :interfaces, %{
enabled_interfaces: [:stdio, :http, :websocket],
stdio: %{enabled: true, handle_stdio: false}, # Don't handle stdio in all mode
http: %{enabled: true, port: $HTTP_PORT, host: \"0.0.0.0\"},
websocket: %{enabled: true, port: $HTTP_PORT}
})
IO.puts(:stderr, \"Multi-interface MCP server ready with tool filtering\")
IO.puts(:stderr, \"STDIO: Available for local MCP clients\")
IO.puts(:stderr, \"HTTP: Available at http://localhost:$HTTP_PORT/\")
IO.puts(:stderr, \"WebSocket: Available at ws://localhost:$HTTP_PORT/mcp/ws\")
Process.sleep(:infinity)
"
;;
esac