Skip to main content
Glama
Saigwe

Ask the Warehouse MCP Server

by Saigwe

"Ask the Warehouse": Semantic Layer + AI Agent

CI

14 metrics defined once in a dbt semantic layer (MetricFlow) over $6.57B of real federal contract spend. An automated check that dashboard numbers equal the semantic layer to the cent, and catches a planted wrong dashboard. An MCP server that gives an AI agent the metrics and no SQL, with guardrails, scored on a 54-question benchmark with hand-written answers.

Author: Stanley Igwe, Lead Data (Analytics) Engineer · Portfolio Stack: dbt Core · dbt Semantic Layer (MetricFlow 0.213) · MCP (Python SDK 2.x) · Claude (Anthropic SDK) · DuckDB · pytest · GitHub Actions Status: Core build complete on real data. The Claude agent run on the benchmark needs an API key and is the next step. See Roadmap.

Project 12 of my portfolio plan. At a global management consultancy I built governed metrics, plus Power BI data-validation and measure-optimisation models, so every client saw the same numbers. This repo rebuilds the problem on public data. No employer or client data, code or logic is used.


90-second summary

Problem

"Spend" means three different numbers on three dashboards (gross, net, net of credits), and a chatbot over raw tables invents a fourth. Nobody can say which is right.

What I built

Metrics defined once in MetricFlow. A reconciliation check that every dashboard cell equals the governed metric. An MCP server whose only tools are list metrics, list dimensions and query metrics, behind guardrails that reject undefined metrics, raw columns, SQL in filters and bulk exports. A Claude agent loop over the same tools, and a benchmark whose answers are written in plain SQL, separately from the semantic layer.

Why it matters

An analyst, a dashboard and an AI assistant get the same answer to "how much did the Park Service spend?", and a wrong dashboard fails CI instead of reaching a board pack.

Proof

Numbers. Benchmark and dashboard reports in results/; CI reruns all of it on every push.

Related MCP server: EzBiz Government Contracting MCP Server

Architecture

flowchart LR
  P10[(Project 10<br/>USAspending spend lines)] -->|load_spend_lines.py| B[(bronze.spend_lines)]
  B -->|dbt| G[(gold: fct_spend_lines<br/>dim_suppliers, time spine)]
  G --> SL[[MetricFlow semantic layer<br/>2 semantic models · 14 metrics]]
  G --> D[dashboard tables<br/>rpt_dashboard_*]
  SL <-->|check_dashboards.py<br/>cell by cell| D
  SL --> GR{guardrails}
  GR --> MCP[MCP server<br/>list_metrics · list_dimensions · query_metrics]
  MCP --> A[Claude agent<br/>or any MCP client]
  SL -->|run_eval.py| E[benchmark<br/>vs hand-written SQL]

Data

Real: the 41,980 categorised contract actions from project 10 (USAspending.gov, Department of the Interior, federal FY2025, public domain), loaded by ingestion/. CI uses a synthetic fixture with the same columns and vocabulary.

Semantic layer

Metric

Type

Definition

net_spend

simple

Obligations minus de-obligations: the definition of spend

gross_obligations, deobligations

simple

New money obligated; money returned (negative)

contract_actions, obligation_actions, active_suppliers

simple

Actions; obligating actions; distinct UEIs

not_competed_share, small_business_share

ratio

Over obligations where competition / size is recorded

average_obligation

ratio

Gross obligations per obligating action

deobligation_rate

derived

−de-obligations / gross obligations

Dimensions: bureau, category, fiscal quarter, competition status, business size, supplier and parent supplier, and metric_time at day to year grain. The four numerator and denominator helpers make up the rest of the 14.

Guardrails (in agent/semantic_layer.py, checked before anything is compiled)

  • Only metrics defined in _semantic.yml; only dimensions MetricFlow lists for those metrics.

  • Filters must be {{ Dimension('x') }} <op> <literal> joined by and/or. Raw columns, SQL keywords, ;, comments and tautologies like or 1 = 1 are rejected.

  • At most 5 metrics, 3 group-bys and 500 rows: it answers questions; it does not export data.

  • There is no tool that runs SQL. Refusals come back as readable tool errors, so the agent can correct itself.

