DEV Community

Vektor Memory
Vektor Memory

Posted on

Vek-sync: One Config File to Rule Them All

Open Source · MCP · Architecture · 12 min read

It started with a missing comma.

We had just added a new tool to our MCP server stack and needed to push the update across our editors. Claude Desktop first, then Cursor, then Windsurf. Three editors, three config files, each with their own format quirks. We were moving fast, copy-pasting JSON blocks between files, and somewhere in the Windsurf config we dropped a comma between two properties. The file broke silently. No error message. No warning. The MCP server just stopped loading, and the AI had no tools and no explanation as to why.

We found the bug twenty minutes later. Fixed it, moved on. Then two weeks after that, we rotated an API key and had to do the whole thing again. Five files this time. Claude Desktop, Cursor, Windsurf, VS Code, Claude Code. Each one formatted differently. Each one with its own location buried somewhere in a different system path. Each one perfectly capable of failing without telling you anything useful.

After the third or fourth time this happened, we stopped and asked an honest question: why does this problem exist?

The Model Context Protocol was designed to unify AI tooling. The whole premise is that any MCP-compatible editor can connect to any MCP server through a standard interface. And that promise largely holds on the server side. But on the configuration side, the ecosystem had quietly fragmented into a mess of incompatible JSON formats, inconsistent key names, and editor-specific quirks that developers had to memorize or rediscover every single time they set up a new machine or added a new tool.

Claude Desktop uses mcpServers. VS Code uses servers. Windsurf uses mcpServers at the top level but insists on calling SSE endpoints serverUrl instead of url. Cursor supports both global and project-level configs. Claude Code shares the Claude Desktop format but lives in a completely different hidden directory. Continue stores servers as an array instead of an object. Codex uses TOML. Cline and Roo Code bury their configs inside VS Code extension storage paths most people have never seen. None of them talk to each other. None of them know what the others have. The moment you add a server to one editor, every other editor falls behind, and there is no automated way to tell.

The deeper problem is structural. Every mature part of the developer stack solved this problem years ago. Git has .gitignore. Docker has docker-compose.yml. Node has package.json. These files exist because the ecosystem recognized that distributed configuration without a source of truth is a maintenance nightmare. MCP arrived without one, and developers are paying the price every time they switch editors or rotate a credential or onboard a new machine.

We built vek-sync because we got tired of paying that price ourselves. We were building Vektor Slipstream, a 42-tool MCP server for persistent agent memory, and every release cycle involved manually touching five config files in five different formats. Getting any one of them wrong meant an agent with no tools and no way to know why. So we stopped and built the infrastructure layer that should have shipped with the protocol.


The Concept

One .mcp.json file holds your server definitions. Three commands handle everything else.

vek-sync export # pull from all editors into .mcp.json
vek-syn

c diff # show what has drifted
vek-sync sync # push .mcp.json to all editors
Eleven editors. One source of truth. No account, no cloud, no dependencies.


How It Works

The first thing we learned building the connectors is that reading and writing JSON is the easy part. The hard part is doing it without breaking anything the editor already has.

Every editor config file contains more than just MCP server definitions. Claude Desktop has a user preferences block that controls sidebar behavior and scheduled tasks. Cursor stores internal project settings alongside the server list. VS Code mixes workspace configuration with the MCP entries. A naive approach that reads the server list and writes it back would silently wipe all of that context. Users would lose settings they had carefully configured and have no idea why.

Every connector in vek-sync solves this with a strict merge pattern. We read the entire existing file first, extract only the MCP server block, merge in the incoming changes, and write the whole thing back with everything else untouched.

javascript
let existing = JSON.parse(readFileSync(cfgPath));
const updated = {
...existing,
mcpServers: { ...existing.mcpServers, ...incoming }
};
writeFileSync(cfgPath, JSON.stringify(updated, null, 2));

Incoming servers win on conflict. Everything else survives unchanged. This means you can run vek-sync sync on a machine that already has a partially configured editor and trust that the sync will add what is missing without destroying what is already working.

Before any write, vek-sync backs up the target config to ~/.mcp-sync/backups//. This is silent and automatic. If something goes wrong, your original file is always recoverable.

The format translation layer sits inside each connector individually. The Windsurf connector converts url to serverUrl on the way in and reverses the translation on the way out. The VS Code connector handles the fact that the top-level key is servers instead of mcpServers. The Continue connector converts between the object format vek-sync uses internally and the array format Continue expects. The Codex connector parses and writes TOML using a minimal zero-dependency parser we wrote specifically for this. Each connector is self-contained and ships no shared runtime dependencies, which means you can read any one of them in isolation and understand exactly what it does.

The Eleven Editors

EditorConfig formatNotesClaude DesktopJSON mcpServersWindows / macOS / LinuxCursorJSON mcpServersGlobal scopeVS CodeJSON serversWorkspace-scopedWindsurfJSON mcpServers + serverUrl quirk-Claude CodeJSON mcpServersShares Claude Desktop formatClineJSON mcpServersVS Code extension storageRoo CodeJSON mcpServersVS Code extension storageGemini CLIJSON mcpServers~/.gemini/settings.jsonGitHub CopilotJSON mcpServers~/.copilot/mcp-config.jsonContinueJSON arrayAuto-converted bidirectionallyCodexTOMLAuto-converted bidirectionally


The Vault

The moment we had sync working, the next problem became obvious. Config files contain secrets. API keys, licence keys, authentication tokens. The whole point of .mcp.json is that you define your servers once and potentially commit the file to version control. But committing secrets to a repository is how credentials end up on breach notification services.

We built a local encrypted vault into vek-sync to solve this cleanly. It uses AES-256-GCM encryption, derives its key from your machine's hostname and a locally stored random salt, and stores everything in ~/.mcp-sync/vault.json. No cloud. No account. Nothing leaves your machine.

The workflow is straightforward. You store a secret once:

vek-sync vault set my-api-key sk-abc123
Then reference it in .mcp.json using a vault prefix:
json
"env": { "API_KEY": "vault:my-api-key" }

At sync time, the tool walks the server configuration and replaces every vault reference with the decrypted value before writing to any editor. The editor gets the real working key. The .mcp.json you commit to Git contains only the reference string, which is useless without the local vault.
The machine-binding is intentional. The encryption key is derived from your hostname combined with a salt that only exists on your local drive. Secrets encrypted on your desktop cannot be decrypted on your laptop. This makes the vault unsuitable as a backup mechanism, but that is fine because backup is not what it is for. It is a secrets-at-rest layer for your local workflow, and in that role it works exactly as needed.


The Diff Problem

The diff command is where most of the interesting engineering lives. The goal is to compare what is in .mcp.json against what each editor actually has configured, and report any meaningful differences. Simple in theory. Surprisingly subtle in practice.
The naive approach is to stringify both sides and compare the strings. This breaks immediately for several reasons. First, editors inject extra fields during normal operation. Second, vault references in .mcp.json never match the resolved plain-text values in the editor configs. Third, key ordering in JSON objects varies between editors and can change between writes.

The solution is canonical comparison. Instead of comparing the raw objects, we extract only the fields that actually determine behavior and compare those.

javascript
const CANONICAL = ['command', 'args', 'url', 'headers'];
function canonical(cfg) {
const out = {};
for (const k of CANONICAL) {
if (cfg[k] !== undefined) out[k] = cfg[k];
}
out.__envKeys = Object.keys(cfg.env ?? {}).sort().join(',');
return JSON.stringify(out);
}

We compare command, args, url, and headers directly. For environment variables, we compare only the key names in sorted order, not the values. A vault reference on one side and a resolved plain-text value on the other both produce the same canonical signature as long as the variable names match. This means diff tells you about genuine structural differences rather than noise from how different connectors represent the same underlying configuration.

The diff command exits non-zero when it detects drift, which makes it composable with CI pipelines:

yaml

  • name: Check MCP config drift run: vek-sync diff

For teams running shared agent infrastructure, this is the difference between hoping that everyone's configs are aligned and actually verifying it on every commit.
The sync command also supports --dry-run, which runs the same diff logic but presents the output inline without writing anything:

vek-sync sync --dry-run
This is the safest way to preview what a sync will actually do before committing to it.


Beyond the Core Three

Version 0.3.0 ships a set of commands that go past the basic sync loop. Each one addresses something that came up repeatedly while using the tool in our own workflow.
vek-sync add - Interactive Server Wizard
Finding and configuring an MCP server by hand means looking up the package name, remembering the right args format, knowing which env keys it needs, and storing those in the vault. The add command collapses that into a prompt:

vek-sync add
vek-sync add github # search first, then prompt
It searches the curated registry, asks for transport type, command, args, and env vars, stores any secrets in the vault automatically, and writes the entry to .mcp.json. Then you run sync.
vek-sync ping - Health Check

Adding a server to config and having it actually respond are two different things. ping spawns each configured stdio server, sends a real MCP initialize handshake with proper Content-Length framing, and checks for a valid JSON-RPC response. HTTP servers get a GET request with an abort-controlled timeout.

vek-sync ping
Output is immediate and unambiguous: green check with response time, or red cross with the actual error.
vek-sync search - Registry Lookup
bash
vek-sync search postgres
vek-sync search slack

Searches the curated registry of well-known MCP servers and falls back to npm's registry for anything not on the list. At the end it offers to add a result directly to your .mcp.json, so the whole flow from discovery to configured is one command.

vek-sync share - Config Sharing
bash
vek-sync share

Strips vault references, uploads the sanitized config to paste.rs, and returns a URL. Your teammate runs:

vek-sync init --from-url
No sensitive data leaves your machine. The vault refs in the shared file are vault: - the recipient sets their own secrets.
vek-sync profile - Named Server Sets
Different projects need different servers. A client engagement might need specific database and communication tools. Your personal projects might run a different stack entirely. Profiles let you save named snapshots and switch between them:

vek-sync profile save work
vek-sync profile use personal
vek-sync profile list
Switching a profile updates .mcp.json. Running sync after pushes the new set to all editors.
--watch Mode

