Last active
September 8, 2026 10:42
-
-
Save Finndersen/c1b477f7c3489757140bb68643124277 to your computer and use it in GitHub Desktop.
Share Cursor CLI MCP OAuth across git worktrees. Wire as a workspace setup script (e.g. Superset) so each new worktree's mcp-auth.json is symlinked to ~/.cursor/shared/mcp-auth.json.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Point this checkout's Cursor MCP OAuth store at the shared one. | |
| # | |
| # Configure this as a workspace setup script for whatever tool creates | |
| # worktrees (e.g. Superset `.superset/config.json` setup). Run it from the | |
| # new workspace so each worktree's Cursor auth file is linked on create. | |
| # | |
| # Cursor CLI keys MCP OAuth tokens by git repo root: | |
| # ~/.cursor/projects/<slug>/mcp-auth.json | |
| # so every git worktree starts with an empty store and every server shows as | |
| # unauthenticated. Symlinking each store at the shared file makes auth global. | |
| # The CLI writes this file in place, so the symlink survives. | |
| # If the shared file does not exist yet, it is created (seeded from this | |
| # worktree's tokens when present). If ~/.cursor is missing (Cursor not | |
| # installed), the script exits 0 and does nothing. | |
| set -euo pipefail | |
| SHARED="${HOME}/.cursor/shared/mcp-auth.json" | |
| cursor_project_slug() { | |
| local path="$1" | |
| case "$path" in | |
| /*) ;; | |
| *) path="$(cd "$path" && pwd)" ;; | |
| esac | |
| path="${path#/}" | |
| local slug="" component rest="$path" | |
| while [ -n "$rest" ]; do | |
| case "$rest" in | |
| */*) | |
| component="${rest%%/*}" | |
| rest="${rest#*/}" | |
| ;; | |
| *) | |
| component="$rest" | |
| rest="" | |
| ;; | |
| esac | |
| # .superset -> superset; remaining dots become dashes via tr below | |
| while [[ "$component" == .* ]]; do | |
| component="${component#.}" | |
| done | |
| component="$(printf '%s' "$component" | tr -C 'A-Za-z0-9-' '-')" | |
| while [[ "$component" == -* ]]; do component="${component#-}"; done | |
| while [[ "$component" == *- ]]; do component="${component%-}"; done | |
| if [ -n "$component" ]; then | |
| if [ -n "$slug" ]; then | |
| slug="${slug}-${component}" | |
| else | |
| slug="$component" | |
| fi | |
| fi | |
| done | |
| printf '%s' "$slug" | |
| } | |
| if [ ! -d "${HOME}/.cursor" ]; then | |
| echo "link-mcp-auth: ~/.cursor not found, skipping (Cursor not installed)" >&2 | |
| exit 0 | |
| fi | |
| root="$(git -C "${1:-$PWD}" rev-parse --show-toplevel 2>/dev/null || echo "${1:-$PWD}")" | |
| slug="$(cursor_project_slug "$root")" | |
| target="${HOME}/.cursor/projects/${slug}/mcp-auth.json" | |
| mkdir -p "$(dirname "$SHARED")" "$(dirname "$target")" | |
| # First run for this machine: create the shared store. Prefer seeding from | |
| # this worktree's existing tokens rather than starting empty. | |
| if [ ! -f "$SHARED" ]; then | |
| if [ -f "$target" ] && [ ! -L "$target" ]; then | |
| mv "$target" "$SHARED" | |
| echo "link-mcp-auth: seeded shared store from ${slug}" | |
| else | |
| printf '{}\n' > "$SHARED" | |
| chmod 600 "$SHARED" | |
| echo "link-mcp-auth: created empty shared store" | |
| fi | |
| fi | |
| if [ -L "$target" ] && [ "$(readlink "$target")" = "$SHARED" ]; then | |
| exit 0 | |
| fi | |
| # If this path is already a regular file, ln -sfn would unlink it. Keep a | |
| # timestamped copy so tokens unique to this worktree are not discarded. | |
| if [ -e "$target" ] && [ ! -L "$target" ]; then | |
| mv "$target" "${target}.bak.$(date +%Y%m%d%H%M%S)" | |
| fi | |
| ln -sfn "$SHARED" "$target" | |
| echo "link-mcp-auth: ${slug} -> shared store" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment