diff --git a/.mcp.json b/.mcp.json
new file mode 100644
index 000000000..fbbe3e742
--- /dev/null
+++ b/.mcp.json
@@ -0,0 +1,11 @@
+{
+ "mcpServers": {
+ "ssh-manager": {
+ "command": "node",
+ "args": ["/tmp/mcp-ssh-manager/node_modules/mcp-ssh-manager/src/index.js"],
+ "env": {
+ "DOTENV_CONFIG_PATH": ".env"
+ }
+ }
+ }
+}
diff --git a/docs/mcp/install-launchd.sh b/docs/mcp/install-launchd.sh
new file mode 100644
index 000000000..701ce2d2a
--- /dev/null
+++ b/docs/mcp/install-launchd.sh
@@ -0,0 +1,222 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+LABEL="com.bvisible.mcp-ssh-manager"
+PLIST_PATH="$HOME/Library/LaunchAgents/${LABEL}.plist"
+LOG_DIR="$HOME/Library/Logs/mcp-ssh-manager"
+OUT_LOG="$LOG_DIR/out.log"
+ERR_LOG="$LOG_DIR/err.log"
+
+fail_cleanup() {
+ if launchctl print "gui/$(id -u)/${LABEL}" >/dev/null 2>&1; then
+ launchctl bootout "gui/$(id -u)" "$PLIST_PATH" >/dev/null 2>&1 || true
+ fi
+ if [ -f "$PLIST_PATH" ]; then
+ rm -f "$PLIST_PATH" || true
+ fi
+}
+
+usage() {
+ echo "usage: $0 {install|uninstall|status|logs}"
+}
+
+pick_node() {
+ if [ -x /opt/homebrew/bin/node ]; then
+ echo /opt/homebrew/bin/node
+ elif [ -x /usr/local/bin/node ]; then
+ echo /usr/local/bin/node
+ elif command -v node >/dev/null 2>&1; then
+ command -v node
+ else
+ echo ""
+ fi
+}
+
+find_repo_up() {
+ local dir="$PWD"
+ for _ in 0 1 2 3 4 5; do
+ local pj="$dir/package.json"
+ if [ -f "$pj" ] && /usr/bin/grep -E '"name"[[:space:]]*:[[:space:]]*"[^\"]*mcp-ssh-manager' "$pj" >/dev/null 2>&1; then
+ echo "$dir"
+ return 0
+ fi
+ dir="$(dirname "$dir")"
+ done
+ return 1
+}
+
+find_repo_search() {
+ local base
+ for base in "$HOME/code" "$HOME/projects" "$HOME/src"; do
+ if [ -d "$base" ]; then
+ local hit
+ hit="$(find "$base" -maxdepth 3 -type d -name '*mcp-ssh-manager*' 2>/dev/null | head -n 1)"
+ if [ -n "$hit" ]; then
+ echo "$hit"
+ return 0
+ fi
+ fi
+ done
+ return 1
+}
+
+find_binary_under() {
+ local base
+ for base in /usr/local /opt/homebrew; do
+ if [ -d "$base" ]; then
+ local hit
+ hit="$(find "$base" -maxdepth 4 -type f -name 'mcp-ssh-manager' 2>/dev/null | head -n 1)"
+ if [ -n "$hit" ]; then
+ echo "$hit"
+ return 0
+ fi
+ fi
+ done
+ return 1
+}
+
+write_plist() {
+ local workdir="$1"
+ shift
+ local -a args=("$@")
+
+ mkdir -p "$(dirname "$PLIST_PATH")" "$LOG_DIR"
+
+ {
+ echo ''
+ echo ''
+ echo ''
+ echo ''
+ echo ' Label'
+ echo " ${LABEL}"
+ echo ''
+ echo ' ProgramArguments'
+ echo ' '
+ for arg in "${args[@]}"; do
+ echo " ${arg}"
+ done
+ echo ' '
+ if [ -n "$workdir" ]; then
+ echo ''
+ echo ' WorkingDirectory'
+ echo " ${workdir}"
+ fi
+ echo ''
+ echo ' EnvironmentVariables'
+ echo ' '
+ echo ' PATH'
+ echo ' /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin'
+ echo ' '
+ echo ''
+ echo ' RunAtLoad'
+ echo ' '
+ echo ''
+ echo ' KeepAlive'
+ echo ' '
+ echo ''
+ echo ' StandardOutPath'
+ echo " ${OUT_LOG}"
+ echo ''
+ echo ' StandardErrorPath'
+ echo " ${ERR_LOG}"
+ echo ''
+ echo ''
+ } > "$PLIST_PATH"
+}
+
+install() {
+ trap 'fail_cleanup' ERR
+
+ local binary_path=""
+ if command -v mcp-ssh-manager >/dev/null 2>&1; then
+ binary_path="$(command -v mcp-ssh-manager)"
+ else
+ binary_path="$(find_binary_under || true)"
+ fi
+
+ if [ -n "$binary_path" ]; then
+ echo "using binary: $binary_path"
+ write_plist "" "$binary_path"
+ else
+ local repo=""
+ repo="$(find_repo_up || true)"
+ if [ -z "$repo" ]; then
+ repo="$(find_repo_search || true)"
+ fi
+
+ if [ -z "$repo" ]; then
+ echo "could not find mcp-ssh-manager binary or repo" >&2
+ exit 1
+ fi
+
+ local pj="$repo/package.json"
+ local has_start=""
+ if [ -f "$pj" ] && /usr/bin/grep -E '"start"[[:space:]]*:' "$pj" >/dev/null 2>&1; then
+ has_start=1
+ fi
+
+ if [ -n "$has_start" ]; then
+ local pm=""
+ if [ -f "$repo/pnpm-lock.yaml" ] && command -v pnpm >/dev/null 2>&1; then
+ pm="$(command -v pnpm)"
+ echo "using pnpm start in repo: $repo"
+ write_plist "$repo" "$pm" "start"
+ elif command -v npm >/dev/null 2>&1; then
+ pm="$(command -v npm)"
+ echo "using npm run start in repo: $repo"
+ write_plist "$repo" "$pm" "run" "start"
+ else
+ echo "start script exists but npm or pnpm not found" >&2
+ exit 1
+ fi
+ else
+ local node
+ node="$(pick_node)"
+ if [ -z "$node" ]; then
+ echo "node not found" >&2
+ exit 1
+ fi
+ local entry=""
+ for p in "dist/index.js" "build/index.js" "index.js" "src/index.ts"; do
+ if [ -f "$repo/$p" ]; then
+ entry="$repo/$p"
+ break
+ fi
+ done
+ if [ -z "$entry" ]; then
+ echo "no entry file found in repo" >&2
+ exit 1
+ fi
+ echo "using node entry: $entry"
+ write_plist "$repo" "$node" "$entry"
+ fi
+ fi
+
+ launchctl bootstrap "gui/$(id -u)" "$PLIST_PATH"
+ launchctl kickstart -k "gui/$(id -u)/${LABEL}"
+
+ echo "installed: $PLIST_PATH"
+ echo "logs: $LOG_DIR"
+}
+
+uninstall() {
+ launchctl bootout "gui/$(id -u)" "$PLIST_PATH" >/dev/null 2>&1 || true
+ rm -f "$PLIST_PATH"
+ echo "removed: $PLIST_PATH"
+}
+
+status() {
+ launchctl print "gui/$(id -u)/${LABEL}"
+}
+
+logs() {
+ tail -f "$OUT_LOG" "$ERR_LOG"
+}
+
+case "${1:-}" in
+ install) install ;;
+ uninstall) uninstall ;;
+ status) status ;;
+ logs) logs ;;
+ *) usage; exit 1 ;;
+esac
diff --git a/docs/mcp/mcp-ssh-manager-macos.md b/docs/mcp/mcp-ssh-manager-macos.md
new file mode 100644
index 000000000..c0b5e6337
--- /dev/null
+++ b/docs/mcp/mcp-ssh-manager-macos.md
@@ -0,0 +1,204 @@
+# mcp-ssh-manager macOS 自启 launchd
+
+本指南适用于 **macOS 13+(含 macOS 26)**,使用 **launchd** 设置登录后自启。方案可回滚、可调试、可日志追踪,不修改业务代码,也不使用第三方守护工具。
+
+## 1) 自适应探测规则
+
+脚本会按顺序自动探测启动方式,成功即用:
+
+1) 若 `command -v mcp-ssh-manager` 存在,使用其绝对路径作为 `ProgramArguments[0]`。
+2) 否则按以下范围搜索仓库或安装路径:
+ - 当前工作目录及其父级(最多向上 5 层),查找 `package.json` 且 `name` 含 `mcp-ssh-manager`。
+ - `~/code`、`~/projects`、`~/src` 下搜索目录名包含 `mcp-ssh-manager`,深度 `<=3`。
+ - `/usr/local`、`/opt/homebrew` 下搜索 `mcp-ssh-manager` 相关文件。
+3) 若找到 Node 项目:
+ - 优先 `pnpm start` 或 `npm run start`(`scripts.start` 存在时)。
+ - 否则使用 `node `,入口依次为:`dist/index.js` -> `build/index.js` -> `index.js` -> `src/index.ts`。
+4) Node 解释器绝对路径优先级:`/opt/homebrew/bin/node` -> `/usr/local/bin/node` -> `which node`。
+5) `ProgramArguments` 使用绝对路径,禁止依赖 shell PATH 或 `~/.zshrc`。
+
+## 2) 安装脚本
+
+同目录脚本:`docs/mcp/install-launchd.sh`。用法:
+
+```
+./install-launchd.sh install
+```
+
+脚本会生成并安装 plist:
+
+```
+~/Library/LaunchAgents/com.bvisible.mcp-ssh-manager.plist
+```
+
+日志目录:
+
+```
+~/Library/Logs/mcp-ssh-manager/
+```
+
+## 3) 生成的 plist 完整内容
+
+脚本会根据探测结果生成 plist。以下为两种可能的完整内容示例。
+
+**示例 A:直接使用二进制**
+
+```
+
+
+
+
+ Label
+ com.bvisible.mcp-ssh-manager
+
+ ProgramArguments
+
+ /usr/local/bin/mcp-ssh-manager
+
+
+ EnvironmentVariables
+
+ PATH
+ /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
+
+
+ RunAtLoad
+
+
+ KeepAlive
+
+
+ StandardOutPath
+ /Users/USER/Library/Logs/mcp-ssh-manager/out.log
+
+ StandardErrorPath
+ /Users/USER/Library/Logs/mcp-ssh-manager/err.log
+
+
+```
+
+**示例 B:Node 项目入口**
+
+```
+
+
+
+
+ Label
+ com.bvisible.mcp-ssh-manager
+
+ ProgramArguments
+
+ /opt/homebrew/bin/node
+ /Users/USER/path/to/mcp-ssh-manager/dist/index.js
+
+
+ WorkingDirectory
+ /Users/USER/path/to/mcp-ssh-manager
+
+ EnvironmentVariables
+
+ PATH
+ /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
+
+
+ RunAtLoad
+
+
+ KeepAlive
+
+
+ StandardOutPath
+ /Users/USER/Library/Logs/mcp-ssh-manager/out.log
+
+ StandardErrorPath
+ /Users/USER/Library/Logs/mcp-ssh-manager/err.log
+
+
+```
+
+## 4) plist 关键字段说明
+
+- `Label`:launchd 唯一标识,用于 `launchctl` 管理。
+- `ProgramArguments`:启动命令与参数,必须为绝对路径,禁止使用 shell 包裹。
+- `WorkingDirectory`:Node 项目使用的工作目录,必须为绝对路径。
+- `EnvironmentVariables`:明确指定 PATH,避免 launchd 的默认 PATH 过短。
+- `RunAtLoad`:plist 加载时立即启动。
+- `KeepAlive`:进程退出时自动拉起。
+- `StandardOutPath`/`StandardErrorPath`:stdout 与 stderr 日志路径。
+
+## 5) 一键命令
+
+以下命令均可直接复制执行:
+
+```
+./install-launchd.sh install
+./install-launchd.sh uninstall
+./install-launchd.sh status
+./install-launchd.sh logs
+```
+
+## 6) 手动命令
+
+**安装与启动:**
+
+```
+launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.bvisible.mcp-ssh-manager.plist
+launchctl kickstart -k gui/$(id -u)/com.bvisible.mcp-ssh-manager
+```
+
+**卸载与停止:**
+
+```
+launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.bvisible.mcp-ssh-manager.plist
+rm -f ~/Library/LaunchAgents/com.bvisible.mcp-ssh-manager.plist
+```
+
+**状态与调试:**
+
+```
+launchctl print gui/$(id -u)/com.bvisible.mcp-ssh-manager
+```
+
+**日志追踪:**
+
+```
+tail -f ~/Library/Logs/mcp-ssh-manager/out.log ~/Library/Logs/mcp-ssh-manager/err.log
+```
+
+## 7) 验证是否自启成功
+
+1) 登录后检查 launchd 状态:
+
+```
+launchctl print gui/$(id -u)/com.bvisible.mcp-ssh-manager
+```
+
+2) 查看日志是否有持续输出:
+
+```
+tail -f ~/Library/Logs/mcp-ssh-manager/out.log
+```
+
+## 8) 常见问题与排查
+
+- **权限问题**:LaunchAgents 以当前用户运行,避免写入 root 目录。
+- **WorkingDirectory 不存在**:确保仓库路径存在且为绝对路径。
+- **Node 路径错误**:确认 `/opt/homebrew/bin/node` 或 `/usr/local/bin/node` 可执行。
+- **端口占用**:检查已有进程是否占用目标端口,必要时先停止旧进程。
+- **PATH 不一致**:保证 `EnvironmentVariables.PATH` 包含常用路径。
+
+**临时前台运行对照验证:**
+
+- 若使用二进制:
+
+```
+/usr/local/bin/mcp-ssh-manager
+```
+
+- 若使用 Node 入口:
+
+```
+/opt/homebrew/bin/node /Users/USER/path/to/mcp-ssh-manager/dist/index.js
+```
+