Skip to main content

SQL MCP Server: agentic access to SQL without NL2SQL

When an AI agent needs to read or write data in a production database, the usual options are bad: hand it raw SQL (NL2SQL — non-deterministic, hallucinates joins, leaks schema), or hand-build a REST API per table (slow, brittle, doubles the security surface). SQL MCP Server, shipped as a feature of Data API builder (DAB) 2.0, is the third path: a config-driven container that exposes any combination of Azure SQL, SQL Server, PostgreSQL, MySQL, and Cosmos DB through a small, fixed Model Context Protocol tool surface — with RBAC, caching, and telemetry enforced at the API layer.

Concept

DAB is the engine. SQL MCP Server is one of three protocols DAB can speak from the same configuration file:

  • REST at /api
  • GraphQL at /graphql
  • MCP at /mcp

All three honor the same entity definitions, role-based permissions, field exclusions, and policies. So the same config that powers your line-of-business app's REST endpoints can also expose those entities to a Foundry agent or to GitHub Copilot in VS Code — without writing a second authorization layer.

The MCP tool surface is fixed and small: 7 DML tools, regardless of how many tables you expose. This keeps the agent's context window focused on reasoning rather than tool definitions.

ToolPurpose
describe_entitiesDiscovers entities and their operations
read_recordsSELECT against tables and views
create_recordINSERT
update_recordUPDATE
delete_recordDELETE
aggregate_recordsGROUP BY / SUM / COUNT / AVG / MIN / MAX
execute_entityRuns a stored procedure (or your own custom tool)

Each tool can be enabled or disabled per server, and stored procedures can be promoted as custom tools when you want to encapsulate business logic instead of exposing raw CRUD.

Architecture

❓ How does an MCP tool call become deterministic T-SQL?

Decision flow — agent → DAB → backend
1
Agent surface
GitHub Copilot in VS Code
Foundry / Agent Framework
Custom chat UI
Talks MCP via .vscode/mcp.json or HTTP
2
DAB runtime
Validates request against role (X-MS-API-ROLE)
Resolves entity + permitted action
Excludes hidden fields per role
Applies @claims policy filters
3
Query Builder
Generates parameterized T-SQL / SQL / GraphQL
No NL2SQL — deterministic per input
L1 in-memory + L2 Redis cache for reads
4
Backend
Azure SQL / SQL Server
PostgreSQL
Cosmos DB (NoSQL)
MySQL
Telemetry → App Insights / OTel
MCP at /mcp
Best forAgents — Copilot, Foundry, custom chat — that need governed CRUD
StrengthFixed 7-tool surface keeps the agent context tight; MCP 2025-06-18
Trade-offNo schema design or DDL — read/write only on declared entities
REST at /api
Best forLine-of-business apps and integrations that already speak OData
StrengthSame RBAC, field exclusions, and cache as MCP — one config
Trade-offOne endpoint per entity; not a query language for ad-hoc joins
GraphQL at /graphql
Best forFrontends that want typed queries, mutations, and field selection
StrengthSingle endpoint, schema-driven, honors the same entity contract
Trade-offSubscriptions and federation are not in scope for DAB

Why DBAs care

This is not a generic "AI plugin." It addresses the specific failure modes that make DBAs nervous about agents touching production:

  • No NL2SQL. The agent never writes T-SQL. It calls typed tools; DAB's Query Builder generates parameterized, deterministic T-SQL. Same input → same query → same result.
  • Schema is hidden. The entity abstraction layer aliases names, excludes columns, and limits operations per role. The agent sees Customer.email, not dbo.SLT_CUST.EMAIL_ADDR_NVCHAR.
  • RBAC at the API layer, in addition to whatever you have at the database layer. Defense in depth — a misconfigured DB grant can't bypass the API contract.
  • Caching included. L1 in-memory and L2 Redis (or Azure Managed Redis) prevent request stampedes from chatty agents.
  • Telemetry first-class. Logs and metrics flow to Application Insights, Azure Log Analytics, and OpenTelemetry collectors out of the box.

When to pick it

OptionWhen to pick itTrade-offDon't use it for
SQL MCP Server (DAB)You want agents to query existing relational data with deterministic, governed accessOne more container to host; learn DAB's config schemaSchema design or DDL operations
NL2SQL inside the modelOne-off exploration on a sandbox; the agent is the only user; data is non-sensitiveHallucinated joins, no RBAC, fragile under schema changeAnything production or multi-tenant
Hand-rolled REST + tool wrapperYou already have a mature REST API and just need to wrap a few endpoints as MCP toolsEvery new entity = code + tests + auth + cacheGreenfield agent enablement on a database

