I wanted an agent to draft release notes for my wallpaper apps straight from GitHub issues. As an indie developer, that is the kind of chore I would happily hand off. So one evening I opened the GitHub MCP setup instructions, and everything in them was written for the IDE.
The CLI is not covered in GitHub's own install guide yet. There is an open request in the GitHub MCP Server repository asking for exactly that. If you are moving over from Gemini CLI, this is the point where it is easy to stall: you cannot tell where the config file belongs.
What I would like to say first is that most of the trouble comes down to the name of the key that holds the remote URL. Antigravity's MCP config requires serverUrl. The older url and httpUrl are not supported. The rest of this post fixes that one word and then walks through confirming the connection.
There are two config files
According to the official MCP documentation, the CLI reads from two places:
- Global:
~/.gemini/config/mcp_config.json - Workspace:
.agents/mcp_config.jsonin the project root
One caveat. The GitHub issue I mentioned lists the global path as ~/.gemini/antigravity-cli/mcp_config.json, which does not match the docs. I cannot say from here which one your install honors.
So before you trust either path, type /mcp at the CLI prompt. It opens the MCP manager, where each server shows a status ring. If the server you wrote never appears, the file is in the wrong place. If you would rather not touch the file at all, Adding MCP Servers Without Opening the Config File: The agy mcp Subcommand is the safer route.
Remote connection: serverUrl and headers
This is the config for GitHub's hosted MCP endpoint:
{
"mcpServers": {
"github": {
"serverUrl": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer YOUR_GITHUB_PAT"
}
}
}
}This solves one thing: reaching a remote MCP server while passing a token. The documented schema says each server needs either command (for stdio) or serverUrl (for remote). For a remote server you write serverUrl, plus headers if needed.
Why serverUrl and not url? Because the docs say so plainly: legacy fields like url and httpUrl are not supported. If you copied a Gemini CLI config, only the key name stops working.
Docker connection: run the server locally
If you would rather keep traffic on your own machine, use a stdio connection. This is the form proposed in the issue:
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PAT"
}
}
}
}I did not run the Docker version for this post. What I checked is that the issue's proposal matches the documented schema (command, args, env), nothing more.
| Aspect | Remote (serverUrl) | Local (Docker) |
|---|---|---|
| Required key | serverUrl | command |
| Prerequisite | Network access and a token | Docker running |
| Length of config | Short | Longer, so typos are easier |
| Good for | Seeing it work quickly | Keeping traffic local |
For a first connection, I would start with the short remote one.
Check the file before the CLI loads it
The config is plain JSON, so one stray comma can make the whole file unreadable. After editing, I run this script before launching anything:
#!/usr/bin/env python3
"""mcp_check.py — catch config shapes that cannot connect, before loading."""
import json, sys, pathlib
LEGACY = {"url": "serverUrl", "httpUrl": "serverUrl"}
def check(path):
problems = []
try:
cfg = json.loads(pathlib.Path(path).read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as e:
return [f"{path}: not valid JSON ({e})"]
servers = cfg.get("mcpServers")
if not isinstance(servers, dict):
return [f"{path}: no mcpServers object"]
for name, spec in servers.items():
if spec.get("disabled"):
continue
for old, new in LEGACY.items():
if old in spec:
problems.append(f"{name}: '{old}' is not supported; use '{new}'")
if "command" not in spec and "serverUrl" not in spec:
problems.append(f"{name}: needs either command or serverUrl")
auth = spec.get("headers", {}).get("Authorization", "")
if "YOUR_" in auth:
problems.append(f"{name}: Authorization is still a placeholder")
return problems
if __name__ == "__main__":
bad = 0
for p in sys.argv[1:]:
issues = check(p)
print(("NG " if issues else "OK ") + p)
for i in issues:
print(" - " + i)
bad += bool(issues)
sys.exit(1 if bad else 0)I ran it against three files: a config copied in the old shape, one fixed to serverUrl, and one with a trailing comma. Here is the output (message text translated from the Japanese original):
NG before.json
- github: 'url' is not supported; use 'serverUrl'
- github: needs either command or serverUrl
- github: Authorization is still a placeholder
OK after.json
NG broken.json
- broken.json: not valid JSON (Expecting property name enclosed in double quotes: line 1 column 78 (char 77))With the old shape you do not only get the url warning. You also get "no command or serverUrl", because from the agent's side there is no destination written at all. That second line is, I think, what hides behind a vague "it won't connect" on screen.
Where the token lives, and what to allow first
Writing a token into headers has one trap. The workspace file, .agents/mcp_config.json, sits inside your project, so an accidental commit takes the key with it.
My own line is this:
- Keep configs that contain tokens in the global file, outside any repository
- Keep only key-free stdio servers in the workspace file
- Use a fine-grained token with only the scopes you need, and start read-only
On permissions, the docs say MCP tools you have not configured run in Ask mode, so you are prompted before each execution. You can allow things per server, like mcp(github/*), or per tool, like mcp(github/tool-name). I like to allow nothing at first and open up only what I actually see in the approval prompts. I wrote about narrowing the list in Scope the MCP Tools You Hand an Agent: A Least-Privilege Allowlist Design.
When it still does not connect
| Symptom | Look here first |
|---|---|
github missing from /mcp | File location (global vs workspace) and JSON syntax |
| Listed but cannot connect | A leftover url or httpUrl |
| Connected but tools do not run | The approval prompt (Ask mode) and the token's scopes |
| Red squiggles in the editor | The editor's schema check may be ahead of the CLI; see the red-squiggle post |
If the file itself seems suspect, the pre-launch validator article is where this script's idea came from.
What to do next
Create one read-only token, write the remote config above, and run it through mcp_check.py. Once /mcp shows github as connected, ask for one small thing, such as listing the issues in your own repository.
Keep the key on your side, and check the file before you load it. I try to hold to that order every time I add a server.