Skip to content

Latest commit

 

History

History
214 lines (150 loc) · 9.05 KB

File metadata and controls

214 lines (150 loc) · 9.05 KB

SQL MCP Server for Fabric SQL without using Containers

When and why is SQL MCP Server needed? Many teams already have data in a SQL database and want to build AI agents that can reason over that data. This supports data discovery, where the model asks new questions and reveals useful insights from existing data.

Agents can also perform CRUD (Create, Read, Update, Delete) operations to insert, update, and maintain records. SQL MCP Server is useful for both scenarios because it provides deterministic tools to read from and write to tables.

The technology behind SQL MCP Server is Data API builder (DAB). SQL MCP Server is not a separate engine, it is a feature of DAB that uses entity abstraction to expose tables, views, and stored procedures defined in your configuration. It also inherits DAB role-based access control, field projection rules, caching, and telemetry without additional setup.

Learn more about Data API builder: https://aka.ms/dab/mcp

Because it runs on the same runtime as REST and GraphQL, every security rule, relationship, and policy is enforced consistently for both apps and agents. We configure it once, and DAB dynamically generates the endpoints. Although teams often deploy this in containers, we run SQL MCP Server on Azure App Service without containers in this walkthrough.

Architecture diagram showing a client app calling SQL MCP Server, which accesses Fabric SQL through Data API builder on Azure App Service without containers

As a cloud endpoint for Foundry, SQL MCP Server integrates cleanly with agents and apps. You get the flexibility of a custom API with the secure, feature-rich experience built into Data API builder.

This article

If you already have a SQL database with tables and want to expose it safely to AI agents, this walkthrough is for you.

Code example: https://github.com/Azure-Samples/SQL-MCP-NoContainer

Using Fabric SQL as the example, we walk through the full setup: create a client service principal, configure RBAC, set up Data API builder (DAB), and run SQL MCP Server. The focus of this walkthrough is a clear production baseline: secure authentication, RBAC, and deterministic SQL tools exposed through SQL MCP Server.

Prerequisites

  • A SQL database in Microsoft Fabric
  • Visual Studio Code with PowerShell

Outcome

By the end of this walkthrough, Data API builder (DAB) is running and exposing endpoints based on your configuration. We will include exact PowerShell commands for each step and you'll have several validation options.

  • REST endpoints through Swagger/OpenAPI
  • GraphQL queries through GraphQL tooling
  • READ and WRITE SQL tables from your agent through SQL MCP Server

Let's get started

Step 0 - Install DAB tool

Data API builder includes a cross-platform command line tool (CLI) for configuration and management. In your terminal, run the following commands to set up the tool. After running these commands, you should see .config subfolder created under your project folder, and dotnet-tools.json created inside .config.

dotnet new tool-manifest 
dotnet tool install microsoft.dataapibuilder --prerelease  
dotnet tool restore  

Step 1 - Register a Microsoft Entra ID app (service principal)

In this step, we create a Microsoft Entra ID app registration. SQL MCP Server uses this identity to access the SQL database in Fabric. We can think of this app registration as the identity for our agent or client application.

  • App name example: sql-mcp-server
  • Save the application (client) ID
  • Create a client secret, then copy and save the Value field immediately. We use this value later as the password in the connection string. Use the secret Value, not the secret ID.

Then grant workspace access in Microsoft Fabric:

  • Add the app registration (sql-mcp-server) to the workspace
  • Assign role: Contributor (minimum required for SQL database access)

The following image shows an example of granting workspace permission to the app registration: Grant permission to the app

Step 2 - Grant SQL permissions to the app

In this step, we grant SQL permissions to the Microsoft Entra app inside the SQL database in Fabric. We can do this in the Fabric portal UI or with T-SQL. In this walkthrough, we use T-SQL because it is explicit and easy to repeat.

Note: that the [sql-mcp-server] in the T-SQL code below is the same as the app registration name we created in Step 1.

