Complete reference for configuring muster system settings, resources, and behavior.
Muster uses a file-based configuration system with YAML files organized in a structured directory hierarchy. Configuration is loaded from ~/.config/muster/ by default, or from a custom path specified with --config-path.
- Simple: Direct YAML files that are easy to edit
- Predictable: Standard directory structure with clear separation
- Flexible: Support for both API-driven and manual file editing
~/.config/muster/
├── config.yaml # Main system configuration
├── mcpservers/ # MCP server definitions
│ ├── kubernetes.yaml
│ ├── github.yaml
│ └── prometheus.yaml
├── workflows/ # Workflow definitions
│ ├── deploy-app.yaml
│ └── backup-database.yaml
└── services/ # Service instances
├── my-web-app.yaml
└── prod-database.yaml
- Default:
~/.config/muster/config.yaml - Custom: Specified via
--config-pathflag
# ~/.config/muster/config.yaml
aggregator:
port: 8090 # Server port (default: 8090)
host: "localhost" # Bind address (default: localhost)
transport: "streamable-http" # MCP transport (default: streamable-http)
enabled: true # Enable aggregator (default: true)
namespace: "default" # Kubernetes namespace for CR discovery (default: default)| Field | Type | Default | Description |
|---|---|---|---|
namespace |
string |
"default" |
Kubernetes namespace for discovering MCPServer and Workflow CRs |
kubernetes |
bool |
false |
Enable Kubernetes CRD mode. When true, uses Kubernetes CRDs for resource storage. When false, uses filesystem YAML files. The Helm chart sets this to true by default. |
aggregator |
AggregatorConfig |
see below | Aggregator service configuration |
auth |
AuthConfig |
see below | Authentication settings for CLI |
The aggregator manages the unified MCP interface and tool aggregation.
| Field | Type | Default | Description |
|---|---|---|---|
port |
int |
8090 |
Port for the aggregator HTTP/WebSocket server |
host |
string |
"localhost" |
Host address to bind the server to |
transport |
string |
"streamable-http" |
MCP transport protocol |
enabled |
bool |
true |
Whether to enable the aggregator service |
| Transport | Description | Use Case |
|---|---|---|
streamable-http |
HTTP with streaming support | Recommended - Most compatible |
sse |
Server-Sent Events | Real-time updates |
stdio |
Standard I/O | Command-line clients |
The sessionDuration field controls how long a user's session remains valid before
re-authentication is required. This sets the server-side refresh token TTL (the muster
refresh token's lifetime).
aggregator:
oauth:
server:
sessionDuration: "720h" # 30 days (default)| Value | Duration | Notes |
|---|---|---|
720h |
30 days | Default, aligned with Dex's absoluteLifetime |
168h |
7 days | More restrictive for high-security environments |
2160h |
90 days | Longer sessions (ensure Dex absoluteLifetime matches) |
Important: Muster uses a rolling refresh token TTL (reset on each token rotation), while Dex's
absoluteLifetimeis an absolute limit measured from the original login that does not reset on rotation. If you increasesessionDurationbeyond Dex'sabsoluteLifetime, the effective session will still be limited by Dex -- the next token refresh after the absolute lifetime expires will fail, forcing re-authentication even if muster's session estimate shows time remaining.Always ensure
sessionDurationdoes not exceed Dex'sabsoluteLifetime.
The access token TTL is not directly configurable; it defaults to 30 minutes
(DefaultAccessTokenTTL), matching Dex's idTokens expiry. The mcp-oauth library's
capTokenExpiry function automatically caps the effective access token lifetime to never
exceed the provider's token lifetime, so even if the default were higher, the actual
expiry would be capped to what Dex issues.
Access tokens are refreshed automatically using the refresh token -- users do not need to
re-authenticate when they expire. The CLI's muster auth status shows the current access
token expiry under "Expires" and the session duration under "Session".
For the full token lifecycle and how muster and Dex tokens interact, see the Security Configuration guide.
The CLI's muster auth status displays an approximate session estimate based on the
default 30-day duration. Custom server-side values are not yet reflected in the CLI
estimate.
muster issues only opaque access tokens. muster is not an identity provider: it never signs tokens, and downstream MCP servers validate identity against dex (or their own IdP), never against muster.
| Field | Type | Default | Description |
|---|---|---|---|
resourceIdentifier |
string |
"" |
RFC 8707 canonical URI for this muster instance as a resource server. Access tokens carry this value in their aud claim; tokens bound to a different resource are rejected, preventing replay across resource servers sharing the same IdP. Defaults to baseUrl when empty. |
| Field | Type | Default | Description |
|---|---|---|---|
trustedProxyCIDRs |
[]string |
[] |
CIDRs from which X-Forwarded-Proto and X-Forwarded-Host headers are trusted for DPoP htu URL reconstruction. Required when muster runs behind a reverse proxy that terminates TLS. |
| Field | Type | Default | Description |
|---|---|---|---|
trustedIssuers |
[]TrustedIssuerConfig |
[] |
Trusted external OIDC issuers. Tokens are accepted as id_token, access_token, or jwt subject_tokens. Use allowedClaims to express Kubernetes ServiceAccount or GitHub Actions trust. |
TrustedIssuerConfig fields:
| Field | Type | Description |
|---|---|---|
issuer |
string |
Expected iss claim value. |
jwksUrl |
string |
JWKS endpoint. Independent of issuer. |
allowedAudiences |
[]string |
Accepted aud values. Empty accepts any audience. |
allowedScopes |
[]string |
Scope ceiling for tokens from this issuer. Nil means no restriction. |
allowedClaims |
map[string]string |
Required claim name→pattern pairs. Keys are JWT claim names; values are exact strings or globs where * spans any chars including / and ? matches one char. Absent or non-string claims are rejected. Empty means no restriction. |
allowPrivateIPJWKS |
bool |
Allow jwksUrl to resolve to a private or loopback address. Required for in-cluster Kubernetes SA trust where the JWKS endpoint is https://kubernetes.default.svc/openid/v1/jwks. Emits a startup warning when set. Default: false. |
Exposes muster's RFC 8693 token exchange to external confidential clients: a broker client POSTs a token-exchange request with an audience parameter to /oauth/token and receives a token minted by the audience's downstream Dex (instead of a muster-issued JWT). Subject tokens are validated against trustedIssuers, so at least one issuer entry covering the broker client's tokens is required.
Policy enforced by the broker path (mcp-oauth): client authentication is mandatory and only confidential clients are accepted; audiences are gated by the per-client allowlist; no refresh tokens are issued (expires_in is bounded by the downstream token's expiry — clients re-exchange); DPoP is rejected.
| Field | Type | Default | Description |
|---|---|---|---|
clientAudiences |
map[string][]string |
{} |
Per-client audience allowlist: broker client ID → audiences it may request. A miss returns invalid_target. |
targets |
map[string]BrokerTargetConfig |
{} |
Audience name (e.g. a cluster name) → downstream Dex exchange target. |
allowPrivateIP |
bool |
false |
Allow downstream token endpoints to resolve to private/loopback IPs. Reduces SSRF protection; internal deployments only. |
BrokerTargetConfig fields:
| Field | Type | Description |
|---|---|---|
dexTokenEndpoint |
string |
Downstream Dex token endpoint URL (HTTPS). Required. |
expectedIssuer |
string |
Expected iss claim of the exchanged token. Derived from dexTokenEndpoint when empty. |
connectorId |
string |
Downstream Dex OIDC connector that trusts the subject token's issuer. Required. |
scopes |
string |
Space-separated downstream scopes (default: openid profile email groups). Kubernetes-bound audiences must include the Dex cross-client scope for the apiserver's client, e.g. audience:server:client_id:dex-k8s-authenticator — without it the exchanged token's aud is the exchange client only, which the kube-apiserver rejects. The client-supplied RFC 8693 scope parameter is intentionally ignored. |
clientCredentialsSecretRef |
object |
Kubernetes Secret with the downstream exchange client credentials: name (required), namespace (defaults to the muster namespace), clientIdKey (default client-id), clientSecretKey (default client-secret). |
Example:
aggregator:
oauth:
server:
trustedIssuers:
- issuer: https://dex.main.example.com
jwksUrl: https://dex.main.example.com/keys
allowedAudiences: ["portal-frontend"]
tokenExchangeBroker:
clientAudiences:
portal-backend: ["cluster-a"]
targets:
cluster-a:
dexTokenEndpoint: https://dex.cluster-a.example.com/token
connectorId: main-dex
scopes: "openid profile email groups audience:server:client_id:dex-k8s-authenticator"
clientCredentialsSecretRef:
name: muster-token-exchange-cluster-aBy default the SSRF guard rejects an OIDC issuer URL that resolves to a private or loopback address. On clusters where the public Dex hostname resolves to an RFC 1918 address (e.g. an Azure internal load balancer, or air-gapped environments), discovery fails with context deadline exceeded and the server starts in degraded mode.
| Field | Type | Default | Description |
|---|---|---|---|
dex.allowPrivateIPOIDC |
bool |
false |
Allow the Dex issuer URL to resolve to a private/loopback IP during OIDC discovery. This is the discovery-path counterpart to allowPrivateIPJWKS. Emits a CWE-918 startup warning when set; only enable it when the issuer is genuinely fronted by an internal-only load balancer. |
Silent re-authentication is controlled via CLI flags only, not configuration file.
By default, muster uses interactive authentication. If your IdP supports OIDC prompt=none (note: Dex does not), you can enable silent re-authentication with the --silent flag:
muster auth login --silent # Attempt silent re-auth before interactive
muster agent --silent # Enable silent auth for agentWhen --silent is used:
- If you have a previous session, muster opens the browser with OIDC
prompt=none - If your IdP session is still valid, authentication completes without user interaction
- If the IdP session has expired, muster falls back to interactive login
Note: Silent auth is disabled by default because Dex (the default IdP) does not support prompt=none. When silent auth fails with Dex, it causes two browser tabs to open.
Security: When enabled, silent re-authentication maintains full security:
- PKCE is enforced on every flow
- State parameter prevents CSRF attacks
- The IdP validates the session, not muster
- Any failure falls back to interactive authentication
# Uses all defaults (namespace: "default", aggregator defaults)
aggregator: {}aggregator:
port: 8091
host: "0.0.0.0"
transport: "streamable-http"
enabled: truenamespace: "muster-system" # Use dedicated namespace for muster CRs
kubernetes: true # Use Kubernetes CRDs instead of filesystem
aggregator:
port: 80
host: "0.0.0.0"
transport: "streamable-http"
enabled: truenamespace: "team-alpha" # Each team uses their own namespace
aggregator:
port: 8090
host: "localhost"
transport: "streamable-http"MCP servers can be configured through YAML files or Kubernetes CRDs. Each server requires:
# Local server example
mcpservers:
- name: filesystem-tools
description: File system operations
toolPrefix: fs
type: stdio # Server execution type
autoStart: true
command: ["npx", "@modelcontextprotocol/server-filesystem", "/workspace"]
env:
DEBUG: "1"
# Streamable HTTP server example
- name: api-server
description: Remote API tools
toolPrefix: api
type: streamable-http
url: "https://api.example.com/mcp"
timeout: 30
headers:
Authorization: "Bearer token"
# SSE server example
- name: sse-server
description: SSE-based MCP server
toolPrefix: sse
type: sse
url: "https://api.example.com/sse"
timeout: 45| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string |
✅ | - | Unique server identifier |
description |
string |
❌ | - | Human-readable description |
toolPrefix |
string |
❌ | - | Tool name prefix |
type |
string |
✅ | - | Server type (stdio, streamable-http, or sse) |
autoStart |
boolean |
❌ | false |
Auto-start server (stdio only) |
command |
[]string |
✅* | - | Command and args (*required for stdio) |
args |
[]string |
❌ | - | Command arguments (stdio only) |
env |
map[string]string |
❌ | {} |
Environment variables |
url |
string |
✅* | - | Server URL (*required for streamable-http and sse) |
timeout |
integer |
❌ | 30 |
Connection timeout in seconds |
headers |
map[string]string |
❌ | {} |
HTTP headers (streamable-http and sse only) |
Location: workflows/*.yaml
apiVersion: muster.giantswarm.io/v1alpha1
kind: Workflow
metadata:
name: deploy-application
namespace: default
spec:
description: "Deploy application with health checks"
args: # Workflow arguments
appName:
type: string
required: true
description: "Application name to deploy"
environment:
type: string
default: "staging"
description: "Target environment"
steps: # Workflow steps
- id: "build"
tool: "build_application"
args:
name: "{{ .input.appName }}"
env: "{{ .input.environment }}"
store: true
description: "Build the application"
- id: "deploy"
tool: "deploy_application"
args:
name: "{{ .input.appName }}"
image: "{{ .results.build.image }}"
env: "{{ .input.environment }}"
condition:
fromStep: "build"
expect:
success: true
description: "Deploy to target environment"
- id: "health-check"
tool: "health_check"
args:
url: "{{ .results.deploy.url }}"
allowFailure: false
description: "Verify deployment health"| Field | Type | Required | Description |
|---|---|---|---|
description |
string |
❌ | Human-readable description |
args |
map[string]ArgDefinition |
❌ | Workflow argument schema |
steps |
[]WorkflowStep |
✅ | Sequence of execution steps |
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
✅ | Unique step identifier |
tool |
string |
✅ | Tool name to execute |
args |
map[string]any |
❌ | Tool arguments (supports templating) |
condition |
WorkflowCondition |
❌ | Execution condition |
store |
bool |
❌ | Store result for later steps |
allowFailure |
bool |
❌ | Continue on failure |
outputs |
map[string]any |
❌ | Output mappings |
description |
string |
❌ | Step documentation |
Location: services/*.yaml
apiVersion: muster.giantswarm.io/v1alpha1
kind: Service
metadata:
name: my-web-app
namespace: default
spec:
args:
port: 3000
replicas: 2
environment: "production"- Defaults: Built-in default values
- Main Config:
config.yamloverrides defaults - Resource Files: Individual resource definitions
Use --config-path to specify a custom configuration directory:
muster serve --config-path /etc/muster
muster create service --config-path ./project-config app-nameCreate different configuration directories for different environments:
# Development
muster serve --config-path ~/.config/muster-dev
# Staging
muster serve --config-path ~/.config/muster-staging
# Production
muster serve --config-path /etc/muster-prodMuster validates configuration on startup and when resources are created:
- Syntax: YAML syntax validation
- Schema: Field types and required values
- References: Tool availability and dependencies
Check resource availability:
# Check specific resources
muster check mcpserver kubernetes
muster check workflow deploy-appUse Go template syntax for dynamic values. Workflow inputs are under .input,
stored step results under .results (the engine renders with missingkey=error,
so a bare {{ .environment }} errors at runtime):
args:
url: "https://{{ .input.environment }}.example.com"
replicas: "{{ .input.replicas }}"
config: "{{ .input.baseConfig }}/{{ .input.serviceName }}"In workflow templates, these context roots are available:
| Context | Reference | Description |
|---|---|---|
| Workflow inputs | .input.<arg> |
Values passed to the workflow |
| Step results | .results.<step-id> |
Output of a previous store: true step (.context.<step-id> is an alias) |
| Loop/user variables | .vars.<name> |
forEach item/index and other bound variables |
| Command | Description |
|---|---|
muster serve |
Start the muster aggregator server |
muster agent |
MCP client for the aggregator server |
muster create |
Create resources (service, workflow) |
muster get |
Get detailed information about resources |
muster list |
List resources |
muster start |
Start services or execute workflows |
muster stop |
Stop services |
muster check |
Check resource availability |
muster test |
Execute test scenarios |
| Resource Type | Create | Get | List | Check | Start |
|---|---|---|---|---|---|
service |
✅ | ✅ | ✅ | ❌ | ✅ |
mcpserver |
❌ | ✅ | ✅ | ✅ | ❌ |
workflow |
✅ | ✅ | ✅ | ✅ | ✅ |
workflow-execution |
❌ | ✅ | ✅ | ❌ | ❌ |
- CLI Reference - Command-line interface documentation
- CRDs Reference - Kubernetes resource specifications
- MCP Tools Reference - Available tools and usage
- API Reference - HTTP and MCP API documentation