Ask an AI assistant whether a SQL Server on build 16.0.4165.4 is patched and it will answer you confidently. It might even be right. The problem is that you cannot tell which, because build numbers, cumulative update levels and support end dates all move faster than any model’s training data, and a half-remembered build number reads exactly like a correct one.
I have been publishing SQL Server error write-ups, wait type explanations and production scripts here for a while now. All of it is checked against real instances, because that is the only kind I would put my name on. The sqldba MCP server takes that same reference and hands it to your AI assistant as something it can look up, rather than something it has to remember.
This post is written for a DBA who has not used MCP before. The first half explains what an MCP server is and why you would want one at all, which is worth knowing whether or not you ever install mine. The second half is how to hook this one up, and what to check before you trust any of them. In a hurry? Jump straight to the install steps.
run_script tool. It cannot reach an instance even if asked.pip install, done. No account, no API key, no port.On this page
- First, What Is an MCP Server?
- Why Give an Assistant Tools At All
- What This Particular Server Gives You
- Two Things It Will Not Do
- Installing It
- Three Questions Worth Trying First
- What to Consider Before You Install Any MCP Server
- Keeping It Current
- How Accurate Is the Retrieval
- What Those Numbers Cannot Tell You
- Common Questions
- Related Scripts
- Summary
First, What Is an MCP Server?
MCP stands for Model Context Protocol. It is an open standard for connecting an AI assistant to things outside itself: your files, your ticketing system, a company wiki, or in this case a reference library. It was published by Anthropic and is now supported well beyond their own products.
The problem it solves is boring and real. Before it, every assistant had its own plugin format, so anyone who wanted to expose a tool had to write it several times over and hope their client of choice was supported. MCP is one protocol instead. Write a server once and it works in any client that speaks MCP. That is the entire pitch, and it is why the ecosystem grew quickly.
Two words are worth getting straight first, because MCP uses them in the opposite sense to what a DBA expects:
A server can offer three kinds of thing, and the real difference between them is who decides to use them:
| Kind | What it is | Who chooses to use it |
|---|---|---|
| Tools | Functions the assistant can call, like lookup_error |
The model, when your question needs one |
| Resources | Documents at a fixed address the client can read | The client, or you, by attaching one |
| Prompts | A saved piece of methodology you can invoke by name | You, deliberately |
Most servers are mainly tools, and that is the part you will notice.
What Happens When You Ask a Question
The flow is worth seeing once, because after that the whole thing stops feeling like magic:
explain_wait, with PAGEIOLATCH_SH as the argument.
Steps 2 through 4 happen in well under a second and you see them as a small “used a tool” note in the transcript. The transport underneath is usually stdio, meaning the client launches the server as a local process and they talk over standard input and output. No port, no daemon, no account. When you close the client, the server stops.
Why Give an Assistant Tools At All
You could paste a reference page into the chat and get a decent answer, and sometimes that is the right move. Here is what a tool gives you that pasting does not.
| What you get | Why it matters |
|---|---|
| Looked up, not remembered | Patch levels, CU numbers and support end dates change every few weeks. A model’s training data does not. This is the single biggest reason and it is why build level was the first thing I put in. |
| A link, so you can check | Every answer carries the URL of the write-up it came from. A claim you can verify in ten seconds is a different thing from a claim you cannot. |
| The same answer twice | A lookup is deterministic. Recall is not, and it is not consistent between two conversations either. |
| Facts a model cannot infer | Whether a script writes data, what permission it needs, what its impact is. That is not derivable from skim-reading the SQL, and it is exactly what you want to know before you run it. |
| It works with no network | The data ships inside the package, so it answers on an air-gapped jump box, which is often exactly where you are when a server is misbehaving. |
| It can say it does not know | A model has no reliable sense of the edge of its own knowledge. A lookup does, because either the row is there or it is not. |
| Nothing leaves your machine | The question is answered by a process running under your account, on your laptop. |
What This Particular Server Gives You
Once it is installed, your assistant gets six tools. You do not call them yourself, you just ask a normal question and it reaches for the right one.
| Ask it | Tool | What comes back |
|---|---|---|
| “What is error 18456?” | lookup_error |
The message text, what it means in practice, the severity, and a link |
| “Is PAGEIOLATCH_SH worth chasing?” | explain_wait |
Whether it matters or is normal noise, when to ignore it, what to do. Paste a whole sys.dm_os_wait_stats result and it triages the set |
| “Is 16.0.4165.4 current?” | check_build |
The version, its patch level on its servicing train, support status, and the KB to install |
| “What do I run to see blocking chains?” | find_script |
The script, its required permissions, and its safety class |
| “Show me that script” | get_script |
The complete verbatim script, header and safety annotations intact |
| “Why is my filegroup full when the disk has space?” | answer_question |
The answer I actually wrote for that question, plus the post it came from |
Here is what is behind those six tools today:
Six tools is a ceiling rather than a target. Past roughly half a dozen an assistant starts picking the wrong one, and a wrong pick is worse than having no server at all, so anything else this could expose is a resource or a prompt instead. There is a test that fails the build if a seventh tool ever appears.
It also exposes the repo documentation as readable resources, and ships the health check triage rubric as a prompt, so an assistant can work through a server the way I would rather than giving generic advice. That prompt is the part that carries judgement instead of facts.
Two Things It Will Not Do
There is deliberately no run_script tool. Having no database connection at all is worth more than the convenience it costs, because it is a property you can verify rather than a policy you have to trust.
It is enforced by a test suite that checks the refusal in both directions, so a server which simply refused everything would fail just as loudly as one that made things up.
Installing It
You need Python 3.10 or newer. Everything below is copy and paste.
One command. It pulls the server and its bundled data straight from the repo.
pip install "sqldba-mcp @ git+https://github.com/peterwhyte-lgtm/dba-tools.git#subdirectory=mcp"
The selftest prints what came with it, including the date the data was generated and how old that is.
sqldba-mcp --selftest
sqldba MCP v0.3.1 | 48 errors | 260 wait types (234 posts) | 7 versions |
492 FAQ answers | 232 scripts (183 SQL, 49 PowerShell) | 9 docs | 1 prompt(s) |
data generated 2026-08-21 (0 days old)
If that line prints, the package and its data are fine, and anything that goes wrong from here is client configuration.
Claude Code takes one command and remembers it for good.
claude mcp add sqldba -- sqldba-mcp
Claude Desktop wants the server adding to claude_desktop_config.json, then a restart of the app.
{
"mcpServers": {
"sqldba": { "command": "sqldba-mcp" }
}
}
On Windows that file lives in %APPDATA%\Claude\. On macOS it is under ~/Library/Application Support/Claude/. For anything else that speaks MCP, the transport is stdio and the command is sqldba-mcp with no arguments. There is no API key and no account.


