> ## Documentation Index
> Fetch the complete documentation index at: https://docs.golf.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# YAML Config Schema

> YAML configuration reference for Golf Gateway Distributed mode

# YAML Configuration Schema

Golf Gateway supports YAML configuration for **Distributed mode** deployments, where server configurations are defined locally in a YAML file while organization policies and monitoring are managed through the Control Plane. This reference documents the complete YAML schema with all fields, types, and validation rules.

## When to Use YAML Configuration

Use YAML configuration when you want to:

* **Version control** your MCP server configurations alongside your infrastructure code
* **GitOps workflows** where server definitions are managed through pull requests
* **Local server definitions** while still benefiting from Control Plane's centralized policy management and monitoring

<Note>
  YAML configuration works in **Distributed mode** only. The mode is auto-detected: when a `control_plane` section is present in the YAML, the gateway runs in Distributed mode. For fully managed deployments without local configuration files, use **Centralized mode** where all settings are managed through the Golf Control Plane.
</Note>

***

## Quick Start Example

Here's a complete, annotated configuration showing the most common settings:

```yaml golf-gateway.yaml theme={null}
# ============================================================
# Golf Gateway Configuration - Distributed Mode
# ============================================================
# Schema version (required, must be "1.0")
version: "1.0"

# -------------------- Control Plane Connection ---------------
# Required for distributed mode - get these values from Control Plane
# Mode is auto-detected: control_plane present = distributed mode
control_plane:
  url: https://control-plane.example.com
  api_key: ${GOLF_CP_API_KEY}
  gateway_id: 550e8400-e29b-41d4-a716-446655440000

# -------------------- Identity Providers --------------------
# Configure OAuth/OIDC providers for authentication
identity_providers:
  - name: auth0                              # Unique name (referenced by servers)
    type: auth0                              # auth0, microsoft-entra-id, descope
    issuer: https://myorg.auth0.com/
    jwks_uri: https://myorg.auth0.com/.well-known/jwks.json
    api_identifiers:
      - https://api.example.com              # Must match JWT audience
    # Management API credentials (optional, for group sync)
    client_id: ${AUTH0_MGMT_CLIENT_ID}       # Environment variable substitution
    client_secret: ${AUTH0_MGMT_CLIENT_SECRET}

# -------------------- MCP Servers ---------------------------
# Configure upstream MCP servers with RBAC
servers:
  - name: github-mcp                         # Unique server name
    url: http://github-mcp:3001              # Server URL
    description: "GitHub integration"
    server_type: third_party                 # third_party or inhouse
    enabled: true

    # RBAC: Control who can access this server
    rbac_enabled: true
    rbac_mode: allow                         # allow (whitelist) or deny (blacklist)
    allowed_groups:
      - engineering
      - devops

    # Link to identity provider for group resolution
    idp: auth0

    # Per-server PII scrubbing overrides (merged with gateway defaults)
    security:
      enabled: true
      sensitive_fields: [token, password]    # Additional fields to mask
      whitelist_fields: [cursor, tool_name]  # Fields to never scrub

  - name: internal-tools
    url: http://tools-mcp:3002
    server_type: inhouse                     # auto-maps to visibility: internal
    rbac_enabled: false                      # No RBAC for internal tools

# -------------------- Gateway Policy -------------------------
gateway_policy:
  scrubbing:
    enabled: true
    sensitive_fields: [password, api_key]
  server_rbac:
    rbac_enabled: true
    rbac_mode: allow
    allowed_groups: [gateway-users]

# -------------------- Security Engine -------------------------
security:
  llm:
    backend: v1                              # v1, v2, or remote
    confidence_threshold: 0.93
  replay_protection:
    enabled: true
  rate_limiting:
    enabled: true
    requests_per_minute: 100                 # Per-user limit
    window_seconds: 60

# -------------------- Audit Log Export ----------------------
exporters:
  elasticsearch:
    - name: primary
      enabled: true
      url: ${ELASTICSEARCH_URL}              # Self-hosted URL
      api_key: ${ELASTICSEARCH_API_KEY}
      index_prefix: golf-gateway             # Creates: golf-gateway-YYYY.MM.DD
```

<Info>
  Use `${VAR}` for required environment variables or `${VAR:default}` for optional ones with defaults.