-- Create an Entra-backed database user.
CREATE USER [sql-mcp-server] FROM EXTERNAL PROVIDER;  
GO 

-- Grant read/write permissions.
ALTER ROLE db_datareader ADD MEMBER [sql-mcp-server]; 
ALTER ROLE db_datawriter ADD MEMBER [sql-mcp-server]; 

-- Optional: Grant db_owner only when admin operations are required.
ALTER ROLE db_owner ADD MEMBER [sql-mcp-server];
GO

The following image shows an example of SQL permission management in Fabric SQL: Manage permission of the SQL database

Step 3 - Build service-principal connection string

In this step, we build the SQL connection string that DAB will use.

Use these values:

  • Server and Database from your SQL database in Microsoft Fabric
  • User Id = the application (client) ID from Step 1
  • Password = the client secret Value from Step 1

We store the full connection string in an environment variable so we can reuse it in later steps.

$Env:SQL_CONNECTION_STRING = `
"Server=<your-server-name>.database.fabric.microsoft.com,1433;  
  Database=<your-database-name>;  
  Encrypt=True;  
  TrustServerCertificate=False;  
  Authentication=Active Directory Service Principal;  
  User Id=<your-application-client-id>;  
  Password=<your-client-secret-value>"  

Step 4 - Initialize DAB config (dab init)

In this step, we initialize Data API builder with the SQL connection string from Step 3.

In PowerShell, run:

dab init --database-type mssql --host-mode Development --connection-string "$Env:SQL_CONNECTION_STRING"

If dab is not available on your path, run:

dotnet tool run dab init --database-type mssql --host-mode Development --connection-string "$Env:SQL_CONNECTION_STRING"

This creates dab-config.json in your project folder.

We initialize once, then edit entities, key fields, and permissions in dab-config.json.

For connection-string, we can keep a full literal value, but using @env('SQL_CONNECTION_STRING') is the recommended approach for local and deployment consistency.

{
  "$schema": "https://github.com/Azure/data-api-builder/releases/download/v1.7.86/dab.draft.schema.json",
  "data-source": {
    "database-type": "mssql",
    "connection-string": "@env('SQL_CONNECTION_STRING')",
    "options": {
      "set-session-context": false
    }
  },
  "runtime": {
    "rest": { "enabled": true },
    "graphql": { "enabled": true },
    "mcp": { "enabled": true },
    "host": {
      "authentication": { "provider": "AppService" },
      "mode": "development"
    }
  },
  "entities": {
    "products": {
      "source": {
        "object": "dbo.products",
        "type": "table",
        "key-fields": ["ProductID"]
      },
      "permissions": [
        { "role": "anonymous", "actions": [ ] }
        { "role": "authenticated", "actions": ["*"] }
      ]
    }
  } 
}

Step 5 - Start DAB (HTTP or STDIO)

There are two ways to start DAB:


dotnet tool run dab start 
-- This will start MCP in HTTP mode. 

dotnet tool run dab start --mcp-stdio role:anonymous 
-- This will start MCP in Stdio mode. 

If you used @env('SQL_CONNECTION_STRING') in dab-config.json for 'connection-string', then every time before you start dab, you need to set the $Env:SQL_CONNECTION_STRING.

Step 6 - REST APIs

After the DAB is started in either HTTP or STDIO mode, you can launch Swagger UIs as shown in the image. UIs for the SQL database and MCP

http://localhost:5000/api/products
http://localhost:5000/api/orders
http://localhost:5000/api/order_details

GraphQL
http://localhost:5000/graphql

Try the following:

query { 
  products { 
    items {  
      ProductID,
      ProductName
    } 
  } 
}  

But the method of running the MCP server is different for HTTP and STDIO mode.

Step 7 - How to run and use the MCP server

Please refer to https://github.com/Azure-Samples/SQL-MCP-NoContainer/blob/main/How-to-Run-MCP.md