← Back to series overview

Load Data into the Lakehouse with Copilot + Fabric MCP

Yes, I know, "Lakehouse, MCP, Copilot, shortcuts and a second source" is a long subtitle. But I found no shorter way to describe what I spent last week figuring out with a customer.

What you'll build in Part 1

  • Fabric MCP connected to GitHub Copilot, your data-loading copilot
  • A SalesLakehouse in OneLake with bronze / silver / gold folders
  • Source A (shortcut = bronze): Blob CSV sales transactions linked zero-copy at Files/bronze/raw_sales
  • Source B (ingested, not a shortcut): Azure SQL product master copied to Files/bronze/dim_product Delta, joinable on ProductKey
  • Verification + join-key checks proving both sources are ready to combine in Part 2

Table of Contents

Why we start with the lakehouse

Yes, I know, starting a Power BI series without opening Power BI Desktop feels wrong. But all started with a customer trying to build that "beautiful report" straight from CSVs in Blob and a product table in SQL. It worked for a week, then broke: two definitions of sales, slow refreshes, and no one knew which ProductKey was right.

Enterprises usually want what my customer wanted here too, one copy of the data with real access control, not five copies emailed around. That's why we start in Fabric, not in Desktop. This series follows the order I wish I'd shown them on day one:

1. Lakehouse
load raw
→
2. Engineer
clean
→
3. Model
meaning
→
4. Report
build
→
5. Beautify
Figma

To start I'm assuming you already have a Fabric workspace with a trial or F2 capacity, if you don't, get one first, the rest won't work without it. Learn more here: Fabric trial docs. Notice I'm talking about the Fabric lakehouse of today (OneLake + shortcuts), not the old ADLS Gen2 + Data Factory V1 pattern, the concepts rhyme, the clicks don't.

A Fabric Lakehouse on OneLake works a bit like those Service Principals from my old SQL article, one identity, one place to grant access, instead of credentials scattered everywhere. Notebooks, pipelines, warehouses and Power BI all see the same files. GitHub Copilot, through Fabric MCP, just writes the boring ingestion code for you.

The tricky part most people miss: the Fabric MCP extension alone only gives Copilot knowledge of the APIs. To touch your real workspace it still needs your login (az login or Azure: Sign In). Don't forget that step, without it you'll get empty tool lists and think the extension is broken. It isn't.

Set up Fabric MCP + Copilot

You need a Fabric capacity (trial works), a GitHub Copilot subscription, and VS Code with the Fabric MCP Server extension. No service principal needed for local work, the extension uses your signed-in user identity.

Option 1: VS Code extension (recommended)

  1. Install GitHub Copilot Chat + Microsoft Fabric MCP Server extensions
  2. Run Azure: Sign In from the Command Palette (or az login in terminal)
  3. Switch Copilot to Agent mode, refresh tools, Fabric tools appear. Done.

The extension is local-first and registers itself automatically, no mcp.json secrets to manage.

Option 2: Manual npx setup (any MCP client)

