-
Notifications
You must be signed in to change notification settings - Fork 401
Description
🧭 Epic
Title: Comprehensive Metadata Attribution for All MCP Gateway Entities
Goal: Track and display comprehensive metadata for all entities (Gateway, Virtual Server, Tool, Prompt, Resource) including creation details, source information, and audit trails for enhanced traceability and governance.
Why now: As MCP Gateway deployments scale across teams and environments, comprehensive metadata tracking becomes essential for security auditing, compliance, debugging, and operational workflows.
🧭 Type of Feature
- Enhancement to existing functionality
- New feature or capability
- Security Related (for auditability)
🙋♂️ User Story 1
As a: gateway admin
I want: to see comprehensive metadata for any entity in detail view
So that: I can trace origin, audit access, and understand entity lifecycle
✅ Acceptance Criteria
Scenario: View comprehensive metadata in detail view
Given I open the Admin UI
When I click "View" on any tool, server, gateway, prompt, or resource
Then I see a metadata section containing:
- Created by (username)
- Created at (timestamp)
- Created from IP address
- Creation source (UI/API/Import/Federation)
- Last modified by (username)
- Last modified at (timestamp)
- Last modified from IP
- Modification source
- Import batch ID (if applicable)
- Federation source gateway (if applicable)
- Version/revision number🙋♂️ User Story 2
As a: API consumer
I want: comprehensive metadata in JSON responses for all entities
So that: I can build audit trails, track provenance, and implement custom governance
✅ Acceptance Criteria
Scenario: Fetch comprehensive metadata via API
When I GET /tools, /servers, /gateways, /prompts, or /resources
Then each object includes metadata fields:
- created_by, created_at, created_from_ip, created_via
- modified_by, modified_at, modified_from_ip, modified_via
- import_batch_id, federation_source, version🙋♂️ User Story 3
As a: security auditor
I want: to track all creation and modification events with full context
So that: I can investigate security incidents and ensure compliance
✅ Acceptance Criteria
Scenario: Audit trail for security investigation
Given an entity was created or modified
When I access its metadata
Then I can see complete provenance including:
- Who performed the action (authenticated user)
- When it happened (precise timestamp)
- From where (IP address, user agent)
- How it was done (UI interaction, API call, bulk import, federation sync)
- What changed (if modification)📐 Design Sketch
🗃️ Schema Changes
Add comprehensive metadata columns to all entity tables:
-- Common metadata columns for all entities
-- Creation metadata
ALTER TABLE tools ADD COLUMN created_by TEXT;
ALTER TABLE tools ADD COLUMN created_at TIMESTAMP DEFAULT now();
ALTER TABLE tools ADD COLUMN created_from_ip INET;
ALTER TABLE tools ADD COLUMN created_via TEXT; -- 'ui', 'api', 'import', 'federation'
ALTER TABLE tools ADD COLUMN created_user_agent TEXT;
-- Modification metadata
ALTER TABLE tools ADD COLUMN modified_by TEXT;
ALTER TABLE tools ADD COLUMN modified_at TIMESTAMP DEFAULT now();
ALTER TABLE tools ADD COLUMN modified_from_ip INET;
ALTER TABLE tools ADD COLUMN modified_via TEXT;
ALTER TABLE tools ADD COLUMN modified_user_agent TEXT;
-- Source tracking metadata
ALTER TABLE tools ADD COLUMN import_batch_id TEXT; -- UUID for bulk imports
ALTER TABLE tools ADD COLUMN federation_source TEXT; -- Source gateway for federated entities
ALTER TABLE tools ADD COLUMN version INTEGER DEFAULT 1; -- For change tracking
-- Apply same schema to all entity tables
-- (repeat for resources, prompts, servers, gateways tables)🔄 Comprehensive Entity Coverage
Entities requiring metadata tracking:
- Tools - Individual MCP tools from servers
- Resources - MCP resources (files, data sources)
- Prompts - Prompt templates
- Servers - Virtual MCP servers (compositions)
- Gateways - Peer gateway instances (federation)
Additional metadata considerations:
- Request ID - Link to specific request that created/modified entity
- Session ID - Track admin UI sessions for user activity correlation
- Bulk Operation ID - Group related bulk import/export operations
- Parent Entity ID - Track hierarchical relationships (e.g., tool -> server)
- Configuration Hash - Detect configuration drift
- Validation Status - Track entity validation state
Migration Strategy: Backfill historical entries with reasonable defaults (
created_by: 'system',created_via: 'migration',created_from_ip: null)
🧩 Pydantic Schema Changes
Add comprehensive metadata to all Read schemas (ToolRead, ServerRead, ResourceRead, PromptRead, GatewayRead):
# Creation metadata
created_by: Optional[str] = Field(None, description="Username who created this entity")
created_at: Optional[datetime] = Field(None, description="When entity was created")
created_from_ip: Optional[str] = Field(None, description="IP address of creator")
created_via: Optional[str] = Field(None, description="Creation method: ui|api|import|federation")
created_user_agent: Optional[str] = Field(None, description="User agent of creation request")
# Modification metadata
modified_by: Optional[str] = Field(None, description="Username who last modified this entity")
modified_at: Optional[datetime] = Field(None, description="When entity was last modified")
modified_from_ip: Optional[str] = Field(None, description="IP address of last modifier")
modified_via: Optional[str] = Field(None, description="Modification method: ui|api|import|federation")
modified_user_agent: Optional[str] = Field(None, description="User agent of modification request")
# Source tracking
import_batch_id: Optional[str] = Field(None, description="UUID of bulk import batch")
federation_source: Optional[str] = Field(None, description="Source gateway for federated entities")
version: Optional[int] = Field(1, description="Entity version for change tracking")
# Optional extended metadata
request_id: Optional[str] = Field(None, description="Request ID that created/modified entity")
session_id: Optional[str] = Field(None, description="Admin UI session ID")
parent_entity_id: Optional[str] = Field(None, description="Parent entity for hierarchical tracking")📊 Metadata Display Schema
Create dedicated metadata response schema for detail views:
class EntityMetadata(BaseModel):
"""Comprehensive metadata for any MCP Gateway entity"""
# Core identification
entity_id: str = Field(description="Entity UUID")
entity_type: str = Field(description="Entity type: tool|resource|prompt|server|gateway")
# Creation tracking
creation: CreationMetadata = Field(description="Creation metadata")
# Modification tracking
last_modification: Optional[ModificationMetadata] = Field(None, description="Last modification metadata")
# Source and lineage
source: SourceMetadata = Field(description="Source and lineage information")
# Operational metadata
operational: OperationalMetadata = Field(description="Operational status and metrics")
class CreationMetadata(BaseModel):
created_by: str
created_at: datetime
created_from_ip: Optional[str]
created_via: str # ui|api|import|federation|system
created_user_agent: Optional[str]
class ModificationMetadata(BaseModel):
modified_by: str
modified_at: datetime
modified_from_ip: Optional[str]
modified_via: str
modified_user_agent: Optional[str]
class SourceMetadata(BaseModel):
import_batch_id: Optional[str]
federation_source: Optional[str]
parent_entity_id: Optional[str]
configuration_hash: Optional[str]
class OperationalMetadata(BaseModel):
version: int
validation_status: str # valid|invalid|pending
last_accessed_at: Optional[datetime]
access_count: Optional[int]🔄 Comprehensive Metadata Workflow
📝 Entity Creation Flow
-
Request Context Capture
- Extract authenticated user:
user: str = Depends(require_auth) - Capture client IP:
request.client.hostor via X-Forwarded-For headers - Extract User-Agent:
request.headers.get("user-agent") - Determine source:
ui(Admin UI),api(direct API),import(bulk),federation(peer sync) - Generate request ID for traceability
- Extract authenticated user:
-
Metadata Population
created_by= authenticated usernamecreated_at= current UTC timestampcreated_from_ip= client IP addresscreated_via= request source typecreated_user_agent= browser/client identificationversion= 1 (initial version)import_batch_id= UUID if part of bulk operationfederation_source= source gateway ID if federated
-
Entity Persistence
- Save entity with complete metadata
- Log creation event for audit trail
- Return entity with metadata in response
✏️ Entity Modification Flow
-
Update Context Capture
- Same context extraction as creation
- Increment
versionnumber - Preserve original creation metadata
-
Modification Tracking
modified_by= authenticated usernamemodified_at= current UTC timestampmodified_from_ip= client IP addressmodified_via= request source typemodified_user_agent= browser/client identification
-
Change Recording
- Log what changed (for audit trail)
- Update modification metadata
- Preserve creation metadata unchanged
🖥️ UI Display Strategy
List Views: Show minimal metadata (created_by, created_at) in tooltip or expandable row
Detail Views: Dedicated "Metadata" section with comprehensive information organized by:
- Creation Info - Who, when, from where, how
- Modification History - Last change details
- Source & Lineage - Import batch, federation source, parent relationships
- Operational Status - Version, validation, usage stats
Metadata Section Layout:
┌─ Metadata ──────────────────────────────────────┐
│ Creation: admin @ 2024-01-15 10:30:00 UTC │
│ Source: Admin UI (192.168.1.100) │
│ Last Change: alice @ 2024-01-16 14:22:00 UTC │
│ Version: 3 │
│ Import Batch: bulk-2024-01-15-001 (if applicable)│
│ Federation: gateway-prod-east (if applicable) │
└─────────────────────────────────────────────────┘
🧭 Implementation Tasks
🗄️ Database & Schema
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Create Alembic migration for metadata columns | High | Add all metadata columns to tools, resources, prompts, servers, gateways tables |
| [ ] | Add database indexes for metadata queries | Medium | Index on created_by, created_at, modified_at for performance |
| [ ] | Create metadata-specific database functions | Low | Stored procedures for common metadata queries |
| [ ] | Design metadata retention policy | Medium | How long to keep detailed metadata vs. summary data |
🛠️ Backend Services
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Create metadata capture utility functions | High | Extract IP, User-Agent, determine source type |
| [ ] | Update all create endpoints with metadata capture | High | tools, resources, prompts, servers, gateways |
| [ ] | Update all update endpoints with modification tracking | High | Preserve creation metadata, track modifications |
| [ ] | Add bulk import metadata tracking | Medium | Track import batch ID and bulk operation context |
| [ ] | Add federation metadata tracking | Medium | Track source gateway for federated entities |
| [ ] | Create metadata service layer | Medium | Centralized metadata management and queries |
| [ ] | Add audit logging for metadata events | Medium | Log creation/modification events for compliance |
📊 API & Schemas
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Update Pydantic Read schemas with metadata fields | High | All entity read schemas |
| [ ] | Create dedicated metadata response schemas | High | EntityMetadata, CreationMetadata, etc. |
| [ ] | Add metadata endpoints | Medium | GET /entities/{id}/metadata for detailed metadata |
| [ ] | Update OpenAPI documentation | Medium | Document all new metadata fields |
| [ ] | Add metadata filtering to list endpoints | Low | Filter by created_by, created_via, date ranges |
🖥️ Admin UI
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Add metadata section to all detail views | High | Show comprehensive metadata in "View" modals |
| [ ] | Update list views with basic metadata | Medium | Tooltips or expandable rows for created_by/created_at |
| [ ] | Add metadata-based filtering and search | Medium | Filter entities by creator, source, date ranges |
| [ ] | Create metadata history view | Low | Show modification history for entities |
| [ ] | Add metadata export functionality | Low | Export metadata reports for auditing |
🔧 Infrastructure & Utilities
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Create request context middleware | High | Capture IP, User-Agent, determine source automatically |
| [ ] | Add metadata validation | Medium | Ensure metadata consistency and completeness |
| [ ] | Create metadata migration script | High | Backfill existing entities with default metadata |
| [ ] | Add metadata configuration options | Medium | Control what metadata to capture via environment variables |
| [ ] | Create metadata cleanup utilities | Low | Archive old metadata, cleanup incomplete records |
🧪 Testing
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Unit tests for metadata capture | High | Test metadata population in all scenarios |
| [ ] | Integration tests for metadata API | High | Test metadata in create/read/update workflows |
| [ ] | UI tests for metadata display | Medium | Test metadata sections in detail views |
| [ ] | Performance tests with metadata | Medium | Ensure metadata doesn't impact performance |
| [ ] | Security tests for metadata access | High | Ensure metadata follows same auth rules as entities |
📚 Documentation
| Task | Description | Priority | Notes |
|---|---|---|---|
| [ ] | Update API documentation | High | Document all metadata fields and endpoints |
| [ ] | Create metadata user guide | Medium | How to use metadata features in admin UI |
| [ ] | Document metadata privacy considerations | High | IP address storage, data retention policies |
| [ ] | Create metadata troubleshooting guide | Low | Common issues and solutions |
🔗 MCP Standards Check
- ✔️ Metadata-only; no effect on MCP wire protocol
- ✔️ All metadata fields are optional; backward-compatible
- ✔️ Does not alter existing auth or business logic
- ✔️ Preserves MCP server functionality and tool execution
- ✔️ Metadata is gateway-specific, not propagated to MCP clients
- ✔️ Does not affect MCP JSON-RPC message format
🔒 Security & Privacy Considerations
🛡️ Data Protection
- IP Address Storage: Consider GDPR/privacy implications of storing IP addresses
- User Agent Storage: May contain personally identifiable information
- Retention Policy: Define how long to retain detailed metadata
- Access Control: Metadata should follow same permissions as parent entity
- Data Anonymization: Option to anonymize metadata after retention period
🔐 Security Features
- Audit Trail: Complete history of who did what, when, and from where
- Access Tracking: Monitor unusual access patterns via metadata
- Change Attribution: Link all changes to authenticated users
- Source Validation: Verify entity source claims against metadata
- Federation Security: Track trusted vs. untrusted federation sources
🚀 Future Enhancements
📊 Advanced Metadata Features
- Change History: Full audit log with before/after state tracking
- Metadata Versioning: Schema evolution for metadata fields
- Custom Metadata: Allow users to add custom metadata fields
- Automated Tagging: Auto-tag entities based on creation patterns
- Metadata Analytics: Usage patterns, popular creators, trend analysis
🔄 Integration Features
- SIEM Integration: Export metadata to security information systems
- Compliance Reporting: Generate compliance reports from metadata
- Workflow Integration: Trigger actions based on metadata changes
- External Identity: Link to external identity providers for richer user context
🌐 Federation Features
- Cross-Gateway Metadata: Sync metadata across federated gateways
- Metadata Conflicts: Handle metadata conflicts in federation scenarios
- Trust Scoring: Rate federation sources based on metadata quality
- Provenance Tracking: Full lineage tracking across gateway federation
🔧 Implementation Guide
Based on codebase analysis, here are the specific files and implementation steps:
📁 Files to Modify
1. Database Models (mcpgateway/db.py)
Current Models: Tool, Resource, Prompt, Server, Gateway
Required Changes: Add metadata columns to all entity models
Example for Tool model (lines 300-435):
# Add these columns to Tool class:
created_by: Mapped[Optional[str]] = mapped_column(String)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
created_from_ip: Mapped[Optional[str]] = mapped_column(String)
created_via: Mapped[Optional[str]] = mapped_column(String) # 'ui', 'api', 'import', 'federation'
created_user_agent: Mapped[Optional[str]] = mapped_column(Text)
modified_by: Mapped[Optional[str]] = mapped_column(String)
modified_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
modified_from_ip: Mapped[Optional[str]] = mapped_column(String)
modified_via: Mapped[Optional[str]] = mapped_column(String)
modified_user_agent: Mapped[Optional[str]] = mapped_column(Text)
import_batch_id: Mapped[Optional[str]] = mapped_column(String) # UUID for bulk imports
federation_source: Mapped[Optional[str]] = mapped_column(String) # Source gateway
version: Mapped[int] = mapped_column(Integer, default=1)Apply same pattern to: Resource (573-764), Prompt (778-946), Server (948-1090), Gateway (1092-1135)
2. Alembic Migration
Create new migration in mcpgateway/alembic/versions/:
alembic revision -m "add_comprehensive_metadata_to_all_entities"Migration content (follow pattern from cc7b95fec5d9_add_tags_support_to_all_entities.py):
def upgrade() -> None:
"""Add comprehensive metadata columns to all entity tables."""
tables = ['tools', 'resources', 'prompts', 'servers', 'gateways']
for table in tables:
# Creation metadata (nullable=True for backwards compatibility)
op.add_column(table, sa.Column('created_by', sa.String(), nullable=True))
op.add_column(table, sa.Column('created_from_ip', sa.String(), nullable=True))
op.add_column(table, sa.Column('created_via', sa.String(), nullable=True))
op.add_column(table, sa.Column('created_user_agent', sa.Text(), nullable=True))
# Modification metadata (nullable=True for backwards compatibility)
op.add_column(table, sa.Column('modified_by', sa.String(), nullable=True))
op.add_column(table, sa.Column('modified_from_ip', sa.String(), nullable=True))
op.add_column(table, sa.Column('modified_via', sa.String(), nullable=True))
op.add_column(table, sa.Column('modified_user_agent', sa.Text(), nullable=True))
# Source tracking (nullable=True for backwards compatibility)
op.add_column(table, sa.Column('import_batch_id', sa.String(), nullable=True))
op.add_column(table, sa.Column('federation_source', sa.String(), nullable=True))
op.add_column(table, sa.Column('version', sa.Integer(), nullable=False, server_default='1'))
# Indexes for performance
try:
op.create_index(f'idx_{table}_created_by', table, ['created_by'])
op.create_index(f'idx_{table}_created_at', table, ['created_at'])
op.add_column(table, sa.Column('modified_at', sa.DateTime(timezone=True), nullable=True))
op.create_index(f'idx_{table}_modified_at', table, ['modified_at'])
except Exception:
pass # SQLite compatibility3. Pydantic Schemas (mcpgateway/schemas.py)
Update Read schemas (lines 802-838 for ToolRead, similar for others):
# Add to ToolRead, ResourceRead, PromptRead, ServerRead, GatewayRead:
created_by: Optional[str] = Field(None, description="Username who created this entity")
created_at: Optional[datetime] = Field(None, description="When entity was created")
created_from_ip: Optional[str] = Field(None, description="IP address of creator")
created_via: Optional[str] = Field(None, description="Creation method: ui|api|import|federation")
created_user_agent: Optional[str] = Field(None, description="User agent of creation request")
modified_by: Optional[str] = Field(None, description="Username who last modified this entity")
modified_at: Optional[datetime] = Field(None, description="When entity was last modified")
modified_from_ip: Optional[str] = Field(None, description="IP address of last modifier")
modified_via: Optional[str] = Field(None, description="Modification method")
modified_user_agent: Optional[str] = Field(None, description="User agent of modification request")
import_batch_id: Optional[str] = Field(None, description="UUID of bulk import batch")
federation_source: Optional[str] = Field(None, description="Source gateway for federated entities")
version: Optional[int] = Field(1, description="Entity version for change tracking")4. Request Context Middleware
Create new file: mcpgateway/middleware/metadata_capture.py
from fastapi import Request
from typing import Optional
class MetadataCapture:
@staticmethod
def extract_request_metadata(request: Request) -> dict:
"""Extract metadata from request for entity creation/modification."""
return {
"from_ip": request.client.host if request.client else None,
"user_agent": request.headers.get("user-agent"),
"via": "ui" if "/admin/" in str(request.url) else "api",
}5. API Endpoints (mcpgateway/main.py & mcpgateway/admin.py)
Update create/update functions to capture metadata:
Example for create_tool (line 1248):
async def create_tool(
tool: ToolCreate,
request: Request, # Add this
db: Session = Depends(get_db),
user: str = Depends(require_auth)
) -> ToolRead:
# Capture metadata
metadata = MetadataCapture.extract_request_metadata(request)
# Pass to service with metadata
return await tool_service.create_tool(
db=db,
tool=tool,
created_by=user,
**metadata
)Update admin endpoints (mcpgateway/admin.py line 1813):
async def admin_add_tool(
request: Request,
db: Session = Depends(get_db),
user: str = Depends(require_auth),
) -> JSONResponse:
# Add metadata capture similar to above6. Service Layer Updates
Update services (mcpgateway/services/tool_service.py, etc.) to accept and store metadata:
async def create_tool(
self,
db: Session,
tool: ToolCreate,
created_by: str,
from_ip: Optional[str] = None,
user_agent: Optional[str] = None,
via: str = "api",
import_batch_id: Optional[str] = None,
federation_source: Optional[str] = None,
) -> ToolRead:
# Create tool with metadata
db_tool = Tool(
**tool.model_dump(),
created_by=created_by,
created_from_ip=from_ip,
created_user_agent=user_agent,
created_via=via,
import_batch_id=import_batch_id,
federation_source=federation_source,
)7. Admin UI Updates (mcpgateway/templates/admin.html)
Update the View modal (around line 1389) to show metadata:
Add metadata section to tool details modal:
<!-- Add to existing tool modal around line 1389 -->
<div class="mt-6 border-t pt-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Metadata</h4>
<div class="grid grid-cols-2 gap-4 text-sm">
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Created By:</span>
<span class="ml-2" id="tool-created-by"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Created At:</span>
<span class="ml-2" id="tool-created-at"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Created From:</span>
<span class="ml-2" id="tool-created-from"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Created Via:</span>
<span class="ml-2" id="tool-created-via"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Last Modified By:</span>
<span class="ml-2" id="tool-modified-by"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Last Modified At:</span>
<span class="ml-2" id="tool-modified-at"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Version:</span>
<span class="ml-2" id="tool-version"></span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Import Batch:</span>
<span class="ml-2" id="tool-import-batch"></span>
</div>
</div>
</div>8. JavaScript Updates (mcpgateway/static/admin.js)
Update viewTool function (line 4778) to populate metadata:
async function viewTool(toolId) {
// ... existing code ...
// Populate metadata fields
document.getElementById('tool-created-by').textContent = tool.createdBy || 'N/A';
document.getElementById('tool-created-at').textContent = tool.createdAt || 'N/A';
document.getElementById('tool-created-from').textContent = tool.createdFromIp || 'N/A';
document.getElementById('tool-created-via').textContent = tool.createdVia || 'N/A';
document.getElementById('tool-modified-by').textContent = tool.modifiedBy || 'N/A';
document.getElementById('tool-modified-at').textContent = tool.modifiedAt || 'N/A';
document.getElementById('tool-version').textContent = tool.version || '1';
document.getElementById('tool-import-batch').textContent = tool.importBatchId || 'N/A';
}9. Authentication Context (mcpgateway/utils/verify_credentials.py)
Current auth function (line 216): require_auth already handles both scenarios:
- When
AUTH_REQUIRED=true: Returns authenticated username - When
AUTH_REQUIRED=false: Returns"anonymous"(line 282, 308)
Usage: Existing pattern works gracefully - user: str = Depends(require_auth) provides either:
- Authenticated username (e.g.,
"admin","alice") "anonymous"when auth is disabled
No code changes needed - the metadata implementation will automatically work with both auth modes.
10. Bulk Import/Export Services
Update import service (mcpgateway/services/import_service.py) to track import batch IDs
Update federation to track federation sources
🧪 Testing Updates
Add tests for:
- Metadata capture in create/update operations
- Metadata display in admin UI
- Metadata filtering and search
- Migration script execution
🔄 Implementation Order
- Database migration - Add columns
- Models - Update ORM models
- Schemas - Update Pydantic schemas
- Middleware - Add metadata capture
- Services - Update business logic
- API endpoints - Update create/update endpoints
- Admin UI - Update templates and JavaScript
- Testing - Add comprehensive tests
🛡️ Auth-Agnostic Implementation
🔧 Graceful Auth Handling
The implementation automatically works with both authentication modes:
✅ When AUTH_REQUIRED=true (Default)
# require_auth returns actual username
user = "admin" # or "alice", "bob", etc.
created_by = user # "admin"✅ When AUTH_REQUIRED=false (Development/Open APIs)
# require_auth returns "anonymous"
user = "anonymous"
created_by = user # "anonymous"📊 Metadata Display Examples
Authenticated Environment:
Created By: admin
Created At: 2024-01-15 10:30:00 UTC
Created From: 192.168.1.100
Created Via: UI
Anonymous Environment:
Created By: anonymous
Created At: 2024-01-15 10:30:00 UTC
Created From: 192.168.1.100
Created Via: UI
🧪 Testing Both Scenarios
Test with auth enabled:
def test_metadata_with_auth():
app.dependency_overrides[require_auth] = lambda: "test_user"
# Test metadata capture
assert tool.created_by == "test_user"Test with auth disabled:
def test_metadata_without_auth():
app.dependency_overrides[require_auth] = lambda: "anonymous"
# Test metadata capture
assert tool.created_by == "anonymous"⚙️ Configuration Impact
No special configuration needed - the implementation adapts automatically based on:
AUTH_REQUIREDenvironment variable- Existing
require_authdependency behavior - Current auth patterns in the codebase
This ensures the metadata feature works seamlessly across all deployment scenarios without breaking existing functionality.
🔄 Backwards Compatibility Strategy
🛡️ Zero-Downtime Migration
The implementation ensures existing gateways can upgrade without data loss or functionality breaks:
📊 Database Migration Strategy
All metadata columns are nullable=True:
-- Existing entities will have NULL values initially
ALTER TABLE tools ADD COLUMN created_by VARCHAR NULL;
ALTER TABLE tools ADD COLUMN created_at TIMESTAMP NULL;
-- ... etc for all metadata columnsVersion column with default:
-- Existing entities get version=1 automatically
ALTER TABLE tools ADD COLUMN version INTEGER NOT NULL DEFAULT 1;🔧 Code Compatibility
Pydantic schemas handle NULL gracefully:
# All metadata fields are Optional with None defaults
created_by: Optional[str] = Field(None, description="Username who created this entity")
created_at: Optional[datetime] = Field(None, description="When entity was created")
# Existing entities: created_by = None, created_at = None
# New entities: created_by = "admin", created_at = "2024-01-15T10:30:00Z"🖥️ UI Display for Legacy Entities
Admin UI handles missing metadata gracefully:
<span class="ml-2" id="tool-created-by">{{ tool.created_by || 'N/A' }}</span>
<span class="ml-2" id="tool-created-at">{{ tool.created_at || 'Unknown' }}</span>JavaScript display logic:
// Handles both existing (null) and new entities
document.getElementById('tool-created-by').textContent = tool.createdBy || 'Legacy Entity';
document.getElementById('tool-created-at').textContent = tool.createdAt || 'Pre-metadata';📈 Migration Scenarios
✅ Scenario 1: Fresh Installation
- All new entities get complete metadata
- Full audit trail from day one
✅ Scenario 2: Existing Gateway Upgrade
- Existing entities: Show "N/A" or "Legacy Entity" for missing metadata
- New entities: Get full metadata tracking
- Mixed display: Legacy and new entities coexist seamlessly
✅ Scenario 3: Bulk Import/Historical Data
- Import services can optionally populate metadata for historical accuracy
- Migration scripts can backfill known information (e.g., system user, approximate dates)
🧪 Backwards Compatibility Testing
Test existing entity access:
def test_legacy_entity_access():
# Create entity without metadata (simulates pre-migration state)
tool = Tool(name="legacy_tool", url="http://example.com")
db.add(tool)
db.commit()
# Verify API still works
response = client.get(f"/tools/{tool.id}")
assert response.status_code == 200
# Verify metadata fields show as None/null
data = response.json()
assert data["createdBy"] is None
assert data["createdAt"] is NoneTest mixed entity display:
def test_mixed_entity_display():
# Legacy entity (no metadata)
legacy_tool = Tool(name="legacy", url="http://example.com")
# New entity (with metadata)
new_tool = create_tool_with_metadata(
name="new_tool",
created_by="admin",
created_at=datetime.utcnow()
)
# Both should display without errors
tools = client.get("/tools").json()
assert len(tools) == 2🔧 Optional Metadata Backfill
For enhanced audit trails, optionally backfill known data:
-- Backfill system-created entities
UPDATE tools SET
created_by = 'system',
created_via = 'migration',
version = 1
WHERE created_by IS NULL;
-- Backfill from existing created_at timestamps if available
UPDATE tools SET created_at = created_at WHERE created_at IS NOT NULL;🎯 Key Benefits
- Zero service interruption during upgrades
- Gradual metadata adoption - new entities get tracking immediately
- Clear legacy identification - easy to spot pre-metadata entities
- Optional enhancement - metadata backfill can be done post-migration
- Future-proof - all new operations include full metadata
This strategy ensures that existing production gateways can upgrade safely while immediately benefiting from metadata tracking for all new operations.