</Info>

Scroll down for detailed documentation of each section.

***

## File Location

The gateway searches for configuration files in this order:

1. `GOLF_CONFIG_FILE` environment variable (explicit path)
2. `/etc/golf-gateway/config.yaml`
3. `/etc/golf-gateway/config.yml`
4. `./golf-gateway.yaml` (current directory)
5. `./golf-gateway.yml` (current directory)

```bash theme={null}
# Explicit path
export GOLF_CONFIG_FILE=/path/to/config.yaml
```

***

## Environment Variable Interpolation

YAML configuration supports environment variable substitution:

| Syntax           | Behavior                                      |
| ---------------- | --------------------------------------------- |
| `${VAR}`         | Required - fails if `VAR` is not set          |
| `${VAR:default}` | Optional - uses `default` if `VAR` is not set |

```yaml theme={null}
# Required variable (fails if not set)
api_key: ${GOLF_API_KEY}

# Optional with default
timeout: ${GOLF_TIMEOUT:30}

# In nested structures
servers:
  - name: github-mcp
    url: ${MCP_SERVER_URL:http://localhost:3001}
```

***

## Root Configuration

```yaml theme={null}
version: "1.0"                    # Required, only "1.0" supported

control_plane:                    # Presence activates distributed mode
  url: https://control-plane.example.com
  api_key: ${GOLF_CP_API_KEY}
  gateway_id: 550e8400-e29b-41d4-a716-446655440000

# Optional sections
identity_providers: []
servers: []
gateway_policy: {}
security: {}
oauth_server: {}
exporters: {}
```

### Root Fields

| Field                | Type   | Required | Default | Description                                                                                            |
| -------------------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `version`            | string | Yes      | -       | Schema version, must be `"1.0"`                                                                        |
| `control_plane`      | object | No       | -       | Control Plane connection settings. Presence activates Distributed mode; absence means Standalone mode. |
| `identity_providers` | array  | No       | `[]`    | Identity provider configurations                                                                       |
| `servers`            | array  | No       | `[]`    | MCP server configurations                                                                              |
| `gateway_policy`     | object | No       | `{}`    | Gateway-level policy defaults                                                                          |
| `security`           | object | No       | `{}`    | Security engine settings (LLM threat detection, replay protection, rate limiting)                      |
| `oauth_server`       | object | No       | `{}`    | Gateway's MCP OAuth authorization server configuration                                                 |
| `exporters`          | object | No       | `{}`    | Log export destinations                                                                                |

<Info>
  The deployment mode is **auto-detected**: if `control_plane` is present, the gateway runs in **Distributed mode**. If absent, it runs in **Standalone mode**. No explicit `mode` field is needed.
</Info>

***

## Identity Providers

Configure OAuth/OIDC identity providers for authentication.

```yaml theme={null}
identity_providers:
  - name: auth0-primary
    type: auth0
    issuer: https://myorg.auth0.com/
    jwks_uri: https://myorg.auth0.com/.well-known/jwks.json
    api_identifiers:
      - https://api.example.com
    client_id: ${AUTH0_CLIENT_ID}
    client_secret: ${AUTH0_CLIENT_SECRET}

  - name: descope-corp
    type: descope
    project_id: ${DESCOPE_PROJECT_ID}
    management_key: ${DESCOPE_MANAGEMENT_KEY}
    # issuer and jwks_uri auto-generated for Descope
```

### Identity Provider Fields

| Field               | Type   | Required    | Description                                                                                          |
| ------------------- | ------ | ----------- | ---------------------------------------------------------------------------------------------------- |
| `name`              | string | Yes         | Unique provider name (1-255 chars)                                                                   |
| `type`              | enum   | Yes         | `auth0`, `microsoft-entra-id`, `descope`                                                             |
| `issuer`            | string | Conditional | OIDC issuer URL (auto-generated for Descope)                                                         |
| `jwks_uri`          | string | Conditional | JWKS endpoint URL (auto-generated for Descope)                                                       |
| `userinfo_endpoint` | string | No          | Userinfo endpoint URL                                                                                |
| `api_identifiers`   | array  | No          | API audience identifiers                                                                             |
| `timeout`           | int    | No          | Request timeout in seconds (default: 10, range: 1-60)                                                |
| `client_id`         | string | No          | Management API client ID (for group sync)                                                            |
| `client_secret`     | string | No          | Management API client secret                                                                         |
| `tenant_id`         | string | Conditional | Tenant ID. Required for Entra ID (Azure AD tenant). Optional for Descope (tenant-scoped operations). |

