{"id":7130,"date":"2026-05-14T12:20:34","date_gmt":"2026-05-14T19:20:34","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=7130"},"modified":"2026-05-14T12:58:41","modified_gmt":"2026-05-14T19:58:41","slug":"sql-mcp-server-nl2sql","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/sql-mcp-server-nl2sql\/","title":{"rendered":"Considering NL2SQL? Should your database really be the prompt? How can SQL MCP Server help?"},"content":{"rendered":"<p>You\u2019ve probably experienced both of these, perhaps at the same time. First, that desire to let an agent get at your data. It\u2019s driven by simplification and better experiences for the user and for you: fewer screens, fewer queries, fewer reports, and less code overall.<\/p>\n<p>Second, and perhaps more importantly, that unrelenting reluctance and reticence against all of it. The voice in your head that makes you seriously uneasy. Your reputation is at stake, yes, but to your enterprise, this might be existential.<\/p>\n<h3><strong>It has a name: NL2SQL. <\/strong><\/h3>\n<p>NL2SQL, or Natural Language to SQL, is where an AI agent turns a natural language prompt into a SQL query. Ask a question, run a query, get an answer. Simple.<\/p>\n<p>But models can\u2019t do this from just a prompt, they need context. This means you include your schema, relationships, table names, column names, and maybe sample rows. From there, the model attempts to infer the query from your database.<\/p>\n<p>But is NL2SQL a good idea?<\/p>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Perspectives<\/strong><\/p>In this article, we\u2019ll walk through most of the real-world considerations every enterprise will need to consider when implementing an agentic solution against production data. There\u2019s always more to consider, but this is a nice baseline for a team starting to lean in to this new interaction model.<\/div><\/p>\n<h2><strong>Schema completeness<\/strong><\/h2>\n<p>Schemas are a reflection of your company\u2019s culture. Here\u2019s what I mean. Through evolution or just business change, a database schema reveals your business model, at least at the time the schema was created, various business applications, different integrated systems from mergers or upgrades, and the drift of best practices and team changes over time.<\/p>\n<p><strong>However, most schemas are not designed to explain. <\/strong>Cryptic table names and inconsistent column names are not wrong, just characteristics. Neither is it a problem when technically valid relationships can be semantically invalid or require additional, unpredictable predicates to be accurate. It\u2019s also okay when column values are sensitive or bespoke. Schemas store data and protect integrity, they don\u2019t communicate business rules.<\/p>\n<p>For this reason, your prompt could be asking a model to infer things that are almost impossible. However, model behavior is the problem. They are not going to give up on your request. Typical model behavior is to try, query, and respond with a \u201cbest effort\u201d approach to problem solving. Consider the risk of making business decisions from that.<\/p>\n<h2><strong>About ontologies<\/strong><\/h2>\n<p>There is renewed interest in data ontology. Much like previous efforts around data dictionaries, ontologies attempt to explain the data and the relationships between the data. This herculean task has an important goal in mind: explaining the data to models in a way that makes inference more successful. Time will tell if system support, enterprise adoption, and model behavior prove this renewed interest in the data graph worthwhile.<\/p>\n<p><div class=\"alert alert-info\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Ontologies describe the logical data, not how to query it.<\/strong><\/p>What I mean is that ontologies, like data dictionaries, help explain the data without necessarily explaining the intricacies of JOIN semantics and filter requirements. For example, an ontology tells me a Salesman is in a Region, but it doesn\u2019t tell me to filter the linking table based on the most recent row-version first to ensure imports from outside systems are properly reflected.<\/div><\/p>\n<p>Ontologies have real value. But they aren\u2019t the solution to NL2SQL.<\/p>\n<h2><strong>Never repeat yourself?<\/strong><\/h2>\n<p>When you add 1 and 1, you get 2 in every circumstance. When you test if 1 is equal to 1, you get a True in every circumstance. These are deterministic behaviors and they make SQL queries powerful tools to excavate data and answer questions.<\/p>\n<p><strong>But model behavior isn\u2019t deterministic. <\/strong>It doesn\u2019t return the same result every time. When you ask a model a question, it will generate a query. But when you ask the same model the same question about the same database, the next query can be different.<\/p>\n<p>In fact, we should expect this behavior. Considering that a model is an inference engine calculating probabilities every turn, variabilities in similarity ranking alone can drive output down vastly different paths. This is indeterminism, and we want to solve it.<\/p>\n<h2><strong>Solving indeterminism<\/strong><\/h2>\n<p>The solution is simple: <em>review every query<\/em>.<\/p>\n<p>It\u2019s okay to allow models to generate a query. All we need to do is intercede before execution with some type of review process. After the user approves the query, the pipeline continues and the results can be returned.<\/p>\n<p><strong>But is that realistic?<\/strong> This assumes users are experts in both the data model and the query language. And should we allow the user to edit the query? How can we defend systems against this new form of SQL injection?<\/p>\n<p>Perhaps worse, user review introduces a fresh vector for errors as users overwhelmed by query complexity and cognitive overload mistakenly approve invalid queries. A litany of biases emerges as the business starts to rely on those errors instead of rooting them out.<\/p>\n<p><strong>And is that practical?<\/strong> Agentic solutions should reduce cognitive load with less intervention and more agentic autonomy. Asking a user to review every query undermines the value of agentic systems and the investments being made into them.<\/p>\n<p>Reviewing queries is an unrealistic and impractical solution to indeterminism.<\/p>\n<h3><strong>Speaking of SQL injection<\/strong><\/h3>\n<p>In app development, SQL injections are a classic bug. It happens when untrusted input is allowed to change the meaning of a query. Developers solved this with parameterization, validation, least privilege, and patterns that keep user input separate from executable SQL.<\/p>\n<p><strong>Models are not just filling in parameters. <\/strong>Models are creating the SQL query. That means the prompt, schema context, conversation history, and retrieved data can all influence what is executed. Moreover, so can the trained behavior of the model.<\/p>\n<p><em>NL2SQL is the SQL injection of the agentic age. <\/em><\/p>\n<p>Listen, we aren\u2019t talking about big headline problems: some agent deletes the database, or some agent drops a table. We can solve most of that with thoughtful security policies. Instead, we are concerned about the subtle errors that allow queries to return conclusions that are wrong but presented with confidence.<\/p>\n<p><strong>This can put any business at risk<\/strong>: asking questions and getting incorrect results. I think dropping a table would be better, at least then we could see the problem. Incorrect results don\u2019t send us looking for database backups. In fact, they don\u2019t trigger any action. They are inaccurate values labeled as accurate ones.<\/p>\n<p>Business decisions from invalid results can have significant consequences.<\/p>\n<h3><strong>Perf problems<\/strong><\/h3>\n<p>There are operational concerns, too. NL2SQL doesn\u2019t just risk wrong answers; it can generate expensive queries. A syntactically valid query can scan too much data, join through the wrong path, ignore indexes, or create load patterns the system was never designed to handle.<\/p>\n<p><strong>Consider the covering index.<\/strong> This common practice intentionally aligns the scope of an index with the predicates in a recurring query. For example, if a system always filters by date, region, and owner, a covering index can intentionally include date, region, and owner in its scope. The result? Extremely fast queries.<\/p>\n<p>But how can this work when every query is different?<\/p>\n<p>Remember, a production database is typically a shared system. A bad query is not just a bad answer. It can become a reliability issue across the whole database. One filter too few, one join too many, or one misplaced aggregate can impact database compute, memory, or even system reliability.<\/p>\n<h3><strong>Irrelevant inferences<\/strong><\/h3>\n<p>There is also the real problem of leakage through inference. Even when the model cannot directly query data, restricted columns, schema names, table and column names, errors, and partial results can reveal the underlying structure, context, and backend system.<\/p>\n<p>The issue isn\u2019t, \u201cCan the agent read the column?\u201d It\u2019s, \u201cWhat can the agent infer from the shape of our system?\u201d Table and column names, relationships, and conventions can reveal more than intended. Based on these, for example, the model can infer your organization uses Dynamics, Salesforce, Workday, or SAP.<\/p>\n<p><strong>Why does it matter?<\/strong> Because this type of inference can change model behavior, shape its assumptions, or disclose unexpected details you never meant to share. It\u2019s a key driver behind systems like Data API builder (DAB) that use abstractions: intermediary schemas that can occlude details unrelated to the immediate business scenario.<\/p>\n<h3><strong>Trouble testing<\/strong><\/h3>\n<p>Testing is harder, too. A fixed API contract can be tested. A generated query is harder to certify because the query is created at runtime. You can test examples, but you can\u2019t exhaustively test every query the model might generate.<\/p>\n<h3><strong>Custody concerns<\/strong><\/h3>\n<p>And finally, there is ownership. When a generated query is wrong, who owns the failure? The model? The developer? The DBA? The user who invoked it? When production systems need accountable boundaries, runtime-generated SQL makes those harder to see.<\/p>\n<h2><strong>The right place for NL2SQL<\/strong><\/h2>\n<p>Don\u2019t read this wrong, NL2SQL isn\u2019t useless. In fact, it can be incredibly valuable outside agentic systems that operate against production data to make business decisions.<\/p>\n<p><strong>The best use case is the developer\u2019s inner loop. <\/strong>This loop describes the developer\u2019s cycle of writing, testing, observing the result, and making the next change. For a database, the developer loop is when the schema is created, tables are altered, relationships are mapped, queries are tested, and assumptions are validated. NL2SQL can greatly accelerate the work.<\/p>\n<p><div class=\"alert alert-info\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Development isn't production<\/strong><\/p>Remember, during the developer loop, the developer is still in control. There is no production data, there is no production system, and the decisions being made are procedural, architectural, and structural. It\u2019s development.<\/div><\/p>\n<p><strong>There\u2019s another use case: information discovery.<\/strong> The goal of information discovery is exploration, not operation. It\u2019s production data, or at least a subset of it, where the user wants to find patterns, compare loosely related data, or ask broad questions that don\u2019t fit a predefined CRUD operation.<\/p>\n<p>Information discovery is the most open-ended scenario for an agent, like letting a hunting dog out into a field to sniff out birds. The difference is that this discovery is just an indicator of places in your data that warrant further investigation. Information discovery is the Shangri-La of agentic data work, pounding against the data to find something new.<\/p>\n<p><em>Even in information discovery, however, it can be critical to give guidance<\/em> to the model beyond the schema itself. You want reliable and valid information to be discovered, something you can drive with operational constraints inside specific guardrails. This distinction matters. NL2SQL may help you explore data, even discover new insights. However, this should not be conflated with safe architecture for agents operating against business systems and production data stores.<\/p>\n<h2><strong>Agentic success<\/strong><\/h2>\n<p>Introducing SQL MCP Server, an agentic interface built for safe production data interactions. With guardrails, contracts, and semantic enhancements, SQL MCP Server gives enterprises a safe approach to expose production data to agents.<\/p>\n<h3><strong>Feature 1: abstraction<\/strong><\/h3>\n<p>SQL MCP Server doesn\u2019t require you to expose the database as-is. It exposes entities that you configure, abstractions of tables, views, and stored procedures on a curated agentic surface with names, permissions, fields, and operations controlled by configuration.<\/p>\n<p><strong>That abstraction is important.<\/strong> The database remains optimized for storage, performance, and even the application, while agents get a surface designed for safe understanding.<\/p>\n<p><em>Example configuration setup:<\/em><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\"><strong>dab add SeriesActors \\\r\n<\/strong>  --source dbo.SeriesActors \\\r\n  --rest.path \"\/cast\" <\/code><\/pre>\n<h3><strong>Feature 2: description<\/strong><\/h3>\n<p>Agents need more than names. A table name might be accurate and still not explain what the data means. SQL MCP Server supports semantic descriptions for the server itself, configured entities, columns, and parameters so models have guidance beyond the raw schema. These contribute to agentic understanding of intent, not just structure.<\/p>\n<p><em>Example configuration setup:<\/em><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab add SeriesActors \\\r\n  --source dbo.SeriesActors \\\r\n  --rest.path \"\/cast\" \\\r\n<strong>  --description \"Actors by Star Trek series. Use this instead of joining Actor, Character, and Series tables.\"<\/strong><\/code><\/pre>\n<h3><strong>Feature 3: authorization<\/strong><\/h3>\n<p>SQL MCP Server is role aware. The agent doesn\u2019t discover every table, field, or operation. It only sees what the current role is allowed to use. This is enabled without requiring any security or structural changes to your database.<\/p>\n<p>This matters because production data access is never just a query problem. It\u2019s a permissions problem. A safe agentic interface must enforce who can read, create, update, delete, or execute before the model ever gets a chance to act.<\/p>\n<p><em>Example configuration setup:<\/em><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab add SeriesActors \\\r\n  --source dbo.SeriesActors \\\r\n<strong>  --permissions \"authenticated:create,read\" \\\r\n<\/strong>  --rest.path \"\/cast\" \\\r\n  --description \"Actors by Star Trek series. Use this instead of joining Actor, Character, and Series tables.\"<\/code><\/pre>\n<h3><strong>Feature 4: API contract<\/strong><\/h3>\n<p>SQL MCP Server gives agents a contract instead of a blank query window. The agent can discover what it\u2019s allowed to do, which entities are available, which fields exist, and which operations are permitted.<\/p>\n<p>That contract is stable, testable, and <em>enforceable<\/em>.<\/p>\n<p><em>Example MCP header request:<\/em><\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"jsonrpc\": \"2.0\",\r\n  \"method\": \"tools\/call\",\r\n  \"params\": {\r\n    \"name\": \"describe_entities\",\r\n    \"arguments\": {}\r\n  }\r\n}<\/code><\/pre>\n<h3><strong>Feature 5: query builder<\/strong><\/h3>\n<p>SQL MCP Server doesn\u2019t ask the model to invent SQL. The model supplies intent through a constrained tool call, and the engine builds the query deterministically.<\/p>\n<p>That means the generated SQL follows the configured contract every time. The agent can still answer useful questions, but the database is no longer the prompt.<\/p>\n<p><em>Example inbound request:<\/em><\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"entity\": \"SeriesActors\",\r\n  \"select\": \"Actor,Series\",\r\n  \"filter\": \"Series eq 'Star Trek: Voyager'\",\r\n  \"orderby\": [ \"Actor asc\" ],\r\n  \"first\": 5\r\n}<\/code><\/pre>\n<p><em>Example backend query:<\/em><\/p>\n<pre class=\"prettyprint language-sql\"><code class=\"language-sql\">SELECT TOP (5) [Actor], [Series]\r\nFROM [dbo].[SeriesActors]\r\nWHERE [Series] = @param0\r\nORDER BY [Actor] ASC;<\/code><\/pre>\n<h3><strong>Feature 6: observability<\/strong><\/h3>\n<p>Production systems need logs, traces, health checks, and operational visibility. If agents are acting against data, teams need to know what they called, when they called it, and whether it succeeded.<\/p>\n<p>Observability helps teams inspect agent behavior, troubleshoot failures, and build confidence that production data access is operating as intended.<\/p>\n<h2><strong>Where does this leave us?<\/strong><\/h2>\n<p>NL2SQL is tempting because it makes a hard problem look simple. But production data is not a blank canvas, and a database schema is not a safe prompt. The closer agents get to business systems, the more the architecture matters.<\/p>\n<p>That doesn\u2019t mean NL2SQL is bad. It means we need to be precise about where it belongs. Use it in the developer loop. Use it for exploration. <strong>Use it where the cost of being wrong is manageable and the human remains in control.<\/strong><\/p>\n<p>But when agents operate against production data, especially when they read, create, update, delete, or execute, they need more than generated SQL. They need abstraction, authorization, contracts, descriptions, deterministic query generation, and observability.<\/p>\n<p>That\u2019s the point of SQL MCP Server. It gives agents a way to work with data without making the database the prompt.<\/p>\n<p><div  class=\"d-flex justify-content-left\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/aka.ms\/sql\/mcp\" target=\"_blank\">Get started with SQL MCP Server<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>You\u2019ve probably experienced both of these, perhaps at the same time. First, that desire to let an agent get at your data. It\u2019s driven by simplification and better experiences for the user and for you: fewer screens, fewer queries, fewer reports, and less code overall. Second, and perhaps more importantly, that unrelenting reluctance and reticence [&hellip;]<\/p>\n","protected":false},"author":96788,"featured_media":6602,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[597,720],"tags":[680],"class_list":["post-7130","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-api-builder-2","category-sql-mcp-server-2","tag-agentic-ai"],"acf":[],"blog_post_summary":"<p>You\u2019ve probably experienced both of these, perhaps at the same time. First, that desire to let an agent get at your data. It\u2019s driven by simplification and better experiences for the user and for you: fewer screens, fewer queries, fewer reports, and less code overall. Second, and perhaps more importantly, that unrelenting reluctance and reticence [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7130","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/96788"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=7130"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7130\/revisions"}],"predecessor-version":[{"id":7131,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7130\/revisions\/7131"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/6602"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=7130"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=7130"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=7130"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}