feat: add install unreal mcp script

This commit is contained in:
Krzysztof kuhy Rudnicki 2025-11-06 20:24:19 +01:00
parent 1ffca72ee8
commit 65754e816b
3 changed files with 341 additions and 1 deletions

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Post-transaction hook to re-apply hosts guard protections (single-layer ro bind)
set -euo pipefail
TARGET=/etc/hosts
ENFORCE=/usr/local/sbin/enforce-hosts.sh
LOGTAG=hosts-guard-hook
@ -8,7 +10,7 @@ LOGTAG=hosts-guard-hook
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2> /dev/null || echo 0; }
collapse_mounts() {
local i=0
if command -v mountpoint > /devnull 2>&1; then
if command -v mountpoint > /dev/null 2>&1; then
while mountpoint -q "$TARGET"; do
umount -l "$TARGET" > /dev/null 2>&1 || break
i=$((i + 1))

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Non-interactive pre-transaction hook to temporarily unlock /etc/hosts
set -euo pipefail
TARGET=/etc/hosts
LOGTAG=hosts-guard-hook

View File

@ -0,0 +1,336 @@
#!/bin/bash
# Install Unreal MCP and connect it to VS Code (via Continue MCP) on Arch Linux
# - Installs deps: git, jq, uv, python
# - Clones https://github.com/chongdashu/unreal-mcp
# - Creates a launcher: ~/.local/bin/unreal-mcp-server
# - Configures VS Code Continue MCP: ~/.continue/config.json
# - Optional: copies UnrealMCP plugin into a specified .uproject's Plugins/
set -euo pipefail
SCRIPT_NAME="$(basename "$0")"
# ---------- User/paths ----------
if [[ -n ${SUDO_USER:-} ]]; then
ACTUAL_USER="$SUDO_USER"
USER_HOME="/home/$SUDO_USER"
else
ACTUAL_USER="$USER"
USER_HOME="$HOME"
fi
INSTALL_ROOT_DEFAULT="$USER_HOME/.local/share/unreal-mcp"
INSTALL_ROOT="$INSTALL_ROOT_DEFAULT"
REPO_URL="https://github.com/chongdashu/unreal-mcp.git"
REPO_DIR="" # will be set after INSTALL_ROOT known
PROJECT_UPROJECT="" # optional: path to .uproject
CONFIGURE_CONTINUE=true
CONFIGURE_VSCODE_USER=true
FORCE_UPDATE=false
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
fail() {
echo "[ERROR] $*" >&2
exit 1
}
usage() {
cat << EOF
Usage: $SCRIPT_NAME [options]
Options:
--install-dir DIR Install root for repo (default: $INSTALL_ROOT_DEFAULT)
--project /path/Game.uproject
Copy UnrealMCP plugin into this Unreal project
--no-continue Skip configuring VS Code Continue MCP
--no-vscode Skip adding MCP server to VS Code user profile via --add-mcp
--force-update If repo exists, fetch and reset to origin/main
-h, --help Show this help
Examples:
$SCRIPT_NAME --project ~/UnrealProjects/MyGame/MyGame.uproject
$SCRIPT_NAME --install-dir "$USER_HOME/dev/unreal-mcp"
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--install-dir)
shift
[[ $# -gt 0 ]] || fail "--install-dir requires a value"
INSTALL_ROOT="$1"
;;
--project)
shift
[[ $# -gt 0 ]] || fail "--project requires a path to .uproject"
PROJECT_UPROJECT="$1"
;;
--no-continue)
CONFIGURE_CONTINUE=false
;;
--no-vscode)
CONFIGURE_VSCODE_USER=false
;;
--force-update)
FORCE_UPDATE=true
;;
-h | --help)
usage
exit 0
;;
*)
fail "Unknown option: $1"
;;
esac
shift
done
REPO_DIR="$INSTALL_ROOT/unreal-mcp"
# ---------- Dependencies ----------
require_cmd() { command -v "$1" > /dev/null 2>&1; }
ensure_packages_arch() {
# Install with pacman using sudo when needed; keep idempotent with --needed
local pkgs=(git jq uv python)
local to_install=()
for p in "${pkgs[@]}"; do
if ! pacman -Qi "$p" > /dev/null 2>&1; then
to_install+=("$p")
fi
done
if [[ ${#to_install[@]} -gt 0 ]]; then
log "Installing packages: ${to_install[*]}"
if [[ $EUID -eq 0 ]]; then
pacman -S --noconfirm --needed "${to_install[@]}"
else
sudo pacman -S --noconfirm --needed "${to_install[@]}"
fi
else
log "All required packages already installed"
fi
}
check_python_version() {
if require_cmd python; then
local v
v=$(python -V 2>&1 | awk '{print $2}')
elif require_cmd python3; then
local v
v=$(python3 -V 2>&1 | awk '{print $2}')
else
log "python not found; pacman install will provide it"
return 0
fi
# Require >= 3.12 (Unreal MCP docs)
local major minor
major=$(echo "$v" | cut -d. -f1)
minor=$(echo "$v" | cut -d. -f2)
if ((major < 3 || (major == 3 && minor < 12))); then
log "Python $v detected; installing newer python via pacman"
if [[ $EUID -eq 0 ]]; then
pacman -S --noconfirm --needed python
else
sudo pacman -S --noconfirm --needed python
fi
fi
}
# ---------- Git clone/update ----------
setup_repo() {
mkdir -p "$INSTALL_ROOT"
if [[ ! -d "$REPO_DIR/.git" ]]; then
log "Cloning unreal-mcp into $REPO_DIR"
if require_cmd git; then
git clone "$REPO_URL" "$REPO_DIR"
else
fail "git is required but not found after install"
fi
else
log "Repo exists at $REPO_DIR"
if [[ $FORCE_UPDATE == true ]]; then
log "Updating repo with --force-update"
git -C "$REPO_DIR" fetch origin
git -C "$REPO_DIR" reset --hard origin/main
git -C "$REPO_DIR" pull --rebase --autostash
else
log "Pulling latest changes"
git -C "$REPO_DIR" pull --rebase --autostash
fi
fi
# Ensure ownership for the real user when script ran via sudo
if [[ $EUID -eq 0 ]]; then
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$INSTALL_ROOT"
fi
}
# ---------- Launcher ----------
install_launcher() {
local bin_dir="$USER_HOME/.local/bin"
local python_dir="$REPO_DIR/Python"
local launcher="$bin_dir/unreal-mcp-server"
mkdir -p "$bin_dir"
cat > "$launcher" << EOF
#!/bin/bash
set -euo pipefail
exec uv --directory "$python_dir" run unreal_mcp_server.py "${1:-}" < /dev/null
EOF
chmod +x "$launcher"
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$launcher"; fi
log "Installed launcher: $launcher"
}
# ---------- VS Code: Continue MCP config ----------
configure_continue() {
if [[ $CONFIGURE_CONTINUE != true ]]; then
log "Skipping Continue config (--no-continue)"
return 0
fi
local cont_dir="$USER_HOME/.continue"
local cont_cfg="$cont_dir/config.json"
local python_dir="$REPO_DIR/Python"
mkdir -p "$cont_dir"
# Base JSON when no config exists
local tmp_file
tmp_file="$(mktemp)"
if [[ ! -f $cont_cfg ]]; then
cat > "$tmp_file" << JSON
{
"mcpServers": {
"unrealMCP": {
"command": "uv",
"args": ["--directory", "$python_dir", "run", "unreal_mcp_server.py"]
}
}
}
JSON
mv "$tmp_file" "$cont_cfg"
else
# Merge using jq: ensure .mcpServers exists, then set/overwrite unrealMCP
if ! require_cmd jq; then
fail "jq is required to merge ~/.continue/config.json"
fi
jq --arg dir "$python_dir" '
.mcpServers = (.mcpServers // {}) |
.mcpServers.unrealMCP = {
command: "uv",
args: ["--directory", $dir, "run", "unreal_mcp_server.py"]
}
' "$cont_cfg" > "$tmp_file" && mv "$tmp_file" "$cont_cfg"
fi
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$cont_cfg"; fi
log "Configured Continue MCP at: $cont_cfg"
}
# ---------- VS Code user MCP (native) ----------
configure_vscode_user_mcp() {
if [[ $CONFIGURE_VSCODE_USER != true ]]; then
log "Skipping VS Code user MCP config (--no-vscode)"
return 0
fi
local code_cmd=""
if command -v code > /dev/null 2>&1; then
code_cmd="code"
elif command -v code-insiders > /dev/null 2>&1; then
code_cmd="code-insiders"
elif command -v codium > /dev/null 2>&1; then
code_cmd="codium"
else
fail "VS Code CLI not found (code/code-insiders/codium). Install VS Code and ensure 'code' CLI is available, or run with --no-vscode to skip."
fi
local python_dir="$REPO_DIR/Python"
if ! require_cmd jq; then
fail "jq is required to compose VS Code --add-mcp JSON"
fi
local json
json=$(jq -n --arg dir "$python_dir" '{name:"unrealMCP", command:"uv", args:["--directory", $dir, "run", "unreal_mcp_server.py"]}')
log "Registering MCP server in VS Code user profile via: $code_cmd --add-mcp"
if "$code_cmd" --add-mcp "$json" > /tmp/vscode-add-mcp.log 2>&1; then
log "VS Code user MCP server 'unrealMCP' added/updated"
else
sed -n '1,120p' /tmp/vscode-add-mcp.log || true
fail "VS Code --add-mcp failed. Ensure your VS Code version supports MCP (update to the latest), or run with --no-vscode to skip."
fi
}
# ---------- Unreal Plugin copy (optional) ----------
install_plugin_into_project() {
[[ -n $PROJECT_UPROJECT ]] || return 0
local upath="$PROJECT_UPROJECT"
if [[ ! -f $upath ]]; then
fail "--project path does not exist or is not a file: $upath"
fi
if [[ ${upath##*.} != "uproject" ]]; then
fail "--project must point to a .uproject file"
fi
local proj_dir
proj_dir="$(cd "$(dirname "$upath")" && pwd)"
local src_plugin="$REPO_DIR/MCPGameProject/Plugins/UnrealMCP"
local dst_plugin="$proj_dir/Plugins/UnrealMCP"
if [[ ! -d $src_plugin ]]; then
fail "Source plugin not found at $src_plugin (did repo layout change?)"
fi
mkdir -p "$proj_dir/Plugins"
log "Copying UnrealMCP plugin to project: $dst_plugin"
rsync -a --delete "$src_plugin/" "$dst_plugin/"
# Set ownership back to actual user if run as root
if [[ $EUID -eq 0 ]]; then chown -R "$ACTUAL_USER:$ACTUAL_USER" "$proj_dir/Plugins"; fi
log "Plugin installed. Enable it from Unreal Editor (Edit > Plugins) if needed."
}
# ---------- Summary ----------
print_summary() {
local python_dir="$REPO_DIR/Python"
cat << EOF
============================================
Unreal MCP setup complete
============================================
Repo: $REPO_DIR
Python dir: $python_dir
Launcher: $USER_HOME/.local/bin/unreal-mcp-server
VS Code (Continue) MCP configured: ${CONFIGURE_CONTINUE}
- File: $USER_HOME/.continue/config.json
- Server ID: unrealMCP
VS Code (User profile) MCP configured: ${CONFIGURE_VSCODE_USER}
- Command used: code --add-mcp '{"name":"unrealMCP", "command":"uv", "args":["--directory","$python_dir","run","unreal_mcp_server.py"]}'
Optional usage:
- Run server manually: unreal-mcp-server
- In VS Code with Continue installed, the unrealMCP server will auto-start when needed.
Unreal plugin:
- Source: MCPGameProject/Plugins/UnrealMCP
- If you provided --project, the plugin was copied to: $(dirname "${PROJECT_UPROJECT:-}")/Plugins/UnrealMCP
- In the Unreal Editor: Edit > Plugins > search "UnrealMCP" and enable. Restart when prompted.
Notes:
- Ensure you have Unreal Engine 5.5+ installed.
- The Python server listens to the Unreal plugin on TCP port 55557 by default.
- For other MCP clients (Claude Desktop, Cursor, Windsurf), copy the JSON snippet from the repo README to their config locations.
EOF
}
main() {
log "Installing prerequisites (Arch Linux)"
ensure_packages_arch
check_python_version
setup_repo
install_launcher
configure_continue
configure_vscode_user_mcp
install_plugin_into_project
print_summary
}
main "$@"