Pick SQL MCP Server if the data lives in a SQL/Postgres/Cosmos/MySQL store and more than one agent or surface needs governed access. Pick NL2SQL only on throwaway sandboxes. Pick hand-rolled wrappers only when an established REST contract already encodes business rules you can't move into the database layer.

How to configure it

Three CLI commands take you from zero to a running MCP server pointed at AdventureWorksLT.

# 1. Install the DAB CLI (one-time)
dotnet tool install -g Microsoft.DataApiBuilder

# 2. Initialize the config
$env:SQL_CONN = "Server=tcp:myserver.database.windows.net;Database=AdventureWorksLT;Authentication=Active Directory Default;Encrypt=True;"
dab init --database-type mssql --connection-string "@env('SQL_CONN')" --host-mode Development

# 3. Add entities with role-scoped permissions
dab add Customer `
--source SalesLT.Customer `
--permissions "agent:read,aggregate"

dab add Order `
--source SalesLT.SalesOrderHeader `
--permissions "agent:read,aggregate"

# 4. Promote a stored procedure as a custom MCP tool
dab add CustomerOrders `
--source SalesLT.uspGetCustomerOrders `
--source.type stored-procedure `
--source.params "CustomerID:1" `
--permissions "agent:execute"

# 5. Add semantic descriptions so the agent picks the right entity
dab update Customer --description "Retail customers who place orders. Use for lookups by name, email, or company."

# 6. Run it
dab start

The generated dab-config.json (excerpt) is the only artifact you ship:

{
"data-source": { "database-type": "mssql", "connection-string": "@env('SQL_CONN')" },
"runtime": {
"mcp": {
"enabled": true,
"path": "/mcp",
"dml-tools": {
"describe-entities": true,
"read-records": true,
"aggregate-records": true,
"execute-entity": true,
"create-record": false,
"update-record": false,
"delete-record": false
}
},
"cache": { "enabled": true, "ttl-seconds": 30 }
},
"entities": {
"Customer": {
"source": { "object": "SalesLT.Customer" },
"description": "Retail customers...",
"permissions": [
{ "role": "agent", "actions": [
{ "action": "read", "fields": { "exclude": ["PasswordHash","PasswordSalt","rowguid"] } },
{ "action": "aggregate" }
]}
]
}
}
}

Then wire it into VS Code by adding to .vscode/mcp.json:

{
"servers": {
"adventureworks": {
"url": "http://localhost:5000/mcp",
"headers": { "X-MS-API-ROLE": "agent" }
}
}
}

GitHub Copilot in VS Code now has a typed view of your database, and writes are blocked because the role only grants read and aggregate.

🔀 Oracle → Azure

Oracle parallel: SQL MCP Server is the agentic descendant of Oracle REST Data Services (ORDS). Both expose database objects through declarative configuration rather than hand-written endpoints, both layer their own RBAC on top of the database, and both let you promote PL/SQL packages (Oracle) or stored procedures (SQL) as named operations. The mapping breaks down at the protocol level: ORDS speaks REST and OAuth; SQL MCP Server adds MCP for native AI agent consumption and ships GraphQL alongside REST in the same config.

Common pitfalls / exam traps

  • ❌ Treating MCP as a synonym for "the model writes SQL." MCP is a tool-calling protocol; SQL MCP Server's whole point is that the model doesn't write SQL.
  • ❌ Granting delete-record on the global dml-tools block "to keep things simple." Disable destructive tools at the runtime level and re-enable only on entities that genuinely need them, scoped by role.
  • ❌ Putting connection strings as literal values in dab-config.json. Use @env('VAR') or Key Vault references — the config file ends up in source control.
  • ❌ Skipping descriptions. Without them the agent sees dbo.t_cust_2024 and guesses; with them it sees "Active retail customers as of 2024 reorg" and picks correctly.
  • ✓ Right mental model: DAB is the engine, MCP is one of three protocols, entity config is the contract, role-scoped permissions are the security boundary.

References

How many DML tools does SQL MCP Server expose, and why is the count fixed?
Click to reveal answer
Seven: describe_entities, read_records, create_record, update_record, delete_record, aggregate_records, execute_entity. Fixed so the agent's context window stays focused on reasoning instead of tool definitions.
1 / 4