Fixed
- (deps) Update module github.com/giantswarm/selfupdate-cosign to v0.1.1 in #347 by @renovate[bot]
Full Changelog: https://github.com/giantswarm/klausctl/compare/v0.4.4...v0.4.5
Full Changelog: https://github.com/giantswarm/klausctl/compare/v0.4.4...v0.4.5
MusterMCPServerFailed and MusterMCPServerFlapping survive a muster rollout (#1203). Both expressions now aggregate over cluster_id, installation, pipeline, provider, namespace, mcpserver_namespace, mcpserver_name (max by for the state gauge, sum by for the transition counter) instead of carrying the scrape labels pod, instance, container, endpoint, service, job and otel_scope_name into the alert. Before, every rollout ended the old pod’s series – Alertmanager sent RESOLVED – and the new pod’s series started a fresh for window that fired again 20 minutes later: four rollouts in one day produced seven notifications for a single backend that never came back. The alert’s identity is now the MCPServer on a cluster; the for windows, labels and annotations are unchanged, and state is no longer an alert label (both rules only select Failed). The promtool suite covers the series moving from one pod to the next mid-window.oauth.server.allowPrivateIPRedirectURIs (Helm: muster.oauth.server.allowPrivateIPRedirectURIs): a client’s redirect URI may resolve to a private address. On a cluster whose own hostnames resolve to an internal load balancer the authorization-time check rejected every platform-hosted client’s callback with redirect_uri: hostname resolves to private IP address (DNS rebinding protection) – klaus-gateway’s Slack sign-in ended in server_error: Failed to start authorization flow right after allowPrivateIPClientMetadata had let the client through. Off by default; emits a startup warning when set; exact redirect-URI matching is unchanged. (#1201)oauth.server.allowPrivateIPClientMetadata (Helm: muster.oauth.server.allowPrivateIPClientMetadata): a CIMD client_id URL – the Client ID Metadata Document an OAuth client such as klaus-gateway self-hosts – may resolve to a private, loopback or link-local address. Needed where the platform’s own hostnames resolve to an internal load balancer (a management cluster reachable only over VPN): until now the SSRF guard rejected such a client with invalid_client: ... client_id metadata URL resolves to private/internal IP address and nothing in muster’s configuration could lift it, although mcp-oauth has had the switch (AllowPrivateIPClientMetadata). Off by default; emits a startup warning when set; PKCE and redirect-URI validation are unchanged. (#1199)Full Changelog: https://github.com/giantswarm/agent-platform/compare/v3.22.6...v3.22.7
list_tools answers one bounded page instead of the whole catalogue. It takes limit (default 50) and offset, reports total and truncated, and projects every entry the way filter_tools does — name, one-line summary, server, kind, annotations — with the full description and the input schema behind describe_tool. Before, it returned every tool of the caller’s catalogue with its full description in one response: measured on an internal installation, 423 KB unscoped and 402 KB (about 135k tokens) under X-Muster-Toolset: preset:read-only, growing the calling model’s next prompt by 105k–120k tokens and staying in its history for the rest of the session. The tool’s description now says what a page costs and points at filter_tools for discovery and describe_tool for detail. servers_requiring_auth is still present (neither paged nor narrowed by a toolset), a header-declared toolset still bounds the listing (preset:none lists nothing) and is echoed in toolset as filter_tools echoes it, the refusal texts are unchanged and list_core_tools is untouched. The muster CLI and REPL listings, tab completion and the test harness page through the catalogue, so they keep listing every tool; the local muster agent MCP server now advertises the aggregator’s meta-tool definitions verbatim instead of a hand-maintained copy, so limit/offset and the new description reach the assistant through it. (#1193)streamable-http backend hands out an Mcp-Session-Id at initialize; a redeployed pod does not know it and answers 404, mcp-go drops the id and from then on every request went out with no session, so every tool call failed (Bad Request: Missing session ID from a Python backend, Invalid session ID from mcp-go) while core_service_status kept reporting connected / healthy, until an operator ran core_service_restart. On gazelle this took every x_pd_* tool away for hours. The client now recognises a lost session – the typed ErrSessionTerminated, or a transport whose session id is gone because the notification listener met the 404 first – re-runs initialize once and retries the call; concurrent callers on the same dead session share one handshake whether it succeeds or fails, a handshake is bounded to the server’s spec.timeout (30 s when unset), one that fails is reported to every caller that waited on it together with the lost-session error (a 401 from the backend still reads as authentication required), and is retried by the next operation, and a client that was closed on purpose never reconnects. Tool calls, listings, resource reads, prompts and the health ping all go through the recovery, for streamable-http servers with and without OAuth; stdio and SSE have no session to lose and are unchanged. Scenario: mcpserver-session-recovery-after-redeploy.filter_tools echoes a header-declared toolset (#1194). The response’s toolset field names the toolset the returned tools were resolved within: the toolset argument when one is given, else the request’s X-Muster-Toolset – as declared, e.g. ["preset:read-only"]. Before, only the argument was echoed: an agent whose toolset the platform sets by header got total/filtered_count scoped and toolset_unmatched filled but no toolset, so it had no way to learn which toolset bounds it short of a refused call_tool, and a transcript did not show which toolset a discovery call ran under. With both header and argument the argument keeps winning (it resolves within the header’s toolset). presets stays behind include_presets or the argument, so a header-scoped discovery call does not grow. list_core_tools, which shares the engine, echoes the header the same way. Scenario: toolset-filter-tools-echo.MUSTER_ORCHESTRATOR_HEALTH_CHECK_INTERVAL, a Go duration); each probe gets the server’s spec.timeout (default 30 s), and a backend that negotiated protocol 2026-07-28, where ping no longer exists, is probed with tools/list. Three failed probes in a row close the client and move the server to failed with a reconnect due at once: its tools are withdrawn from every session, one MCPServerHealthCheckFailed event names the count and the error, the CR status shows Failed with lastError and nextRetryAfter, and the reconnect loop restarts it on its next tick (MCPServerRecoveryStarted). A reconnect that fails follows the usual MCPServerFailed backoff schedule whatever the endpoint answered – a 404 from a route being reprogrammed as much as a refused connection – until the backend serves again. A passing probe, a successful start or a stop reset the count, so a single slow ping costs nothing; a JSON-RPC error reply, a probe cancelled by shutdown, and a server that is being stopped or restarted are not counted. Servers served per session (forwardToken, tokenExchange, OAuth) have no shared client and are not probed. Before, a server that reached connected stayed connected / healthy with its tools listed whatever happened to the connection afterwards – a redeployed, hung or dead backend meant every call failed until an operator ran core_service_restart; the service’s CheckHealth() existed but nothing called it. core_service_status exposes the running count as metadata.consecutiveHealthCheckFailures. The aggregator no longer emits a second MCPServerHealthCheckFailed for the same transition. Scenarios: mcpserver-health-probe-restarts-dead-backend, mcpserver-health-probe-restart-failure-is-retried, mcpserver-health-probe-spares-session-auth-server, mcpserver-health-probe-spares-per-session-oauth-server.Full Changelog: https://github.com/giantswarm/muster/compare/v5.15.5...v5.15.6