### Descope-Specific Fields

| Field            | Type   | Required      | Description                           |
| ---------------- | ------ | ------------- | ------------------------------------- |
| `project_id`     | string | Yes (Descope) | Descope Project ID                    |
| `management_key` | string | No            | Descope Management Key for group sync |

***

## Servers

Configure MCP upstream servers with RBAC and security settings.

```yaml theme={null}
servers:
  - name: github-mcp
    url: http://github-mcp:3001
    description: "GitHub integration server"
    server_type: third_party
    enabled: true

    # RBAC
    rbac_enabled: true
    rbac_mode: allow
    allowed_groups:
      - engineering
      - devops

    # Capability RBAC
    capability_rbac_enabled: true
    capability_overrides:
      - capability: "tools/delete_repo"
        rbac_enabled: true
        rbac_mode: allow
        allowed_groups: [repo-admins]

    # Per-server PII scrubbing overrides (merged with gateway defaults)
    security:
      enabled: true
      sensitive_fields: [password, token]
      whitelist_fields: [cursor, tool_name]
      recognizers:
        - entity_type: EMAIL_ADDRESS
          enabled: true
          replacement: "[PII_EMAIL]"

    # Per-server threat whitelist
    threat_whitelist_patterns:
      - "GitHub API rate limit exceeded"

    # Identity provider reference
    idp: auth0-primary
```

### Server Schema

