167 lines
4.6 KiB
Bash
Executable File
167 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
||
# 启动小红书 MCP 服务
|
||
|
||
XHS_MCP="$HOME/.local/bin/xiaohongshu-mcp"
|
||
PID_FILE="$HOME/.xiaohongshu/mcp.pid"
|
||
LOG_FILE="$HOME/.xiaohongshu/mcp.log"
|
||
XVFB_PID_FILE="$HOME/.xiaohongshu/xvfb.pid"
|
||
XVFB_DISPLAY_FILE="$HOME/.xiaohongshu/xvfb.display"
|
||
|
||
# Cookies 路径(可通过环境变量覆盖)
|
||
# XHS_COOKIES_SRC: 源 cookies 文件(用于远程服务器场景)
|
||
# 默认检查 ~/cookies.json 和 ~/.xiaohongshu/cookies.json
|
||
COOKIES_DST="/tmp/cookies.json"
|
||
|
||
mkdir -p "$HOME/.xiaohongshu"
|
||
|
||
# 检测是否有显示器(桌面环境)
|
||
has_display() {
|
||
[ -n "$DISPLAY" ] && xdpyinfo >/dev/null 2>&1
|
||
}
|
||
|
||
# 在无桌面环境下自动启动 Xvfb
|
||
ensure_display() {
|
||
if has_display; then
|
||
return 0
|
||
fi
|
||
|
||
# 已有 Xvfb 在运行
|
||
if [ -f "$XVFB_PID_FILE" ]; then
|
||
local pid
|
||
pid=$(cat "$XVFB_PID_FILE")
|
||
if kill -0 "$pid" 2>/dev/null; then
|
||
export DISPLAY=$(cat "$XVFB_DISPLAY_FILE" 2>/dev/null || echo ":99")
|
||
echo "复用已有 Xvfb (PID: $pid, DISPLAY=$DISPLAY)"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# 检查 Xvfb 是否安装
|
||
if ! command -v Xvfb >/dev/null 2>&1; then
|
||
echo "⚠ 未检测到桌面环境,且未安装 Xvfb。"
|
||
echo " 请安装:sudo apt-get install -y xvfb"
|
||
echo " 安装后重新运行本脚本即可自动配置。"
|
||
exit 1
|
||
fi
|
||
|
||
echo "未检测到桌面环境,自动启动 Xvfb 虚拟显示..."
|
||
|
||
# 自动选择可用的 display 号(99-109)
|
||
local display_num=""
|
||
local d
|
||
for d in $(seq 99 109); do
|
||
if [ ! -e "/tmp/.X${d}-lock" ]; then
|
||
display_num=$d
|
||
break
|
||
fi
|
||
# 锁文件存在但进程已死,尝试清理后使用
|
||
local lock_pid
|
||
lock_pid=$(cat "/tmp/.X${d}-lock" 2>/dev/null | tr -d ' ')
|
||
if [ -n "$lock_pid" ] && ! kill -0 "$lock_pid" 2>/dev/null; then
|
||
rm -f "/tmp/.X${d}-lock" "/tmp/.X11-unix/X${d}" 2>/dev/null
|
||
if [ ! -e "/tmp/.X${d}-lock" ]; then
|
||
display_num=$d
|
||
break
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ -z "$display_num" ]; then
|
||
echo "✗ 无法找到可用的 display 号(:99-:109 均被占用)"
|
||
exit 1
|
||
fi
|
||
|
||
# -ac: 关闭访问控制,允许 chromium 连接虚拟显示(仅用于 headless 自动化)
|
||
Xvfb ":${display_num}" -screen 0 1024x768x24 -ac >/dev/null 2>&1 &
|
||
echo $! > "$XVFB_PID_FILE"
|
||
echo ":${display_num}" > "$XVFB_DISPLAY_FILE"
|
||
export DISPLAY=":${display_num}"
|
||
sleep 1
|
||
|
||
if kill -0 "$(cat "$XVFB_PID_FILE")" 2>/dev/null; then
|
||
echo "✓ Xvfb 已启动 (DISPLAY=:${display_num})"
|
||
else
|
||
echo "✗ Xvfb 启动失败"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 同步 cookies(支持多个可能的来源)
|
||
sync_cookies() {
|
||
local src=""
|
||
|
||
# 优先使用环境变量指定的路径
|
||
if [ -n "$XHS_COOKIES_SRC" ] && [ -f "$XHS_COOKIES_SRC" ]; then
|
||
src="$XHS_COOKIES_SRC"
|
||
elif [ -f "$HOME/cookies.json" ]; then
|
||
src="$HOME/cookies.json"
|
||
elif [ -f "$HOME/.xiaohongshu/cookies.json" ]; then
|
||
src="$HOME/.xiaohongshu/cookies.json"
|
||
fi
|
||
|
||
if [ -n "$src" ]; then
|
||
if [ ! -f "$COOKIES_DST" ] || [ "$src" -nt "$COOKIES_DST" ]; then
|
||
install -m 600 "$src" "$COOKIES_DST"
|
||
echo "已同步 cookies: $src -> $COOKIES_DST"
|
||
fi
|
||
else
|
||
# 确保已有的 cookies 文件权限正确
|
||
[ -f "$COOKIES_DST" ] && chmod 600 "$COOKIES_DST"
|
||
fi
|
||
}
|
||
|
||
sync_cookies
|
||
ensure_display
|
||
|
||
# 检查是否已在运行
|
||
if [ -f "$PID_FILE" ]; then
|
||
PID=$(cat "$PID_FILE")
|
||
if kill -0 "$PID" 2>/dev/null; then
|
||
echo "MCP 服务已在运行 (PID: $PID)"
|
||
echo "如需重启,请先运行 stop-mcp.sh"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# 解析参数
|
||
HEADLESS="true"
|
||
PORT="${XHS_MCP_PORT:-18060}"
|
||
for arg in "$@"; do
|
||
case $arg in
|
||
--headless=false)
|
||
HEADLESS="false"
|
||
;;
|
||
--port=*)
|
||
PORT="${arg#*=}"
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# 校验端口号
|
||
if [[ ! "$PORT" =~ ^[0-9]+$ ]]; then
|
||
echo "错误: 无效端口号: $PORT"
|
||
exit 1
|
||
fi
|
||
|
||
# 启动服务
|
||
echo "启动小红书 MCP 服务..."
|
||
if [ "$HEADLESS" = "false" ]; then
|
||
nohup "$XHS_MCP" -port ":${PORT}" -headless=false > "$LOG_FILE" 2>&1 &
|
||
else
|
||
nohup "$XHS_MCP" -port ":${PORT}" > "$LOG_FILE" 2>&1 &
|
||
fi
|
||
|
||
echo $! > "$PID_FILE"
|
||
sleep 2
|
||
|
||
# 验证启动
|
||
if kill -0 $(cat "$PID_FILE") 2>/dev/null; then
|
||
echo "✓ MCP 服务已启动 (PID: $(cat $PID_FILE))"
|
||
echo " 端点: http://localhost:${PORT}/mcp"
|
||
echo " 日志: $LOG_FILE"
|
||
else
|
||
echo "✗ 启动失败,查看日志: $LOG_FILE"
|
||
cat "$LOG_FILE"
|
||
exit 1
|
||
fi
|