Checking It Actually Worked
Restart the client first. Then work through these, in order:
- Ask it something only the server can answer, such as “what is SQL Server error 3154?”
- Look for the tool call in the transcript, not just at the answer. A plausible answer with no tool call means the model answered from memory and the server is not connected.
- In Claude Code, run
/mcp. It lists what is registered and whether it started cleanly. - Then stop mentioning it. Once it is working you never name the server in a question. Ask about an error number or a wait type and the assistant reaches for it on its own.
Three Questions Worth Trying First
Once it is running, these three show you what it is for better than any description:
SELECT @@VERSION output and ask if you should patch



That third one matters more than it looks. Generated SQL never tells you whether it reads, writes or creates objects. Every script in this library carries that classification in its header, and the server passes it through, leading with a warning on the 14 of 232 that change something and staying quiet on the other 218. A warning on everything is a warning on nothing.
What to Consider Before You Install Any MCP Server
This applies to mine as much as anyone else’s, and it is the section I would want if I were reading this cold. An MCP server is a program that runs on your machine with your permissions, and your assistant will call it without asking you each time. That is convenient, and it is worth a few minutes of scrutiny first.
| Ask | What a good answer looks like | This server |
|---|---|---|
| What can it reach? | The first question, and usually the only one that really matters. A reference server should need no connection string, no credential and no route into production. One that manages infrastructure necessarily does, and deserves a much harder look. | Nothing. No driver, no network calls |
| How many tools does it register? | Every server competes for the model’s attention. Two servers with twenty tools each will degrade tool selection for everything, including the ones that were working fine. | Six, capped by a test |
| Does it cite anything? | A tool that returns an unattributed answer has moved the guess rather than removed it. You want a link or an identifier you can check independently. | A source URL on every answer |
| How old is its data, and does it admit it? | Any bundled dataset ages. The useful behaviour is a server that reports its own data age in the answer, so staleness is visible rather than something you have to remember to wonder about. | Reports its generation date and age |
| What does it do when it does not know? | Ask it something deliberately outside its scope in your first ten minutes. A server that returns the least-bad row it has is worse than no server, because the answer arrives with the authority of a lookup. | Says so, and points at the index |
| Does it declare itself read-only? | MCP lets a tool state that it is read-only and non-destructive, which is what allows a client to auto-approve it instead of prompting you six times for a reference lookup. A tool that does not declare it should be prompting you, and you should let it. | All six declare it |
| Can you read the source? | You are installing software. Check the licence, look at the dependency list, and see whether the data ships as something readable. | MIT, one dependency, plain JSON data |
| Where do corrections go? | If you find something wrong, is there a route to fix it at the source, or does the error just live there? A server nobody can correct decays quietly. | Issues on the public repo |
Keeping It Current
The data ages, and the build and lifecycle information ages fastest. The server reports its own data age, so if what it tells you is months old you will see that in the answer rather than having to wonder. Every answer now ends with the server version and the date its data was generated, so a stale install names itself.
Everything in it is generated from this blog and the script repo, so corrections happen in one place. If I fix an explanation in a post or a safety classification in a script header, the next release carries it. There is no second copy to drift, and a build check enforces that: the datasets are re-derived from the source files and compared byte for byte, so a hand-edited dataset fails the build and names the file.
That is the arrangement I would recommend to anyone building one of these. One source of truth, three ways to reach it.
A correction made at the source improves all three at once.
How Accurate Is the Retrieval
Very few MCP servers publish a number for this, and I think that is a gap rather than an oversight, so here is mine. Retrieval is scored against the real questions and errors published on this site, with each one reworded so the search cannot simply match text it already holds.
| Suite | n | Top 1 | Top 3 |
|---|---|---|---|
| FAQ, questions reworded | 492 | 95.1% | 99.4% |
| Errors, phrase reworded | 48 | 95.8% | 100% |
| FAQ, verbatim question | 492 | 98.8% | 99.8% |
| Errors, by number | 47 | 100% | 100% |
| Wait types, by name | 260 | 100% | 100% |
| Scripts, asked in a DBA’s own words | 44 | 56.8% | 95.5% |
Only the bold rows are retrieval measures. Searching with the verbatim question that is already in the index scores 98.8% and means nothing, it is string equality wearing a costume. The script row is bolded on recall rather than top 1 on purpose: find_script hands back eight scripts with their safety classes and you pick, so "is the one I meant in the list" is the question that matters and "did it guess first" is not. Its top 1 is 56.8% and it is printed here rather than left out. Even the bold numbers are an upper bound: rewording drops words but does not introduce new ones, so it is still easier than a genuinely different way of asking. Run it yourself with python tests/eval_faq.py.
Scored honestly, the search behind it was getting 29.8%: type incorrect syntax instead of Incorrect syntax near and you were told it was not in the library. That is fixed, and it now scores 95.8% first time.
A test that cannot fail is worse than no test, because it gets quoted.
What Those Numbers Cannot Tell You
Every suite in that table scores the same narrow thing. Take a record out of the corpus, reword it, check the search finds it again. That measures the ranker, and it cannot fail for a record that is missing, mislabelled, or simply wrong. I found out how large that gap is by using the server rather than testing it.
On 19 August I asked it nine ordinary questions, the kind I would actually type at work. Six exposed a defect. All 129 unit tests and every suite above were green throughout, because none of them can see the failures I hit.
- I asked whether SQL Server 2022 Standard has data compression. It does, and has since 2016 SP1. Two of my own posts said it was Enterprise only, and the server repeated that at rank 1 with a working citation.
- I asked for the default SQL Server ports. There is a published post that answers exactly that, and the server had no path to it, because the corpus is assembled from FAQ blocks and that post carries none.
- I asked about
LCK_M_RIn_NL, a wait type with its own published write-up, and was told it was not in the library.
The third is the worst of them. The refusal wording is written to be trusted, so a false refusal does not merely fail to help. It sends someone away from an answer that already exists.
A Second Suite, Asking From Outside
Those questions are now a permanent test file, and it grows every time somebody asks something real. It is the only suite here that can fail for the right reasons, and it proved that within an hour of being written. It caught check_build answering “windows server 2019” with SQL Server 2019 patch levels, a bug I had introduced in a fix made the same evening. A predictable URL, a plausible answer, and completely wrong.
What It Refuses, Measured
Declining to answer is the whole promise, so it deserves a number rather than a claim. Against 38 off-domain questions the server declines honestly 34 times. That is 89.5%, and I am publishing it because 89.5% is what it is. Eight of those 38 were written by someone who had not seen the test file, precisely because the number had stopped being a measurement: an earlier 86.7% was reported after tuning against the same probes it was scored on. Run cold, four of the eight fresh ones were answered confidently, and every one had matched on a single ordinary word – "better", "worth", "security". The coverage floor counted every term as worth the same, so an ordinary word carried a match as easily as PAGEIOLATCH would. Weighting it by how rare a term actually is fixed that.
Further back it was 73.3%, and that one moved for a different reason. In every one of the failures the answer it chose shared no word at all with the question asked, because the coverage floor is computed against the whole record and a pair can clear it on words buried in its answer text. Requiring one term in common between the question asked and the question answered fixed four of them, and fixed a real question at the same time: “my log file keeps growing what do I do” had started returning an answer about autogrowth events that shared nothing with it, while the transaction log answer sat two places below.
The eight it gets wrong share one shape: questions built from SQL Server vocabulary that ask something the library does not cover. “How much should a DBA be paid” is made of words this corpus knows. A guard that works on vocabulary cannot catch a question whose vocabulary is legitimate, so that number will not reach 100% by tuning a threshold. It needs a different mechanism, and I would rather say so than quietly stop counting.
Microsoft’s Page, Alongside Mine
Where Microsoft publishes a page for an error, the answer now cites that as well as the write-up here. 23 of the 48 have one.
None of those links are constructed at build time, even though the URL pattern is predictable. Predictable is exactly what makes it dangerous: a guessed link that 404s looks like provenance and is not. Every candidate was fetched once and kept only if it returned 200 and still named that error. That second condition earned itself immediately. Error 10054 returns 200 and redirects to a general TLS page, so a check that only looked at the status code would have shipped a citation that appeared correct and pointed somewhere else.
The Server Now Checks the Blog
The compression mistake was not a retrieval failure. It was a wrong sentence I had written, retrieved perfectly, and no retrieval test can ever catch that. So the same data now runs in the other direction.
A gate reads the published estate and looks for three things: claims that contradict each other across posts, features gated to an edition they left versions ago, and error severities that disagree with sys.messages on a real instance. All 45 published severities match the engine, checked against a real instance. Two of the 47 numbered errors carry no severity on purpose – 53 and 10054 are client and network layer, and are not in sys.messages at all. It also lists every post claiming something was verified or proven, because that is the strongest claim on this site and the only one anybody had checked turned out to be false.
It ships with a self test that replays the compression sentence and asserts the checks fail on it. A gate that goes green on its first run is precisely the one you should not trust, and this one went green on its first run, for the honest reason that the posts had been corrected an hour earlier.
What It Does Not Reach
The server is a structured reference layer. It indexes errors, wait types, builds, scripts and the questions answered inside posts. It is not a search engine for the whole site: full article bodies never cross into it, and the depth stays here. It does now carry a record for every one of the 495 published posts – title, opening line and URL – so it can tell you which article covers something even when it holds no quotable answer.
That was not true a week ago, and the way it failed is worth keeping. The index was built from the question-and-answer blocks inside posts, and at the time 319 of 488 carried none, so 74 were invisible: not ranked badly, absent. Asking for the default SQL Server ports returned an honest refusal even though the post exists and answers it exactly. I tried closing that by indexing every post title and excerpt as a fallback. It fixed the ports question and I reverted it, because no threshold separated a post that covers your question from a post that merely shares words with it: “what is the best sql server book” matched a Kerberos post more strongly than the ports question matched the ports post.
So the boundary stands, and I would rather state it than let you find it. If your question is an error number, a wait type, a build, a script, or something I have written a direct answer to, the server should have it. If it is a general “how does X work” question, the site has more than the server can see, and the search box is still the better door.
Common Questions
Do I need to be running Claude to use this?
No. MCP is an open protocol and this server has nothing Claude specific in it. Any client that speaks MCP over stdio will work. Claude Code and Claude Desktop are simply the two I have tested it against most.
Is an MCP server the same thing as a plugin?
Close enough to start with, and the difference matters later. A plugin is usually written for one application. An MCP server is written once against an open protocol, so the same server works in whatever client you move to next. That portability is most of the reason the standard exists.
Does it send my data anywhere?
No. It makes no network calls at all. The data ships inside the package, and your questions are answered locally by the server running on your own machine. Whatever your AI client does with the conversation is a separate question, and one worth asking of the client rather than of this server.
Can it run scripts against my instance for me?
No, and that is deliberate. It has no database driver and no connection string, so it cannot reach a server even if something asked it to. You run the scripts. It tells your assistant which one fits and what the output means.
How do I know whether the assistant actually used it?
Look for the tool call in the transcript, not just the answer. Every MCP client shows when a tool was invoked and what it returned. If you get a confident answer with no tool call, the model answered from memory, which is exactly the situation the server exists to replace. In Claude Code, /mcp shows which servers are registered and whether they started cleanly.
What happens when it does not know something?
It says so. It tells you the topic is not in the library rather than filling the gap, and it points you at the index so you can check for yourself. Of the 48 errors it carries, 43 have a full write-up to link to and 5 do not. Those 5 still return the message text, meaning and severity, and the answer says no article exists yet, so an assistant can quote them and knows it cannot cite them.
Will adding more MCP servers make my assistant better?
Up to a point, then it makes it worse. Every server adds tools, and every tool is another option the model has to choose between. Past a couple of dozen across all your servers, selection accuracy starts to slide and you get wrong-tool answers on questions that used to work. Add them one at a time, and remove the ones you stopped using.
Is it safe to install on a work machine?
It is a small Python package with one dependency, the MCP SDK. The source is public under the MIT licence and the datasets ship as plain readable JSON, so you or your security team can see exactly what is in it before installing. It opens no ports, stores nothing, and makes no outbound connections.
How do I get something corrected?
Open an issue on the repo. Corrections from working DBAs are the point of publishing it. The fix goes into the source, the post or the script header, not into the shipped data, so it lands on the blog and in the server at the same time.
Related Scripts
- Run a Full SQL Server Health Check, the workflow whose triage rubric this server ships as a prompt
- The DBA Scripts library, all 232 scripts the server can point you at
- SQL Server Error 18456, an example of the error write-ups behind the lookups
- PAGEIOLATCH_SH, an example of a wait type verdict
Summary
An MCP server is a small local program that hands your AI assistant a set of tools it can call, over an open protocol, so the same server works in whichever client you use. That is all it is. The reason to give an assistant one is not that it makes the model cleverer. It is that a verified answer with a link beats a confident guess, particularly for the things that change underneath you like patch levels and support dates, and for the things where being almost right is worse than being no help at all, like a script that writes data when you thought it only read.
Leave a Reply