Skip to main content

Overview

Infisical provides end-to-end encrypted secrets management for your MCP Server. Store API keys, credentials, and configuration securely with automatic injection and rotation.
Infisical is an open-source alternative to HashiCorp Vault with a focus on developer experience and end-to-end encryption.

Why Infisical?

Security

  • End-to-end encryption
  • Zero-knowledge architecture
  • Audit logging
  • Secret versioning

Developer Experience

  • Simple API
  • CLI tools
  • SDK support
  • Auto-injection

Operations

  • Secret rotation
  • Access controls
  • Environment sync
  • Compliance ready

Integration

  • Kubernetes native
  • CI/CD pipelines
  • Cloud platforms
  • Docker Compose

Quick Start

1

Sign Up

  1. Go to https://app.infisical.com
  2. Create account
  3. Create organization
  4. Create project: “mcp-server-langgraph”
2

Create Service Account

In Infisical Dashboard:
  1. Go to Project Settings → Service Accounts
  2. Click “Create Service Account”
  3. Name: langgraph-production
  4. Select environment: production
  5. Set permissions: Read
  6. Copy Client ID and Client Secret
3

Configure Application

# .env
INFISICAL_CLIENT_ID=your-client-id
INFISICAL_CLIENT_SECRET=your-client-secret
INFISICAL_PROJECT_ID=your-project-id
INFISICAL_ENVIRONMENT=production  # dev, staging, production
4

Add Secrets to Infisical

In Infisical Dashboard:
  1. Go to Secrets
  2. Select production environment
  3. Add secrets:
    • ANTHROPIC_API_KEY
    • GOOGLE_API_KEY
    • JWT_SECRET_KEY
    • KEYCLOAK_CLIENT_SECRET
    • REDIS_PASSWORD
5

Test Integration

from mcp_server_langgraph.config import settings

# Secrets automatically loaded from Infisical
print(f"LLM Provider: {settings.llm_provider}")
print(f"Has API Key: {bool(settings.anthropic_api_key)}")

Self-Hosted Deployment

  • Docker Compose
  • Kubernetes
# docker-compose.yml
infisical:
  image: infisical/infisical:latest
  environment:
    - ENCRYPTION_KEY=${ENCRYPTION_KEY}
    - JWT_SECRET=${JWT_SECRET}
    - MONGO_URL=mongodb://mongo:27017/infisical
    - REDIS_URL=redis://redis:6379
  ports:
    - "8080:8080"
  depends_on:
    - mongo
    - redis

mongo:
  image: mongo:6
  volumes:
    - mongo-data:/data/db

redis:
  image: redis:7-alpine
  volumes:
    - redis-data:/data
# Generate secrets
export ENCRYPTION_KEY=$(openssl rand -hex 32)
export JWT_SECRET=$(openssl rand -hex 32)

# Start Infisical
docker compose up -d infisical

Usage Patterns

Automatic Secret Loading

Secrets are automatically loaded on application startup:
from mcp_server_langgraph.core.config import settings

## All secrets loaded from Infisical
api_key = settings.anthropic_api_key
db_password = settings.redis_password
jwt_secret = settings.jwt_secret_key

Manual Secret Retrieval

from infisical import InfisicalClient

client = InfisicalClient(
    client_id=os.getenv("INFISICAL_CLIENT_ID"),
    client_secret=os.getenv("INFISICAL_CLIENT_SECRET")
)

## Get single secret
secret = client.get_secret(
    secret_name="ANTHROPIC_API_KEY",
    project_id=os.getenv("INFISICAL_PROJECT_ID"),
    environment="production"
)
print(secret.secret_value)

## Get all secrets
secrets = client.get_all_secrets(
    project_id=os.getenv("INFISICAL_PROJECT_ID"),
    environment="production"
)

for secret in secrets:
    print(f"{secret.secret_name}: {secret.secret_value}")

Environment-Specific Secrets

## Load secrets based on environment
environment = os.getenv("ENVIRONMENT", "development")

secrets = client.get_all_secrets(
    project_id=project_id,
    environment=environment  # dev, staging, production
)

Kubernetes Integration

Infisical Operator

## Install operator
kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8s-operator/operator.yaml

## Create secret sync
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: langgraph-secrets
  namespace: mcp-server-langgraph
spec:
  hostAPI: https://app.infisical.com/api
  resyncInterval: 60
  authentication:
    universalAuth:
      credentialsRef:
        secretName: infisical-credentials
        secretNamespace: mcp-server-langgraph
  managedSecretReference:
    secretName: mcp-server-langgraph-secrets
    secretNamespace: mcp-server-langgraph

Service Account Credentials

apiVersion: v1
kind: Secret
metadata:
  name: infisical-credentials
  namespace: mcp-server-langgraph
type: Opaque
stringData:
  clientId: your-client-id
  clientSecret: your-client-secret

Auto-Inject Secrets

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-server-langgraph
spec:
  template:
    spec:
      containers:
      - name: agent
        envFrom:
        - secretRef:
            name: mcp-server-langgraph-secrets  # Auto-synced from Infisical

Secret Organization

Folder Structure

