Skip to main content

Overview

The MCP Server with LangGraph uses YAML configuration files and environment variables for flexible, declarative configuration. This reference documents all configuration files and their options.

.env.example

Complete environment variable template for service configuration

ldap_mappers.yaml

LDAP/AD attribute mapping configuration

oidc_providers.yaml

OpenID Connect provider definitions

role_mappings.yaml

Keycloak to OpenFGA role mapping rules

.env.example

Complete environment variable template for configuring the MCP Server with LangGraph.

Location

/.env.example

Usage

## Copy template and customize
cp .env.example .env

## Edit values (NEVER commit .env to git)
nano .env

## Load for local development
source .env
python -m mcp_server_langgraph

Configuration Sections

SERVICE_NAME=mcp-server-langgraph
SERVICE_VERSION=2.8.0
ENVIRONMENT=development  # development, staging, production
# Primary provider: google, anthropic, openai, azure, bedrock, ollama
LLM_PROVIDER=google

# Model settings
MODEL_NAME=gemini-2.5-flash
MODEL_TEMPERATURE=0.7
MODEL_MAX_TOKENS=8192
MODEL_TIMEOUT=60

# Fallback models (tries in order if primary fails)
ENABLE_FALLBACK=true
# FALLBACK_MODELS=["claude-haiku-4-5-20251001","gpt-5.1"]
Supported Providers:
  • google: Gemini (AI Studio or Vertex AI)
  • anthropic: Claude models
  • openai: GPT-4, GPT-3.5
  • azure: Azure OpenAI
  • bedrock: AWS Bedrock
  • ollama: Local models
  • Google Gemini
  • Anthropic
  • OpenAI
  • Azure OpenAI
  • AWS Bedrock
  • Ollama
# Option 1: AI Studio (development)
GOOGLE_API_KEY=your-key-here
# Get from: https://aistudio.google.com/apikey

# Option 2: Vertex AI (production)
VERTEX_PROJECT=your-gcp-project-id
VERTEX_LOCATION=us-central1

# On GKE: Use Workload Identity (no credentials needed)
# Locally: Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
# Auth Provider: inmemory, keycloak
AUTH_PROVIDER=inmemory

# Auth Mode: token (JWT), session
AUTH_MODE=token

# JWT Configuration
# ⚠️ PRODUCTION: Generate with: openssl rand -base64 32
JWT_SECRET_KEY=your-secret-key-change-in-production
JWT_ALGORITHM=HS256
JWT_EXPIRATION_SECONDS=3600

# OpenFGA (run setup_openfga.py to get IDs)
OPENFGA_API_URL=http://localhost:8080
OPENFGA_STORE_ID=
OPENFGA_MODEL_ID=
# When AUTH_PROVIDER=keycloak
KEYCLOAK_SERVER_URL=http://localhost:8082
KEYCLOAK_REALM=langgraph-agent
KEYCLOAK_CLIENT_ID=langgraph-client
KEYCLOAK_CLIENT_SECRET=your-client-secret-here
KEYCLOAK_VERIFY_SSL=true
KEYCLOAK_TIMEOUT=30
KEYCLOAK_HOSTNAME=localhost  # Public hostname for token validation
# Session Backend: memory, redis
SESSION_BACKEND=memory
SESSION_TTL_SECONDS=86400  # 24 hours

# Redis (when SESSION_BACKEND=redis)
REDIS_URL=redis://localhost:6379/0
REDIS_MAX_CONNECTIONS=10
REDIS_SOCKET_CONNECT_TIMEOUT=5
REDIS_HEALTH_CHECK_INTERVAL=30
# Infisical Integration
INFISICAL_ENABLED=false
INFISICAL_CLIENT_ID=your-client-id
INFISICAL_CLIENT_SECRET=your-client-secret
INFISICAL_PROJECT_ID=your-project-id
INFISICAL_ENVIRONMENT=dev  # dev, staging, prod
INFISICAL_API_URL=https://app.infisical.com/api
# Logging
LOG_LEVEL=INFO  # DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_FORMAT=json  # json, text
LOG_FILE=  # Optional file path

