Skip to content

feat: Add structured audit logging for MCP feature server #6452

@patelchaitany

Description

@patelchaitany

Is your feature request related to a problem? Please describe.

Feast can expose the Python feature server as an MCP server (feature_server.type: mcp, mcp_enabled: true, endpoint /mcp) via fastapi_mcp. Operators and platform teams need a clear audit trail for agent/MCP access: who invoked which tool, what resource was accessed, whether authentication and authorization succeeded or failed, and a correlation ID that links MCP calls to internal REST requests.

Today, MCP integration only logs startup/errors (sdk/python/feast/infra/mcp_servers/mcp_server.py). That is not enough for security and operations use cases:

Mechanism What it does Gap for MCP audit
feature_logging Logs served feature values to the offline store Not a security audit log; not wired on the Python FastAPI MCP server
Uvicorn access logs HTTP path/status (off by default) No principal, no MCP tool name
RBAC logs Unstructured permission messages in app logs No MCP correlation; often DEBUG-only for allows

With auth.type: no_auth: MCP tool calls are effectively anonymous — no principal in logs.

With auth.type: oidc / kubernetes: RBAC applies on secured REST routes when the MCP client forwards Authorization (default in fastapi_mcp), but there is still no structured audit stream for MCP tools/call, successful reads, or request correlation. The /mcp transport itself is not audited.

Registry MCP (registry.mcp.enabled: true) has the same gap.

Describe the solution you'd like

Add structured audit logging (JSONL) for the Python MCP feature server, separate from feature_logging:

  1. Config under feature_server (e.g. audit_logging.enabled, sink, file_path, require_auth_for_mcp, log_successful_reads).
  2. Audit events with stable schema: event_type, UTC timestamp, request_id, principal, source (IP, transport), action (MCP tool / HTTP path), resource, outcome, duration_ms.
  3. Two emission layers:
    • MCP middleware on /mcp (mcp.tools.call, session events).
    • REST + RBAC hooks (authn.*, authz.decision, http.request) on secured endpoints.
  4. Header propagation via FastApiMCP(headers=[...]) so MCP and REST events share request_id (and optionally tool name).
  5. No sensitive payloads in audit logs (no tokens, entity rows, or feature values).

Optional follow-ups: registry MCP parity, OTEL sink, operator CRD fields.

Example config:

feature_server:
  type: mcp
  mcp_enabled: true
  audit_logging:
    enabled: true
    sink: stdout

Example event (JSONL):

{
  "event_type": "mcp.tools.call",
  "timestamp": "2026-05-28T12:00:00.000Z",
  "request_id": "",
  "principal": {
    "username": "jane.doe@company.com",
    "roles": ["feast-reader", "ml-engineer"],
    "auth_type": "oidc"
  },
  "source": { "ip": "10.0.0.1", "transport": "mcp-http" },
  "action": { "mcp_tool": "get_online_features", "path": "/get-online-features" },
  "resource": { "type": "feature_service", "name": "driver_activity_v1", "actions": ["READ_ONLINE"] },
  "outcome": "success",
  "duration_ms": 42
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions