Pathfinder-Experience: Foundry MCP Env Vars + Adapter Policy Skeleton

1) Environment variable block

Use this as a starter .env block for the ingestion adapter.

# Foundry MCP endpoint (Cloudflare Tunnel hostname)
FOUNDRY_MCP_URL="https://mcp-foundry.example.com"
 
# Cloudflare Access service token (recommended)
# Leave blank only if you intentionally run without Access (not recommended)
CF_ACCESS_CLIENT_ID=""
CF_ACCESS_CLIENT_SECRET=""
 
# Adapter behavior
FOUNDRY_MCP_TIMEOUT_MS="12000"
FOUNDRY_MCP_RETRIES="2"
FOUNDRY_MCP_POLL_INTERVAL_SEC="120"
FOUNDRY_MCP_ENABLED="true"
 
# Safety controls
FOUNDRY_MCP_FAIL_CLOSED="true"
FOUNDRY_MCP_ALLOWLIST_PATH="./config/foundry-mcp-allowlist.yaml"
FOUNDRY_MCP_AUDIT_LOG="./logs/foundry-mcp-audit.log"

Notes

  • Keep FOUNDRY_MCP_FAIL_CLOSED=true.
  • If Access is enabled, requests must include both CF_ACCESS_CLIENT_ID + CF_ACCESS_CLIENT_SECRET headers.
  • Keep polling conservative during live sessions.

2) Adapter policy skeleton (YAML)

Create: config/foundry-mcp-allowlist.yaml

version: 1
mode: deny_by_default
sourceTag: foundry-live
 
transport:
  baseUrlEnv: FOUNDRY_MCP_URL
  timeoutMsEnv: FOUNDRY_MCP_TIMEOUT_MS
  retriesEnv: FOUNDRY_MCP_RETRIES
  cloudflareAccessHeaders:
    clientIdEnv: CF_ACCESS_CLIENT_ID
    clientSecretEnv: CF_ACCESS_CLIENT_SECRET
 
# Only these tool/resource names are allowed.
# Replace example names with real names from recon.
allow:
  - name: foundry.getWorldInfo
    class: SAFE_READ
    cacheTtlSec: 300
  - name: foundry.getInitiative
    class: SAFE_READ
    cacheTtlSec: 10
  - name: foundry.getPartyStatus
    class: SAFE_READ
    cacheTtlSec: 15
 
# Sensitive reads may be allowed only with explicit filters.
sensitive:
  - name: foundry.listActors
    class: SENSITIVE_READ
    requireFilters:
      - hideGmOnly
      - hideHiddenNpc
      - hidePrivateNotes
 
# Always blocked, regardless of caller intent.
# Use wildcard/prefix patterns your adapter supports.
deny:
  - pattern: "*.create*"
  - pattern: "*.update*"
  - pattern: "*.delete*"
  - pattern: "*.set*"
  - pattern: "*.execute*"
  - pattern: "*.eval*"
  - pattern: "*.admin*"
 
responsePolicy:
  includeSourceTag: true
  includeToolName: true
  includeFetchedAt: true
  redactFields:
    - gmNotes
    - privateNotes
    - hidden
    - secret
    - ownership
 
observability:
  auditLogPathEnv: FOUNDRY_MCP_AUDIT_LOG
  logDeniedCalls: true
  logAllowedCalls: true
  metrics:
    enabled: true
 
failurePolicy:
  failClosedEnv: FOUNDRY_MCP_FAIL_CLOSED
  onPolicyMismatch: deny
  onMissingAuth: deny
  onTimeout: fail

3) Minimal request header contract (if Access enabled)

CF-Access-Client-Id: <CF_ACCESS_CLIENT_ID>
CF-Access-Client-Secret: <CF_ACCESS_CLIENT_SECRET>

4) Quick adapter pseudo-flow

incoming query
  -> resolve required tool
  -> check allowlist (deny by default)
  -> attach Access headers (if configured)
  -> call MCP with timeout + retries
  -> apply field redaction policy
  -> stamp metadata (source/tool/fetchedAt)
  -> return sanitized payload

5) Acceptance checks

  • Denied tool call returns policy error.
  • Allowed read call returns payload with source=foundry-live.
  • Sensitive call removes redacted fields.
  • Missing Access headers (when configured) fails closed.