# OpenTelemetry
OTEL_ENABLED=false
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=mcp-server-langgraph
OTEL_TRACES_SAMPLER=always_on  # always_on, always_off, parentbased_always_on

# LangSmith Tracing
LANGCHAIN_TRACING_V2=false
LANGCHAIN_API_KEY=your-langsmith-key
LANGCHAIN_PROJECT=mcp-server-langgraph

# Prometheus Metrics
METRICS_ENABLED=true
METRICS_PORT=9090
# Checkpointing (persistence)
CHECKPOINT_ENABLED=true
CHECKPOINT_BACKEND=redis  # memory, redis, postgres

# PostgreSQL Checkpointer
# POSTGRES_URL=postgresql://user:pass@localhost:5432/langgraph

# Graph Settings
MAX_ITERATIONS=100
RECURSION_LIMIT=50
ENABLE_HUMAN_IN_LOOP=true

Security Best Practices

NEVER commit .env files to version control! Always use .env.example as a template and add .env to .gitignore.
1

Generate Strong Secrets

# JWT secret
openssl rand -base64 32

# Session secret
openssl rand -base64 64
2

Use Secrets Management

Production deployments should use:
  • Kubernetes Secrets
  • External Secrets Operator
  • Infisical (integrated)
  • HashiCorp Vault
  • AWS Secrets Manager
3

Environment-Specific Files

.env.development
.env.staging
.env.production

# Load based on environment
source .env.${ENVIRONMENT}

config/ldap_mappers.yaml

Defines how LDAP/Active Directory attributes map to Keycloak user attributes.

Location

/config/ldap_mappers.yaml

Used By

Structure

Maps LDAP attributes to Keycloak user attributes.
attribute_mappers:
  - name: email
    ldap_attribute: mail  # AD attribute
    keycloak_attribute: email  # Keycloak attribute
    read_only: true
    always_read_from_ldap: true
    mandatory: false

  - name: firstName
    ldap_attribute: givenName
    keycloak_attribute: firstName
    read_only: true
    always_read_from_ldap: true
    mandatory: false

  - name: lastName
    ldap_attribute: sn
    keycloak_attribute: lastName
    read_only: true
    always_read_from_ldap: true
    mandatory: false
Standard Mappings:
  • mailemail
  • givenNamefirstName
  • snlastName
  • displayNamedisplayName
  • departmentdepartment
  • titletitle
  • telephoneNumberphoneNumber
  • mobilemobilePhone
  • employeeNumberemployeeNumber
  • managermanager
Synchronizes LDAP groups to Keycloak groups.
group_mapper:
  enabled: true
  groups_dn: OU=Groups,DC=example,DC=com
  group_name_attribute: cn
  group_object_classes: group
  membership_attribute: member
  membership_type: DN
  preserve_inheritance: true
  user_attribute: distinguishedName
  groups_path: /
  mode: READ_ONLY
Parameters:
  • groups_dn: Base DN for group search
  • group_name_attribute: Attribute containing group name (usually cn)
  • membership_attribute: Attribute listing group members (AD: member)
  • preserve_inheritance: Maintain group hierarchy
  • mode: READ_ONLY (groups managed in LDAP only)
Controls synchronization schedule and behavior.
sync_settings:
  full_sync_period: 86400  # Daily (24 hours)
  changed_sync_period: 3600  # Hourly
  batch_size: 1000
  connection_timeout: 10000  # 10 seconds
  read_timeout: 30000  # 30 seconds
  connection_pooling: true
  pagination: true
Sync Types:
  • Full sync: Complete LDAP directory scan
  • Changed sync: Only changed users (requires USN changed attribute)
Maps LDAP groups to Keycloak roles.
role_mappings:
  - ldap_group: CN=Administrators,OU=Groups,DC=example,DC=com
    keycloak_role: admin

  - ldap_group: CN=Premium Users,OU=Groups,DC=example,DC=com
    keycloak_role: premium

  - ldap_group: CN=Engineers,OU=Groups,DC=example,DC=com
    keycloak_role: engineer
