feat: Add structured audit logging for MCP feature server
- Dominant language
- Python
- Stars
- 7.3k
- Forks
- 1.4k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 15
Description
### 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:
```yaml
feature_server:
type: mcp
mcp_enabled: true
audit_logging:
enabled: true
sink: stdout
```
Example event (JSONL):
```json
{
"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
}
```
Contributor guide
Assessment
This issue has not been assessed yet.