- hubtoken: HubTokenRenewer.Token() no longer hands out an already-expired
token on mint failure — returns "" so the round-tripper falls back to the
License-Key instead of looping on 401s.
- utils/http: hub clients no longer follow SSO redirects (StopOnSSORedirect
CheckRedirect on 302/303), and IsAuthRequired covers 302+303, so auth
detection is reliable instead of silently following to an HTML login page.
- mcpRunner: fetchHubMCP/callHubTool/fetchAndDisplayTools/callDownloadFile
use utils.IsAuthRequired (401 + unfollowed redirect) instead of bare 401;
download path checks it before writing the body to disk; URL-mode auth
message now also mentions the License-Key fallback.
fetchAndDisplayTools used a no-token client, so 'kubeshark mcp
--list-tools' 401'd against a gated Hub even with a valid --token. Factor
the proxy/url token-source selection into hubTokenSource() (reused by
runMCPWithConfig) and pass it through to fetchAndDisplayTools, which now
also reports a clear 401 instead of an opaque parse error.
Review follow-up. HubTokenRenewer.Token() re-minted on every request while
the token was empty, so a cluster where minting can't succeed (no RBAC, SA
missing) paid a blocking ~10s CreateToken round-trip per request (under the
lock). Add a 30s retry throttle: on mint failure, back off and fall back to
the prior token / License-Key. Also correct the proxy-mode 401 message — a
token-bearing 401 means the minted token was rejected (allowlist/audience),
not an RBAC-to-mint failure.
The MCP server minted a hub SA token once at startup and reused it for
the life of the process, so a long-running server 401'd silently after
the ~1h token TTL.
- utils/http: the hub round-tripper now sources the SA token via a
func() string per request (static constructors preserved), so a
renewing source keeps long-lived clients authenticated.
- kubernetes: add HubTokenRenewer — re-mints the kubeshark-cli token
before expiry (using the TokenRequest expiry, 5m margin), concurrency-safe.
- mcp proxy mode: use the renewer so the token auto-renews.
- mcp --url mode: cannot mint (no kube access) — accept an explicit
--token / KUBESHARK_HUB_TOKEN, and on 401 surface a clear 'token
expired/invalid, re-mint and restart' message instead of an opaque
API error.
console is intentionally untouched (non-functional pending the
Connect-RPC re-point); it gets renewal when that migration lands.
Provider.MintHubToken requests a short-lived token (audience kubeshark-hub)
for the kubeshark-cli ServiceAccount via the TokenRequest API. The Hub
client now prefers that token via the X-Kubeshark-Authorization custom
header (which survives the kube API-server proxy), falling back to
License-Key when minting isn't possible (--url mode, SA missing, or no
RBAC to mint). The MCP runner mints once at startup.
Pairs with hub branch cli-sa-auth. Needs the helm kubeshark-cli SA + RBAC
and the hub AUTH_CLI_SERVICE_ACCOUNTS allowlist to validate end-to-end.
Add a License-Key RoundTripper plus NewHubHTTPClient / HubAuthTransport
helpers in utils, and route the MCP runner's Hub clients (connect, --url
validate, file download, tools list) through them so the CLI keeps working
once the Hub enforces auth. License-Key is a custom header, so it survives
the kube API-server service proxy (a bearer token would not). Surface
ErrHubAuthRequired on a 401/302 from the Hub.
console already sends License-Key on its ws connection. pprof is not
covered here: it shells out to 'go tool pprof <hubUrl>' / opens a browser,
external fetches that can't carry a custom header (follow-up).
* Reapply "Add get_file_url and download_file MCP tools"
This reverts commit a46f05c4aa.
* Use dedicated HTTP client for file downloads to support large files
The default httpClient has a 30s total timeout that would fail for
large PCAP downloads (up to 10GB). Use a separate client with only
connection-level timeouts (TLS handshake, response headers) so the
body can stream without a deadline.
When tools like export_snapshot_pcap return a relative file path,
the MCP client needs a way to resolve it to a full URL or download
the file locally. These two new tools bridge that gap.
The Hub API expects 'name' field but the MCP server was sending 'tool'.
This caused all Hub-forwarded tools (list_l4_flows, get_l4_flow_summary,
list_api_calls, etc.) to fail with 'tool name is required' error.
Local tools like check_kubeshark_status were unaffected as they don't
call the Hub API.
* Add MCP (Model Context Protocol) server command
Implement `kubeshark mcp` command that runs an MCP server over stdio,
enabling AI assistants to query Kubeshark's network visibility data.
Features:
- MCP protocol implementation (JSON-RPC 2.0 over stdio)
- Dynamic tool discovery from Hub's /api/mcp endpoint
- Local cluster management tools (check_kubeshark_status, start_kubeshark, stop_kubeshark)
- --url flag for direct connection to existing Kubeshark deployment
- --kubeconfig flag for proxy mode with kubectl
- --allow-destructive flag to enable start/stop operations (safe by default)
- --list-tools flag to display available tools
- --mcp-config flag to generate MCP client configuration
- 5-minute cache TTL for Hub tools/prompts
- Prompts for common analysis tasks
* Address code review comments for MCP implementation
- Add 30s timeout to HTTP client to prevent hanging requests
- Add scanner.Err() check after stdin processing loop
- Close HTTP response bodies to prevent resource leaks
- Add goroutine to wait on started process to prevent zombies
- Simplify polling loop by removing ineffective context check
- Advertise check_kubeshark_status in URL mode (was callable but hidden)
- Update documentation to clarify URL mode only disables start/stop
* Fix lint errors in mcpRunner.go
- Use type conversion instead of struct literals for hubMCPTool -> mcpTool
and hubMCPPromptArg -> mcpPromptArg (S1016 gosimple)
- Lowercase error string to follow Go conventions (ST1005 staticcheck)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>