Schema MCP#

A local, read-only MCP server that lets an AI agent read the structure of a SQL Server database — objects, code, dependencies, columns — and never its data.

MCP, the Model Context Protocol, is a standard for adding tools to the harness of an agent, that is, to the program that carries out what the AI model asks for. That harness is the AI application you install, such as Claude Desktop, or Claude Code and GitHub Copilot in VS Code. An MCP server is a program that provides such tools: the model asks for a tool the way it asks to read a file, the harness passes the request on to the MCP server, and the answer comes back into the conversation. Here, the tools query a SQL Server database. If the loop between the model and its harness is not familiar to you, it is described separately.

This page presents the MCP server: what it does, what guarantees it, and what it costs. The step-by-step setup — the scripts, the installation, the declaration of connections — is in the README of the repository, which is the reference.

The idea#

How do you let someone work on a database without showing them the data it holds? The question is as old as databases themselves, and SQL Server answers it with rights.

A login that holds only the VIEW DEFINITION right sees the structure of a database. It sees the list of tables and their columns. It reads the text of views, stored procedures and functions. It sees the indexes and the foreign keys. But it cannot read a single row of any table. And it cannot change anything.

Schema MCP applies the same answer to an AI agent. The agent queries the database through the MCP server. The MCP server connects to the SQL Server instance with a login that holds only that right. So the agent knows the structure of the database, and nothing more.

When you write SQL with an agent, there is then no need to paste the result of a catalog query into the conversation so that the agent knows how the database is built. The agent looks up the exact names of tables and columns, their types, the procedures that use a table. The SQL it proposes is based on the real database, not on what it assumes.

If granting that access is your call, as a DBA or an IT manager, the question is a different one: what can this agent do on the database, and how can that be checked? What guarantees that the agent does not read the data, below, answers it.

Where it runs#

The MCP server is a program that runs on your own computer, next to the AI application that uses it. That application starts it when it needs it, and talks to it through the standard input and output of the program. The MCP standard calls this a local server.

Three conditions follow.

The AI application is installed on the same computer, and it supports local MCP servers. This MCP server is tested with Claude Desktop, and checked with Claude Code and with GitHub Copilot in VS Code. Any MCP client that can start a local server will do as well. A chat opened in a web browser, on the other hand, runs on the servers of its provider: it cannot start a program on your computer, so it cannot use this MCP server.

The computer runs Windows. The MCP server keeps your connections in a file encrypted with DPAPI, the encryption mechanism of Windows.

The computer reaches the SQL Server instance over the network, as SSMS would. The MCP server opens no network port: its only connection is the one it makes to the instance, with the login you give it.

Whatever the MCP server returns becomes part of the conversation. It is therefore sent to the provider of the AI model, like the rest of what you type. What it returns is the structure of the database, and never its data.

What guarantees that the agent does not read the data#

Two protections, and only one of them is the guarantee#

The first protection is the code of the MCP server. It only runs queries written in advance, which read the SQL Server catalog, that is, the system views that describe the objects of the database. Neither you nor the agent can change these queries. The tools of the MCP server take parameters, such as a schema name or part of an object name. They never take SQL. This code is public, and you can read it in the repository.

The second protection is the one that makes the guarantee: the rights of the login. Even if the code of the MCP server had a bug, or had been modified, it could not do more than its login allows. And those rights are granted by you, with a script you read before running it. So you do not have to trust the MCP server: you check for yourself, on your own instance, what its login can and cannot do.

One login, one role, one right#

The repository provides the script that creates this login. It creates the login at the level of the instance, then the matching user in the database. It then creates a role, makes that user a member of it, and grants the role the VIEW DEFINITION right. If another account ever needs the same access, it only has to be added to the role: no right has to be granted again.

By default, the right covers the whole database. You can limit it to one schema. The MCP server is not told about that limit: it simply sees fewer objects. The limit lives in the rights, where you control it, and not in a setting of the MCP server.

The script adds four denies, and only four. When database diagrams have been created in SSMS, four procedures of the dbo schema write into the table dbo.sysdiagrams, and the role public, which every user of the database belongs to, is allowed to run them. This is the only way to write that the default rights of a database leave open, and the script closes it. A global deny, such as a deny select on the whole database, would also apply to the system views the MCP server reads: the login would see nothing at all.

A check you run yourself#

