feat: mcpctl v0.0.1 — first public release
Comprehensive MCP server management with kubectl-style CLI. Key features in this release: - Declarative YAML apply/get round-trip with project cloning support - Gated sessions with prompt intelligence for Claude - Interactive MCP console with traffic inspector - Persistent STDIO connections for containerized servers - RBAC with name-scoped bindings - Shell completions (fish + bash) auto-generated - Rate-limit retry with exponential backoff in apply - Project-scoped prompt management - Credential scrubbing from git history Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,28 +1,32 @@
|
||||
# mcpctl bash completions — auto-generated by scripts/generate-completions.ts
|
||||
# DO NOT EDIT MANUALLY — run: pnpm completions:generate
|
||||
|
||||
_mcpctl() {
|
||||
local cur prev words cword
|
||||
_init_completion || return
|
||||
|
||||
local commands="status login logout config get describe delete logs create edit apply backup restore mcp console approve 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 prompts promptrequests"
|
||||
local commands="status login logout config get describe delete logs create edit apply patch backup restore approve console"
|
||||
local project_commands="get describe delete logs create edit attach-server detach-server"
|
||||
local global_opts="-v --version --daemon-url --direct -p --project -h --help"
|
||||
local resources="servers instances secrets templates projects users groups rbac prompts promptrequests serverattachments all"
|
||||
local resource_aliases="servers instances secrets templates projects users groups rbac prompts promptrequests serverattachments all server srv instance inst secret sec template tpl project proj user group rbac-definition rbac-binding prompt promptrequest pr serverattachment sa"
|
||||
|
||||
# Check if --project was given
|
||||
# Check if --project/-p was given
|
||||
local has_project=false
|
||||
local i
|
||||
for ((i=1; i < cword; i++)); do
|
||||
if [[ "${words[i]}" == "--project" ]]; then
|
||||
if [[ "${words[i]}" == "--project" || "${words[i]}" == "-p" ]]; then
|
||||
has_project=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Find the first subcommand (skip --project and its argument, skip flags)
|
||||
# Find the first subcommand
|
||||
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
|
||||
if [[ "${words[i]}" == "--project" || "${words[i]}" == "--daemon-url" || "${words[i]}" == "-p" ]]; then
|
||||
((i++))
|
||||
continue
|
||||
fi
|
||||
if [[ "${words[i]}" != -* ]]; then
|
||||
@@ -32,116 +36,215 @@ _mcpctl() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Find the resource type after get/describe/delete/edit
|
||||
# Find the resource type after resource commands
|
||||
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
|
||||
if [[ "${words[i]}" != -* ]] && [[ " $resource_aliases " == *" ${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 | jq -r '.[][].name' 2>/dev/null)
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
|
||||
# Fetch resource names dynamically (jq extracts only top-level names)
|
||||
_mcpctl_resource_names() {
|
||||
local rt="$1"
|
||||
if [[ -n "$rt" ]]; then
|
||||
# Instances don't have a name field — use server.name instead
|
||||
if [[ "$rt" == "instances" ]]; then
|
||||
mcpctl get instances -o json 2>/dev/null | jq -r '.[][].server.name' 2>/dev/null
|
||||
else
|
||||
mcpctl get "$rt" -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the --project value from the command line
|
||||
# Helper: get --project/-p value
|
||||
_mcpctl_get_project_value() {
|
||||
local i
|
||||
for ((i=1; i < cword; i++)); do
|
||||
if [[ "${words[i]}" == "--project" ]] && (( i+1 < cword )); then
|
||||
if [[ "${words[i]}" == "--project" || "${words[i]}" == "-p" ]] && (( i+1 < cword )); then
|
||||
echo "${words[i+1]}"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case "$subcmd" in
|
||||
config)
|
||||
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
||||
COMPREPLY=($(compgen -W "view set path reset claude claude-generate setup impersonate help" -- "$cur"))
|
||||
# Helper: fetch resource names
|
||||
_mcpctl_resource_names() {
|
||||
local rt="$1"
|
||||
if [[ -n "$rt" ]]; then
|
||||
if [[ "$rt" == "instances" ]]; then
|
||||
mcpctl get instances -o json 2>/dev/null | jq -r '.[][].server.name' 2>/dev/null
|
||||
else
|
||||
mcpctl get "$rt" -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null
|
||||
fi
|
||||
return ;;
|
||||
fi
|
||||
}
|
||||
|
||||
# Helper: find sub-subcommand (for config/create)
|
||||
_mcpctl_get_subcmd() {
|
||||
local parent_pos="$1"
|
||||
local i
|
||||
for ((i=parent_pos+1; i < cword; i++)); do
|
||||
if [[ "${words[i]}" != -* ]]; then
|
||||
echo "${words[i]}"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# If completing option values
|
||||
if [[ "$prev" == "--project" || "$prev" == "-p" ]]; then
|
||||
local names
|
||||
names=$(mcpctl get projects -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
|
||||
case "$subcmd" in
|
||||
status)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "-o --output -h --help" -- "$cur"))
|
||||
return ;;
|
||||
login)
|
||||
COMPREPLY=($(compgen -W "--url --email --password -h --help" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "--mcpd-url -h --help" -- "$cur"))
|
||||
return ;;
|
||||
logout)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
return ;;
|
||||
mcp)
|
||||
return ;;
|
||||
console)
|
||||
# First arg is project name
|
||||
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
||||
local names
|
||||
names=$(mcpctl get projects -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null)
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
config)
|
||||
local config_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
||||
if [[ -z "$config_sub" ]]; then
|
||||
COMPREPLY=($(compgen -W "view set path reset claude claude-generate setup impersonate help" -- "$cur"))
|
||||
else
|
||||
case "$config_sub" in
|
||||
view)
|
||||
COMPREPLY=($(compgen -W "-o --output -h --help" -- "$cur"))
|
||||
;;
|
||||
set)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
path)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
reset)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
claude)
|
||||
COMPREPLY=($(compgen -W "--project -o --output --inspect --stdout -h --help" -- "$cur"))
|
||||
;;
|
||||
claude-generate)
|
||||
COMPREPLY=($(compgen -W "--project -o --output --inspect --stdout -h --help" -- "$cur"))
|
||||
;;
|
||||
setup)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
impersonate)
|
||||
COMPREPLY=($(compgen -W "--quit -h --help" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
return ;;
|
||||
get|describe|delete)
|
||||
get)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "$resources" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "$resources -o --output --project -A --all -h --help" -- "$cur"))
|
||||
else
|
||||
local names
|
||||
names=$(_mcpctl_resource_names "$resource_type")
|
||||
COMPREPLY=($(compgen -W "$names -o --output -h --help" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "$names -o --output --project -A --all -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
describe)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "$resources -o --output --show-values -h --help" -- "$cur"))
|
||||
else
|
||||
local names
|
||||
names=$(_mcpctl_resource_names "$resource_type")
|
||||
COMPREPLY=($(compgen -W "$names -o --output --show-values -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
delete)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "$resources --project -h --help" -- "$cur"))
|
||||
else
|
||||
local names
|
||||
names=$(_mcpctl_resource_names "$resource_type")
|
||||
COMPREPLY=($(compgen -W "$names --project -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
logs)
|
||||
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
||||
local names
|
||||
names=$(mcpctl get instances -o json 2>/dev/null | jq -r '.[][].server.name' 2>/dev/null)
|
||||
COMPREPLY=($(compgen -W "$names -t --tail -i --instance -h --help" -- "$cur"))
|
||||
else
|
||||
COMPREPLY=($(compgen -W "-t --tail -i --instance -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
create)
|
||||
local create_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
||||
if [[ -z "$create_sub" ]]; then
|
||||
COMPREPLY=($(compgen -W "server secret project user group rbac prompt serverattachment promptrequest help" -- "$cur"))
|
||||
else
|
||||
case "$create_sub" in
|
||||
server)
|
||||
COMPREPLY=($(compgen -W "-d --description --package-name --docker-image --transport --repository-url --external-url --command --container-port --replicas --env --from-template --env-from-secret --force -h --help" -- "$cur"))
|
||||
;;
|
||||
secret)
|
||||
COMPREPLY=($(compgen -W "--data --force -h --help" -- "$cur"))
|
||||
;;
|
||||
project)
|
||||
COMPREPLY=($(compgen -W "-d --description --proxy-mode --prompt --gated --no-gated --server --force -h --help" -- "$cur"))
|
||||
;;
|
||||
user)
|
||||
COMPREPLY=($(compgen -W "--password --name --force -h --help" -- "$cur"))
|
||||
;;
|
||||
group)
|
||||
COMPREPLY=($(compgen -W "--description --member --force -h --help" -- "$cur"))
|
||||
;;
|
||||
rbac)
|
||||
COMPREPLY=($(compgen -W "--subject --binding --operation --force -h --help" -- "$cur"))
|
||||
;;
|
||||
prompt)
|
||||
COMPREPLY=($(compgen -W "--project --content --content-file --priority --link -h --help" -- "$cur"))
|
||||
;;
|
||||
serverattachment)
|
||||
COMPREPLY=($(compgen -W "--project -h --help" -- "$cur"))
|
||||
;;
|
||||
promptrequest)
|
||||
COMPREPLY=($(compgen -W "--project --content --content-file --priority -h --help" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
return ;;
|
||||
edit)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "servers projects" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "servers secrets projects groups rbac prompts promptrequests -h --help" -- "$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"))
|
||||
apply)
|
||||
COMPREPLY=($(compgen -f -W "-f --file --dry-run -h --help" -- "$cur"))
|
||||
return ;;
|
||||
create)
|
||||
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
||||
COMPREPLY=($(compgen -W "server secret project user group rbac prompt promptrequest help" -- "$cur"))
|
||||
patch)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "$resources -h --help" -- "$cur"))
|
||||
else
|
||||
local names
|
||||
names=$(_mcpctl_resource_names "$resource_type")
|
||||
COMPREPLY=($(compgen -W "$names -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
apply)
|
||||
COMPREPLY=($(compgen -f -- "$cur"))
|
||||
return ;;
|
||||
backup)
|
||||
COMPREPLY=($(compgen -W "-o --output -p --password -h --help" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "-o --output -p --password -r --resources -h --help" -- "$cur"))
|
||||
return ;;
|
||||
restore)
|
||||
COMPREPLY=($(compgen -W "-i --input -p --password -c --conflict -h --help" -- "$cur"))
|
||||
return ;;
|
||||
attach-server)
|
||||
# Only complete if no server arg given yet (first arg after subcmd)
|
||||
if [[ $((cword - subcmd_pos)) -ne 1 ]]; then return; fi
|
||||
local proj names all_servers proj_servers
|
||||
proj=$(_mcpctl_get_project_value)
|
||||
if [[ -n "$proj" ]]; then
|
||||
all_servers=$(mcpctl get servers -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null)
|
||||
proj_servers=$(mcpctl --project "$proj" get servers -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null)
|
||||
all_servers=$(mcpctl get servers -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
||||
proj_servers=$(mcpctl --project "$proj" get servers -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
||||
names=$(comm -23 <(echo "$all_servers" | sort) <(echo "$proj_servers" | sort))
|
||||
else
|
||||
names=$(_mcpctl_resource_names "servers")
|
||||
@@ -149,22 +252,33 @@ _mcpctl() {
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
return ;;
|
||||
detach-server)
|
||||
# Only complete if no server arg given yet (first arg after subcmd)
|
||||
if [[ $((cword - subcmd_pos)) -ne 1 ]]; then return; fi
|
||||
local proj names
|
||||
proj=$(_mcpctl_get_project_value)
|
||||
if [[ -n "$proj" ]]; then
|
||||
names=$(mcpctl --project "$proj" get servers -o json 2>/dev/null | jq -r '.[][].name' 2>/dev/null)
|
||||
names=$(mcpctl --project "$proj" get servers -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
||||
fi
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
return ;;
|
||||
approve)
|
||||
if [[ -z "$resource_type" ]]; then
|
||||
COMPREPLY=($(compgen -W "promptrequest" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "promptrequest -h --help" -- "$cur"))
|
||||
else
|
||||
local names
|
||||
names=$(_mcpctl_resource_names "$resource_type")
|
||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||
COMPREPLY=($(compgen -W "$names -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
mcp)
|
||||
COMPREPLY=($(compgen -W "-p --project -h --help" -- "$cur"))
|
||||
return ;;
|
||||
console)
|
||||
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
||||
local names
|
||||
names=$(mcpctl get projects -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
||||
COMPREPLY=($(compgen -W "$names --inspect --stdin-mcp -h --help" -- "$cur"))
|
||||
else
|
||||
COMPREPLY=($(compgen -W "--inspect --stdin-mcp -h --help" -- "$cur"))
|
||||
fi
|
||||
return ;;
|
||||
help)
|
||||
|
||||
Reference in New Issue
Block a user