# Requires Node 20+
npx -y @microsoft/fabric-mcp@latest server start --mode all
// .vscode/mcp.json, minimal, user auth via Azure CLI
{
  "servers": {
    "fabric": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@microsoft/fabric-mcp@latest", "server", "start", "--mode", "all"],
      "env": {
        "FABRIC_WORKSPACE_ID": "${env:FABRIC_WORKSPACE_ID}"
      }
    }
  }
}
No service principal for Parts 1 to 3: stay signed in as yourself. You only need one in Part 4 for unattended CI/CD (GitHub Actions can't do interactive login). We'll set that up there.
You: List all items in my SalesAnalytics workspace to confirm the connection works
Copilot: Querying OneLake via Fabric MCP…
// MCP Call: fabric.listOneLakeItems(workspaceId)
Connected! Workspace is empty, ready for our lakehouse. Let's create it next.

Create your lakehouse & folder structure

You: Create a lakehouse called SalesLakehouse with medallion folders bronze, silver, gold under Files, plus a notebooks folder
Copilot: Creating lakehouse structure…
// MCP Call: fabric.createLakehouse(workspaceId, { name: "SalesLakehouse" })
// MCP Call: fabric.createFolders(workspaceId, ["Files/bronze","Files/silver","Files/gold","Files/notebooks"])
📁 SalesLakehouse/Files/
  📁 bronze/raw_sales    ← Source A shortcut to Blob CSV (bronze as shortcut)
  📁 bronze/dim_product  ← Source B Delta snapshot from Azure SQL
  📁 silver/             ← cleaned + joined tables (Part 2)
  📁 gold/               ← star schema (Part 2)
  📁 notebooks/          ← engineering code (Part 2)

Source A (shortcut): sales CSVs as bronze, zero-copy

Sales transactions live as daily CSVs in Azure Blob (sales-raw container). They're immutable drops, large, and already partitioned by date, ideal for a OneLake shortcut. The shortcut is our bronze for this source: no copy, always fresh. We go straight shortcut to Silver in Part 2.

You: Create a shortcut in bronze called raw_sales pointing to Blob container sales-raw, path daily/. This shortcut is our bronze for sales, no Delta copy
Copilot:
// MCP Call: fabric.createOneLakeShortcut({
  lakehouse: "SalesLakehouse",
  path: "Files/bronze/raw_sales",
  source: { type: "BlobStorage", container: "sales-raw", path: "daily/" }
})
Shortcut live at Files/bronze/raw_sales, zero bytes copied. Part 2 reads these CSVs directly into Silver Delta.
What I missed the first time: shortcut-as-bronze only works because source files are immutable and versioned by date path. If Blob retention deletes old days, we lose replay. Fine for this series. Risky for regulated data (then materialize bronze Delta instead).

Source B (ingested): SQL product master to bronze Delta

Product details live in Azure SQL (sql-contoso-prod.database.windows.net / SalesDW / dim.Product) with ProductKey, Category, Subcategory, Brand, UnitCost. We deliberately do NOT shortcut this one:

  • Small dimension, copy is cheap, query is fast as Delta
  • OLTP source, we don't want Spark scans hammering it; take a daily snapshot
  • Needs history/offline availability even if SQL is down
  • Joinable to Source A on ProductKey, the bridge between the two sources
You: Create pipeline Bronze Product Snapshot: source Azure SQL dim.Product full copy, sink Files/bronze/dim_product Delta overwrite, schedule daily 3 AM after sales files land, 2 retries
Copilot: Building pipeline…
// MCP Call: fabric.createPipeline(workspaceId, {
  name: "Bronze Product Snapshot",
  activities: [{
    type: "Copy",
    source: { type: "AzureSQL", server: "sql-prod.database.windows.net",
      database: "SalesDW", table: "dim.Product" },
    sink: { type: "OneLakeDelta", table: "Files/bronze/dim_product",
      writeMode: "Overwrite" }
  }],
  schedule: "0 3 * * *",
  retry: { attempts: 2, intervalMin: 15 }
})
Pipeline created. Snapshot lands ~2,400 products in seconds, our join dimension is ready.

Verify both sources + join keys with Copilot

You: Check Source A shortcut CSVs (row count, null SalesKey/ ProductKey, negative amounts) and Source B dim_product Delta (row count, distinct ProductKey). Then report ProductKey overlap, % of sales keys found in product master
Copilot:
// MCP: fabric.readCSV(ws, "Files/bronze/raw_sales/daily/2026/09/15/sales.csv", { sample: 5 })
// MCP: fabric.readDeltaTable(ws, "Files/bronze/dim_product", { sample: 5 })
CheckResultStatus
Sales rows (shortcut CSV)145,230OK
Null SalesKey / ProductKey0 / 0OK
Negative SalesAmount14 (returns)REVIEW IN PART 2
Products (SQL snapshot Delta)2,412OK
Sales ProductKey in master99.98% (32 missing)QUARANTINE IN PART 2
Both sources ready. The 14 returns + 32 unknown products go to quarantine in Part 2, where we join sales to product.

What's next in Part 2

Raw is not ready, and two sources is not one dataset. In Part 2 we do data engineering with Copilot: read shortcut CSVs + SQL snapshot Delta, validate the ProductKey join, quarantine orphans, and build silver to gold star schema.

  • Silver notebook joining Source A (shortcut) + Source B (SQL snapshot)
  • Referential-integrity checks + quarantine pattern
  • Gold star-schema tables with conformed DimProduct
Continue to Part 2: Data Engineering →