- Enhanced Agent struct with current_activity, current_files, and activity_history fields - Created ActivityTracker module to infer activities from tool calls - Integrated activity tracking into MCP server tool routing - Updated task board APIs to include activity information - Agents now show real-time status like 'Reading file.ex', 'Editing main.py', 'Sequential thinking', etc. - Added activity history to track recent agent actions - All file operations and tool calls are now tracked and displayed
235 lines
7.1 KiB
Bash
Executable File
235 lines
7.1 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
|
|
|
|
export PATH="$HOME/.asdf/shims:$PATH"
|
|
|
|
# Change to the project directory
|
|
cd "$(dirname "$0")/.."
|
|
|
|
# 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 |