<ResponseField name="servers" type="array">
  List of upstream MCP server configurations.

  <Expandable title="server object" defaultOpen>
    <ResponseField name="name" type="string" required>
      Unique server name (1-255 characters). Used as identifier in logs and routing.
    </ResponseField>

    <ResponseField name="url" type="string" required>
      Server URL (e.g., `http://mcp-server:3001`).
    </ResponseField>

    <ResponseField name="description" type="string" default="&#x22;&#x22;">
      Human-readable server description.
    </ResponseField>

    <ResponseField name="server_type" type="enum" default="third_party">
      Server classification: `inhouse` or `third_party`.
    </ResponseField>

    <ResponseField name="enabled" type="boolean" default="true">
      Enable or disable this server.
    </ResponseField>

    <ResponseField name="visibility" type="enum" default="third_party">
      Visibility level: `third_party`, `internal`, or `public`.
    </ResponseField>

    <ResponseField name="upstream_auth_type" type="enum" default="oauth">
      Authentication type for upstream: `oauth`, `none`, or `api_key`.
    </ResponseField>

    <ResponseField name="session_affinity" type="boolean" default="true">
      Maintain session affinity to the same upstream instance.
    </ResponseField>

    <ResponseField name="idp" type="string">
      Reference to an identity provider name for group resolution.
    </ResponseField>

    <ResponseField name="rbac_enabled" type="boolean" default="false">
      Enable server-level role-based access control.
    </ResponseField>

    <ResponseField name="rbac_mode" type="enum" default="allow">
      RBAC mode: `allow` (whitelist) or `deny` (blacklist).
    </ResponseField>

    <ResponseField name="allowed_groups" type="array" default="[]">
      Groups with access when `rbac_mode: allow`.
    </ResponseField>

    <ResponseField name="denied_groups" type="array" default="[]">
      Groups denied access when `rbac_mode: deny`.
    </ResponseField>

    <ResponseField name="rbac_audit" type="boolean" default="true">
      Log RBAC access decisions to audit log.
    </ResponseField>

    <ResponseField name="capability_rbac_enabled" type="boolean" default="false">
      Enable per-capability RBAC overrides.
    </ResponseField>

    <ResponseField name="capability_overrides" type="array">
      Per-capability RBAC rules that override server-level settings.

      <Expandable title="capability override object">
        <ResponseField name="capability" type="string" required>
          Capability pattern (e.g., `tools/*`, `resources/file`, `tools/delete_repo`).
        </ResponseField>

        <ResponseField name="rbac_enabled" type="boolean" default="true">
          Enable RBAC for this specific capability.
        </ResponseField>

        <ResponseField name="rbac_mode" type="enum" default="allow">
          RBAC mode for this capability: `allow` or `deny`.
        </ResponseField>

        <ResponseField name="allowed_groups" type="array">
          Groups with access to this capability.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="threat_whitelist_patterns" type="array" default="[]">
      Regex patterns for content from this server that should bypass LLM threat detection.
    </ResponseField>

    <ResponseField name="preregistered_client_id" type="string">
      Pre-registered OAuth client ID for this server (bypasses Dynamic Client Registration).
    </ResponseField>

    <ResponseField name="preregistered_client_secret" type="string">
      Pre-registered OAuth client secret for this server.
    </ResponseField>

    <ResponseField name="auth_server_url" type="string">
      OAuth issuer URL override. Set when the upstream doesn't publish discovery metadata at its resource origin.
    </ResponseField>

    <ResponseField name="scopes_override" type="string">
      Space-separated OAuth scopes to request, replacing those advertised in discovery.
    </ResponseField>

    <ResponseField name="security" type="object">
      Per-server PII scrubbing overrides. These settings are merged on top of gateway-level defaults using union merge.

      <Expandable title="properties">
        <ResponseField name="enabled" type="boolean" default="false">
          Enable PII scrubbing for this server's traffic.
        </ResponseField>

        <ResponseField name="sensitive_fields" type="array" default="[]">
          Additional field names to mask (e.g., `password`, `api_key`). Merged via union with gateway-level fields.
        </ResponseField>

        <ResponseField name="whitelist_fields" type="array" default="[]">
          Field names that should never be scrubbed, even if they match PII patterns (e.g., `cursor`, `tool_name`).
        </ResponseField>

        <ResponseField name="custom_rules" type="array" default="[]">
          Custom regex-based scrubbing rules.

          <Expandable title="custom rule object">
            <ResponseField name="pattern" type="string" required>
              Regex pattern to match sensitive content.
            </ResponseField>

            <ResponseField name="method" type="enum" required>
              Masking method: `mask`, `remove`, `hash`, or `replace`.
            </ResponseField>

            <ResponseField name="replacement" type="string">
              Custom replacement text (required when method is `replace`).
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name="recognizers" type="array" default="[]">
          Toggle and configure built-in PII recognizers. When merging across layers, `enabled: true` wins over `enabled: false` (most-restrictive doctrine).

          <Expandable title="recognizer config object">
            <ResponseField name="entity_type" type="string" required>
              Entity type (e.g., `EMAIL_ADDRESS`, `CREDIT_CARD`, `US_SSN`).
            </ResponseField>

            <ResponseField name="enabled" type="boolean" default="true">
              Enable or disable this recognizer.
            </ResponseField>

            <ResponseField name="replacement" type="string">
              Custom replacement text for this entity type (e.g., `[PII_EMAIL]`). Per-server replacements override gateway defaults.
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

***

## Gateway Policy

Gateway-level policy defaults that apply to all servers unless overridden. In distributed mode, these are merged with organization policies from the Control Plane.

```yaml theme={null}
gateway_policy:
  scrubbing:
    enabled: true
    sensitive_fields:
      - password
      - api_key
    whitelist_fields:
      - connection_id
      - session_id
      - cursor
    custom_rules:
      - pattern: "sk-[a-zA-Z0-9]+"
        method: mask
    recognizers:
      - entity_type: EMAIL_ADDRESS
        enabled: true
      - entity_type: URL
        enabled: false        # Disable URL scrubbing

  server_rbac:
    rbac_enabled: true
    rbac_mode: allow
    allowed_groups: [gateway-users]
    denied_groups: []
    capability_rbac_enabled: false

  capability_rbac:
    read_only:
      default_groups: [all-users]
    destructive:
      default_groups: [power-users]
    unspecified:
      default_groups: [all-users]

  # Gateway-level threat whitelist patterns
  threat_whitelist_patterns:
    - "Rate limit exceeded for tenant [A-Za-z0-9_-]+"
```

### Scrubbing Policy

The scrubbing configuration uses the same schema at both gateway and server levels. All fields are merged using union — if any layer adds a field or rule, it applies.

