The most tedious part of moving to a new work machine was carrying over my MCP servers.
Open the old config file, copy each server definition across, mistype an environment variable name, drop a closing brace, and only discover it when the tool list comes up empty. As an indie developer moving between app work and web work, that chore came back every single time I changed hardware.
Antigravity CLI 1.1.16, released on August 20, turns that chore into a command. A new mcp subcommand gives you add, remove, list, enable, and disable for the user-level mcp_config.json, and a --type flag that covers both stdio and HTTP servers.
I read this less as a feature and more as a change that removes places where my hand can slip. Here is how it went when I rebuilt my setup with it.
What I was redoing by hand every time
When I list the ways the migration used to break, the failures fall into clear categories.
| Failure | When you notice | Via the subcommand |
|---|---|---|
| Trailing comma or missing brace | After launch, every server is gone | You never write JSON at all |
args written as a string, not an array | After launch, that one server fails | Built from the argument list |
| Misspelled server name | When a tool call fails | list confirms it right away |
| Typo in an environment variable key | Surfaces as an auth error | --env keeps the shape consistent |
| Wrong spelling of the URL key for HTTP | The handshake never returns | --type fixes the schema |
The behavior where one malformed entry took every other server down with it improved in CLI 1.1.14 on August 18. Invalid entries are now logged, skipped, and the rest load normally. That said, if the file as a whole is not parseable JSON, everything still fails on any version. If the parser cannot read the file, it has no way to decide which single entry to discard.
I covered the "catch it before launch" side of this in Why none of your MCP servers start, and the 40 lines that tell you which entry broke. This piece is one step earlier: not writing the file by hand in the first place.
Adding a stdio server in one command
Start with the shape you will use most — a server that runs as a local process over stdio.
# Name, transport type, then the launch command
agy mcp add filesystem \
--type stdio \
-- npx -y @modelcontextprotocol/server-filesystem /Users/me/projectsEverything after -- becomes the launch command and its arguments. Because that part is parsed as a list, you cannot accidentally write a single argument as a bare string.
Servers that need credentials take --env:
agy mcp add github \
--type stdio \
--env GITHUB_TOKEN=YOUR_TOKEN_HERE \
-- npx -y @modelcontextprotocol/server-githubThen confirm the result on the spot:
agy mcp listIf the name and transport look right in that output, you never need to open the file. I have made list a reflex that follows every add. Reading back what you just wrote is ordinary discipline; the real gain is being able to do it without opening an editor.
HTTP servers differ only in how headers are passed
For a server running remotely, use --type http and pass authentication with --header.
agy mcp add my-remote-tools \
--type http \
--header "Authorization: Bearer YOUR_API_KEY" \
https://mcp.example.com/mcpAlways include the scheme in the URL. A config that says example.com/mcp will not reveal its problem until the handshake fails. Declaring the transport explicitly makes that class of mistake easier to catch.
Keep in mind that whatever you pass to --header is written into the config file. If you would rather not store a token in plain text, let the shell expand it at runtime so the literal value stays out of your backups and shell history.
agy mcp add my-remote-tools \
--type http \
--header "Authorization: Bearer ${MY_MCP_TOKEN}" \
https://mcp.example.com/mcpUse disable, not remove, when you are isolating a problem
The quietly useful one turned out to be disable.
When a server misbehaved, I used to cut its block out of the config file, park it somewhere, and paste it back after testing. Lose track of where you parked it and the definition is simply gone.
agy mcp disable heavy-indexer # keep the definition, drop it from loading
agy mcp list # check the state
agy mcp enable heavy-indexer # put it backDropping servers one at a time to watch how the symptom changes no longer risks losing a definition. Reserve agy mcp remove <name> for the ones you are genuinely done with.
One side effect I did not expect: when startup felt slow, my instinct had always been to suspect the server I added most recently. Once toggling became cheap, I started suspecting the heaviest server instead — and that was usually the right guess.
Script the setup so it travels
Now that every step is a command, the setup itself can travel as a shell script. Mine looks roughly like this.
#!/usr/bin/env bash
# mcp-bootstrap.sh — reproduce the MCP setup on a fresh machine
set -euo pipefail
: "${GITHUB_TOKEN:?Set GITHUB_TOKEN before running}"
# Make the script safe to re-run
safe_add() {
local name="$1"; shift
agy mcp remove "$name" >/dev/null 2>&1 || true
agy mcp add "$name" "$@"
}
safe_add filesystem --type stdio \
-- npx -y @modelcontextprotocol/server-filesystem "$HOME/projects"
safe_add github --type stdio \
--env "GITHUB_TOKEN=${GITHUB_TOKEN}" \
-- npx -y @modelcontextprotocol/server-github
agy mcp listsafe_add exists so that running the script twice produces the same result as running it once. Interrupting a migration halfway and starting over is a normal thing to happen.
Secrets stay out of the file and arrive through the environment. The : guard at the top stops the script before it leaves a half-built setup behind. I used the same pattern in Using GEMINI_API_KEY direct auth in Antigravity CLI 1.1.13 where sign-in is not possible.
What the subcommand does not solve
A few boundaries are worth knowing before you lean on this.
First, the mcp subcommand manages the user-level config. If you keep a per-repository .antigravity/mcp_config.json, that file is still managed separately. Shared, team-wide servers belong in the repository; machine-specific ones belong at the user level.
Second, the config file has not gone away. The command changed the entry point, not the destination. Keep it in your backups.
Third, 1.1.16 also fixed something adjacent that is easy to miss: an unparseable settings.json used to be overwritten with defaults, silently resetting everything the next time anything was saved. Now a rejected save leaves the file byte-for-byte intact. The longer an environment has been in use, the more that fix is worth. Before you upgrade, make a copy of both files.
What to do next
Run agy mcp list once and look at what is actually registered on your machine right now. If the list is longer than you expected, or contains names you cannot place, that is where to start pruning. Transcribe the survivors into an mcp-bootstrap.sh and your next machine migration becomes a single command.
I am still refining how I carry this setup around, but simply not transcribing JSON by hand has made rebuilding an environment feel much less daunting. Thanks for reading.