Users in the LDAP group automatically get assigned the corresponding Keycloak role.

Customization

  • Active Directory
  • Generic LDAP
  • Custom Attributes
Default configuration works with AD. Common AD attributes:
  • sAMAccountName: Username
  • userPrincipalName: UPN (email-like)
  • distinguishedName: DN
  • memberOf: Group memberships

config/oidc_providers.yaml

Defines OpenID Connect identity provider configurations for federation.

Location

/config/oidc_providers.yaml

Used By

Structure

Each provider has:
  • Basic settings (alias, display name, enabled)
  • OIDC endpoints and credentials
  • Attribute mappers (claims → user attributes)
providers:
  google:
    alias: google
    display_name: Google
    provider_id: google  # Keycloak built-in provider
    enabled: true
    trust_email: true
    config:
      client_id: ${GOOGLE_CLIENT_ID}
      client_secret: ${GOOGLE_CLIENT_SECRET}
      default_scope: "openid profile email"
      hosted_domain: ${GOOGLE_HOSTED_DOMAIN:-}

    mappers:
      - name: email
        claim: email
        user_attribute: email
      - name: firstName
        claim: given_name
        user_attribute: firstName
Keycloak has built-in support for:
  • Google
  • Microsoft
  • GitHub
google:
  alias: google
  display_name: Google
  provider_id: google
  config:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
    default_scope: "openid profile email"
    hosted_domain: ""  # Optional: restrict to domain
Get credentials from Google Cloud Console
For Okta, Auth0, OneLogin, or custom OIDC providers:
  • Okta
  • Auth0
  • Generic Template
okta:
  alias: okta
  display_name: Okta
  provider_id: oidc  # Generic OIDC
  config:
    client_id: ${OKTA_CLIENT_ID}
    client_secret: ${OKTA_CLIENT_SECRET}
    default_scope: "openid profile email groups"
    authorization_url: https://${OKTA_DOMAIN}/oauth2/v1/authorize
    token_url: https://${OKTA_DOMAIN}/oauth2/v1/token
    user_info_url: https://${OKTA_DOMAIN}/oauth2/v1/userinfo
    jwks_url: https://${OKTA_DOMAIN}/oauth2/v1/keys
    issuer: https://${OKTA_DOMAIN}
    validate_signature: true
    use_jwks_url: true
Maps OIDC claims to Keycloak user attributes:
mappers:
  - name: email
    claim: email  # OIDC claim
    user_attribute: email  # Keycloak attribute

  - name: firstName
    claim: given_name
    user_attribute: firstName

  - name: lastName
    claim: family_name
    user_attribute: lastName

  - name: groups
    claim: groups  # Provider-specific
    user_attribute: oktaGroups
Standard OIDC Claims:
  • sub: Subject (unique ID)
  • email: Email address
  • given_name: First name
  • family_name: Last name
  • preferred_username: Username
  • picture: Profile picture URL
global_settings:
  # Account linking strategy
  account_linking_strategy: AUTO  # AUTO, PROMPT, DISABLED

  # First broker login flow
  first_broker_login_flow: first broker login

  # Token exchange
  store_token: false  # Don't store IdP tokens
  add_read_token_role: false

  # Sync mode
  sync_mode: IMPORT  # IMPORT, FORCE, LEGACY
Account Linking:
  • AUTO: Automatically link to existing Keycloak account with same email
  • PROMPT: Ask user to confirm account linking
  • DISABLED: Always create new account
Sync Mode:
  • IMPORT: Import on first login
  • FORCE: Always update from IdP
  • LEGACY: Legacy behavior

config/role_mappings.yaml

Defines how Keycloak roles, groups, and attributes map to OpenFGA tuples.

Location

/config/role_mappings.yaml

Purpose

Enables flexible, declarative authorization without code changes. Automatically creates OpenFGA tuples based on Keycloak user data.

