Skip to content

fix(cli): correct mcp secrets sync apply behavior and thread cobra ctx#1814

Open
SarthakB11 wants to merge 3 commits intokagent-dev:mainfrom
SarthakB11:sarth/cli-mcp-secrets-ctx
Open

fix(cli): correct mcp secrets sync apply behavior and thread cobra ctx#1814
SarthakB11 wants to merge 3 commits intokagent-dev:mainfrom
SarthakB11:sarth/cli-mcp-secrets-ctx

Conversation

@SarthakB11
Copy link
Copy Markdown
Contributor

@SarthakB11 SarthakB11 commented May 7, 2026

summary

three issues in mcp secrets sync:

  • SyncSecretsMcp and applySecretToCluster passed context.TODO() to every clientset Get/Create/Update call. ctrl-c during a slow apply (remote cluster, hung api-server connection) silently fell through to whatever the kubernetes client default did rather than honoring cancellation. fix: thread cmd.Context() from the cobra RunE through SyncSecretsMcp and applySecretToCluster. matches the existing kagent cli convention used by InstallCmd, UninstallCmd, InvokeCmd, DashboardCmd, and DeployCmd, which all take ctx as the first argument and are wired from cmd.Context() at the top level in cmd/kagent/main.go.
  • the Get error path was treated as "secret does not exist" without inspecting the error, so RBAC forbidden, network errors, and ctx-cancellation all surfaced as confusing "failed to create secret" messages instead of the real cause. fix: branch on apierrors.IsNotFound(err) so only true-NotFound triggers Create; any other Get error returns a wrapped message immediately.
  • the update path discarded the Get result, so the Secret being sent to Update had no metadata.resourceVersion. kubernetes Update requires resourceVersion and rejects optimistic-concurrency-violating writes, so updates against a populated cluster would fail with a validation error. fix: capture the live object from Get and copy its resourceVersion onto the secret built from .env before calling Update.

the second and third items were flagged by copilot on the initial revision of this PR; addressed in the follow-up commit cf8b5efd.

ai model disclosure

used claude code (claude opus 4.7) to triage the context.TODO() call sites and draft the diff. self-reviewed against go/core/cli/internal/cli/agent/deploy.go to confirm the apierrors import alias and the ctx-as-first-arg pattern, and against cmd/kagent/main.go to confirm cmd.Context() is the established wiring point. verified locally via:

go vet ./core/cli/...
./bin/golangci-lint run ./core/cli/internal/cli/mcp/...   # 0 issues
go build ./core/cli/...
go test -race -count=1 ./core/cli/internal/cli/mcp/...    # ok

SyncSecretsMcp and applySecretToCluster passed context.TODO() to every
clientset Get/Create/Update call against the kubernetes API. that means
ctrl-c during a slow apply (e.g. against a remote cluster with a hung
api-server connection) silently fell through to whatever the kubernetes
client default did rather than honoring cancellation.

thread cmd.Context() from the cobra RunE through both functions so the
calls respect signal cancellation (and any future timeout the caller
attaches). matches the existing kagent cli convention used by InstallCmd,
UninstallCmd, InvokeCmd, DashboardCmd, and DeployCmd, which all take ctx
as the first argument and are wired from cmd.Context() at the top level
in cmd/kagent/main.go.

Signed-off-by: SarthakB11 <sarthak.bhardwaj21b@iiitg.ac.in>
Copilot AI review requested due to automatic review settings May 7, 2026 21:29
@github-actions github-actions Bot added the bug Something isn't working label May 7, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR threads the Cobra cmd.Context() through the MCP secrets sync path so Kubernetes API calls honor cancellation (e.g., Ctrl-C) instead of using context.TODO().

Changes:

  • Updated SyncSecretsMcp and applySecretToCluster to accept a context.Context and pass it into Kubernetes client Get/Create/Update calls.
  • Wired cmd.Context() from the kagent mcp secrets sync Cobra command into SyncSecretsMcp.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
go/core/cli/internal/cli/mcp/secrets.go Accepts/passes context.Context for Kubernetes secret apply operations.
go/core/cli/internal/cli/mcp/root.go Passes cmd.Context() into SyncSecretsMcp for the secrets sync command.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread go/core/cli/internal/cli/mcp/secrets.go Outdated
Comment on lines 128 to 134
// Check if secret exists
_, err = clientset.CoreV1().Secrets(secret.Namespace).Get(context.TODO(), secret.Name, metav1.GetOptions{})
_, err = clientset.CoreV1().Secrets(secret.Namespace).Get(ctx, secret.Name, metav1.GetOptions{})
if err != nil {
// Create if it doesn't exist
_, err = clientset.CoreV1().Secrets(secret.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
_, err = clientset.CoreV1().Secrets(secret.Namespace).Create(ctx, secret, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("failed to create secret: %w", err)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. pushed cf8b5efd which switches on apierrors.IsNotFound(err): only true-NotFound triggers Create now, any other Get error (RBAC forbidden, network, ctx cancellation) returns a wrapped message immediately instead of falling through.

Comment thread go/core/cli/internal/cli/mcp/secrets.go Outdated
Comment on lines 137 to 141
} else {
// Update if it exists
_, err = clientset.CoreV1().Secrets(secret.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
_, err = clientset.CoreV1().Secrets(secret.Namespace).Update(ctx, secret, metav1.UpdateOptions{})
if err != nil {
return fmt.Errorf("failed to update secret: %w", err)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. pushed cf8b5efd which captures the live object from Get and copies existing.ResourceVersion onto the secret before calling Update. matches the kubernetes optimistic-concurrency contract.

…ion to Update

per copilot review on PR kagent-dev#1814:

(1) the previous code treated any Get error as 'secret does not exist'
    and proceeded to Create, so RBAC forbidden, network errors, and
    ctx-cancellation all surfaced as confusing 'failed to create secret'
    messages instead of the real cause. switch on apierrors.IsNotFound
    so only true-NotFound triggers Create; any other Get error returns
    a wrapped message immediately.

(2) the update path discarded the Get result, so the Secret being sent
    to Update had no metadata.resourceVersion. kubernetes Update requires
    resourceVersion and rejects optimistic-concurrency-violating writes,
    so updates against a populated cluster would fail. capture the live
    object from Get and copy its resourceVersion onto the secret built
    from .env before calling Update.

Signed-off-by: SarthakB11 <sarthak.bhardwaj21b@iiitg.ac.in>
@SarthakB11 SarthakB11 changed the title fix(cli): thread cobra ctx into mcp secrets sync kubernetes calls fix(cli): correct mcp secrets sync apply behavior and thread cobra ctx May 8, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants