MCP · DXT · Windows · AI Tooling

Into the
labyrinth:
building a
34-tool MCP
server

We set out to build a memory layer for AI agents. We ended up debugging Groq's app before they did. This is Part 1 — the quest begins, the dragons emerge, and Windows does what Windows does.

8 MIN READ PART 1 OF 3 MCP · DXT · WINDOWS · NODE.JS
// THREE_PART_SERIES
PART 01 Into the Labyrinth — MCP, DXT, and the Windows dragon
THE_BEGINNING

It started with
a simple idea.
Nothing is ever simple.

The idea was straightforward: build persistent memory for AI agents using local SQLite. No cloud. No subscriptions. No vendor lock-in. A graph database that lives on your machine and gives every AI app a brain that actually remembers things between sessions.

What we didn't anticipate was the labyrinth between "working Node.js package" and "seamlessly installed across six different AI apps on Windows." That journey involved Windows path hell, a Node ABI mismatch, a PowerShell popup dragon, and ultimately fixing a bug in Groq's own desktop app before their engineers did.

"Anyone who tells you cross-platform AI tooling is easy has never tried to ship a native Node binary across nvm versions on Windows."

This is that story. Three parts. Real code, real errors, real blood on the floor. And at the end — a 34-tool MCP server that configures itself across Claude Desktop, Cursor, Windsurf, VS Code, Continue, and Groq Desktop in 60 seconds.

UNDERSTANDING_THE_TERRAIN

What MCP actually is
(and why DXT changes everything)

The Model Context Protocol is Anthropic's open standard for connecting AI models to external tools. Think of it as a universal adapter: instead of every AI app needing a custom integration for every tool, MCP defines one protocol that any app can speak and any tool can implement.

An MCP server is a process that runs locally on your machine and exposes a set of tools via JSON-RPC over stdio. When Claude Desktop starts, it reads a config file, spawns your MCP server as a child process, discovers its tools, and makes them available in every conversation. The AI can then call those tools — and your server executes real code in response.

claude_desktop_config.json
// The config that wires everything together { "mcpServers": { "vektor-slipstream": { "command": "node", "args": ["/path/to/vektor.mjs", "mcp"], "env": { "VEKTOR_LICENCE_KEY": "your-key-here" } } } }

That's the basic pattern. Claude Desktop reads this, spawns node /path/to/vektor.mjs mcp, and your server sits waiting on stdin for tool calls. Clean, simple, powerful.

Enter DXT

DXT — Desktop Extension — is Anthropic's packaging format for MCP servers. A .dxt file is a small manifest that tells Claude Desktop everything it needs to know: where to find the server, what environment variables to ask the user for, what the tool descriptions are. Drag it onto Claude Desktop's Extensions page and it configures everything automatically.

Before DXT, every user had to manually edit a JSON config file. On Windows, this was a minefield — one wrong character, one BOM (Byte Order Mark) injected by Notepad, and the entire MCP connection silently fails. DXT eliminates that entirely. One drag-and-drop, done.

WITHOUT DXT
Manual JSON editing per app
BOM corruption risk on Windows
Hardcoded paths that break on update
Different format for each app
No guided licence key entry
WITH DXT
Drag-and-drop installation
No file editing required
Dynamic path resolution
Guided UI for configuration
Auto-restarts on update
THE_FIRST_DRAGON

Windows path hell
and the .ps1 popup dragon

The first major obstacle wasn't the code — it was Windows itself. Node Version Manager on Windows (nvm4w) installs Node binaries in a non-standard location. When npm installs global packages, they land somewhere like C:\nvm4w\nodejs2\nodejs\node_modules\. When your DXT config says "command": "node", Windows has to find that binary — and depending on PATH configuration, it sometimes doesn't.

The fix was obvious in hindsight: use process.execPath instead of the string "node". This gives you the absolute path to the exact Node binary that's currently running — no PATH lookup, no ambiguity.

vektor-setup-wizard.js
// WRONG — relies on PATH resolution const serverEntry = { command: 'node', args: [vektorMjs, 'mcp'] } // RIGHT — absolute path, always works const serverEntry = { command: process.execPath, // e.g. C:\nvm4w\nodejs2\nodejs\node.exe args: [vektorMjs, 'mcp'] }

The popup dragon

Then came the popup dragon. Every time any npm-installed binary ran on Windows, a PowerShell console window would flash open and close. Open an app, popup. Run a command, popup. It was everywhere, suddenly, on every tool.

The cause: npm on Windows creates three shim files for every package — a .cmd file, a no-extension file, and a .ps1 PowerShell file. Something had changed in our environment that made Windows prefer the .ps1 shim — and PowerShell shims always spawn a visible console window.

The nuclear option: delete every .ps1 shim in the Node bin directory. The .cmd shims do exactly the same job. Nothing breaks. The popups vanish permanently.

PowerShell — nuclear option
# Delete all .ps1 shims — .cmd takes over, no more popups Get-ChildItem "C:\nvm4w\nodejs2\nodejs" -Filter "*.ps1" | Remove-Item -Force Get-ChildItem "C:\Users\minimaxa\AppData\Local\nvm\v24.1.0\node_modules\.bin" ` -Filter "*.ps1" -Recurse | Remove-Item -Force

Two commands. Dragon slain. Zero popups from that point forward — across every app, every tool, every install.

THE_SECOND_DRAGON

The better-sqlite3
ABI nightmare

VEKTOR's memory engine uses better-sqlite3 — a native Node addon that compiles to a .node binary. Native addons are compiled against a specific Node ABI version. If your MCP server runs on a different Node version than the one that compiled the binary, you get a cryptic error and a dead server.

The deeper problem: better-sqlite3 inside our obfuscated core module uses the bindings package to locate its compiled binary. bindings resolves the binary relative to the current working directory — not the package directory. So when Claude Desktop spawned the MCP server from C:\Users\minimaxa\, it looked for the binary relative to the home folder and found nothing.

3
Node ABI
versions involved
v24
Node version
that finally worked
1
Line fix:
process.chdir()

The fix: a process.chdir() call before loading the core module, setting the working directory to the package folder where better-sqlite3 lives. One line. Hours of debugging to find it.

This is what nobody writes about. The real work of shipping developer tools isn't the algorithms or the architecture — it's the 47 environmental assumptions that silently fail on someone else's machine. Every one of those assumptions is a dragon in the labyrinth.

THE_SOLUTION_EMERGES

The setup wizard:
one command,
six apps, 60 seconds

After solving the path problems, the ABI issues, and the popup dragon, we had a working MCP server. But customers still had to manually configure each app. Different apps use different config file locations, different JSON formats, different root keys (mcpServers vs servers). It was a documentation nightmare.

So we built a setup wizard. Run vektor setup and it scans for installed AI apps, shows you what it found, asks for confirmation per app, and writes the correct config for each one automatically. It backs up existing configs before touching them. It validates JSON before and after writing. It uses process.execPath so the paths are always correct.

Terminal output — vektor setup
// Step 6 output ✓ Claude Desktop — found ✓ Cursor — found ✓ Windsurf — found ✓ VS Code — found ✓ Continue — found ✓ Groq Desktop — found Configure Claude Desktop? [y/N]: y ✓ Claude Desktop configured ✓ Profile: full (34 tools) Configure Cursor? [y/N]: y ✓ Cursor configured ✓ Profile: dev (15 tools — optimised for 40-tool limit)

Each app gets the right config format. Cursor gets a warning about its 40-tool limit and a dev-optimised profile. VS Code gets servers as the root key instead of mcpServers. Continue gets a YAML-format drop file. All handled automatically, transparently, without the user needing to know any of it.

"The best developer experience is the one where the developer never has to think about the infrastructure at all."

COMING_NEXT

Part 2:
the boss battle

We had six apps configured. Then we tested Groq Desktop — and every single tool call failed with a JSON schema error. The trail led directly into Groq Desktop's source code, to a comment that said "Removed additionalProperties to be less strict."

We found the bug, fixed it, rebuilt their app, and sent them the bug report. All before they knew it existed.

→ READ PART 2: THE BOSS BATTLE