A second script checks what the login can actually do. It runs connected as that login, since it checks the rights of the connection that runs it. It changes nothing, and gives four verdicts, PASS or FAIL: the login sees the definitions; it reads no data, and an actual attempt to read a table is refused by SQL Server; it writes nothing, and an actual attempt to create a table is refused, inside a transaction that is rolled back; finally, the dependency functions answer.

A third script lists what the database grants to the role public. Every user is a member of it, the login of the MCP server included, and cannot be removed from it: a right granted to public is therefore held by everyone.

The README details these three scripts in four steps, with the account each one runs under and the expected result.

The one figure about the data#

Two tools give the approximate number of rows of each table. At first sight, this looks as if the MCP server had read the tables. It has not: SQL Server keeps that number in its catalog, in the system view sys.partitions, and the VIEW DEFINITION right shows it, just as SSMS shows it in the properties of a table. The MCP server never counts the rows, and never reads them.

With your Windows account#

The MCP server can also connect with Windows authentication. It then connects as the account that started the AI application: in practice, your own, the one you also use in SSMS.

This changes what the rights can guarantee. The working loop involves two identities: the agent reads the structure with the rights of the MCP server, and you apply the scripts it proposes with your own rights. With Windows authentication, these two identities are one and the same. If your account keeps the rights you work with, the MCP server holds them too, and the guarantee then rests on its code. If your account is limited to VIEW DEFINITION, the guarantee holds again, but you can no longer apply anything with it. A SQL Server login dedicated to the MCP server keeps the two identities apart.

The rights of the login bound this MCP server, and nothing else. Your AI application may offer the model other tools, such as another MCP server that runs SQL, or a command line that can start sqlcmd. Those tools run under your Windows account, with its rights, whichever way this MCP server connects.

The MCP server reports the two cases where an account certainly reads all the data: a sysadmin account, and an account that holds the SELECT right on the whole database. It says so in the console when you test the connection, once in the first result the agent receives, and every time the server_info tool is asked. When it detects nothing, it says nothing, and that silence is not a guarantee: an account can be restricted on some tables and not on others.

What the code of your database can reveal#

The VIEW DEFINITION right gives access to the text of views, procedures, functions and triggers, as it was written. If that code holds passwords or API tokens in plain text, the agent will read them, and they will go to the provider of the model along with the rest of the structure. The MCP server does not try to make up for that practice. The risk already exists for anyone who has been granted that right, and the README gives a query to look for such information before opening access.

What the agent gets#

The MCP server supports a simple working loop. The agent reads the structure of the database through the MCP server. It proposes a script. You review that script, and you apply it yourself. The MCP server provides exact facts about the database, and the AI model writes the SQL with them: the real names of tables and columns, the real types, the real nullability.

Eight tools serve that loop, and a ninth is added when you provide a conventions file.

Browsing the database. list_objects lists the tables, views, procedures, functions, triggers and sequences, filtered by schema, name, type or modification date. For each table, it gives the approximate number of rows, which shows at once the main table among its satellites. For each module, it gives the length of its text: the agent knows what an object will cost to read before asking for it. find_columns finds the tables and views that have a column of a given name.

Understanding an object. describe_object gives a compact summary of it: for a table, its columns and their types, its keys, indexes, foreign keys, checks and triggers; for a procedure or a function, its parameters. On request, it adds the descriptions (MS_Description) of the object and of its columns. script_object returns the complete CREATE script of the object, as SSMS produces it. The agent uses it when it has to change the object.

Measuring the impact of a change. find_references tells what uses an object, or what it uses, from the dependency graph that SQL Server maintains. But that graph does not see dynamic SQL: when a procedure builds a query in a character string and then runs it, the name of the table is inside the string, and SQL Server does not record it as a dependency. search_modules searches for a fragment in the text of the modules, and finds that name. So the two tools are read together. On a production database that was measured, a little over 1 % of the procedures, views and functions held dynamic SQL.

Knowing which database you are working on. use_connection chooses the database among the connections you have declared. Every result names the database it comes from: a wrong target shows at once. server_info gives the version of the MCP server, its location, and the commands that manage the connections. The agent can then answer if you ask it how to remove one.

Following your team’s conventions, if you have any. Put a conventions.md file next to the executable, and the MCP server offers the read_conventions tool, which returns that file as it is. The description of the tool asks the agent to call it before writing SQL. Without the file, the tool does not exist, and it costs nothing. The MCP server imposes no convention and ships none; the repository publishes an example.

