Current section
Files
Jump to
Current section
Files
bin/ragex-mcp
#!/usr/bin/env bash
#
# ragex-mcp -- Start Ragex as an MCP server in stdio mode.
#
# Designed for editors that communicate with MCP servers over stdin/stdout
# (Zed, Cursor, Claude Desktop, etc.).
#
# Usage:
# bin/ragex-mcp # basic startup
# bin/ragex-mcp --project /path/to/code # auto-analyze a project on startup
# bin/ragex-mcp --log-level debug # override log level
#
# Environment variables (all optional):
# RAGEX_PROJECT -- same as --project
# RAGEX_LOG_LEVEL -- same as --log-level (default: info)
# RAGEX_EMBEDDING_MODEL -- embedding model to use
set -euo pipefail
ORIGINAL_PWD="$PWD"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
cd "$PROJECT_DIR"
# -- Defaults ---------------------------------------------------------------
PROJECT="${RAGEX_PROJECT:-}"
LOG_LEVEL="${RAGEX_LOG_LEVEL:-info}"
# -- Parse arguments --------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
--project)
PROJECT="$2"
shift 2
;;
--project=*)
PROJECT="${1#*=}"
shift
;;
--log-level)
LOG_LEVEL="$2"
shift 2
;;
--log-level=*)
LOG_LEVEL="${1#*=}"
shift
;;
--help|-h)
cat <<'EOF'
Usage: ragex-mcp [--project PATH] [--log-level LEVEL]
Start Ragex as an MCP server communicating over stdio.
Options:
--project PATH Auto-analyze a project directory on startup
--log-level LEVEL Set log level (debug|info|warning|error)
Environment:
RAGEX_PROJECT Same as --project
RAGEX_LOG_LEVEL Same as --log-level (default: info)
RAGEX_EMBEDDING_MODEL Embedding model to use
EOF
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
# -- Auto-detect Elixir project if not explicitly set -----------------------
if [[ -z "$PROJECT" ]]; then
find_mix_exs() {
local dir="$1"
while [[ "$dir" != "/" ]]; do
if [[ -f "$dir/mix.exs" ]]; then
echo "$dir"
return 0
fi
dir="$(dirname "$dir")"
done
return 1
}
PROJECT="$(find_mix_exs "$ORIGINAL_PWD" || true)"
if [[ -z "$PROJECT" ]]; then
echo "[ragex-mcp] Not an Elixir project (no mix.exs found in $ORIGINAL_PWD or parents). Skipping startup." >&2
exit 0
fi
fi
# -- Environment for MCP stdio mode -----------------------------------------
export MIX_ENV=prod
export RAGEX_STDIO=1
export LOG_LEVEL="$LOG_LEVEL"
if [[ -n "$PROJECT" ]]; then
export RAGEX_AUTO_ANALYZE="$PROJECT"
fi
# -- Detect running instance ------------------------------------------------
# If a Ragex server is already listening on the Unix socket, bridge to it
# instead of starting a second BEAM VM (which would OOM on GPU allocation).
SOCKET_PATH="/tmp/ragex_mcp.sock"
if [[ -S "$SOCKET_PATH" ]]; then
# Try a lightweight ping via the socket to confirm it's alive.
# Send MCP ping, read one response line, check for "result".
PING='{"jsonrpc":"2.0","id":0,"method":"ping","params":{}}'
# timeout 2s: if no response, server is stale
PONG=$(echo "$PING" | timeout 2 socat - UNIX-CONNECT:"$SOCKET_PATH" 2>/dev/null | head -1)
if echo "$PONG" | grep -q '"result"'; then
echo "[ragex-mcp] Reusing running server via $SOCKET_PATH" >&2
exec "$SCRIPT_DIR/ragex-bridge"
fi
fi
# -- No running instance, start full server ---------------------------------
# Compile silently (all output to stderr so it never pollutes stdio JSON-RPC)
mix compile >&2 2>&1
# Run the server (only JSON-RPC goes to stdout)
exec mix run --no-halt --no-compile