#!/usr/bin/env bash # Vikunja MCP 启动包装。 # # 存在理由: # 1. 凭据只留在 vikunja.env(已 gitignore),不进 .mcp.json、不进仓库、不进 shell 历史。 # 2. @0xk3vin/vikunja-mcp 内部自己拼 /api/v1(dist/vikunja-client.js:128), # 而 vikunja.env 里的 apiurl 是带 /api/v1 的完整地址。直接透传会请求 # /api/v1/api/v1/... 并 404,所以这里必须剥掉一次。 # 3. 版本写死。上游改了工具名或行为会直接改变 agent 行为,与 # 「交付产物新旧以 SHA-256 判断」同源,不接受静默升级。 # 4. 优先用全局安装的二进制,起得快且不依赖网络;缺失时才回退 npx。 # # 本脚本不含凭据,必须提交进仓库:其他 agent 与其他机器都靠它接入同一套配置。 set -euo pipefail MCP_VERSION="${VIKUNJA_MCP_VERSION:-1.1.1}" REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # 凭据查找顺序:显式指定 > 仓库根目录 > 旧的家目录位置(向后兼容)。 find_env_file() { if [ -n "${VIKUNJA_ENV_FILE:-}" ]; then printf '%s\n' "$VIKUNJA_ENV_FILE" return fi for candidate in "$REPO_ROOT/vikunja.env" "$HOME/.config/vikunja/env" "$HOME/.claude/vikunja.env"; do if [ -r "$candidate" ]; then printf '%s\n' "$candidate" return fi done printf '%s\n' "$REPO_ROOT/vikunja.env" } ENV_FILE="$(find_env_file)" if [ ! -r "$ENV_FILE" ]; then echo "vikunja-mcp: 读不到凭据文件 $ENV_FILE(参照 vikunja.env.example 创建)" >&2 exit 1 fi # 只取需要的两个键,忽略文件里其余内容;tr -d '\r' 兼容 Windows 侧写出的 CRLF。 read_key() { sed -n "s/^[[:space:]]*$1[[:space:]]*=[[:space:]]*//Ip" "$ENV_FILE" | tr -d '\r' | tail -n1 } apiurl="$(read_key apiurl)" apikey="$(read_key apikey)" if [ -z "$apiurl" ] || [ -z "$apikey" ]; then echo "vikunja-mcp: $ENV_FILE 缺少 apiurl 或 apikey" >&2 exit 1 fi VIKUNJA_URL="${apiurl%/}" VIKUNJA_URL="${VIKUNJA_URL%/api/v1}" export VIKUNJA_URL export VIKUNJA_API_TOKEN="$apikey" # 全局安装存在且版本相符时直接用它;否则回退 npx(首次启动会联网拉包)。 if command -v vikunja-mcp >/dev/null 2>&1 && [ "$(npm ls -g --depth=0 --json @0xk3vin/vikunja-mcp 2>/dev/null | sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' | tail -n1)" = "$MCP_VERSION" ]; then exec vikunja-mcp "$@" fi exec npx -y "@0xk3vin/vikunja-mcp@${MCP_VERSION}" "$@"