2026-02-27 17:05:05 +00:00
|
|
|
# mcpctl bash completions — auto-generated by scripts/generate-completions.ts
|
|
|
|
|
# DO NOT EDIT MANUALLY — run: pnpm completions:generate
|
|
|
|
|
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
_mcpctl() {
|
|
|
|
|
local cur prev words cword
|
|
|
|
|
_init_completion || return
|
|
|
|
|
|
2026-04-29 15:58:46 +01:00
|
|
|
local commands="status login logout config get describe delete logs create edit apply chat chat-llm patch backup approve console cache provider test migrate rotate"
|
2026-02-27 17:05:05 +00:00
|
|
|
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"
|
feat(cli+docs+smoke): inference-task CLI + GC ticker + smoke + docs (v5 Stage 4)
CLI surface for the durable queue:
- `mcpctl get tasks` — table view (ID, STATUS, POOL, LLM, MODEL,
STREAM, AGE, WORKER). Aliases `task`, `tasks`, `inference-task`,
`inference-tasks` all normalize to the canonical plural so URL
construction works uniformly. RESOURCE_ALIASES + completions
generator updated.
- `mcpctl chat-llm <name> --async -m <msg>` — enqueue and exit. stdout
is just the task id (pipeable into `xargs mcpctl get task`); stderr
carries human-readable status. REPL mode is rejected for --async
(fire-and-forget doesn't make sense without -m).
GC ticker in mcpd: 5-min interval. Pending tasks past 1 h queue
timeout flip to error with a clear message; terminal tasks past 7 d
retention get deleted. Both queries are index-backed.
Crash fix uncovered by the smoke: when the async route doesn't await
ref.done, a later cancel/error rejected the in-flight Promise as
unhandled and crashed mcpd. The route now attaches a no-op `.catch`
so the legacy `done` semantic still works for sync callers (chat,
direct infer) without taking out the process for async ones. The
EnqueueInferOptions also gained an explicit `ownerId` field so the
async API can stamp the authenticated user on the row instead of
inheriting 'system' from the constructor's resolveOwner — without
this, every GET/DELETE from the original caller would 404 due to
foreign-owner mismatch.
Smoke (tests/smoke/inference-task.smoke.test.ts):
1. POST /inference-tasks while no worker bound → row=pending.
2. Bring a registrar online → bindSession drain claims and
dispatches → worker complete()s → row=completed → GET returns
the assistant body.
3. Stop worker, enqueue, DELETE → row=cancelled, persisted.
docs/inference-tasks.md (new): full data model, lifecycle diagram,
async API reference, CLI examples, RBAC table, GC defaults, and the
v5 limitations / v6 roadmap. Cross-linked from virtual-llms.md and
agents.md.
Tests + smoke: mcpd 893/893, mcplocal 723/723, cli 437/437, full
smoke 146/146 (was 144, +2 new task smoke). Live mcpd verified via
manual curl: enqueue → cancel → re-fetch — no crash, owner scoping
returns 404 on foreign ids, GC ticker logs at info when it sweeps.
v5 complete: durable queue (Stage 1) + VirtualLlmService rewire
(Stage 2) + async API & RBAC (Stage 3) + CLI/GC/smoke/docs (Stage 4).
2026-04-28 15:25:09 +01:00
|
|
|
local resources="servers instances secrets secretbackends llms agents personalities templates projects users groups rbac prompts promptrequests serverattachments proxymodels inference-tasks all"
|
|
|
|
|
local resource_aliases="servers instances secrets secretbackends llms agents personalities templates projects users groups rbac prompts promptrequests serverattachments proxymodels inference-tasks all server srv instance inst secret sec secretbackend sb llm agent personality template tpl project proj user group rbac-definition rbac-binding prompt promptrequest pr serverattachment sa proxymodel pm task tasks inference-task"
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Check if --project/-p was given
|
2026-02-23 19:08:29 +00:00
|
|
|
local has_project=false
|
|
|
|
|
local i
|
|
|
|
|
for ((i=1; i < cword; i++)); do
|
2026-02-27 17:05:05 +00:00
|
|
|
if [[ "${words[i]}" == "--project" || "${words[i]}" == "-p" ]]; then
|
2026-02-23 19:08:29 +00:00
|
|
|
has_project=true
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Find the first subcommand
|
2026-02-23 19:08:29 +00:00
|
|
|
local subcmd=""
|
|
|
|
|
local subcmd_pos=0
|
|
|
|
|
for ((i=1; i < cword; i++)); do
|
2026-02-27 17:05:05 +00:00
|
|
|
if [[ "${words[i]}" == "--project" || "${words[i]}" == "--daemon-url" || "${words[i]}" == "-p" ]]; then
|
|
|
|
|
((i++))
|
2026-02-23 19:08:29 +00:00
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
if [[ "${words[i]}" != -* ]]; then
|
|
|
|
|
subcmd="${words[i]}"
|
|
|
|
|
subcmd_pos=$i
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Find the resource type after resource commands
|
2026-02-23 19:08:29 +00:00
|
|
|
local resource_type=""
|
|
|
|
|
if [[ -n "$subcmd_pos" ]] && [[ $subcmd_pos -gt 0 ]]; then
|
|
|
|
|
for ((i=subcmd_pos+1; i < cword; i++)); do
|
2026-02-27 17:05:05 +00:00
|
|
|
if [[ "${words[i]}" != -* ]] && [[ " $resource_aliases " == *" ${words[i]} "* ]]; then
|
2026-02-23 19:08:29 +00:00
|
|
|
resource_type="${words[i]}"
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Helper: get --project/-p value
|
|
|
|
|
_mcpctl_get_project_value() {
|
|
|
|
|
local i
|
|
|
|
|
for ((i=1; i < cword; i++)); do
|
|
|
|
|
if [[ "${words[i]}" == "--project" || "${words[i]}" == "-p" ]] && (( i+1 < cword )); then
|
|
|
|
|
echo "${words[i+1]}"
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
2026-02-23 19:08:29 +00:00
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Helper: fetch resource names
|
2026-02-23 19:08:29 +00:00
|
|
|
_mcpctl_resource_names() {
|
|
|
|
|
local rt="$1"
|
|
|
|
|
if [[ -n "$rt" ]]; then
|
2026-02-23 19:32:18 +00:00
|
|
|
if [[ "$rt" == "instances" ]]; then
|
|
|
|
|
mcpctl get instances -o json 2>/dev/null | jq -r '.[][].server.name' 2>/dev/null
|
|
|
|
|
else
|
2026-02-27 17:05:05 +00:00
|
|
|
mcpctl get "$rt" -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null
|
2026-02-23 19:32:18 +00:00
|
|
|
fi
|
2026-02-23 19:08:29 +00:00
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# Helper: find sub-subcommand (for config/create)
|
|
|
|
|
_mcpctl_get_subcmd() {
|
|
|
|
|
local parent_pos="$1"
|
2026-02-23 19:32:18 +00:00
|
|
|
local i
|
2026-02-27 17:05:05 +00:00
|
|
|
for ((i=parent_pos+1; i < cword; i++)); do
|
|
|
|
|
if [[ "${words[i]}" != -* ]]; then
|
|
|
|
|
echo "${words[i]}"
|
2026-02-23 19:32:18 +00:00
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-27 17:05:05 +00:00
|
|
|
# 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
|
|
|
|
|
|
2026-02-23 19:08:29 +00:00
|
|
|
case "$subcmd" in
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
status)
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "-o --output -h --help" -- "$cur"))
|
2026-02-23 12:00:31 +00:00
|
|
|
return ;;
|
|
|
|
|
login)
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "--mcpd-url -h --help" -- "$cur"))
|
2026-02-23 12:00:31 +00:00
|
|
|
return ;;
|
|
|
|
|
logout)
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
return ;;
|
2026-02-27 17:05:05 +00:00
|
|
|
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)
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "-p --project -o --output --inspect --stdout -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
claude-generate)
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "-p --project -o --output --inspect --stdout -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
setup)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
impersonate)
|
|
|
|
|
COMPREPLY=($(compgen -W "--quit -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
2026-02-24 00:52:05 +00:00
|
|
|
return ;;
|
2026-02-27 17:05:05 +00:00
|
|
|
get)
|
|
|
|
|
if [[ -z "$resource_type" ]]; then
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "$resources -o --output -p --project -A --all -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
else
|
2026-02-25 23:56:23 +00:00
|
|
|
local names
|
2026-02-27 17:05:05 +00:00
|
|
|
names=$(_mcpctl_resource_names "$resource_type")
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "$names -o --output -p --project -A --all -h --help" -- "$cur"))
|
2026-02-25 23:56:23 +00:00
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-02-27 17:05:05 +00:00
|
|
|
describe)
|
2026-02-23 19:08:29 +00:00
|
|
|
if [[ -z "$resource_type" ]]; then
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "$resources -o --output --show-values -h --help" -- "$cur"))
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
else
|
2026-02-23 19:08:29 +00:00
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "$resource_type")
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "$names -o --output --show-values -h --help" -- "$cur"))
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-02-27 17:05:05 +00:00
|
|
|
delete)
|
2026-02-23 19:08:29 +00:00
|
|
|
if [[ -z "$resource_type" ]]; then
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "$resources -p --project --agent -h --help" -- "$cur"))
|
2026-02-23 19:08:29 +00:00
|
|
|
else
|
|
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "$resource_type")
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "$names -p --project --agent -h --help" -- "$cur"))
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-02-23 12:00:31 +00:00
|
|
|
logs)
|
2026-02-27 17:05:05 +00:00
|
|
|
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
|
2026-02-23 12:00:31 +00:00
|
|
|
return ;;
|
|
|
|
|
create)
|
2026-02-27 17:05:05 +00:00
|
|
|
local create_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$create_sub" ]]; then
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "server secret llm agent secretbackend project user group rbac mcptoken prompt personality serverattachment promptrequest help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
else
|
|
|
|
|
case "$create_sub" in
|
|
|
|
|
server)
|
2026-03-03 19:07:39 +00:00
|
|
|
COMPREPLY=($(compgen -W "-d --description --package-name --runtime --docker-image --transport --repository-url --external-url --command --container-port --replicas --env --from-template --env-from-secret --force -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
secret)
|
|
|
|
|
COMPREPLY=($(compgen -W "--data --force -h --help" -- "$cur"))
|
|
|
|
|
;;
|
feat(mcpd): Llm resource — CRUD + CLI + apply
Why: every client that wants an LLM (the agent, HTTP-mode mcplocal, Claude
Code's STDIO mcplocal) today has to know the provider URL + key, and each
user's ~/.mcpctl/config.json carries them. Centralising the catalogue on the
server is the prerequisite for Phase 2 (mcpd proxies inference so credentials
never leave the cluster).
This phase adds the `Llm` resource and its CRUD surface — no proxy yet, no
client pivot yet. Just enough to register what you have.
Schema:
- New `Llm` model: name/type/model/url/tier/description + {apiKeySecretId,
apiKeySecretKey} FK pair. Reverse `llms` relation on Secret.
- Provider types: anthropic | openai | deepseek | vllm | ollama | gemini-cli.
- Tiers: fast | heavy.
mcpd:
- LlmRepository + LlmService + Zod validation schema + /api/v1/llms routes.
- API surface exposes `apiKeyRef: {name, key}` — the service translates to/
from the FK pair so clients never deal in cuids.
- `resolveApiKey(llmName)` reads through SecretService (which itself dispatches
to the right SecretBackend). That's the hook Phase 2's inference proxy uses.
- RBAC: added `'llms'` to RBAC_RESOURCES + resource alias. Standard
view/create/edit/delete semantics.
- Wired into main.ts (repo, service, routes).
CLI:
- `mcpctl create llm <name> --type X --model Y --tier fast|heavy --api-key-ref SECRET/KEY [--url ...] [--extra k=v ...]`
- `mcpctl get|describe|delete llm` — standard resource verbs.
- `mcpctl apply -f` with `kind: llm` (single- or multi-doc yaml/json).
Applied after secrets, before servers — apiKeyRef resolves an existing Secret.
- Shell completions regenerated.
Tests: 11 service unit tests + 9 route tests (happy path, 404s, 409, validation).
Full suite 1812/1812 (+20 from the 1792 Phase 0 baseline). TypeScript clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:28:43 +01:00
|
|
|
llm)
|
feat(mcpd+cli+mcplocal): /llms/<name>/members + POOL column + --pool-name (v4 Stage 2)
Surfaces the v4 pool model end-to-end:
- mcpd: GET /api/v1/llms/:name/members returns the effective pool the
named anchor belongs to, plus aggregate stats (size, activeCount,
explicit vs implicit pool key). RBAC inherits from `view:llms` —
same as the single-Llm route. Members are full LlmView shapes so
callers don't need a second roundtrip to render the pool block.
- mcpd: VirtualLlmService.register accepts an optional `poolName` on
RegisterProviderInput; the route's `coerceProviderInput` validates
the same character set as CreateLlmSchema.poolName. Backwards
compatible — older mcplocals that don't send the field continue to
publish solo Llms.
- CLI `get llm` table: new POOL column right after NAME. Solo rows
show "-" so the "no pool / pool of 1" case is unambiguous (per
user direction "make sure we see it, prominently visible and
impossible to mistake").
- CLI `describe llm`: fetches /members and renders a Pool block at
the top of the detail view when the row is in an explicit pool OR
when its implicit pool has size > 1. Each member line shows
kind/status; the anchor row gets "← this row". Block is suppressed
for solo rows so describe stays compact in the common case.
- CLI `create llm --pool-name <name>` flag and apply schema both
accept the new field. Yaml round-trip preserves it: get -o yaml
emits `poolName: <name>`, apply -f re-imports it without diff.
Verified end-to-end against the live mcpd.
- mcplocal: LlmProviderFileEntry gains optional `poolName`; main.ts
and registrar.ts thread it through into the register payload. Use
case for distributed inference: each user's mcplocal picks a
unique `name` (e.g. `vllm-<host>-qwen3`) but a shared `poolName`
(e.g. `user-vllm-qwen3-thinking`); agents see one logical pool
that auto-grows as workers come online.
- Shell completions: regenerated from source via the existing
scripts/generate-completions.ts. `--pool-name` now suggests in
fish + bash for `mcpctl create llm`.
Tests: +3 new mcpd route tests for /members (explicit pool, solo
pool of 1, missing-anchor 404). All suites green:
mcpd 868/868 (was 865, +3),
mcplocal 723/723,
cli 437/437.
Stage 3 (next): live smoke against 2 publishers sharing a pool name +
docs.
2026-04-27 23:18:53 +01:00
|
|
|
COMPREPLY=($(compgen -W "--type --model --url --tier --description --api-key-ref --extra --pool-name --force --skip-auth-check -h --help" -- "$cur"))
|
feat(mcpd): Llm resource — CRUD + CLI + apply
Why: every client that wants an LLM (the agent, HTTP-mode mcplocal, Claude
Code's STDIO mcplocal) today has to know the provider URL + key, and each
user's ~/.mcpctl/config.json carries them. Centralising the catalogue on the
server is the prerequisite for Phase 2 (mcpd proxies inference so credentials
never leave the cluster).
This phase adds the `Llm` resource and its CRUD surface — no proxy yet, no
client pivot yet. Just enough to register what you have.
Schema:
- New `Llm` model: name/type/model/url/tier/description + {apiKeySecretId,
apiKeySecretKey} FK pair. Reverse `llms` relation on Secret.
- Provider types: anthropic | openai | deepseek | vllm | ollama | gemini-cli.
- Tiers: fast | heavy.
mcpd:
- LlmRepository + LlmService + Zod validation schema + /api/v1/llms routes.
- API surface exposes `apiKeyRef: {name, key}` — the service translates to/
from the FK pair so clients never deal in cuids.
- `resolveApiKey(llmName)` reads through SecretService (which itself dispatches
to the right SecretBackend). That's the hook Phase 2's inference proxy uses.
- RBAC: added `'llms'` to RBAC_RESOURCES + resource alias. Standard
view/create/edit/delete semantics.
- Wired into main.ts (repo, service, routes).
CLI:
- `mcpctl create llm <name> --type X --model Y --tier fast|heavy --api-key-ref SECRET/KEY [--url ...] [--extra k=v ...]`
- `mcpctl get|describe|delete llm` — standard resource verbs.
- `mcpctl apply -f` with `kind: llm` (single- or multi-doc yaml/json).
Applied after secrets, before servers — apiKeyRef resolves an existing Secret.
- Shell completions regenerated.
Tests: 11 service unit tests + 9 route tests (happy path, 404s, 409, validation).
Full suite 1812/1812 (+20 from the 1792 Phase 0 baseline). TypeScript clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:28:43 +01:00
|
|
|
;;
|
feat(agents): mcpctl chat REPL + agent CRUD + completions (Stage 5)
This is the moment the user can actually talk to an agent end-to-end:
mcpctl create llm qwen3-thinking --type openai --model qwen3-thinking \
--url http://litellm.nvidia-nim.svc.cluster.local:4000/v1 \
--api-key-ref litellm-key/API_KEY
mcpctl create agent reviewer --llm qwen3-thinking --project mcpctl-dev \
--description "I review security design — ask me after each major change."
mcpctl chat reviewer
Pieces:
* src/cli/src/commands/chat.ts (new) — REPL + one-shot. Streams the SSE
endpoint and prints text deltas to stdout as they arrive; tool_call /
tool_result events go to stderr in dim-style brackets so the chat
output stays clean. LiteLLM-style flags (--temperature / --top-p /
--top-k / --max-tokens / --seed / --stop / --allow-tool / --extra)
layer over agent.defaultParams. In-REPL slash-commands: /set KEY VAL,
/system <text>, /tools (list project's MCP servers), /clear (new
thread), /save (PATCH agent.defaultParams = current overrides),
/quit.
* src/cli/src/commands/create.ts — `create agent` mirroring the llm
pattern. Every yaml-applyable field has a corresponding flag (memory
rule); --default-temperature / --default-top-p / --default-top-k /
--default-max-tokens / --default-seed / --default-stop /
--default-extra / --default-params-file all populate agent.defaultParams.
* src/cli/src/commands/apply.ts — AgentSpecSchema accepts both `llm:
qwen3-thinking` shorthand and `llm: { name: ... }` long form; runs
after llms in the apply order so apiKey/llm references resolve. Round-
trips with `get agent foo -o yaml | apply -f -` (memory rule).
* src/cli/src/commands/get.ts — agentColumns (NAME, LLM, PROJECT,
DESCRIPTION, ID); RESOURCE_KIND mapping for yaml export.
* src/cli/src/commands/shared.ts — `agent`/`agents`/`thread`/`threads`
added to RESOURCE_ALIASES.
* src/cli/src/index.ts — wires createChatCommand into the program; passes
the resolved baseUrl + token so chat can stream SSE without going
through ApiClient (which only does buffered request/response).
* completions/mcpctl.{fish,bash} regenerated. scripts/generate-completions.ts
knows about agents (canonical + aliases) and emits a special-case
`chat)` block that completes the first arg with `mcpctl get agents`
names. tests/completions.test.ts: +9 new assertions covering agents in
the resource list, chat in the commands list, --llm flag for create
agent, agent-name completion for chat, etc.
CLI suite: 430/430 (was 421). Completions --check is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:02:38 +01:00
|
|
|
agent)
|
|
|
|
|
COMPREPLY=($(compgen -W "--llm --project --description --system-prompt --system-prompt-file --proxy-model --default-temperature --default-top-p --default-top-k --default-max-tokens --default-seed --default-stop --default-extra --default-params-file --force -h --help" -- "$cur"))
|
|
|
|
|
;;
|
2026-04-18 19:29:55 +01:00
|
|
|
secretbackend)
|
2026-04-20 17:28:05 +01:00
|
|
|
COMPREPLY=($(compgen -W "--type --description --default --url --namespace --mount --path-prefix --auth --token-secret --role --auth-mount --sa-token-path --config --wizard --setup-token --policy-name --token-role --no-promote-default --force -h --help" -- "$cur"))
|
2026-04-18 19:29:55 +01:00
|
|
|
;;
|
2026-02-27 17:05:05 +00:00
|
|
|
project)
|
2026-04-19 18:28:46 +01:00
|
|
|
COMPREPLY=($(compgen -W "-d --description --proxy-model --prompt --llm --llm-model --gated --no-gated --server --force -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
user)
|
|
|
|
|
COMPREPLY=($(compgen -W "--password --name --force -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
group)
|
|
|
|
|
COMPREPLY=($(compgen -W "--description --member --force -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
rbac)
|
2026-04-17 01:03:57 +01:00
|
|
|
COMPREPLY=($(compgen -W "--subject --roleBindings --force -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
2026-04-17 01:12:43 +01:00
|
|
|
mcptoken)
|
|
|
|
|
COMPREPLY=($(compgen -W "-p --project --rbac --bind --ttl --description --force -h --help" -- "$cur"))
|
|
|
|
|
;;
|
2026-02-27 17:05:05 +00:00
|
|
|
prompt)
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "-p --project --agent --content --content-file --priority --link -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
personality)
|
|
|
|
|
COMPREPLY=($(compgen -W "--agent --description --priority -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
serverattachment)
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "-p --project -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
promptrequest)
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "-p --project --content --content-file --priority -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
|
|
|
|
edit)
|
|
|
|
|
if [[ -z "$resource_type" ]]; then
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "servers secrets projects groups rbac prompts promptrequests personalities -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
else
|
|
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "$resource_type")
|
|
|
|
|
COMPREPLY=($(compgen -W "$names -h --help" -- "$cur"))
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
fi
|
|
|
|
|
return ;;
|
|
|
|
|
apply)
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -f -W "-f --file --dry-run -h --help" -- "$cur"))
|
|
|
|
|
return ;;
|
feat(agents): mcpctl chat REPL + agent CRUD + completions (Stage 5)
This is the moment the user can actually talk to an agent end-to-end:
mcpctl create llm qwen3-thinking --type openai --model qwen3-thinking \
--url http://litellm.nvidia-nim.svc.cluster.local:4000/v1 \
--api-key-ref litellm-key/API_KEY
mcpctl create agent reviewer --llm qwen3-thinking --project mcpctl-dev \
--description "I review security design — ask me after each major change."
mcpctl chat reviewer
Pieces:
* src/cli/src/commands/chat.ts (new) — REPL + one-shot. Streams the SSE
endpoint and prints text deltas to stdout as they arrive; tool_call /
tool_result events go to stderr in dim-style brackets so the chat
output stays clean. LiteLLM-style flags (--temperature / --top-p /
--top-k / --max-tokens / --seed / --stop / --allow-tool / --extra)
layer over agent.defaultParams. In-REPL slash-commands: /set KEY VAL,
/system <text>, /tools (list project's MCP servers), /clear (new
thread), /save (PATCH agent.defaultParams = current overrides),
/quit.
* src/cli/src/commands/create.ts — `create agent` mirroring the llm
pattern. Every yaml-applyable field has a corresponding flag (memory
rule); --default-temperature / --default-top-p / --default-top-k /
--default-max-tokens / --default-seed / --default-stop /
--default-extra / --default-params-file all populate agent.defaultParams.
* src/cli/src/commands/apply.ts — AgentSpecSchema accepts both `llm:
qwen3-thinking` shorthand and `llm: { name: ... }` long form; runs
after llms in the apply order so apiKey/llm references resolve. Round-
trips with `get agent foo -o yaml | apply -f -` (memory rule).
* src/cli/src/commands/get.ts — agentColumns (NAME, LLM, PROJECT,
DESCRIPTION, ID); RESOURCE_KIND mapping for yaml export.
* src/cli/src/commands/shared.ts — `agent`/`agents`/`thread`/`threads`
added to RESOURCE_ALIASES.
* src/cli/src/index.ts — wires createChatCommand into the program; passes
the resolved baseUrl + token so chat can stream SSE without going
through ApiClient (which only does buffered request/response).
* completions/mcpctl.{fish,bash} regenerated. scripts/generate-completions.ts
knows about agents (canonical + aliases) and emits a special-case
`chat)` block that completes the first arg with `mcpctl get agents`
names. tests/completions.test.ts: +9 new assertions covering agents in
the resource list, chat in the commands list, --llm flag for create
agent, agent-name completion for chat, etc.
CLI suite: 430/430 (was 421). Completions --check is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:02:38 +01:00
|
|
|
chat)
|
|
|
|
|
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
|
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "agents")
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "$names -m --message --thread --system --system-file --system-append --personality --temperature --top-p --top-k --max-tokens --seed --stop --allow-tool --extra --no-stream -h --help" -- "$cur"))
|
feat(agents): mcpctl chat REPL + agent CRUD + completions (Stage 5)
This is the moment the user can actually talk to an agent end-to-end:
mcpctl create llm qwen3-thinking --type openai --model qwen3-thinking \
--url http://litellm.nvidia-nim.svc.cluster.local:4000/v1 \
--api-key-ref litellm-key/API_KEY
mcpctl create agent reviewer --llm qwen3-thinking --project mcpctl-dev \
--description "I review security design — ask me after each major change."
mcpctl chat reviewer
Pieces:
* src/cli/src/commands/chat.ts (new) — REPL + one-shot. Streams the SSE
endpoint and prints text deltas to stdout as they arrive; tool_call /
tool_result events go to stderr in dim-style brackets so the chat
output stays clean. LiteLLM-style flags (--temperature / --top-p /
--top-k / --max-tokens / --seed / --stop / --allow-tool / --extra)
layer over agent.defaultParams. In-REPL slash-commands: /set KEY VAL,
/system <text>, /tools (list project's MCP servers), /clear (new
thread), /save (PATCH agent.defaultParams = current overrides),
/quit.
* src/cli/src/commands/create.ts — `create agent` mirroring the llm
pattern. Every yaml-applyable field has a corresponding flag (memory
rule); --default-temperature / --default-top-p / --default-top-k /
--default-max-tokens / --default-seed / --default-stop /
--default-extra / --default-params-file all populate agent.defaultParams.
* src/cli/src/commands/apply.ts — AgentSpecSchema accepts both `llm:
qwen3-thinking` shorthand and `llm: { name: ... }` long form; runs
after llms in the apply order so apiKey/llm references resolve. Round-
trips with `get agent foo -o yaml | apply -f -` (memory rule).
* src/cli/src/commands/get.ts — agentColumns (NAME, LLM, PROJECT,
DESCRIPTION, ID); RESOURCE_KIND mapping for yaml export.
* src/cli/src/commands/shared.ts — `agent`/`agents`/`thread`/`threads`
added to RESOURCE_ALIASES.
* src/cli/src/index.ts — wires createChatCommand into the program; passes
the resolved baseUrl + token so chat can stream SSE without going
through ApiClient (which only does buffered request/response).
* completions/mcpctl.{fish,bash} regenerated. scripts/generate-completions.ts
knows about agents (canonical + aliases) and emits a special-case
`chat)` block that completes the first arg with `mcpctl get agents`
names. tests/completions.test.ts: +9 new assertions covering agents in
the resource list, chat in the commands list, --llm flag for create
agent, agent-name completion for chat, etc.
CLI suite: 430/430 (was 421). Completions --check is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:02:38 +01:00
|
|
|
else
|
2026-04-26 19:32:48 +01:00
|
|
|
COMPREPLY=($(compgen -W "-m --message --thread --system --system-file --system-append --personality --temperature --top-p --top-k --max-tokens --seed --stop --allow-tool --extra --no-stream -h --help" -- "$cur"))
|
feat(agents): mcpctl chat REPL + agent CRUD + completions (Stage 5)
This is the moment the user can actually talk to an agent end-to-end:
mcpctl create llm qwen3-thinking --type openai --model qwen3-thinking \
--url http://litellm.nvidia-nim.svc.cluster.local:4000/v1 \
--api-key-ref litellm-key/API_KEY
mcpctl create agent reviewer --llm qwen3-thinking --project mcpctl-dev \
--description "I review security design — ask me after each major change."
mcpctl chat reviewer
Pieces:
* src/cli/src/commands/chat.ts (new) — REPL + one-shot. Streams the SSE
endpoint and prints text deltas to stdout as they arrive; tool_call /
tool_result events go to stderr in dim-style brackets so the chat
output stays clean. LiteLLM-style flags (--temperature / --top-p /
--top-k / --max-tokens / --seed / --stop / --allow-tool / --extra)
layer over agent.defaultParams. In-REPL slash-commands: /set KEY VAL,
/system <text>, /tools (list project's MCP servers), /clear (new
thread), /save (PATCH agent.defaultParams = current overrides),
/quit.
* src/cli/src/commands/create.ts — `create agent` mirroring the llm
pattern. Every yaml-applyable field has a corresponding flag (memory
rule); --default-temperature / --default-top-p / --default-top-k /
--default-max-tokens / --default-seed / --default-stop /
--default-extra / --default-params-file all populate agent.defaultParams.
* src/cli/src/commands/apply.ts — AgentSpecSchema accepts both `llm:
qwen3-thinking` shorthand and `llm: { name: ... }` long form; runs
after llms in the apply order so apiKey/llm references resolve. Round-
trips with `get agent foo -o yaml | apply -f -` (memory rule).
* src/cli/src/commands/get.ts — agentColumns (NAME, LLM, PROJECT,
DESCRIPTION, ID); RESOURCE_KIND mapping for yaml export.
* src/cli/src/commands/shared.ts — `agent`/`agents`/`thread`/`threads`
added to RESOURCE_ALIASES.
* src/cli/src/index.ts — wires createChatCommand into the program; passes
the resolved baseUrl + token so chat can stream SSE without going
through ApiClient (which only does buffered request/response).
* completions/mcpctl.{fish,bash} regenerated. scripts/generate-completions.ts
knows about agents (canonical + aliases) and emits a special-case
`chat)` block that completes the first arg with `mcpctl get agents`
names. tests/completions.test.ts: +9 new assertions covering agents in
the resource list, chat in the commands list, --llm flag for create
agent, agent-name completion for chat, etc.
CLI suite: 430/430 (was 421). Completions --check is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:02:38 +01:00
|
|
|
fi
|
|
|
|
|
return ;;
|
feat(cli): mcpctl chat-llm + KIND/STATUS columns (v1 Stage 5)
Closes the loop on user-facing surface:
$ mcpctl get llm
NAME KIND STATUS TYPE MODEL TIER KEY ID
qwen3-thinking public active openai qwen3-thinking fast ... ...
vllm-local virtual active openai Qwen/Qwen2.5-7B-Instruct fast - ...
$ mcpctl chat-llm vllm-local
────────────────────────────────────────
LLM: vllm-local openai → Qwen/Qwen2.5-7B-Instruct-AWQ
Kind: virtual Status: active
────────────────────────────────────────
> hello?
Hi! …
New: chat-llm command (commands/chat-llm.ts)
- Stateless chat with any mcpd-registered LLM. No threads, no tools,
no project prompts. POSTs to /api/v1/llms/<name>/infer; mcpd's
kind=virtual branch handles relay-through-mcplocal transparently,
so the same CLI command works for both public and virtual LLMs.
- Reuses installStatusBar / formatStats / recordDelta / styleStats /
PhaseStats from chat.ts (now exported) so the bottom-row tokens-per-
second ticker behaves identically to mcpctl chat.
- Flags: --message (one-shot), --system, --temperature, --max-tokens,
--no-stream. Streaming uses OpenAI chat.completion.chunk SSE.
- REPL mode keeps a per-session history array so multi-turn flows
feel natural; each turn is an independent inference call.
Updated: get.ts
- LlmRow gains optional kind/status fields.
- llmColumns layout: NAME, KIND, STATUS, TYPE, MODEL, TIER, KEY, ID.
Defaults gracefully when older mcpd responses don't return them.
Updated: chat.ts
- Re-exports the helpers chat-llm.ts needs (PhaseStats, newPhase,
recordDelta, formatStats, styleStats, styleThinking, STDERR_IS_TTY,
StatusBar, installStatusBar). No behavior change.
Completions: chat-llm picks up the standard option enumeration
automatically; bash gets a special-case for first-arg LLM-name
completion via _mcpctl_resource_names "llms".
CLI suite: 437/437 (was 430, +7 from auto-discovered test cases in
the regenerated completions golden). Workspace: 2043/2043 across
152 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:25:38 +01:00
|
|
|
chat-llm)
|
|
|
|
|
if [[ $((cword - subcmd_pos)) -eq 1 ]]; then
|
|
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "llms")
|
feat(cli+docs+smoke): inference-task CLI + GC ticker + smoke + docs (v5 Stage 4)
CLI surface for the durable queue:
- `mcpctl get tasks` — table view (ID, STATUS, POOL, LLM, MODEL,
STREAM, AGE, WORKER). Aliases `task`, `tasks`, `inference-task`,
`inference-tasks` all normalize to the canonical plural so URL
construction works uniformly. RESOURCE_ALIASES + completions
generator updated.
- `mcpctl chat-llm <name> --async -m <msg>` — enqueue and exit. stdout
is just the task id (pipeable into `xargs mcpctl get task`); stderr
carries human-readable status. REPL mode is rejected for --async
(fire-and-forget doesn't make sense without -m).
GC ticker in mcpd: 5-min interval. Pending tasks past 1 h queue
timeout flip to error with a clear message; terminal tasks past 7 d
retention get deleted. Both queries are index-backed.
Crash fix uncovered by the smoke: when the async route doesn't await
ref.done, a later cancel/error rejected the in-flight Promise as
unhandled and crashed mcpd. The route now attaches a no-op `.catch`
so the legacy `done` semantic still works for sync callers (chat,
direct infer) without taking out the process for async ones. The
EnqueueInferOptions also gained an explicit `ownerId` field so the
async API can stamp the authenticated user on the row instead of
inheriting 'system' from the constructor's resolveOwner — without
this, every GET/DELETE from the original caller would 404 due to
foreign-owner mismatch.
Smoke (tests/smoke/inference-task.smoke.test.ts):
1. POST /inference-tasks while no worker bound → row=pending.
2. Bring a registrar online → bindSession drain claims and
dispatches → worker complete()s → row=completed → GET returns
the assistant body.
3. Stop worker, enqueue, DELETE → row=cancelled, persisted.
docs/inference-tasks.md (new): full data model, lifecycle diagram,
async API reference, CLI examples, RBAC table, GC defaults, and the
v5 limitations / v6 roadmap. Cross-linked from virtual-llms.md and
agents.md.
Tests + smoke: mcpd 893/893, mcplocal 723/723, cli 437/437, full
smoke 146/146 (was 144, +2 new task smoke). Live mcpd verified via
manual curl: enqueue → cancel → re-fetch — no crash, owner scoping
returns 404 on foreign ids, GC ticker logs at info when it sweeps.
v5 complete: durable queue (Stage 1) + VirtualLlmService rewire
(Stage 2) + async API & RBAC (Stage 3) + CLI/GC/smoke/docs (Stage 4).
2026-04-28 15:25:09 +01:00
|
|
|
COMPREPLY=($(compgen -W "$names -m --message --system --temperature --max-tokens --no-stream --async -h --help" -- "$cur"))
|
feat(cli): mcpctl chat-llm + KIND/STATUS columns (v1 Stage 5)
Closes the loop on user-facing surface:
$ mcpctl get llm
NAME KIND STATUS TYPE MODEL TIER KEY ID
qwen3-thinking public active openai qwen3-thinking fast ... ...
vllm-local virtual active openai Qwen/Qwen2.5-7B-Instruct fast - ...
$ mcpctl chat-llm vllm-local
────────────────────────────────────────
LLM: vllm-local openai → Qwen/Qwen2.5-7B-Instruct-AWQ
Kind: virtual Status: active
────────────────────────────────────────
> hello?
Hi! …
New: chat-llm command (commands/chat-llm.ts)
- Stateless chat with any mcpd-registered LLM. No threads, no tools,
no project prompts. POSTs to /api/v1/llms/<name>/infer; mcpd's
kind=virtual branch handles relay-through-mcplocal transparently,
so the same CLI command works for both public and virtual LLMs.
- Reuses installStatusBar / formatStats / recordDelta / styleStats /
PhaseStats from chat.ts (now exported) so the bottom-row tokens-per-
second ticker behaves identically to mcpctl chat.
- Flags: --message (one-shot), --system, --temperature, --max-tokens,
--no-stream. Streaming uses OpenAI chat.completion.chunk SSE.
- REPL mode keeps a per-session history array so multi-turn flows
feel natural; each turn is an independent inference call.
Updated: get.ts
- LlmRow gains optional kind/status fields.
- llmColumns layout: NAME, KIND, STATUS, TYPE, MODEL, TIER, KEY, ID.
Defaults gracefully when older mcpd responses don't return them.
Updated: chat.ts
- Re-exports the helpers chat-llm.ts needs (PhaseStats, newPhase,
recordDelta, formatStats, styleStats, styleThinking, STDERR_IS_TTY,
StatusBar, installStatusBar). No behavior change.
Completions: chat-llm picks up the standard option enumeration
automatically; bash gets a special-case for first-arg LLM-name
completion via _mcpctl_resource_names "llms".
CLI suite: 437/437 (was 430, +7 from auto-discovered test cases in
the regenerated completions golden). Workspace: 2043/2043 across
152 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:25:38 +01:00
|
|
|
else
|
feat(cli+docs+smoke): inference-task CLI + GC ticker + smoke + docs (v5 Stage 4)
CLI surface for the durable queue:
- `mcpctl get tasks` — table view (ID, STATUS, POOL, LLM, MODEL,
STREAM, AGE, WORKER). Aliases `task`, `tasks`, `inference-task`,
`inference-tasks` all normalize to the canonical plural so URL
construction works uniformly. RESOURCE_ALIASES + completions
generator updated.
- `mcpctl chat-llm <name> --async -m <msg>` — enqueue and exit. stdout
is just the task id (pipeable into `xargs mcpctl get task`); stderr
carries human-readable status. REPL mode is rejected for --async
(fire-and-forget doesn't make sense without -m).
GC ticker in mcpd: 5-min interval. Pending tasks past 1 h queue
timeout flip to error with a clear message; terminal tasks past 7 d
retention get deleted. Both queries are index-backed.
Crash fix uncovered by the smoke: when the async route doesn't await
ref.done, a later cancel/error rejected the in-flight Promise as
unhandled and crashed mcpd. The route now attaches a no-op `.catch`
so the legacy `done` semantic still works for sync callers (chat,
direct infer) without taking out the process for async ones. The
EnqueueInferOptions also gained an explicit `ownerId` field so the
async API can stamp the authenticated user on the row instead of
inheriting 'system' from the constructor's resolveOwner — without
this, every GET/DELETE from the original caller would 404 due to
foreign-owner mismatch.
Smoke (tests/smoke/inference-task.smoke.test.ts):
1. POST /inference-tasks while no worker bound → row=pending.
2. Bring a registrar online → bindSession drain claims and
dispatches → worker complete()s → row=completed → GET returns
the assistant body.
3. Stop worker, enqueue, DELETE → row=cancelled, persisted.
docs/inference-tasks.md (new): full data model, lifecycle diagram,
async API reference, CLI examples, RBAC table, GC defaults, and the
v5 limitations / v6 roadmap. Cross-linked from virtual-llms.md and
agents.md.
Tests + smoke: mcpd 893/893, mcplocal 723/723, cli 437/437, full
smoke 146/146 (was 144, +2 new task smoke). Live mcpd verified via
manual curl: enqueue → cancel → re-fetch — no crash, owner scoping
returns 404 on foreign ids, GC ticker logs at info when it sweeps.
v5 complete: durable queue (Stage 1) + VirtualLlmService rewire
(Stage 2) + async API & RBAC (Stage 3) + CLI/GC/smoke/docs (Stage 4).
2026-04-28 15:25:09 +01:00
|
|
|
COMPREPLY=($(compgen -W "-m --message --system --temperature --max-tokens --no-stream --async -h --help" -- "$cur"))
|
feat(cli): mcpctl chat-llm + KIND/STATUS columns (v1 Stage 5)
Closes the loop on user-facing surface:
$ mcpctl get llm
NAME KIND STATUS TYPE MODEL TIER KEY ID
qwen3-thinking public active openai qwen3-thinking fast ... ...
vllm-local virtual active openai Qwen/Qwen2.5-7B-Instruct fast - ...
$ mcpctl chat-llm vllm-local
────────────────────────────────────────
LLM: vllm-local openai → Qwen/Qwen2.5-7B-Instruct-AWQ
Kind: virtual Status: active
────────────────────────────────────────
> hello?
Hi! …
New: chat-llm command (commands/chat-llm.ts)
- Stateless chat with any mcpd-registered LLM. No threads, no tools,
no project prompts. POSTs to /api/v1/llms/<name>/infer; mcpd's
kind=virtual branch handles relay-through-mcplocal transparently,
so the same CLI command works for both public and virtual LLMs.
- Reuses installStatusBar / formatStats / recordDelta / styleStats /
PhaseStats from chat.ts (now exported) so the bottom-row tokens-per-
second ticker behaves identically to mcpctl chat.
- Flags: --message (one-shot), --system, --temperature, --max-tokens,
--no-stream. Streaming uses OpenAI chat.completion.chunk SSE.
- REPL mode keeps a per-session history array so multi-turn flows
feel natural; each turn is an independent inference call.
Updated: get.ts
- LlmRow gains optional kind/status fields.
- llmColumns layout: NAME, KIND, STATUS, TYPE, MODEL, TIER, KEY, ID.
Defaults gracefully when older mcpd responses don't return them.
Updated: chat.ts
- Re-exports the helpers chat-llm.ts needs (PhaseStats, newPhase,
recordDelta, formatStats, styleStats, styleThinking, STDERR_IS_TTY,
StatusBar, installStatusBar). No behavior change.
Completions: chat-llm picks up the standard option enumeration
automatically; bash gets a special-case for first-arg LLM-name
completion via _mcpctl_resource_names "llms".
CLI suite: 437/437 (was 430, +7 from auto-discovered test cases in
the regenerated completions golden). Workspace: 2043/2043 across
152 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:25:38 +01:00
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-02-27 17:05:05 +00:00
|
|
|
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
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
return ;;
|
|
|
|
|
backup)
|
2026-03-08 01:14:28 +00:00
|
|
|
local backup_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$backup_sub" ]]; then
|
2026-03-08 13:53:12 +00:00
|
|
|
COMPREPLY=($(compgen -W "log restore help" -- "$cur"))
|
2026-03-08 01:14:28 +00:00
|
|
|
else
|
|
|
|
|
case "$backup_sub" in
|
|
|
|
|
log)
|
|
|
|
|
COMPREPLY=($(compgen -W "-n --limit -h --help" -- "$cur"))
|
|
|
|
|
;;
|
2026-03-08 01:17:03 +00:00
|
|
|
restore)
|
2026-03-08 01:14:28 +00:00
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
return ;;
|
2026-02-23 19:32:18 +00:00
|
|
|
attach-server)
|
2026-02-23 19:36:45 +00:00
|
|
|
if [[ $((cword - subcmd_pos)) -ne 1 ]]; then return; fi
|
2026-02-23 19:32:18 +00:00
|
|
|
local proj names all_servers proj_servers
|
|
|
|
|
proj=$(_mcpctl_get_project_value)
|
|
|
|
|
if [[ -n "$proj" ]]; then
|
2026-02-27 17:05:05 +00:00
|
|
|
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)
|
2026-02-23 19:32:18 +00:00
|
|
|
names=$(comm -23 <(echo "$all_servers" | sort) <(echo "$proj_servers" | sort))
|
|
|
|
|
else
|
|
|
|
|
names=$(_mcpctl_resource_names "servers")
|
|
|
|
|
fi
|
|
|
|
|
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
|
|
|
|
return ;;
|
|
|
|
|
detach-server)
|
2026-02-23 19:36:45 +00:00
|
|
|
if [[ $((cword - subcmd_pos)) -ne 1 ]]; then return; fi
|
2026-02-23 19:32:18 +00:00
|
|
|
local proj names
|
|
|
|
|
proj=$(_mcpctl_get_project_value)
|
|
|
|
|
if [[ -n "$proj" ]]; then
|
2026-02-27 17:05:05 +00:00
|
|
|
names=$(mcpctl --project "$proj" get servers -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null)
|
2026-02-23 19:32:18 +00:00
|
|
|
fi
|
2026-02-23 19:08:29 +00:00
|
|
|
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
|
|
|
|
return ;;
|
2026-02-25 00:21:31 +00:00
|
|
|
approve)
|
|
|
|
|
if [[ -z "$resource_type" ]]; then
|
2026-02-27 17:05:05 +00:00
|
|
|
COMPREPLY=($(compgen -W "promptrequest -h --help" -- "$cur"))
|
2026-02-25 00:21:31 +00:00
|
|
|
else
|
|
|
|
|
local names
|
|
|
|
|
names=$(_mcpctl_resource_names "$resource_type")
|
2026-02-27 17:05:05 +00:00
|
|
|
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)
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "$names --stdin-mcp --audit -h --help" -- "$cur"))
|
2026-02-27 17:05:05 +00:00
|
|
|
else
|
feat: audit console TUI, system prompt management, and CLI improvements
Audit Console Phase 1: tool_call_trace emission from mcplocal router,
session_bind/rbac_decision event kinds, GET /audit/sessions endpoint,
full Ink TUI with session sidebar, event timeline, and detail view
(mcpctl console --audit).
System prompts: move 6 hardcoded LLM prompts to mcpctl-system project
with extensible ResourceRuleRegistry validation framework, template
variable enforcement ({{maxTokens}}, {{pageCount}}), and delete-resets-
to-default behavior. All consumers fetch via SystemPromptFetcher with
hardcoded fallbacks.
CLI: -p shorthand for --project across get/create/delete/config commands,
console auto-scroll improvements, shell completions regenerated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:50:54 +00:00
|
|
|
COMPREPLY=($(compgen -W "--stdin-mcp --audit -h --help" -- "$cur"))
|
2026-02-25 00:21:31 +00:00
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-03-07 23:36:36 +00:00
|
|
|
cache)
|
|
|
|
|
local cache_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$cache_sub" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "stats clear help" -- "$cur"))
|
|
|
|
|
else
|
|
|
|
|
case "$cache_sub" in
|
|
|
|
|
stats)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
clear)
|
|
|
|
|
COMPREPLY=($(compgen -W "--older-than -y --yes -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-04-29 15:58:46 +01:00
|
|
|
provider)
|
|
|
|
|
local provider_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$provider_sub" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "status up down help" -- "$cur"))
|
|
|
|
|
else
|
|
|
|
|
case "$provider_sub" in
|
|
|
|
|
status)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
up)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
down)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
feat: HTTP-mode mcplocal container + mcpctl test mcp + token-auth preHandler
Delivers the final piece of the mcptoken stack: a containerized,
network-accessible mcplocal that serves Streamable-HTTP MCP to off-host
clients (the vLLM use case), authenticated by project-scoped McpTokens.
New binary (same package, new entry):
- src/mcplocal/src/serve.ts — HTTP-only entry. Reads MCPLOCAL_MCPD_URL,
MCPLOCAL_MCPD_TOKEN, MCPLOCAL_HTTP_HOST/PORT, MCPLOCAL_CACHE_DIR from
env. No StdioProxyServer, no --upstream.
- src/mcplocal/src/http/token-auth.ts — Fastify preHandler that
validates mcpctl_pat_ bearers via mcpd's /api/v1/mcptokens/introspect.
30s positive / 5s negative TTL. Rejects wrong-project with 403.
Shared HTTP MCP client:
- src/shared/src/mcp-http/ — reusable McpHttpSession with initialize,
listTools, callTool, close. Handles http+https, SSE, id correlation,
distinct McpProtocolError / McpTransportError. Plus mcpHealthCheck
and deriveBaseUrl helpers.
New CLI verb `mcpctl test mcp <url>`:
- Flags: --token (also $MCPCTL_TOKEN), --tool, --args (JSON),
--expect-tools, --timeout, -o text|json, --no-health.
- Exit codes: 0 PASS, 1 TRANSPORT/AUTH FAIL, 2 CONTRACT FAIL.
Container + deploy:
- deploy/Dockerfile.mcplocal (Node 20 alpine, multi-stage, pnpm
workspace, CMD node src/mcplocal/dist/serve.js, VOLUME
/var/lib/mcplocal/cache, HEALTHCHECK on :3200/healthz).
- scripts/build-mcplocal.sh mirrors build-mcpd.sh.
- fulldeploy.sh is now a 4-step pipeline that also builds + rolls out
mcplocal (gated on `kubectl get deployment/mcplocal` so the script
stays green before the Pulumi stack lands).
Audit + cache:
- project-mcp-endpoint.ts passes MCPLOCAL_CACHE_DIR into FileCache at
both construction sites and, when request.mcpToken is present, calls
collector.setSessionMcpToken(id, ...) so audit events carry the
tokenName/tokenSha.
Tests:
- 9 unit cases on `mcpctl test mcp` (happy path, health miss,
expect-tools hit/miss, transport throw, tool isError, json report,
$MCPCTL_TOKEN env fallback, invalid --args).
- Smoke test src/mcplocal/tests/smoke/mcptoken.smoke.test.ts —
gated on healthz($MCPGW_URL), skipped cleanly when unreachable.
Covers happy path, wrong-project 403, --expect-tools contract
failure, and revocation 401 within the negative-cache window.
1773/1773 workspace tests pass. Pulumi resources (Deployment, Service,
Ingress, PVC, Secret, NetworkPolicy) still need to land in
../kubernetes-deployment before the smoke gate flips on.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 01:21:42 +01:00
|
|
|
test)
|
|
|
|
|
local test_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$test_sub" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "mcp help" -- "$cur"))
|
|
|
|
|
else
|
|
|
|
|
case "$test_sub" in
|
|
|
|
|
mcp)
|
|
|
|
|
COMPREPLY=($(compgen -W "--token --tool --args --expect-tools --timeout -o --output --no-health -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
2026-04-18 19:29:55 +01:00
|
|
|
migrate)
|
|
|
|
|
local migrate_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$migrate_sub" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "secrets help" -- "$cur"))
|
|
|
|
|
else
|
|
|
|
|
case "$migrate_sub" in
|
|
|
|
|
secrets)
|
|
|
|
|
COMPREPLY=($(compgen -W "--from --to --names --keep-source --dry-run -h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
feat(openbao): wizard-provisioning + daily token rotation
One-command setup replaces the 6-step manual flow — `mcpctl create
secretbackend bao --type openbao --wizard` takes the OpenBao admin token
once, provisions a narrow policy + token role, mints the first periodic
token, stores it on mcpd, verifies end-to-end, and prints the migration
command. The admin token is NEVER persisted.
The stored credential auto-rotates daily: mcpd mints a successor via the
token role (self-rotation capability is part of the policy it was issued
with), verifies the successor, writes it over the backing Secret, then
revokes the predecessor by accessor. TTL 720h means a week of rotation
failures still leaves 20+ days of runway.
Shared:
- New `@mcpctl/shared/vault` — pure HTTP wrappers (verifyHealth,
ensureKvV2, writePolicy, ensureTokenRole, mintRoleToken, revokeAccessor,
lookupSelf, testWriteReadDelete) and policy HCL builder.
mcpd:
- `tokenMeta Json @default("{}")` on SecretBackend. Self-healing schema
migration — empty default lets `prisma db push` add the column cleanly.
- SecretBackendRotator.rotateOne: mint → verify → persist → revoke-old →
update tokenMeta. Failures surface via `lastRotationError` on the row;
the old token keeps working.
- SecretBackendRotatorLoop: on startup rotates overdue backends, schedules
per-backend timers with ±10min jitter. Stops cleanly on shutdown.
- New `POST /api/v1/secretbackends/:id/rotate` (operation
`rotate-secretbackend` — added to bootstrap-admin's auto-migrated ops
alongside migrate-secrets, which was previously missing too).
CLI:
- `--wizard` on `create secretbackend` delegates to the interactive flow.
All prompts can be pre-answered via flags (--url, --admin-token,
--mount, --path-prefix, --policy-name, --token-role,
--no-promote-default) for CI.
- `mcpctl rotate secretbackend <name>` — convenience verb; hits the new
rotate endpoint.
- `describe secretbackend` renders a Token health section (healthy /
STALE / WARNING / ERROR) with generated/renewal/expiry timestamps and
last rotation error. Only shown when tokenMeta.rotatable is true — the
existing k8s-auth + static-token backends don't surface it.
Tests: 15 vault-client unit tests (shared), 8 rotator unit tests (mcpd),
3 wizard flow tests (cli, including a regression test that the admin
token never appears in stdout). Full suite 1885/1885 (+32). Completions
regenerated for the new flags.
Out of scope (explicit): kubernetes-auth wizard, Vault Enterprise
namespaces in the wizard path, rotation for non-wizard static-token
backends. See plan file for details.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 17:20:37 +01:00
|
|
|
rotate)
|
|
|
|
|
local rotate_sub=$(_mcpctl_get_subcmd $subcmd_pos)
|
|
|
|
|
if [[ -z "$rotate_sub" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "secretbackend help" -- "$cur"))
|
|
|
|
|
else
|
|
|
|
|
case "$rotate_sub" in
|
|
|
|
|
secretbackend)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
return ;;
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
help)
|
|
|
|
|
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
|
|
|
|
return ;;
|
|
|
|
|
esac
|
|
|
|
|
|
2026-02-23 19:08:29 +00:00
|
|
|
# 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
|
feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
complete -F _mcpctl mcpctl
|