Bifrost
The Rainbow Bridge - Communications Gateway & MCP Admin Portal.
Overview
Bifrost is the unified gateway connecting Norns AI agents to all communication realms and external services. It provides centralized tool management, channel configuration, service integration, credential management, and execution metrics.
Access
| Service | URL |
|---|---|
| API | https://bifrost-api.ravenhelm.dev |
| Admin Portal | https://bifrost.ravenhelm.dev |
| GitLab Repo | https://gitlab.ravenhelm.dev/nwalker85/bifrost |
Features
MCP Tool Registry
- Centralized tool definitions
- Executor routing (Norns, n8n, HTTP, native, custom executors)
- Input/output schema validation
- Execution audit logging
- Tool domains for categorization
Executor Types
Bifrost routes tool execution through specialized executors based on executor_type:
| Executor Type | Description | Tools |
|---|---|---|
native | Built-in Bifrost tools | System tools |
openapi | OpenAPI spec-based execution | Imported API tools |
mcp_proxy | Proxy to external MCP servers | MCP-compatible services |
norns_delegate | Delegate to Norns agent | Legacy Norns tools |
n8n_workflow | Execute n8n workflows | Workflow automations |
bifrost_internal | Internal Bifrost operations | onboard_user, CMDB, AIOps |
google_calendar | Google Calendar API | Calendar tools |
google_maps | Google Maps API | get_directions, get_travel_time, search_places |
observability | Grafana/Loki stack | check_metrics, container_status, grafana_dashboard, query_logs |
grocy | Grocy inventory API | add_shopping_item, query_inventory |
home_assistant | Home Assistant API | home_command, home_status |
todoist | Todoist task management | complete_task, create_task, get_daily_summary, query_projects, query_tasks, update_task |
telephony | Voice gateway | check_call_status, make_phone_call |
knowledge | Weather/search APIs | get_weather, search_news, web_search |
Credential Management
- Secure credential storage via OpenBao vault
- Write-only API (secrets never returned)
- Support for API keys, OAuth2, and basic auth
- Masked credential display (
has_*boolean flags) - Auth failure responses with proper error codes
- Legacy Fernet encryption for backward compatibility
Execution Metrics
- Real-time tool execution tracking
- Success/failure rates
- Latency percentiles (p50, p95, p99)
- Per-tool and per-executor breakdowns
- Error breakdown analysis
- Time-series data for charts
- OpenTelemetry instrumentation
Channel Management
- Slack workspace integration
- Discord server connections
- Email (SMTP/IMAP)
- SMS via Twilio
Agent Management
- Register AI agents
- Credential management
- Capability tracking
- Health monitoring
OAuth Scopes
- Fine-grained permission scopes
- Tool, domain, and service-level access control
- Scope assignments to users, agents, API keys
n8n Integration
- Workflow discovery
- Tool synchronization
- Direct workflow execution
Service Integrations
- OpenAPI spec import
- MCP server proxying
- Native tool handlers
Architecture
Bifrost
├── bifrost-api (FastAPI)
│ ├── /api/v1/tools - Tool registry
│ ├── /api/v1/credentials - Credential management
│ ├── /api/v1/channels - Channel management
│ ├── /api/v1/agents - Agent registration
│ ├── /api/v1/metrics - Execution metrics
│ ├── /api/v1/scopes - OAuth scopes
│ ├── /api/v1/n8n/* - n8n integration
│ ├── /api/v1/openapi/* - OpenAPI imports
│ ├── /mcp/tools/list - MCP protocol
│ └── /mcp/tools/call - Tool execution
├── Executors
│ ├── router.py - Routes to appropriate executor
│ ├── base.py - ExecutorType enum & base class
│ ├── norns_delegate.py - Delegate to Norns
│ ├── n8n_workflow.py - n8n workflow execution
│ ├── openapi.py - OpenAPI spec execution
│ ├── mcp_proxy.py - MCP server proxy
│ ├── bifrost_internal.py - Internal operations
│ ├── google_calendar.py - Calendar
│ ├── google_maps.py - Navigation
│ ├── observability.py - Metrics/logs
│ ├── grocy.py - Inventory
│ ├── home_assistant.py - Smart home
│ ├── todoist.py - Task management
│ ├── telephony.py - Voice calls
│ └── knowledge.py - Weather/search
└── bifrost-admin (Next.js)
├── Dashboard
├── Tools browser & detail pages
├── Credentials management
├── Metrics dashboard
├── Channels config
├── Services management
├── OAuth Scopes
└── Agents management
Custom Executors
Each custom executor handles specific tool categories with their own credential requirements:
Google Maps (google_maps)
- Credential:
google_mapsAPI key - Tools:
get_directions,get_travel_time,search_places - API: Google Maps Platform APIs
Observability (observability)
- Credential:
grafanaAPI key - Tools:
check_metrics,container_status,grafana_dashboard,query_logs - APIs: Grafana, Loki, Prometheus
Grocy (grocy)
- Credential:
grocyAPI key - Tools:
add_shopping_item,query_inventory - API: Grocy HTTP API
Home Assistant (home_assistant)
- Credential:
home_assistantLong-Lived Access Token - Tools:
home_command,home_status - API: Home Assistant REST API
Todoist (todoist)
- Credential:
todoistAPI key - Tools:
complete_task,create_task,get_daily_summary,query_projects,query_tasks,update_task - API: Todoist REST API v2
Telephony (telephony)
- Credential: Internal voice-gateway auth
- Tools:
check_call_status,make_phone_call - API: Voice Gateway HTTP API
Knowledge (knowledge)
- Credentials:
openweathermapAPI key,tavilyAPI key - Tools:
get_weather,search_news,web_search - APIs: OpenWeatherMap, Tavily Search
Bifrost Internal (bifrost_internal)
- Tools:
onboard_user, CMDB tools, AIOps tools - Purpose: Internal Bifrost operations requiring database access
Credential Management
Overview
Bifrost uses a hybrid storage model for credentials:
- Metadata (name, description, auth_type, timestamps) stored in PostgreSQL
- Secrets (API keys, tokens, passwords) stored in OpenBao vault
Storage Types
| Type | Description | Use Case |
|---|---|---|
vault | Secrets stored in OpenBao | New credentials (default) |
fernet | Legacy encrypted in database | Existing credentials |
Security Features
- Encrypted at rest: OpenBao with GCP KMS auto-unseal
- Encrypted in transit: HTTPS/TLS to vault.ravenhelm.dev
- Write-only API: Secrets never returned after submission
- Masked display:
has_*boolean flags show which fields are set - Audit logging: All credential operations logged
Vault Path Structure
secret/data/bifrost/{org_id}/{credential_id}
Example:
secret/data/bifrost/00000000-0000-0000-0000-000000000001/a3b63bce-4ceb-4a85-9c40-d5e5aa662fbf
Auth Types
| Type | Required Fields | Optional Fields |
|---|---|---|
api_key | api_key | - |
oauth2 | client_id, client_secret | access_token, refresh_token |
basic | client_id, client_secret | - |
none | - | - |
API Response Format
Credentials are returned with masked fields:
{
"credential_id": "a3b63bce-4ceb-4a85-9c40-d5e5aa662fbf",
"name": "todoist",
"auth_type": "api_key",
"has_client_id": false,
"has_client_secret": false,
"has_api_key": true,
"has_access_token": false,
"has_refresh_token": false,
"storage_type": "vault"
}
Auth Failure Error Codes
| Code | Description |
|---|---|
CREDENTIAL_NOT_FOUND | Credential ID doesn't exist |
CREDENTIAL_MISSING_FIELD | Required field not set |
CREDENTIAL_EXPIRED | OAuth token expired |
AUTH_FAILED | External API rejected credentials |
VAULT_ERROR | Failed to communicate with vault |
Migration from Fernet to Vault
A migration script is available at:
/Users/ravenhelm/ravenhelm/services/bifrost/scripts/migrate_credentials_to_openbao.py
Usage:
# Dry run (shows what would be migrated)
python migrate_credentials_to_openbao.py --dry-run
# Actual migration
python migrate_credentials_to_openbao.py
Admin Portal Pages
| Page | Path | Description |
|---|---|---|
| Dashboard | / | Overview and quick stats |
| Tools | /tools | Browse all MCP tools with execution metrics |
| Tool Detail | /tools/[id] | Tool config, input schema, execution log |
| Credentials | /credentials | Credential management |
| Metrics | /metrics | Execution analytics dashboard |
| Channels | /channels | Communication channel configuration |
| Services | /services | OpenAPI and MCP service integrations |
| Scopes | /scopes | OAuth scope management |
| Agents | /agents | Registered AI agents |
| Audit | /audit | Audit log viewer |
API Endpoints
Credentials
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/credentials | List credentials (metadata only) |
| GET | /api/v1/credentials/{id} | Get credential (metadata only) |
| POST | /api/v1/credentials | Create credential |
| PATCH | /api/v1/credentials/{id} | Update credential |
| DELETE | /api/v1/credentials/{id} | Delete credential |
| POST | /api/v1/credentials/{id}/test | Test credential validity |
| POST | /api/v1/credentials/{id}/rotate | Rotate/invalidate credential |
Tools
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/admin/tools | List all tools |
| GET | /api/v1/admin/tools/{id} | Get tool details |
| GET | /api/v1/admin/domains | List tool domains |
Metrics
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/metrics/summary | Aggregated metrics with percentiles |
| GET | /api/v1/metrics/timeseries | Time-bucketed metrics for charts |
| GET | /api/v1/metrics/tools/{id} | Tool-specific metrics |
| GET | /api/v1/metrics/tools/{id}/executions | Tool execution log |
Channels
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/channels | List channels |
| POST | /api/v1/channels | Create channel |
| PUT | /api/v1/channels/{id} | Update channel |
| DELETE | /api/v1/channels/{id} | Delete channel |
| POST | /api/v1/channels/{id}/test | Test channel connectivity |
Scopes
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/scopes | List scopes |
| POST | /api/v1/scopes | Create scope |
| PATCH | /api/v1/scopes/{id} | Update scope |
| DELETE | /api/v1/scopes/{id} | Delete scope |
| POST | /api/v1/scopes/check-access | Check access permissions |
Health
| Method | Endpoint | Description |
|---|---|---|
| GET | /health | Basic health check |
| GET | /health/db | Database health |
| GET | /health/docs/infrastructure/redis | Redis health |
| GET | /health/vault | OpenBao vault health |
MCP Protocol
| Method | Endpoint | Description |
|---|---|---|
| GET | /mcp/tools/list | List available tools (MCP spec) |
| POST | /mcp/tools/call | Execute a tool (MCP spec) |
Authentication
MCP endpoints require agent authentication via headers:
| Header | Description |
|---|---|
X-Agent-ID | UUID of the registered agent |
X-API-Key | API key associated with the agent |
Scope-Based Authorization
The /mcp/tools/call endpoint enforces scope-based authorization. Agents must have appropriate scopes to execute tools.
Scope Patterns:
| Scope | Description |
|---|---|
* | Full access (wildcard) |
tools:execute | Execute any tool (wildcard) |
tools:execute:{tool_name} | Execute specific tool only |
Authorization Logic:
- Agent must have at least one of:
*,tools:execute, ortools:execute:{tool_name} - Scopes are checked against the authenticated agent's assigned scopes
- Missing scope returns
SCOPE_DENIEDerror
Request Format:
{
"organization_id": "00000000-0000-0000-0000-000000000001",
"tool_name": "get_weather",
"arguments": {"location": "San Francisco"}
}
Error Response (Missing Scope):
{
"success": false,
"error": "Missing required scope: 'tools:execute' or 'tools:execute:get_weather'",
"error_code": "SCOPE_DENIED"
}
Example Scope Assignments:
- Production agent:
*(full access) - Weather bot:
tools:execute:get_weather,tools:execute:search_news - Read-only agent: No
tools:executescopes (can only list tools)
Observability
Bifrost integrates with the observability stack:
OpenTelemetry
- Traces exported to Tempo via Alloy
- Metrics exported to Prometheus via Alloy
- OTLP endpoint:
alloy:4317(gRPC)
Metrics Collected
| Metric | Type | Description |
|---|---|---|
bifrost_tool_executions_total | Counter | Total tool executions by tool, executor, success |
bifrost_tool_execution_duration_ms | Histogram | Execution duration distribution |
bifrost_tool_execution_errors_total | Counter | Error count by tool and error type |
bifrost_active_executions | UpDownCounter | Currently running executions |
Database Audit (Requester Identity)
All tool executions are logged to the tool_executions table with:
- Input arguments
- Results or errors
- Execution time
- Agent and request context
- Requester identity: auth_method, auth_subject, authorized_via
Configuration
Environment Variables
# Database
BIFROST_DB_HOST=postgres
BIFROST_DB_PORT=5432
BIFROST_DB_NAME=ravenmaskos
BIFROST_DB_USER=ravenhelm
BIFROST_DB_PASSWORD=xxx
# Redis
BIFROST_REDIS_HOST=redis
BIFROST_REDIS_PORT=6379
# Security
BIFROST_API_KEY=xxx
BIFROST_ENCRYPTION_KEY=xxx # Legacy, for Fernet-encrypted credentials
# OpenBao Vault
BIFROST_VAULT_ADDR=https://vault.ravenhelm.dev
BIFROST_VAULT_ROLE_ID=xxx
BIFROST_VAULT_SECRET_ID=xxx
BIFROST_VAULT_MOUNT_PATH=secret
# Zitadel OAuth
BIFROST_ZITADEL_ISSUER=https://auth.ravenhelm.dev
BIFROST_ZITADEL_CLIENT_ID=xxx
# Norns Integration
BIFROST_NORNS_URL=http://docs/AI-ML-Platform/norns-agent:8000
BIFROST_NORNS_API_KEY=xxx
# n8n Integration
BIFROST_N8N_URL=https://n8n.ravenhelm.dev
BIFROST_N8N_API_KEY=xxx
# External Service APIs (for executors)
GOOGLE_MAPS_API_KEY=xxx
OPENWEATHERMAP_API_KEY=xxx
TAVILY_API_KEY=xxx
HOME_ASSISTANT_URL=http://homeassistant.local:8123
HOME_ASSISTANT_TOKEN=xxx
GROCY_URL=http://grocy.ravenhelm.dev
GROCY_API_KEY=xxx
VOICE_GATEWAY_URL=http://voice-gateway:8080
# OpenTelemetry
BIFROST_OTEL_ENDPOINT=alloy:4317
Operations
Start Service
cd /Users/ravenhelm/ravenhelm/services/bifrost
docker compose up -d
Rebuild After Changes
cd /Users/ravenhelm/ravenhelm/services/bifrost
docker compose build bifrost-api bifrost-admin
docker compose up -d bifrost-api bifrost-admin
View Logs
docker logs bifrost-api -f
docker logs bifrost-admin -f
Health Check
# Basic health
curl https://bifrost-api.ravenhelm.dev/health
# Vault health
curl https://bifrost-api.ravenhelm.dev/health/vault
Related Services
- Norns - AI agents that use Bifrost for tool execution
- OpenBao - Secrets management (vault.ravenhelm.dev)
- Vidar - SRE automation (uses separate tool registry)
- Alloy - OTLP collector for traces and metrics
- Prometheus - Metrics storage
- Tempo - Trace storage
- Home Assistant - Smart home control
- Grocy - Inventory management
- Voice Gateway - Telephony services
Database Tables
Bifrost uses the ravenmaskos database:
Core
organizations- Multi-tenant orgsapi_keys- API authenticationregistered_agents- AI agents
Tools
tool_definitions- MCP tool registrytool_domains- Tool categorizationtool_executions- Execution audit log
Credentials
oauth_credentials- Credential metadata and legacy encrypted secretscredential_migration_log- Migration tracking
Channels
channels- Channel configsconnections- Service connectionschannel_messages- Message history
Services
external_services- OpenAPI/MCP service registrations
RBAC
oauth_scopes- Permission scopesscope_assignments- Scope grantsuser_organization_roles- Role assignmentspermission_grants- Direct permissions
Audit Log Fields
Every tool execution is logged with complete requester identity:
| Field | Description | Example Values |
|---|---|---|
| auth_method | How the requester authenticated | internal, api_key, agent, oauth |
| auth_subject | Human-readable identity | "Norns Agent", "API Key: prod-key", "internal service" |
| auth_subject_id | UUID of the authenticated principal | agent_id, key_id, user_id |
| authorized_via | What permission granted access | "internal", "read, execute", scope names |
This ensures all tool executions can be traced back to exactly who made the request and what authority they used.
Changelog
January 2025 - MCP Tool Migration (v2.0)
Migrated all hardcoded Norns tools to Bifrost custom executors:
- RAV-214: Google Maps executor (navigation tools)
- RAV-215: Grocy executor (inventory tools)
- RAV-216: Observability executor (metrics/logging tools)
- RAV-217: Knowledge executor (weather/search tools)
- RAV-218: Todoist executor (task management tools)
- RAV-219: Home Assistant executor (smart home tools)
- RAV-220: Telephony executor (voice call tools)
- RAV-221: Bifrost Internal executor (admin/CMDB/AIOps tools)
This migration moves tool execution from direct API calls in Norns to the centralized Bifrost gateway, enabling:
- Unified credential management via OpenBao
- Consistent execution metrics and audit logging
- Centralized tool configuration
- Better separation of concerns between agent logic and external integrations