cd /news/ai-agents/teaching-a-1999-vb6-app-to-talk-to-a… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-160481] src=sql-server-tool.com β†— pub= topic=ai-agents verified=true sentiment=↑ positive

Teaching a 1999 VB6 app to talk to AI agents

SQL Server Comparison Tool (SCT) version 6.0 shipped with a headless mode and a JSON output format that let Anthropic's Claude run schema and data comparisons and explain the results, according to the tool's developer. The 1999-era Visual Basic 6 application keeps its comparison engine nearly untouched, with a separate .NET Framework 4.8 console program, SctMcpServer.exe, speaking the Model Context Protocol over JSON-RPC and passing back versioned JSON envelopes (schema_version 1, sct_version "6.0.205") that separate errors from warnings. The developer converted every modal dialog on the comparison path into structured errors so background runs always terminate, and cross-checked the JSON against the existing text reports, which remain as a second output.

read7 min views9 publishedOct 29, 2026

SQL Server Comparison Tool (SCT) has been around since 1999. It compares SQL Server schemas and data, and it is still written in Visual Basic 6. It has always been a classic Windows program: you open it, click through some dialogs, and read a report.

This year I wanted to know whether an AI assistant could drive it. Not a chatbot that pretends to know your database, but Claude actually running a comparison and explaining the result. The answer turned out to be yes, and the result shipped in SCT version 6.0. Getting there meant solving a few problems that I suspect anyone with an old desktop app will run into, so here are my notes.

The plan: don't make VB6 speak a new protocol #

AI assistants connect to local tools through the Model Context Protocol (MCP): JSON-RPC messages over a program's standard input and output. Teaching a VB6 program to do that directly would have been painful. Instead I split the work in two:

  • VB6 side: make SCT run a comparison with no user interface and write the result as JSON.
  • C# side: a small separate program that speaks MCP, starts SCT in the background, and passes the JSON back.

That kept the 27-year-old comparison engine almost untouched. Everything new lives at the edges.

Step 1: make a GUI program run without a GUI #

A desktop program assumes someone is sitting in front of it. Every MsgBox is a question for that person. Run the same program in the background for an AI and each of those message boxes becomes a hang: the process waits forever for a click that never comes.

So the first job was a headless mode that always terminates:

  • A command-line parser, so a saved comparison can be started without opening any window.
  • Every modal dialog on the comparison path converted into a structured error that is collected and reported instead of shown.
  • A result collector that gathers errors and warnings as the comparison runs and writes them out at the end, whatever happens.

The interactive program behaves exactly as before. The headless path just routes the same events somewhere a machine can read them.

Step 2: output for a machine reader #

SCT already produced text reports, and the tempting shortcut was to hand those to the AI. I decided against it. A report written for people mixes layout with facts, and an AI reading it has to guess where one ends and the other begins. Structured data is unambiguous.

Every run now produces a JSON document with a versioned envelope:

{
  "schema_version": 1,
  "sct_version": "6.0.205",
  "comparison_id": 1,
  "comparison_name": "Sync check - Northwind vs Southwind",
  "started_utc": "2026-10-10T23:08:30Z",
  "finished_utc": "2026-10-10T23:09:57Z",
  "status": "success",
  "errors": [],
  "warnings": [],
  "results": { ... }
}

A few decisions that paid off:

  • A version number from day one, so the format can evolve without breaking whoever reads it.
  • Errors and warnings as separate arrays, so "the comparison ran but found a problem" is never confused with "the comparison failed".
  • The text report stays. JSON is a second output, not a replacement, so existing users and scripts see no change.
  • Cross-checking against the old reports. I instrumented every comparison scenario and compared the JSON with the text report for the same run. Where they disagreed, one of them was wrong, and that was the fastest way to find out which.

One more point on VB6: it has no built-in JSON writer, so the output is assembled by hand. The detail that matters is escaping. Database object names can contain quotes, brackets and backslashes, and one unescaped character produces a file no parser will accept.

Step 3: a small MCP server in C# #

The bridge, SctMcpServer.exe, is a .NET Framework 4.8 console program. I chose Framework 4.8 rather than modern .NET because it is preinstalled on every Windows 10 and 11 machine: nothing extra for customers to install. It has no third-party packages at all. For a local server with two tools, the protocol surface is small: answer the initialization handshake, list the tools, and handle tool calls.