| Field              | Type  | Default | Description                                                                     |
| ------------------ | ----- | ------- | ------------------------------------------------------------------------------- |
| `enabled`          | bool  | `false` | Enable PII scrubbing                                                            |
| `sensitive_fields` | array | `[]`    | Field names to always mask as `[MASKED]`                                        |
| `whitelist_fields` | array | `[]`    | Field names that should never be scrubbed (protects operational data)           |
| `custom_rules`     | array | `[]`    | Custom regex-based scrubbing rules (see [server security](#servers) for schema) |
| `recognizers`      | array | `[]`    | Toggle and configure built-in PII recognizers                                   |

<Info>
  When recognizer configs are merged across layers (org → gateway → server), **`enabled: true` wins** over `enabled: false` (most-restrictive doctrine). Server-specific `replacement` text overrides gateway defaults.
</Info>

### Server RBAC Policy

| Field                     | Type  | Default | Description                          |
| ------------------------- | ----- | ------- | ------------------------------------ |
| `rbac_enabled`            | bool  | `false` | Default RBAC enabled for new servers |
| `rbac_mode`               | enum  | `allow` | Default RBAC mode                    |
| `allowed_groups`          | array | `[]`    | Default allowed groups               |
| `denied_groups`           | array | `[]`    | Default denied groups                |
| `capability_rbac_enabled` | bool  | `false` | Default capability RBAC enabled      |

### Capability RBAC Policy

| Field                        | Type  | Description                           |
| ---------------------------- | ----- | ------------------------------------- |
| `read_only.default_groups`   | array | Default groups for read-only tools    |
| `destructive.default_groups` | array | Default groups for destructive tools  |
| `unspecified.default_groups` | array | Default groups for unclassified tools |

### Local Servers Policy

Controls the gateway-level blocking policy for locally-defined servers.

| Field     | Type  | Default | Description                         |
| --------- | ----- | ------- | ----------------------------------- |
| `enabled` | bool  | `false` | Enable local server blocking policy |
| `mode`    | enum  | `allow` | Blocking mode: `allow` or `deny`    |
| `groups`  | array | `null`  | Groups affected by this policy      |

### Threat Whitelist Patterns

| Field                       | Type  | Default | Description                                                                                    |
| --------------------------- | ----- | ------- | ---------------------------------------------------------------------------------------------- |
| `threat_whitelist_patterns` | array | `[]`    | Regex patterns for content that should bypass LLM threat detection at the gateway policy level |

***

## Security

The security section controls how the security subsystem operates: LLM backend, threat detection model, replay protection, and rate limiting. This is **operational configuration**, not policy — it does not participate in the org → gateway → server policy merge cascade.

```yaml theme={null}
security:
  llm:
    backend: v1                              # v1, v2, or remote
    model_name: qualifire/prompt-injection-jailbreak-sentinel-v2
    confidence_threshold: 0.93
    whitelist_patterns:                      # Content that bypasses threat detection
      - "Unauthorized: Your organization \\(org_[A-Za-z0-9]+\\)"

    # Remote backend config (required when backend: remote)
    # remote:
    #   endpoint: https://my-model.eastus.inference.ml.azure.com/score
    #   api_key_env: GOLF_SECURITY_REMOTE_API_KEY

  replay_protection:
    enabled: true

  rate_limiting:
    enabled: true
    requests_per_minute: 100
    window_seconds: 60
```

### LLM Threat Detection

| Field                | Type   | Default | Description                                                    |
| -------------------- | ------ | ------- | -------------------------------------------------------------- |
| `backend`            | string | `v1`    | LLM backend: `v1`, `v2`, or `remote` (HTTP endpoint)           |
| `whitelist_patterns` | array  | `[]`    | Regex patterns for content that should bypass threat detection |
| `remote`             | object | -       | Remote inference config (required when `backend: remote`)      |

### Remote Inference Config

Required when `security.llm.backend` is `remote`.

| Field               | Type   | Default                              | Description                                      |
| ------------------- | ------ | ------------------------------------ | ------------------------------------------------ |
| `endpoint`          | string | **Required**                         | URL of the remote inference endpoint             |
| `api_key_env`       | string | `GOLF_SECURITY_REMOTE_API_KEY`       | Environment variable name containing the API key |
| `tenant_id_env`     | string | `GOLF_SECURITY_REMOTE_TENANT_ID`     | Env var for Azure AD tenant ID                   |
| `client_id_env`     | string | `GOLF_SECURITY_REMOTE_CLIENT_ID`     | Env var for Azure AD client ID                   |
| `client_secret_env` | string | `GOLF_SECURITY_REMOTE_CLIENT_SECRET` | Env var for Azure AD client secret               |

<Note>
  Protocol is auto-detected from the endpoint URL: `azure_ml` for `*.inference.ml.azure.com` URLs, `generic` otherwise. Set all three Azure AD fields to enable Azure AD authentication; otherwise key-based auth is used.
</Note>

### Replay Protection

| Field     | Type | Default | Description                     |
| --------- | ---- | ------- | ------------------------------- |
| `enabled` | bool | `true`  | Enable replay attack protection |

### Rate Limiting

| Field                 | Type | Default | Range  | Description                  |
| --------------------- | ---- | ------- | ------ | ---------------------------- |
| `enabled`             | bool | `true`  | -      | Enable rate limiting         |
| `requests_per_minute` | int  | `1000`  | 1-5000 | Requests per minute per user |
| `window_seconds`      | int  | `60`    | 10-300 | Rate limit window            |

<Note>
  YAML configures the **per-user** limit only. System-wide (**global**) and **per-server** limits are managed through the Control Plane. See [Configure Rate Limiting](/gateway/guides/operations/configure-rate-limiting) for the full model.
</Note>

***

## OAuth Server

Configure the gateway's MCP OAuth authorization server for third-party server authentication flows.

```yaml theme={null}
oauth_server:
  token_ttl: 3600
  refresh_token_ttl: 604800
  authorization_code_ttl: 60
  idp_client_id: ${GOLF_OAUTH_SERVER_IDP_CLIENT_ID}
  idp_client_secret: ${GOLF_OAUTH_SERVER_IDP_CLIENT_SECRET}
```

| Field                    | Type   | Default     | Range        | Description                               |
| ------------------------ | ------ | ----------- | ------------ | ----------------------------------------- |
| `issuer`                 | string | gateway URL | -            | OAuth issuer URL                          |
| `token_ttl`              | int    | `3600`      | 300-86400    | Access token TTL in seconds               |
| `refresh_token_ttl`      | int    | `604800`    | 3600-2592000 | Refresh token TTL in seconds              |
| `authorization_code_ttl` | int    | `60`        | 30-600       | Authorization code TTL in seconds         |
| `idp_client_id`          | string | -           | -            | IdP client ID for the OAuth server        |
| `idp_client_secret`      | string | -           | -            | IdP client secret (supports `${ENV_VAR}`) |

***

## Exporters

Configure multiple export destinations for audit logs. You can configure multiple exporters of each type.

```yaml theme={null}
exporters:
  elasticsearch:
    - name: primary-es
      enabled: true
      url: ${ELASTICSEARCH_URL}
      api_key: ${ELASTICSEARCH_API_KEY}
      index_prefix: golf-gateway
      timeout: 30

  otel:
    - name: primary-otel
      enabled: true
      endpoint: ${OTEL_ENDPOINT}
      protocol: grpc
      service_name: golf-gateway
      export_logs: true

  sentinel:
    - name: azure-sentinel
      enabled: true
      dcr_immutable_id: ${SENTINEL_DCR_ID}
      dcr_endpoint: ${SENTINEL_DCR_ENDPOINT}
      tenant_id: ${AZURE_TENANT_ID}
      client_id: ${AZURE_CLIENT_ID}
      client_secret: ${AZURE_CLIENT_SECRET}
```

### Exporter Schema

<ResponseField name="exporters" type="object">
  Configure audit log export destinations.

  <Expandable title="exporter types" defaultOpen>
    <ResponseField name="elasticsearch" type="array">
      Elasticsearch export configurations.

      <Expandable title="elasticsearch exporter">
        <ResponseField name="name" type="string" required>
          Unique exporter name.
        </ResponseField>

        <ResponseField name="enabled" type="boolean" default="true">
          Enable this exporter.
        </ResponseField>

        <ResponseField name="url" type="string">
          Elasticsearch URL for self-hosted deployments (e.g., `https://localhost:9200`).
        </ResponseField>

        <ResponseField name="cloud_id" type="string">
          Elastic Cloud ID (alternative to `url`).
        </ResponseField>

        <ResponseField name="api_key" type="string">
          API key for authentication.
        </ResponseField>

        <ResponseField name="index_prefix" type="string" default="golf-gateway">
          Index name prefix. Creates indices like `golf-gateway-2024.01.15`.
        </ResponseField>

        <ResponseField name="timeout" type="integer" default="30">
          Request timeout in seconds (5-120).
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="otel" type="array">
      OpenTelemetry export configurations.

      <Expandable title="otel exporter">
        <ResponseField name="name" type="string" required>
          Unique exporter name.
        </ResponseField>

        <ResponseField name="enabled" type="boolean" default="true">
          Enable this exporter.
        </ResponseField>

        <ResponseField name="endpoint" type="string" required>
          OTLP endpoint URL (e.g., `http://localhost:4317`).
        </ResponseField>

        <ResponseField name="protocol" type="enum" default="grpc">
          OTLP protocol: `grpc`, `http/protobuf`, or `http/json`.
        </ResponseField>

        <ResponseField name="service_name" type="string" default="golf-gateway">
          Service name in OpenTelemetry.
        </ResponseField>

        <ResponseField name="timeout" type="integer" default="30">
          Export timeout in seconds (5-120).
        </ResponseField>

        <ResponseField name="export_logs" type="boolean" default="true">
          Export audit logs as OTLP logs.
        </ResponseField>

        <ResponseField name="export_metrics" type="boolean" default="false">
          Export gateway metrics.
        </ResponseField>

        <ResponseField name="export_traces" type="boolean" default="false">
          Export request traces.
        </ResponseField>

        <ResponseField name="headers" type="object" default="{}">
          Additional HTTP headers (e.g., `Authorization: Bearer TOKEN`).
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="sentinel" type="array">
      Microsoft Sentinel export configurations.

      <Expandable title="sentinel exporter">
        <ResponseField name="name" type="string" required>
          Unique exporter name.
        </ResponseField>

        <ResponseField name="enabled" type="boolean" default="true">
          Enable this exporter.
        </ResponseField>

        <ResponseField name="dcr_immutable_id" type="string" required>
          Data Collection Rule immutable ID.
        </ResponseField>

        <ResponseField name="dcr_endpoint" type="string" required>
          DCR logs ingestion endpoint (HTTPS URL).
        </ResponseField>

        <ResponseField name="dcr_stream_name" type="string" default="Custom-GolfGateway_CL">
          DCR stream name for the custom table.
        </ResponseField>

        <ResponseField name="tenant_id" type="string" required>
          Azure AD tenant ID.
        </ResponseField>

        <ResponseField name="client_id" type="string" required>
          Service principal client ID.
        </ResponseField>

        <ResponseField name="client_secret" type="string" required>
          Service principal client secret.
        </ResponseField>

        <ResponseField name="timeout" type="integer" default="30">
          Request timeout in seconds (5-120).
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  For Elasticsearch, use either `url` (self-hosted) or `cloud_id` (Elastic Cloud), not both.
</Note>

***

## Control Plane Connection

Connects the gateway to the Control Plane for centralized policy management and monitoring. The presence of this section activates **Distributed mode**.

```yaml theme={null}
control_plane:
  url: https://control-plane.example.com
  api_key: ${GOLF_CP_API_KEY}
  gateway_id: 550e8400-e29b-41d4-a716-446655440000
  timeout: 30
  cache_ttl: 300
```

| Field        | Type   | Required | Default                | Description                                        |
| ------------ | ------ | -------- | ---------------------- | -------------------------------------------------- |
| `url`        | string | Yes      | `https://api.golf.dev` | Control Plane URL                                  |
| `api_key`    | string | Yes      | -                      | API key for authentication (supports `${ENV_VAR}`) |
| `gateway_id` | UUID   | Yes      | -                      | Gateway UUID                                       |
| `timeout`    | int    | No       | `30`                   | Request timeout (5-120 seconds)                    |
| `cache_ttl`  | int    | No       | `300`                  | Policy cache TTL in seconds (60-3600)              |

***

## Complete Example

A complete Distributed mode configuration with Control Plane connection, identity providers, servers, security, and exporters:

```yaml theme={null}
version: "1.0"

# Control Plane connection (activates distributed mode)
control_plane:
  url: https://control-plane.example.com
  api_key: ${GOLF_CP_API_KEY}
  gateway_id: 550e8400-e29b-41d4-a716-446655440000

# Identity providers for authentication
identity_providers:
  - name: auth0
    type: auth0
    issuer: https://myorg.auth0.com/
    jwks_uri: https://myorg.auth0.com/.well-known/jwks.json
    api_identifiers:
      - https://api.example.com
    client_id: ${AUTH0_MGMT_CLIENT_ID}
    client_secret: ${AUTH0_MGMT_CLIENT_SECRET}

# MCP servers (YAML is source of truth for servers in distributed mode)
servers:
  - name: github-mcp
    url: http://github-mcp:3001
    server_type: third_party
    rbac_enabled: true
    allowed_groups: [engineering]
    idp: auth0
    security:
      enabled: true
      sensitive_fields: [token]
    threat_whitelist_patterns:
      - "GitHub API rate limit exceeded"

  - name: internal-tools
    url: http://tools-mcp:3002
    server_type: inhouse
    rbac_enabled: false

# OAuth authorization server for third-party server auth flows
oauth_server:
  idp_client_id: ${GOLF_OAUTH_SERVER_IDP_CLIENT_ID}
  idp_client_secret: ${GOLF_OAUTH_SERVER_IDP_CLIENT_SECRET}

# Local policy (merged with org policy from Control Plane)
gateway_policy:
  scrubbing:
    enabled: true
    sensitive_fields: [ssn, account_number]
    whitelist_fields: [connection_id, session_id]
  server_rbac:
    rbac_enabled: true
    allowed_groups: [gateway-users]

# Security engine settings
security:
  llm:
    backend: v1
    confidence_threshold: 0.93
  replay_protection:
    enabled: true
  rate_limiting:
    enabled: true
    requests_per_minute: 100

# Audit log exporters
exporters:
  elasticsearch:
    - name: primary
      url: ${ELASTICSEARCH_URL}
      api_key: ${ELASTICSEARCH_API_KEY}
```

***

## Validation Rules

### Version

* Must be exactly `"1.0"`
* Required field

### Identity Providers

* Names must be unique across all providers
* For non-Descope providers: `issuer` and `jwks_uri` are required
* For Descope: `project_id` is required; `issuer` and `jwks_uri` are auto-generated
* For Entra ID: `tenant_id` is required

### Servers

* Names must be unique across all servers
* `idp` references must match an existing identity provider name
* `url` must be a valid URL
* When gateway and server both enable RBAC, their `rbac_mode` must be consistent (cannot mix `allow` and `deny` across policy levels)

### Exporters

* Names must be unique within each exporter type
* Elasticsearch: use `url` OR `cloud_id`, not both
* OTEL: `endpoint` required when enabled
* Sentinel: all DCR and auth fields required when enabled

### Security

* When `security.llm.backend` is `remote`, the `security.llm.remote` block is required

### Control Plane

* When present, `url`, `api_key`, and `gateway_id` are required
* `organization_id` is optional — resolved from Control Plane during activation if not set
* Mode is auto-detected: `control_plane` present = Distributed mode

***

## Configuration Validation CLI

Validate configuration files before deployment:

```bash theme={null}
# The gateway validates config on startup
GOLF_CONFIG_FILE=/path/to/config.yaml python -m golf_gateway.main --validate

# Check for undefined environment variables
GOLF_CONFIG_FILE=/path/to/config.yaml python -c "
from golf_gateway.config.yaml_loader import validate_yaml_config
errors = validate_yaml_config('/path/to/config.yaml')
for error in errors:
    print(error)
"
```

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Environment Variables" icon="terminal" href="/gateway/reference/environment-variables">
    Configure Golf Gateway using environment variables
  </Card>

  <Card title="Audit Log Schema" icon="scroll" href="/gateway/reference/audit-log-schema">
    Complete audit log entry structure reference
  </Card>

  <Card title="RBAC Configuration" icon="users" href="/gateway/guides/rbac">
    Set up role-based access control
  </Card>

  <Card title="Deployment Guide" icon="rocket" href="/gateway/guides/deployment">
    Deploy Golf Gateway to production
  </Card>
</CardGroup>