mcp-server-langgraph/
├── production/
│   ├── api-keys/
│   │   ├── ANTHROPIC_API_KEY
│   │   ├── GOOGLE_API_KEY
│   │   └── OPENAI_API_KEY
│   ├── authentication/
│   │   ├── JWT_SECRET_KEY
│   │   ├── KEYCLOAK_CLIENT_SECRET
│   │   └── REDIS_PASSWORD
│   └── observability/
│       └── LANGSMITH_API_KEY
├── staging/
│   └── ...
└── development/
    └── ...

Naming Conventions

Good:
  • ANTHROPIC_API_KEY (service + type)
  • DATABASE_PASSWORD (resource + type)
  • JWT_SECRET_KEY (purpose + type)
Bad:
  • KEY1 (unclear)
  • secret (not descriptive)
  • temp_api_key (indicates temporary usage)

Access Control

Role-Based Access

## Read-only for application
service_account_read = client.create_service_account(
    name="langgraph-prod-readonly",
    permissions=["read"]
)

## Write access for CI/CD
service_account_write = client.create_service_account(
    name="cicd-deploy",
    permissions=["read", "write"]
)

Audit Logging

Enable audit logs to track secret access:
## View audit logs
logs = client.get_audit_logs(
    project_id=project_id,
    start_date="2025-10-01",
    end_date="2025-10-12"
)

for log in logs:
    print(f"{log.timestamp}: {log.user} {log.action} {log.secret_name}")

Secret Rotation

Manual Rotation

## Update secret value
client.update_secret(
    secret_name="ANTHROPIC_API_KEY",
    secret_value="new-api-key",
    project_id=project_id,
    environment="production"
)

## Application automatically picks up new value on next fetch

Automatic Rotation

import schedule
import time

def rotate_jwt_secret():
    """Rotate JWT secret weekly"""
    new_secret = generate_secure_key(256)

    client.update_secret(
        secret_name="JWT_SECRET_KEY",
        secret_value=new_secret,
        project_id=project_id,
        environment="production"
    )

    print(f"Rotated JWT secret at {datetime.now()}")

## Schedule weekly rotation
schedule.every().sunday.at("02:00").do(rotate_jwt_secret)

while True:
    schedule.run_pending()
    time.sleep(3600)

Zero-Downtime Rotation

## 1. Add new secret with version suffix
client.create_secret(
    secret_name="ANTHROPIC_API_KEY_V2",
    secret_value="new-key",
    project_id=project_id,
    environment="production"
)

## 2. Deploy application using new secret

## 3. Delete old secret
client.delete_secret(
    secret_name="ANTHROPIC_API_KEY_V1",
    project_id=project_id,
    environment="production"
)

Best Practices

Never commit secrets to Git:
# Add to .gitignore
.env
.env.*
secrets.yaml
credentials.json

# Scan for leaked secrets
git secrets --scan
Create dedicated service accounts per environment:
  • langgraph-dev (development)
  • langgraph-staging (staging)
  • langgraph-prod (production)
  • cicd-deploy (CI/CD pipelines)
Grant minimal necessary permissions:
# Application: read-only
app_account = create_service_account(
    name="app",
    permissions=["read"]
)

# Operators: read + write
ops_account = create_service_account(
    name="ops",
    permissions=["read", "write"]
)
Establish rotation schedule:
  • API Keys: Every 90 days
  • Passwords: Every 60 days
  • JWT Secrets: Every 30 days
  • After Incidents: Immediately
Enable and review audit logs:
# Weekly audit review
logs = client.get_audit_logs(
    project_id=project_id,
    start_date=last_week
)

# Alert on suspicious activity
for log in logs:
    if log.action == "delete" or log.failed_attempts > 3:
        send_alert(log)

Migration from .env Files

1

Export Secrets

# Extract from .env
grep -v '^#' .env | grep -v '^$' > secrets.txt
```html
</Step>

<Step title="Import to Infisical">

Import script

with open(‘secrets.txt’) as f: for line in f: key, value = line.strip().split(’=’, 1) client.create_secret( secret_name=key, secret_value=value, project_id=project_id, environment=“production” )

</Step>

<Step title="Update Application">
```bash
# Remove .env file
rm .env

# Add Infisical config
echo "INFISICAL_CLIENT_ID=..." > .env
echo "INFISICAL_CLIENT_SECRET=..." >> .env
echo "INFISICAL_PROJECT_ID=..." >> .env
2

Verify

# Test application loads secrets
python -c "from mcp_server_langgraph.config import settings; print(settings.anthropic_api_key[:10])"

Troubleshooting

# Verify credentials
echo $INFISICAL_CLIENT_ID
echo $INFISICAL_CLIENT_SECRET

# Test authentication
curl -X POST https://app.infisical.com/api/v1/auth/universal-auth/login \
  -H "Content-Type: application/json" \
  -d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}"
Check:
  • Secret name matches exactly (case-sensitive)
  • Correct environment selected
  • Service account has access
  • Project ID correct
# List all secrets
secrets = client.get_all_secrets(
    project_id=project_id,
    environment="production"
)
print([s.secret_name for s in secrets])
Solutions:
  • Cache secrets locally
  • Use Kubernetes operator for auto-sync
  • Batch secret retrieval
# Cache secrets
from functools import lru_cache

@lru_cache(maxsize=1)
def get_secrets():
    return client.get_all_secrets(
        project_id=project_id,
        environment="production"
    )

Next Steps


Secure by Default: Infisical ensures your secrets are encrypted and centrally managed!