_mcpctl() { local cur prev words cword _init_completion || return local commands="status login logout config get describe delete logs create edit apply backup restore help" local project_commands="attach-server detach-server get describe delete logs create edit help" local global_opts="-v --version --daemon-url --direct --project -h --help" local resources="servers instances secrets templates projects users groups rbac" # Check if --project was given local has_project=false local i for ((i=1; i < cword; i++)); do if [[ "${words[i]}" == "--project" ]]; then has_project=true break fi done # Find the first subcommand (skip --project and its argument, skip flags) local subcmd="" local subcmd_pos=0 for ((i=1; i < cword; i++)); do if [[ "${words[i]}" == "--project" || "${words[i]}" == "--daemon-url" ]]; then ((i++)) # skip the argument continue fi if [[ "${words[i]}" != -* ]]; then subcmd="${words[i]}" subcmd_pos=$i break fi done # Find the resource type after get/describe/delete/edit local resource_type="" if [[ -n "$subcmd_pos" ]] && [[ $subcmd_pos -gt 0 ]]; then for ((i=subcmd_pos+1; i < cword; i++)); do if [[ "${words[i]}" != -* ]] && [[ " $resources " == *" ${words[i]} "* ]]; then resource_type="${words[i]}" break fi done fi # If completing the --project value if [[ "$prev" == "--project" ]]; then local names names=$(mcpctl get projects -o json 2>/dev/null | grep -oP '"name":\s*"\K[^"]+') COMPREPLY=($(compgen -W "$names" -- "$cur")) return fi # Fetch resource names dynamically _mcpctl_resource_names() { local rt="$1" if [[ -n "$rt" ]]; then mcpctl get "$rt" -o json 2>/dev/null | grep -oP '"name":\s*"\K[^"]+' fi } case "$subcmd" in config) if [[ $((cword - subcmd_pos)) -eq 1 ]]; then COMPREPLY=($(compgen -W "view set path reset claude-generate impersonate help" -- "$cur")) fi return ;; status) COMPREPLY=($(compgen -W "-h --help" -- "$cur")) return ;; login) COMPREPLY=($(compgen -W "--url --email --password -h --help" -- "$cur")) return ;; logout) return ;; get|describe|delete) if [[ -z "$resource_type" ]]; then COMPREPLY=($(compgen -W "$resources" -- "$cur")) else local names names=$(_mcpctl_resource_names "$resource_type") COMPREPLY=($(compgen -W "$names -o --output -h --help" -- "$cur")) fi return ;; edit) if [[ -z "$resource_type" ]]; then COMPREPLY=($(compgen -W "servers projects" -- "$cur")) else local names names=$(_mcpctl_resource_names "$resource_type") COMPREPLY=($(compgen -W "$names -h --help" -- "$cur")) fi return ;; logs) COMPREPLY=($(compgen -W "--tail --since -f --follow -h --help" -- "$cur")) return ;; create) if [[ $((cword - subcmd_pos)) -eq 1 ]]; then COMPREPLY=($(compgen -W "server secret project user group rbac help" -- "$cur")) fi return ;; apply) COMPREPLY=($(compgen -f -- "$cur")) return ;; backup) COMPREPLY=($(compgen -W "-o --output -p --password -h --help" -- "$cur")) return ;; restore) COMPREPLY=($(compgen -W "-i --input -p --password -c --conflict -h --help" -- "$cur")) return ;; attach-server|detach-server) local names names=$(_mcpctl_resource_names "servers") COMPREPLY=($(compgen -W "$names" -- "$cur")) return ;; help) COMPREPLY=($(compgen -W "$commands" -- "$cur")) return ;; esac # No subcommand yet — offer commands based on context if [[ -z "$subcmd" ]]; then if $has_project; then COMPREPLY=($(compgen -W "$project_commands $global_opts" -- "$cur")) else COMPREPLY=($(compgen -W "$commands $global_opts" -- "$cur")) fi fi } complete -F _mcpctl mcpctl