Structure

Direct 1:1 mapping from Keycloak roles to OpenFGA relations:
simple_mappings:
  # Admin role grants system-wide admin access
  - keycloak_role: admin
    realm: true  # Realm role (vs client role)
    openfga_relation: admin
    openfga_object: system:global

  # Premium role for paid users
  - keycloak_role: premium
    realm: true
    openfga_relation: assignee
    openfga_object: role:premium

  # Client-specific roles
  - keycloak_role: executor
    realm: false  # Client role
    openfga_relation: executor
    openfga_object: tool:all
Creates OpenFGA tuple:
user:{user_id}, admin, system:global
Maps Keycloak group hierarchy to organizations/teams using regex:
group_mappings:
  # Top-level groups → Organizations
  # Pattern: /acme → organization:acme
  - pattern: "^/([^/]+)$"
    openfga_relation: member
    openfga_object_template: "organization:{group_name}"

  # Nested groups → Teams
  # Pattern: /acme/engineering → team:engineering
  - pattern: "^/([^/]+)/([^/]+)$"
    openfga_relation: member
    openfga_object_template: "team:{group_name}"

  # Department-specific groups
  - pattern: "^/departments/([^/]+)$"
    openfga_relation: member
    openfga_object_template: "department:{group_name}"
Example:
  • User in /acme/engineering creates:
    • user:{id}, member, organization:acme
    • user:{id}, member, team:engineering
Grants permissions based on user attributes:
conditional_mappings:
  # Finance department gets access to financial reports
  - condition:
      attribute: department
      operator: "=="
      value: finance
    openfga_tuples:
      - relation: viewer
        object: resource:financial-reports
      - relation: viewer
        object: resource:audit-logs

  # High security clearance
  - condition:
      attribute: security_clearance
      operator: ">="
      value: 3
    openfga_tuples:
      - relation: viewer
        object: resource:classified

  # Manager role
  - condition:
      attribute: job_title
      operator: "in"
      value: [Manager, Director, VP, CEO]
    openfga_tuples:
      - relation: admin
        object: resource:team-reports

  # Region-specific access
  - condition:
      attribute: region
      operator: "=="
      value: EMEA
    openfga_tuples:
      - relation: viewer
        object: resource:emea-data
Supported Operators:
  • ==: Equals
  • !=: Not equals
  • in: Value in list
  • >=: Greater than or equal
  • <=: Less than or equal
Defines role inheritance:
hierarchies:
  # Admin inherits all permissions
  admin:
    - premium
    - user

  # Premium inherits user permissions
  premium:
    - user

  # Manager inherits contributor permissions
  manager:
    - contributor
    - user

  # Contributor inherits user permissions
  contributor:
    - user
Roles inherit all permissions from their children. Applied after all other mappings.

Application Order

Rules are applied in this order:
1

Simple Mappings

Process all simple role mappings first
2

Group Mappings

Apply group-based mappings with regex matching
3

Conditional Mappings

Evaluate conditions and create tuples
4

Hierarchies

Apply role inheritance
5

Deduplication

Remove duplicate tuples automatically

Examples

  • User with Admin Role
  • User in Engineering Group
  • Finance Manager
Keycloak:
  • Role: admin (realm role)
Creates OpenFGA Tuples:
user:alice, admin, system:global
user:alice, assignee, role:premium  (from hierarchy)
user:alice, assignee, role:user     (from hierarchy)

Best Practices

Version Control

  • Commit .yaml config files to git
  • NEVER commit .env files
  • Use .env.example as template
  • Document custom configurations

Secrets Management

  • Use Infisical or Vault for production
  • Rotate secrets regularly
  • Use Kubernetes Secrets for deployment
  • Audit secret access

Environment Separation

  • Separate configs per environment
  • Different secrets per environment
  • Test config changes in staging
  • Use CI/CD for config deployment

Validation

  • Validate YAML syntax
  • Test regex patterns
  • Verify OIDC endpoints
  • Check LDAP connectivity

See Also