Bifrost MCP Gateway
The Rainbow Bridge - Communications Gateway & Tool Registry for Ravenhelm Agents
Overview
Bifrost provides:
- Tool Registry - Centralized ownership of all tool definitions with permission-based access
- Execution Gateway - Routes tool calls to appropriate executors (Norns, n8n, OpenAPI)
- n8n Auto-Discovery - Automatically discovers and syncs n8n workflows as MCP tools
- Channel Gateway - Routes messages from multiple channels (Slack, SIP, Web) to agents
- Admin Portal - Configure channels, tools, and permissions
Services
| Service | Port | URL | Purpose |
|---|---|---|---|
| bifrost-api | 8000 | https://bifrost-api.ravenhelm.dev | Tool execution API |
| bifrost-admin | 3000 | https://bifrost.ravenhelm.dev | Admin UI (Next.js) |
Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ BIFROST TOOL REGISTRY │
├─────────────────────────────────────────────────────────────────────────┤
│ Tool Sources │ Execution Gateway │
│ ┌─────────────┐ │ ┌─────────────────────────────────┐ │
│ │ Norns │─────┐ │ │ POST /mcp/tools/call │ │
│ │ (delegate) │ │ │ │ │ │
│ ├─────────────┤ │ │ │ ┌─────────────────────────┐ │ │
│ │ n8n │─────┼──────────▶│ │ │ ExecutorRouter │ │ │
│ │ workflows │ │ │ │ │ - NornsDelegateExecutor│ │ │
│ ├─────────────┤ │ │ │ │ - N8nWorkflowExecutor │ │ │
│ │ OpenAPI │─────┘ │ │ │ - OpenAPIExecutor (*) │ │ │
│ │ imports (*)│ │ │ │ - MCPProxyExecutor (*) │ │ │
│ └─────────────┘ │ │ └─────────────────────────┘ │ │
│ │ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
▲
┌───────────────┼───────────────┐
│ │ │
┌────┴────┐ ┌─────┴─────┐ ┌────┴────┐
│ Norns │ │ Voice │ │ Future │
│ Agent │ │ Gateway │ │ Agents │
└─────────┘ └───────────┘ └─────────┘
(*) = Planned, not yet implemented
n8n Auto-Discovery
Bifrost can automatically discover n8n workflows and register them as MCP tools.
Discovery Criteria
Workflows are discovered when they:
- Have the
[MCP]prefix in their name (e.g.,[MCP] Send Alert), OR - Are tagged with
tool:enabled - Have a Webhook trigger node with a valid path
- Are active (not draft/inactive)
n8n Integration API
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/n8n/connections | GET | List configured n8n connections |
/api/v1/n8n/discover | GET | Preview discoverable workflows |
/api/v1/n8n/sync | POST | Sync workflows to tool registry |
/api/v1/n8n/sync/history | GET | View sync history |
Discovery Commands
# Preview what will be synced
curl -s "http://localhost:8000/api/v1/n8n/discover" \
-H "X-API-Key: $BIFROST_API_KEY"
# Sync workflows to tool registry
curl -s -X POST "http://localhost:8000/api/v1/n8n/sync" \
-H "X-API-Key: $BIFROST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"connection_name": "default"}'
# Check sync history
curl -s "http://localhost:8000/api/v1/n8n/sync/history" \
-H "X-API-Key: $BIFROST_API_KEY"
Workflow Metadata (YAML Front Matter)
Add metadata to the workflow Notes field for custom tool configuration:
---
mcp_tool:
enabled: true
name: send_alert
description: Send an alert to Slack
domain: notifications
timeout_ms: 30000
input_schema:
type: object
required:
- message
properties:
message:
type: string
description: Alert message
---
Database Tables
-- n8n connection configuration
CREATE TABLE n8n_connections (
connection_id UUID PRIMARY KEY,
org_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
display_name VARCHAR(255),
n8n_url VARCHAR(500) NOT NULL,
api_key_encrypted TEXT,
auto_sync BOOLEAN DEFAULT false,
sync_interval_minutes INTEGER DEFAULT 5,
status VARCHAR(50) DEFAULT 'active',
last_sync_at TIMESTAMPTZ,
last_sync_status VARCHAR(50)
);
-- Sync history for auditing
CREATE TABLE n8n_sync_history (
sync_id UUID PRIMARY KEY,
connection_id UUID REFERENCES n8n_connections(connection_id),
org_id UUID NOT NULL,
status VARCHAR(50) NOT NULL,
workflows_discovered INTEGER DEFAULT 0,
tools_created INTEGER DEFAULT 0,
tools_updated INTEGER DEFAULT 0,
error_message TEXT,
started_at TIMESTAMPTZ DEFAULT NOW(),
completed_at TIMESTAMPTZ,
duration_ms INTEGER
);
See [[../Automation/n8n#Bifrost MCP Integration]] for workflow creation details.
Executor Framework
Tools are executed through specialized executors based on executor_type:
NornsDelegateExecutor
Forwards tool calls to Norns agent during transition period:
# Flow: Bifrost → Norns /api/tool/execute → LangChain @tool → Result
executor_config = {
"norns_tool_name": "query_tasks", # Tool name in Norns
"timeout_override": 60000 # Optional timeout
}
N8nWorkflowExecutor
Executes n8n workflows via production webhooks:
executor_config = {
"webhook_url": "https://n8n.ravenhelm.dev/webhook/abc123",
"workflow_id": "abc123", # For reference
"webhook_secret": "...", # Optional
"timeout_override": 60000 # Optional
}
Webhook Payload Format:
{
"arguments": {...},
"context": {
"request_id": "uuid",
"org_id": "uuid",
"agent_id": "uuid",
"agent_name": "norns"
}
}
Expected Response:
{
"success": true,
"result": {...},
"metadata": {...}
}
ExecutorRouter
Routes tool calls to appropriate executor:
router = ExecutorRouter(
norns_url="http://docs/AI-ML-Platform/norns-agent:8000",
norns_api_key="...",
n8n_url="https://n8n.ravenhelm.dev",
n8n_api_key="..."
)
result = await router.execute(tool, arguments, context)
API Endpoints
Health Checks
GET /health- Basic healthGET /health/db- Database connectivityGET /health/docs/infrastructure/redis- Redis connectivity
Organizations
GET /api/v1/organizations- List organizations
Channels
GET /api/v1/channels- List channelsPOST /api/v1/channels- Create channelPUT /api/v1/channels/{id}- Update channelDELETE /api/v1/channels/{id}- Delete channelPOST /api/v1/channels/{id}/test- Test connectivity
Tools
GET /api/v1/tools- List tool definitionsPOST /api/v1/tools- Create toolPUT /api/v1/tools/{id}- Update tool
n8n Integration
GET /api/v1/n8n/connections- List n8n connectionsGET /api/v1/n8n/discover- Preview discoverable workflowsPOST /api/v1/n8n/sync- Sync workflows to registryGET /api/v1/n8n/sync/history- View sync history
MCP Protocol (Agent-facing)
POST /mcp/tools/list- List available tools (filtered by permissions)POST /mcp/tools/call- Execute a tool
Documentation
GET /docs- Swagger UIGET /openapi.json- OpenAPI spec
Tool Registry
See [[Bifrost-Tool-Catalog]] for complete tool documentation with examples.
Current Tools (22)
| Domain | Tools |
|---|---|
| tasks | query_tasks, create_task, update_task, complete_task, query_projects |
| calendar | calendar_read, calendar_create |
| home | home_status, home_command |
| shopping | add_shopping_item, query_inventory |
| navigation | get_directions, get_travel_time, search_places |
| observability | container_status, query_logs, check_metrics, grafana_dashboard |
| assistant | get_daily_summary |
| admin | onboard_user |
| system | n8n_echo, bifrost_echo_tool |
Tool Execution Flow
1. Agent calls POST /mcp/tools/call
2. Bifrost looks up tool in tool_definitions table
3. ExecutorRouter selects executor based on executor_type
4. Executor invokes target system (Norns, n8n, etc.)
5. Result returned through chain to agent
Database Schema
tool_definitions
CREATE TABLE tool_definitions (
tool_id UUID PRIMARY KEY,
org_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
input_schema JSONB NOT NULL,
output_schema JSONB,
executor_type VARCHAR(50) NOT NULL, -- 'norns_delegate', 'n8n_workflow', etc.
executor_config JSONB DEFAULT '{}',
domain VARCHAR(100),
status VARCHAR(50) DEFAULT 'active',
timeout_ms INTEGER DEFAULT 30000,
n8n_connection_id UUID, -- For n8n-synced tools
n8n_workflow_id VARCHAR(255), -- n8n workflow ID
last_synced_at TIMESTAMPTZ, -- Last sync timestamp
created_at TIMESTAMPTZ DEFAULT NOW()
);
tool_executions (Audit Log)
CREATE TABLE tool_executions (
execution_id UUID PRIMARY KEY,
tool_id UUID REFERENCES tool_definitions(tool_id),
org_id UUID NOT NULL,
agent_id VARCHAR(255),
arguments JSONB,
result JSONB,
success BOOLEAN,
error_message TEXT,
execution_time_ms INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Authentication
API Authentication
All API endpoints require:
X-API-Key: <bifrost_api_key>
Admin Portal SSO
The admin portal uses Zitadel OIDC via NextAuth.js:
- Client ID:
BIFROST_ZITADEL_CLIENT_ID - Issuer:
https://auth.ravenhelm.dev
Configuration
Environment Variables
# Database
BIFROST_DB_HOST=postgres
BIFROST_DB_PORT=5432
BIFROST_DB_NAME=ravenmaskos
BIFROST_DB_USER=ravenhelm
BIFROST_DB_PASSWORD=<password>
# Redis
BIFROST_REDIS_HOST=redis
BIFROST_REDIS_PORT=6379
BIFROST_REDIS_PASSWORD=<password>
# Norns Integration
BIFROST_NORNS_URL=http://docs/AI-ML-Platform/norns-agent:8000
NORNS_API_KEY=<key>
# n8n Integration
BIFROST_N8N_URL=https://n8n.ravenhelm.dev
BIFROST_N8N_API_KEY=<key>
# API Security
BIFROST_API_KEY=<key>
BIFROST_ZITADEL_ISSUER=https://auth.ravenhelm.dev
# Admin Portal
AUTH_ZITADEL_CLIENT_ID=<client_id>
AUTH_ZITADEL_CLIENT_SECRET=<secret>
AUTH_SECRET=<nextauth_secret>
NEXTAUTH_URL=https://bifrost.ravenhelm.dev
BIFROST_API_URL=http://bifrost-api:8000
Docker Compose
services:
bifrost-api:
build:
context: ./api
dockerfile: Dockerfile
container_name: bifrost-api
networks:
- ravenhelm_net
environment:
- BIFROST_DB_HOST=postgres
- BIFROST_NORNS_URL=http://docs/AI-ML-Platform/norns-agent:8000
labels:
- "traefik.http.routers.bifrost-api.rule=Host(\`bifrost-api.ravenhelm.dev\`)"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
bifrost-admin:
build:
context: ./admin
dockerfile: Dockerfile
container_name: bifrost-admin
networks:
- ravenhelm_net
environment:
- NEXTAUTH_URL=https://bifrost.ravenhelm.dev
- BIFROST_API_URL=http://bifrost-api:8000
labels:
- "traefik.http.routers.bifrost-admin.rule=Host(\`bifrost.ravenhelm.dev\`)"
depends_on:
- bifrost-api
Common Operations
Start/Restart
cd ~/ravenhelm/services/bifrost
docker-compose up -d
# View logs
docker-compose logs -f bifrost-api
Test Tool Execution
curl -X POST https://bifrost-api.ravenhelm.dev/mcp/tools/call \
-H "Content-Type: application/json" \
-H "X-API-Key: $BIFROST_API_KEY" \
-d '{
"organization_id": "00000000-0000-0000-0000-000000000001",
"tool_name": "get_daily_summary",
"arguments": {}
}'
List Tools
curl https://bifrost-api.ravenhelm.dev/api/v1/tools \
-H "X-API-Key: $BIFROST_API_KEY"
Sync n8n Tools
# Discover available workflows
curl https://bifrost-api.ravenhelm.dev/api/v1/n8n/discover \
-H "X-API-Key: $BIFROST_API_KEY"
# Sync to registry
curl -X POST https://bifrost-api.ravenhelm.dev/api/v1/n8n/sync \
-H "X-API-Key: $BIFROST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"connection_name": "default"}'
Troubleshooting
Tool Execution Fails
-
Check Bifrost logs:
docker logs bifrost-api --tail=100 -
Verify executor target is healthy:
- Norns:
curl http://docs/AI-ML-Platform/norns-agent:8000/health - n8n:
curl https://n8n.ravenhelm.dev/healthz
- Norns:
-
Check tool_executions table for error details:
SELECT * FROM tool_executions
WHERE success = false
ORDER BY created_at DESC LIMIT 10;
n8n Tool Not Discovered
- Verify workflow is active in n8n
- Check workflow has
[MCP]prefix ORtool:enabledtag - Verify webhook node exists with valid path
- Check n8n API key is configured in Bifrost
Admin Portal Auth Issues
- Verify Zitadel configuration
- Check NextAuth logs:
docker logs bifrost-admin - Confirm callback URL is registered in Zitadel
Connection Errors
-
Verify containers are on same network:
docker network inspect ravenhelm_net -
Test internal DNS resolution:
docker exec bifrost-api nslookup norns-agent
Roadmap
- N8nWorkflowExecutor - Execute n8n workflows as tools
- n8n Auto-Discovery - Automatically sync workflows as tools
- OpenAPI Executor - Import external APIs as tools
- MCP Proxy Executor - Forward to external MCP servers
- Native Executor - In-process Python functions
- Tool permissions - Fine-grained access control
- Rate limiting - Per-tool and per-agent limits
- Caching - Result caching for idempotent tools
- Auto-sync scheduling - Periodic discovery without manual trigger
See Also
- [[Norns-Agent]] - Primary AI agent
- [[../DevOps/MCP-Servers]] - MCP server integration
- [[../Automation/n8n]] - Workflow automation with Bifrost integration