讓 AI Agent 安全理解資料平台
Production-oriented MCP Server 參考實作:把 PostgreSQL、Vertica、Airflow、Metadata、Lineage、Logs、Runbooks 與 producer-owned ETL metadata 轉成標準 MCP capabilities,並加入 OIDC、RBAC、Multi-tenancy、Audit、OpenTelemetry、Kubernetes / Helm 與 Air-gapped Delivery。
MCP SDK v2PostgreSQLVerticaAirflow 3SQLGlotOIDC/JWTOpenTelemetryKubernetesHelm不是讓 LLM 直接連 DB,而是加一層「受控、可稽核、可治理」的 MCP Data Platform Gateway。
# MCP Host asks... › 哪些資料表與 daily_sales 有關? # Server performs... ✓ OIDC / Bearer validation ✓ RBAC scope check ✓ Tenant source boundary ✓ Catalog + Lineage lookup ✓ Audit + trace correlation # No destructive write tool exists
面試官 5 分鐘速讀
先回答「為什麼值得看」,再進入實作細節。
LLM 不該直接拿 DB 權限
直接暴露資料庫、排程器與 Logs 容易造成越權、Prompt Injection、credential expansion 與不可追蹤操作。
MCP 作為受控介面層
Catalog、Metadata、Lineage、SQL Explain、Airflow 與 Log Search 被封裝成標準 MCP Tool,底層由 Adapter 隔離。
不是 Demo-only
OIDC/JWT、RBAC、Tenant boundary、Audit、OTel、Helm、NetworkPolicy、External Secrets、Trivy 與 air-gap 都納入。
Engineering Decisions & Production Evidence
核心不是「把 DB 包成 Tool」,而是建立標準化、可治理、可稽核的 integration boundary,避免 AI client 直接取得 backend-native privilege。
Problem
若每個 Agent 自己連 PostgreSQL、Vertica、Airflow、Logs,identity、tenant、SQL safety、audit 與 backend error semantics 都會被複製。
Key Decision
MCP Tool Contract + Adapter Pattern。Role 決定 what,Tenant Policy 決定 which source,SQL safety 不靠 Prompt。
Defense-in-Depth
No destructive tool → SQLGlot AST policy → DB/session read-only → OIDC/RBAC/Tenant → Audit/OTel。
| Decision | Benefit | Trade-off |
|---|---|---|
| MCP Tool Contract | Client 不需要 backend-specific credential / API semantics | 增加 protocol、schema、compatibility 維護 |
| Adapter Pattern | PostgreSQL / Vertica / Airflow / Logs 可各自演進 | 需維護 timeout、error normalization 與 backend 差異 |
| RBAC + Tenant separation | Operation 與 data-source authorization 可獨立 reason / audit | v0.4 是 source-level isolation,不等同 row-level RLS |
| Failure Scenario | Engineering Response | Evidence |
|---|---|---|
| Write / malformed SQL | 在 DB 執行前拒絕,DB session 本身仍維持 read-only | test_security.py |
| OIDC / role / tenant violation | Fail closed,不降級成 anonymous privileged access | test_auth_audit.py |
| Backend integration outage | 相關 Tool bounded failure,不以更高權限連線或放寬 policy 作為 fallback | test_integrations.py |
ETL Metadata / Lineage Integration
enterprise-etl-platform 產生 truth;MCP Server 只提供 governed read-only access。
enterprise-etl-platform
Pentaho / Hop parser、normalized metadata、migration analysis、structural / inferred lineage classification。
Data Platform MCP Server
讀取 exported JSON contract,套用 scope、audit、identity、telemetry;不重新解析 KTR/KJB/Hop。
DataOps / MCP Hosts
可查 pipeline、steps、dependencies、table lineage 與 metadata;RCA 與 agent reasoning 仍留在 consumer layer。
export DPMCP_ETL_METADATA_DIR=/srv/etl-metadata export DPMCP_ETL_METADATA_MAX_FILES=500 # Kubernetes Helm: existing PVC is mounted read-only etlMetadata: enabled: true existingClaim: etl-metadata
整體架構
從 MCP Host 到 Data Platform backend 的完整 request path。
Adapter Pattern
MCP Tool 不直接知道 PostgreSQL、Vertica 或 Airflow 的細節。Backend-specific behavior 封裝在 Adapter,降低耦合。
Read-only by Design
沒有 INSERT / UPDATE / DELETE / DDL / DAG trigger / secret update 等 destructive Tool。
一次 MCP Request 發生什麼?
以取得 Vertica table metadata 為例。
get_table_metadata 需要 catalog:read。vertica。VerticaCatalogAdapter 查 v_catalog,session 維持 READ ONLY。版本演進
每版對應一個工程成熟度里程碑。
v0.1 · MCP Foundation
MCP SDK v2、stdio/HTTP、Demo、PostgreSQL read-only、Docker、pytest/Ruff、Trivy。
v0.2 · DataOps Integration
Airflow 3、OpenSearch、Loki、MCP Resources/Prompts、protocol tests。
v0.3 · Enterprise Data Platform
Vertica、Composite Catalog、Metadata、Lineage、SQLGlot AST、Bearer RBAC、Audit。
v0.4 · Production Delivery
OIDC/JWT、Multi-tenancy、OTel、Kubernetes/Helm、External Secrets、NetworkPolicy、Air-gap、gated Release。
v0.5 · ETL Metadata / Lineage Integration
Producer-owned ETL metadata、six read-only tools、ETL resource、classification preservation、read-only PVC。
MCP Tool Catalog
可搜尋 tool / scope / purpose。
| Tool | Scope | Tenant | Purpose |
|---|---|---|---|
health | platform:read | — | health/version |
whoami | platform:read | — | actor / role / tenant / scopes |
list_data_sources | catalog:read | filter | tenant-visible sources |
list_schemas | catalog:read | yes | schemas |
list_tables | catalog:read | yes | tables/views |
describe_table | catalog:read | yes | column metadata |
table_statistics | catalog:read | yes | lightweight statistics |
get_table_metadata | catalog:read | yes | owner/type/projections |
get_table_lineage | lineage:read | yes | catalog-backed lineage |
analyze_sql_lineage | lineage:read | — | SQL AST lineage |
explain_sql | sql:explain | yes | guarded EXPLAIN |
list_dags | operations:read | — | DAG discovery |
get_dag_status | operations:read | — | latest DAG state |
search_etl_logs | logs:read | — | OpenSearch/Loki log search |
search_runbooks | runbook:read | — | troubleshooting knowledge |
list_etl_pipelines | catalog:read | — | producer pipeline discovery |
get_etl_pipeline | catalog:read | — | normalized ETL contract |
get_etl_pipeline_steps | catalog:read | — | ETL step metadata |
get_etl_pipeline_dependencies | lineage:read | — | step/workflow dependencies |
get_etl_table_lineage | lineage:read | — | producer lineage + boundary |
search_etl_metadata | catalog:read | — | ETL metadata search |
Metadata & Lineage
把 catalog fact、SQL AST derivation 與 ETL producer lineage 刻意分開。
資料庫觀察到的血緣
Vertica 使用 v_catalog.view_tables。
vertica.public.orders
│
▼
vertica.mart.daily_salesSQL AST 推導血緣
analyze_sql_lineage 解析實際 input tables 與 CTE。
WITH recent AS ( SELECT * FROM public.orders ) SELECT * FROM recent JOIN mart.customers c ... Inputs: - public.orders - mart.customers CTE: - recent
ETL metadata lineage
保留 structural、inferred-deterministic 與 capability boundary;AI interpretation 不冒充 deterministic truth。
staging.orders
│ structural / inferred
▼
analytics.orders_enrichedSecurity / Authorization
多層控制,而不是只做登入驗證。
OIDC / JWT
JWKS signature、algorithm allow-list、issuer、audience、expiration、subject、role mapping、tenant claim。
RBAC + Tenant
readeranalystoperatoradmin
Role 決定 operation;Tenant 決定 source。
SQL + DB boundary
SQLGlot AST 拒絕 DML/DDL/multi-statement/SELECT INTO/write CTE;PostgreSQL/Vertica session 仍維持 read-only。
Multi-tenancy Example
Role 與 Tenant 是兩個不同的授權維度。
export DPMCP_TENANT_ENABLED=true
export DPMCP_TENANT_ALLOWED_SOURCES_JSON='{
"tenant-a":["postgres"],
"tenant-b":["vertica"],
"platform-admin":["*"]
}'tenant-a + analyst ├─ metadata(postgres) ✓ ├─ lineage(postgres) ✓ ├─ explain(postgres) ✓ ├─ metadata(vertica) ✗ └─ list_dags ✗ lacks operations:read
Audit + OpenTelemetry
從 actor 一路追到 latency 與 distributed trace。
Signals
dpmcp.<action>spansdpmcp.invocationsdpmcp.invocation.duration
透過 OTLP/HTTP 送至 Collector,再轉 Grafana/Tempo/Prometheus/Azure Monitor/Datadog 等。
{
"action": "metadata.get_table",
"actor": "agent-client",
"tenant": "tenant-a",
"role": "analyst",
"outcome": "success",
"trace_id": "012345...abcdef"
}Kubernetes / Helm
安全預設直接進 Chart defaults。
Pod Security
- runAsNonRoot
- UID/GID 10001
- readOnlyRootFilesystem
- drop ALL capabilities
- RuntimeDefault seccomp
Reliability
- replicas = 2
- ETL metadata PVC read-only mount
- readiness/liveness
- requests/limits
- PDB
- optional HPA
Secrets / Network
- ServiceAccount token disabled
- External Secrets Operator
- Azure Key Vault example
- NetworkPolicy
- non-DNS egress denied by default
kubectl apply -f examples/kubernetes/namespace-restricted.yaml helm upgrade --install dpmcp \ deploy/helm/data-platform-mcp-server \ --namespace data-platform-mcp
使用方式
從 Demo 到 Multi-source / OIDC。
1. Local Demo
git clone https://github.com/kewinall/data-platform-mcp-server.git cd data-platform-mcp-server python -m venv .venv source .venv/bin/activate pip install -e '.[dev]' cp .env.example .env DPMCP_TRANSPORT=streamable-http data-platform-mcp
Endpoint: http://127.0.0.1:8000/mcp
2. PostgreSQL + Vertica Multi-source
export DPMCP_MODE=multi export DPMCP_POSTGRES_DSN='postgresql://readonly_user:change-me@postgres:5432/analytics' export DPMCP_VERTICA_DSN='vertica://readonly_user:change-me@vertica:5433/warehouse?tlsmode=require' data-platform-mcp
3. OIDC
export DPMCP_TRANSPORT=streamable-http export DPMCP_AUTH_ENABLED=true export DPMCP_AUTH_MODE=oidc export DPMCP_AUTH_ISSUER_URL='https://idp.example.com/realms/data-platform' export DPMCP_AUTH_RESOURCE_URL='https://mcp.example.com/mcp' export DPMCP_OIDC_JWKS_URL='https://idp.example.com/realms/data-platform/protocol/openid-connect/certs' export DPMCP_OIDC_AUDIENCE='data-platform-mcp' export DPMCP_OIDC_ROLE_CLAIM='realm_access.roles' export DPMCP_OIDC_TENANT_CLAIM='tenant'
4. OpenTelemetry
export DPMCP_OTEL_ENABLED=true export DPMCP_OTEL_SERVICE_NAME=data-platform-mcp-server export DPMCP_OTEL_EXPORTER_OTLP_ENDPOINT='http://otel-collector.observability:4318' export DPMCP_DEPLOYMENT_ENVIRONMENT=prod
Air-gapped Delivery
目標環境不需要連 PyPI / Docker Hub / GitHub。
Build
make airgap
Output: dist/data-platform-mcp-server-0.4.0-airgap.tar.gz
Bundle
wheelhouse/ images/ helm/ docs/ .env.example README.md LICENSE SHA256SUMS verify-airgap-bundle.sh
CI / Security / Release
同一 main commit 的 CI 與 Security 都成功才發布。
CI
- Python 3.11 / 3.12
- Ruff / pytest / compileall
- Docker build
- Shell syntax
- Helm lint / template
Security
- pip-audit
- Trivy filesystem
- render Kubernetes YAML
- Trivy config scan
.tgz asset。v0.4.0 已實際通過完整 pipeline
面試怎麼講
把「用了哪些工具」轉成「解了什麼工程問題」。
60 秒版本
「我做了一個 Data Platform MCP Server,把 PostgreSQL、Vertica、Airflow、Log Search 與 Metadata/Lineage 封裝成標準 MCP capabilities,讓 AI Agent 不需要拿到底層系統的直接寫入權限。安全上分成 OIDC authentication、RBAC scope、tenant source boundary、SQL AST policy 與 database read-only 多層控制,再把 Audit 與 OpenTelemetry 串起來。部署面有 Helm、Pod Security、NetworkPolicy、External Secrets、Trivy,也支援 air-gapped bundle。」
可追問的題目
- 為何 MCP,而不是直接做 SQL Agent?
- 如何防 Prompt Injection?
- Role 與 Tenant 有什麼不同?
- Multi-tenancy 做到哪一層?
- 為何需要 DB-side read-only?
- 如何部署到企業 Kubernetes / 封閉網路?
FAQ
常見使用者與面試官問題。
會讓 AI 直接讀正式資料嗎?
Repository 預設 synthetic demo data;真實環境需自行設定 read-only DB 帳號、Secret 與 NetworkPolicy。
這算完整 Multi-tenant SaaS 嗎?
不是。v0.4 明確是 catalog source-level isolation reference;row/column security 應結合 DB RLS/CLS 或後續 OPA/Cedar 等 policy engine。
為什麼不直接 COUNT(*)?
定位為 operational metadata inspection,避免大表掃描;Vertica 使用 projection storage,PostgreSQL 使用 planner estimate。
為什麼要 Air-gapped?
企業資料平台常存在封閉網段;wheelhouse、container image、Helm chart 與 checksum 一起交付可展示離線部署思考。
English Executive Summary
For interviewers who prefer an English overview.
Data Platform MCP Server is a production-oriented reference implementation that exposes enterprise data-platform capabilities to MCP-compatible AI clients without granting unrestricted backend access.
It integrates PostgreSQL, Vertica, Airflow 3, OpenSearch/Loki, metadata and lineage through adapter abstractions. The security model combines bearer/OIDC authentication, role-based scopes, tenant-aware source authorization, AST-based read-only SQL validation, database-level read-only sessions, structured audit logging, and OpenTelemetry correlation.
The production layer includes a hardened Kubernetes Helm chart, NetworkPolicy, External Secrets Operator integration, CI/Security gates, Trivy scans, and an air-gapped deployment bundle. It demonstrates a transition from Data Engineering/DataOps into MCP and AI Platform Engineering.