Known limits#

  • Dependencies are given at the level of the object, not of the column. SQL Server does not resolve column dependencies reliably, so the MCP server does not promise them.
  • A module created with the with encryption option has no readable text, so search_modules does not find it.
  • The modification date of a table also changes when one of its indexes changes. For views, procedures and functions, it does show the last change to the code.
  • Database triggers, the ones that fire on DDL statements, are not covered: they belong to no schema. Triggers on tables and views are.

What these choices cost#

Each bound of the MCP server has its counterpart. They are worth reading before adopting it.

No data, not even a sample. The MCP server shows no row, no statistic, no column profile. An index statistic holds real values of the column: reading it would already be reading data. In return, the agent cannot check an assumption about the content of a table on its own. It gives you the query, and you are the one who runs it.

No writes. The MCP server produces no SQL and applies none. The agent proposes, and you apply: that is a manual step at every change, and it is also what lets the login keep the lowest rights.

Capped answers. Every answer takes room in the conversation, and that room is counted in tokens. So a list never goes beyond 200 rows by default, a ceiling set by the environment variable DDL_MAX_RESULTS, which the agent cannot change. When a request is too broad, the tool returns how the results are spread, per schema, per type or per name prefix, rather than a truncated list. The agent then has to narrow its request, or ask you a question. For the same reason, describe_object is the tool to know a table: on a large table of a production database, it returned about a sixth of what script_object returned, in one second rather than forty.

Tool definitions to load. The nine tools take about 3,000 tokens. A client that loads its tools in advance pays them in every conversation, even one that has nothing to do with a database. A client that loads them on demand pays them only when a conversation looks for them.

A load on the instance, small but real. The MCP server only reads the catalog, and those queries are usually fast. The most expensive one is a search through the text of every module, without a filter: on a database of 36,000 objects and 32,000 modules, it took 11 seconds. The search stops as soon as it has found more results than it can return.

Windows, and an executable that is not signed yet. The encryption of connections relies on DPAPI, and the published executable is built for Windows x64. Without a signature, Windows may block it on a machine where Smart App Control is on.

Trying it#

Without going near a database that matters. The repository provides a script that creates a demo database: about twenty objects spread over four schemas, with no data at all. Several of these objects are traps, each announced by a comment: a name holding the special characters of like, dynamic SQL, a reference to a table that does not exist, a view broken by the removal of a column. The same database serves the integration tests of the repository.

The installation. The MCP server is a single executable, schema-mcp.exe, of about 93 MB. It contains the .NET runtime: nothing else needs to be installed. Each release publishes the executable, a file holding its SHA-256 fingerprint, and the notices of the third-party components it ships. Checking the fingerprint proves that the download is complete and intact; it does not prove who built the file. The executable can also be built from the source, with the .NET SDK.

The connections. You declare them in a console, with the executable itself: the name of the instance, the database, the login and the password. The MCP server never asks for them during a conversation, and the agent never sees them. They are stored in a file encrypted for your Windows account. That encryption protects the file if it is stolen or exposed by accident, in a backup or during a screen share. A program running under the same account, however, can decrypt it, exactly as the MCP server does. This level of protection matches what the password allows: reading object definitions, and nothing else.

The client. Each AI application declares its MCP servers in a configuration file of its own, whose format differs from one client to another, and sometimes from one version to the next. The declaration still comes down to three pieces of information, the same for every client: a name for the MCP server, the full path of the executable, and the location of the file of connections. The simplest way is to ask the agent of your client to write that declaration, then to restart the client and ask the agent which version of the MCP server is running. To answer, the agent calls the tool server_info; if it does not find it, the client has not loaded the MCP server.

The Installation part of the README gives the commands, and the latest release holds the executable.

Status and license#

The first releases date from September 2026. The changelog says what each version changed.

The code is published under the MIT license: github.com/SharpPyxis/SharpPyxis.SqlServer.SchemaMcp. The published executable also contains the .NET runtime and third-party libraries, each under its own license, and the repository lists them. One of them, Microsoft.Data.SqlClient.SNI, is not open source: it is distributed under the Microsoft Software License Terms.

Like everything SharpPyxis publishes, this MCP server is designed and written with an AI agent. Every commit of the repository says so, with a co-author line.