vek-sync sync --watch
Runs fs.watch on .mcp.json with a 200ms debounce. Every time you save the file - from any editor, any tool - it automatically syncs to all connected editors. For workflows where you are iterating quickly on your server configuration, this eliminates the manual sync step entirely.
--from Bootstrapping

vek-sync init --from cursor
Pulls whatever Cursor currently has configured and writes it into a fresh .mcp.json. The fastest way to bootstrap the file on a machine that already has editors set up. Works with any of the eleven supported connectors.


The VS Code Scoping Question
VS Code handles MCP configuration differently from every other editor in the support matrix, and it is worth explaining clearly because it trips people up.

VS Code MCP servers are workspace-scoped. There is no global config file. Servers live in .vscode/mcp.json inside your project directory. This means running vek-sync sync from your home directory has no effect on VS Code at all. You need to run it from inside a project for it to write anything useful.

We considered adding detection logic that would warn users when they run sync outside a VS Code workspace. We decided against it because the scoping is actually a feature. VS Code's model acknowledges that different projects need different MCP servers, and vek-sync respects that. Run the sync command from inside the project where you want the servers, and everything works as expected.


The Vektor Connection

Everything described above solves a general problem. Any MCP user with more than one editor benefits from a single source of truth for their server configuration. But there is a specific scenario where config drift causes damage that goes beyond missing tools and wasted time.
That scenario is persistent agent memory.

Vektor Slipstream is a 42-tool MCP server that gives AI editors access to a persistent memory layer. When Claude stores something in Vektor, it is available the next session, the next week, and across every editor that has access to the same server. Recall, graph traversal, automated briefings, pattern recognition across long timelines. The entire value proposition depends on every editor in your workflow pointing at the same running instance.

Config drift breaks this in ways that are genuinely hard to debug. An agent in Cursor with no Vektor connection has no access to what Claude Desktop stored yesterday. An agent in Windsurf pointing at a stale binary path has no tools at all and no error message explaining why. You end up in a situation where some editors have memory and others do not, and the inconsistency produces agent behavior that is confusing and difficult to reproduce.

vek-sync makes this a one-time configuration problem rather than a recurring maintenance task.

npm install -g vektor-slipstream
vektor activate YOUR-LICENCE-KEY

vek-sync vault set vektor-licence-key YOUR-LICENCE-KEY
vek-sync export
vek-sync sync

Four commands. Every editor on your machine now runs the same Vektor instance with the same configuration. When you update Vektor, you update one path in .mcp.json and run sync again. The licence key stays in the vault and never touches a config file that could be committed or shared.
The result is that memory becomes genuinely portable across your entire workflow. Claude can recall an architectural conversation you had in Cursor three days ago. Windsurf can pick up business context that Claude Code stored last week. The memory graph is consistent because the server is consistent, and the server is consistent because the configuration has a single authoritative source.


What Comes Next

vek-sync is open source, Apache 2.0 licensed, and requires no account to use. Zero production dependencies - pure Node.js ESM. The vault works completely standalone. You do not need Vektor to benefit from encrypted local secret storage and synchronized editor configs.
The roadmap for the next release focuses on two areas: additional vault backends and team workflows. Local machine-bound encryption is the right default, but teams sometimes need shared secret access. We are working on 1Password CLI integration and macOS Keychain / Windows Credential Manager as vault backends, so secrets can be stored in infrastructure that teams already manage.

On the editor side, Zed is next on the connector list. After that we are watching the Windsurf and Gemini ecosystems closely as both are moving quickly on their MCP implementations.
For the format itself, vek-sync validate - a command that checks .mcp.json against the spec and reports structural issues before you sync - is something we use internally and will ship as a first-class command in the next version.

If you are running Vektor, vek-sync is the piece that makes your memory server genuinely omnipresent. If you are not running Vektor yet, the sync tool will still save you a meaningful amount of configuration overhead every time you add or update an MCP server.
And when you are ready to give your agents memory that persists across sessions, editors, and restarts, Vektor is one install away.

npm install -g @vektormemory/vek-sync
npm install -g vektor-slipstream


GitHub: github.com/Vektor-Memory/vek-sync
npm: @vektormemory/vek-sync
Vektor Memory: vektormemory.com

Top comments (2)

Collapse
 
mads_hansen_27b33ebfee4c9 profile image
Mads Hansen

This nails a very unglamorous MCP problem: the protocol standardizes the server interface, but the operator experience still fragments at the config layer.

The silent-failure part is the scary bit. An MCP server disappearing because one editor config has a missing comma is not just annoying — it changes what the agent can and cannot do, often without the user understanding why the behavior changed.

A few things I like in this design:

  • diff as a first-class command, not an afterthought
  • merge instead of overwrite
  • editor-specific translation isolated per connector
  • a local vault instead of pretending config files do not contain secrets
  • one source of truth that can be reviewed like infrastructure

This feels similar to what happened with Docker Compose and package lockfiles: the boring config layer becomes infrastructure once teams depend on it.

For MCP adoption, reliability will come as much from these operational guardrails as from better tools themselves.

Collapse
 
vektor_memory_43f51a32376 profile image
Vektor Memory

Appreciated, we updated to 3.0 with more connectors and a few extra functions.