The two tools are deliberately minimal:

  • list_saved_comparisons : what comparisons has the user saved in SCT?
  • run_comparison : run one of them and return the JSON result.
Claude Desktop  ->  SctMcpServer.exe  ->  sct.exe (headless)  ->  SQL Server
               JSON-RPC over stdio     writes JSON result

Once the first build worked, Claude could list my saved comparisons from a chat window. Then the comparisons themselves started failing.

The bug that only happened inside Claude Desktop #

From a command prompt, everything worked. Started by Claude Desktop, every comparison failed with:

ADO error 3706: Provider cannot be found. It may not be properly installed.

The provider was certainly installed; the same machine ran the same comparison seconds earlier. The difference turned out to be the environment. Claude Desktop starts MCP servers with a stripped-down set of environment variables: about 17, compared with about 60 in a normal interactive session.

One of the missing variables was %CommonProgramFiles%. The OLE DB provider SCT uses (SQLOLEDB) is registered with a path that relies on it. Without the variable, COM could not resolve where the provider lives, and ADO reported that it didn't exist.

The fix is a small block at the start of the MCP server that restores the standard Windows variables before it starts sct.exe. A simplified sketch of the idea:

// Simplified: restore standard Windows variables that the
// host process may not have passed on, before starting sct.exe
var psi = new ProcessStartInfo(sctExePath, args) { UseShellExecute = false };
SetIfMissing(psi, "CommonProgramFiles",
    Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles));
SetIfMissing(psi, "ProgramFiles",
    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles));
SetIfMissing(psi, "SystemRoot",
    Environment.GetFolderPath(Environment.SpecialFolder.Windows));
// ...and the other standard ones

static void SetIfMissing(ProcessStartInfo psi, string name, string value)
{
    if (string.IsNullOrEmpty(psi.EnvironmentVariables[name]))
        psi.EnvironmentVariables[name] = value;
}

The general lesson for anyone writing a local MCP server on Windows, especially one that touches COM, ADO or anything registry-driven: don't assume your process inherits a normal environment. Log the environment you actually received the first time something works in a terminal and fails under the AI host. It would have saved me a lot of guessing.

Designing for an AI that might misunderstand #

The part I spent the most time on wasn't code. An AI agent connected to production databases should make any DBA nervous, and it made me nervous too. So the design starts from what the AI must not be able to do, even if it misreads a request or is manipulated by text it reads somewhere:

The rules

  • No choosing servers. The AI can only run comparisons a person created and saved in SCT. It never supplies a server name or connection string, so it can't be talked into connecting somewhere else.
  • No credentials. Passwords are stored by SCT, encrypted with Windows DPAPI, and never appear in anything the MCP server returns.
  • No writes. Nothing in the integration changes a database. To apply differences, a person generates the update script in SCT, reviews it, and runs it.
  • No row data. Data comparisons report counts of differing and missing rows, never the row contents.

These limits also made the integration easier to explain to customers. "It can only do these two things" is a much shorter conversation than a list of safeguards around a powerful tool.

Shipping it #

The rest was ordinary release work: a code-signed build, log rotation so diagnostic logs can't grow forever, a configurable timeout for very large databases, and a setup guide. For users, connecting Claude Desktop comes down to one entry in its configuration file:

{
  "mcpServers": {
    "SQL Server Comparison Tool": {
      "command": "C:\\Program Files (x86)\\SQL Server Comparison Tool\\SctMcpServer.exe"
    }
  }
}

If you maintain an old desktop app #

  • Leave the core alone. Put a thin, modern layer in front of it instead of rewriting it.
  • Headless means it always exits. Find every place the program waits for a person, and turn it into an error.
  • Give the AI facts, not reports. Structured, versioned output is easier for a model to explain correctly.
  • Test under the real host. A server that works in a terminal may still fail when an AI app starts it.
  • Start with what the AI can't do. A small, safe surface is easier to build, to trust and to sell.

SCT is a VB6 program that predates most of the tools now talking to it, and it didn't need a rewrite to join them. That may be the most encouraging part of the whole project.

Try the AI Agent Integration on your own databases.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @sql server comparison tool 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/teaching-a-1999-vb6-…] indexed:0 read:7min 2026-10-29 Β· β€”