Numbers

All from the real build (make all) unless marked.

Metric

Value

Spend lines

41,980 contract actions, $6.57B net

dbt build

25 nodes (7 models, 18 data tests) in 1.9 s, plus 2 semantic models and 14 metrics

Benchmark, reference requests through the semantic layer

44/44 answers equal the hand-written SQL

Benchmark, requests that must be refused

10/10 refused by the guardrails

Query latency through MetricFlow

p50 17 ms, p95 26 ms (laptop, DuckDB)

Dashboard check

8 dashboard columns, 258 cells, all equal to the cent; the planted legacy dashboard is caught on all 22 of its cells

Tests (pytest)

15 pass: guardrail cases, the MCP server over an in-process client, and the agent loop with scripted Claude replies

Claude agent on the benchmark

not run yet (needs an API key; see Roadmap)

The planted legacy dashboard makes the two classic mistakes. It shows gross obligations as "spend" (Bureau of Indian Affairs: $408.7M on the dashboard vs $365.7M governed net). And it computes small-business share on net instead of obligated amounts (73.1% vs 72.8%). The check fails CI if it ever stops catching them.

What the reference benchmark proves, and what it doesn't: it shows the metric definitions, the time spine joins, the filters and the guardrails produce the right numbers for 44 realistic questions, and refuse 10 bad requests. It does not yet measure how often an LLM picks the right request. That is make agent-eval, which scores Claude through the same tools against the same answers.

How to run

Requires Python 3.12 (what CI uses) and make, or run the commands in the Makefile by hand.

python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt
make fixture-all          # synthetic fixture: dbt build, benchmark, dashboard check, tests (CI)
make all                  # real data from ../procurement-spend-cube (build it first)
make mcp                  # serve the metrics over MCP (stdio), e.g. for Claude Code or Claude Desktop
make agent-eval           # Claude agent on the benchmark: needs ANTHROPIC_API_KEY, about 54 short agent runs

Roadmap

  • Scaffold: fixture, staging with key tests, first marts, CI

  • Define the metrics once (MetricFlow semantic models, 14 metrics) on real USAspending data

  • Automated test that dashboard numbers equal semantic-layer numbers, with a planted bug it must catch

  • Expose metrics to an LLM through an MCP server, with no raw-table access and guardrails

  • Benchmark of 54 questions (44 answerable, 10 to refuse) with hand-written gold SQL; accuracy and latency tracked in CI

  • Run the Claude agent on the benchmark and report execution accuracy, refusal accuracy, latency and cost per question

  • Saved queries and a Power BI or Evidence.dev front end reading the same metrics

  • 3-minute Loom walkthrough

Interview topics this project prepares

  • Semantic layers and metric governance (MetricFlow: measures, ratio and derived metrics, time spines)

  • Testing BI numbers against a single source of truth

  • LLM-to-data evaluation: execution accuracy against independent gold answers, refusal accuracy

  • Guardrails for AI on data, and MCP as the interface

Data and licence

  • USAspending: U.S. government data, public domain.

  • Fixture: synthetic, fixed seed, tests/fixtures/make_fixture.py. It describes no real company or person.

  • Code: MIT (see LICENSE).

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables AI agents to search and analyze federal government contract opportunities and awards from SAM.gov and USASpending.gov, with tools for contract search, detail, agency spending, and trending sectors.
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to search federal contracts, analyze agency spending, track competitor wins, and monitor small business set-aside opportunities using SAM.gov, USASpending.gov, and FPDS data.
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Exposes a governed semantic layer built on dbt Core and DuckDB, enabling AI agents to query predefined metric definitions for a P&C insurance dataset. Prevents metric hallucination by restricting agents to governed tools and read-only data access.
    -