Skip to content

Add antigravity MCP install target - #265

Open
robertjamesprior wants to merge 5 commits into
mainfrom
hypeship/add-antigravity-mcp-target
Open

robertjamesprior wants to merge 5 commits into
mainfrom
hypeship/add-antigravity-mcp-target

Conversation

@robertjamesprior

@robertjamesprior robertjamesprior commented Sep 20, 2026

Copy link
Copy Markdown

Summary

Adds kernel mcp install --target antigravity, so Antigravity users don't have to hand-edit JSON to reach the Kernel MCP server.

Written output:

{
  "mcpServers": {
    "kernel": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.onkernel.com/mcp",
        "--static-oauth-client-metadata",
        "{\"client_name\":\"Antigravity\"}"
      ]
    }
  }
}

--static-oauth-client-metadata names the OAuth client. Without it mcp-remote registers as MCP CLI Proxy, and the consent screen asks the user to trust that name rather than Antigravity.

Config goes to ~/.gemini/config/mcp_config.json, home-relative on every platform, so no per-OS branch is needed.

Why stdio rather than a remote server

Antigravity does support remote servers, keyed off serverUrl — it ignores url and httpUrl, so none of the existing HTTP target shapes work for it. But its remote-server client can complete the OAuth flow and still send initialize without the bearer token, which comes back as 401 Unauthorized (antigravity-cli#25, open since May). A serverUrl entry fails on first contact.

So this writes the npx mcp-remote stdio entry instead, matching claude, windsurf, goose and zed — half the existing targets, and the shape we already use for every client whose native remote path doesn't work. mcp-remote runs the OAuth flow itself, so the token never depends on Antigravity's client.

The server side is healthy either way: unauthenticated initialize returns 401 with a spec-correct WWW-Authenticate naming the protected-resource metadata, that metadata resolves, and dynamic registration returns 200. The failure is entirely client-side.

Reinstall behavior

installForAntigravity merges into any existing mcpServers.kernel object rather than replacing it, so hand-added fields survive. It sets command and args and deletes serverUrl, url and httpUrl — the remote-transport keys, which nothing reads under stdio — and migrates anyone who installed the earlier serverUrl shape.

A hand-added headers block is preserved but inert under stdio; mcp-remote takes --header arguments, not a headers object. Deleting someone's credential config silently is worse, and those users land on mcp-remote's OAuth, which works. kernel/docs#623 rewrites that section to pass the key through mcp-remote's --header-file.

The file is written with writePrivateJSONFile (0600, chmods an existing file) because a preserved headers block can hold an API key. Only fx did that before.

Validation

  • go build ./..., go vet ./cmd/mcp/, gofmt -l: all clean.
  • go test ./...: all packages pass, including three tests covering an existing config, a clean machine, and a reinstall over a serverUrl entry with a hand-added headers block. All three fail against the previous commit (command = <nil>, want npx).
  • Ran the built binary against a throwaway HOME, for both a clean install and a reinstall over an existing config: writes the entry above, strips the stale keys, leaves other servers alone, tightens 0644 to 0600, and prints the new next steps.
  • Ran npx with the exact args the built binary writes: it discovers the authorization server, registers as Antigravity, and reaches the authorization step. Registering without the flag comes back MCP CLI Proxy, which is what the consent screen showed in review.
  • Not driven inside Antigravity itself. The config path and token-store location come from Antigravity's MCP documentation; the stdio config shape is confirmed working there by review.

Merge order

kernel/docs#612 has already merged and documents this target, so the published page names a CLI command no released binary has and shows the serverUrl config that doesn't work. kernel/docs#623 corrects that page.

Land #623 first. It fixes a published page whose manual-config path is wrong today and needs no CLI to be right, so there's no reason to hold it behind this. This one closes the remaining gap when it ships in a release.

🤖 Generated with Claude Code


Note

Low Risk
Scoped CLI changes that only write local MCP JSON; tighter file permissions reduce exposure if API keys are preserved in config.

Overview
Adds kernel mcp install --target antigravity for Google Antigravity, writing Kernel MCP settings to ~/.gemini/config/mcp_config.json and documenting Antigravity-specific next steps (reload MCP servers, OAuth, verify connection).

Because Antigravity’s native remote MCP path can OAuth without sending a bearer token on initialize, the installer configures stdio via npx mcp-remote (with --static-oauth-client-metadata so the consent screen shows Antigravity), not serverUrl/url/httpUrl. Reinstalls merge into an existing mcpServers.kernel entry, drop stale remote keys, and keep hand-added fields such as headers; the config file is written with 0600 permissions when secrets might be present.

Tests cover fresh install, merging with other servers, and reinstall over a prior remote-shaped entry including preserved headers.

Reviewed by Cursor Bugbot for commit 631ce29. Bugbot is set up for automated code reviews on this repo. Configure here.

Antigravity keys remote servers off serverUrl rather than url, so the
existing HTTP target shapes don't work for it. Config lives at
~/.gemini/config/mcp_config.json.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robertjamesprior
robertjamesprior marked this pull request as ready for review September 20, 2026 08:23
@robertjamesprior
robertjamesprior requested review from masnwilliams and rgarcia and removed request for rgarcia September 20, 2026 19:29
@rgarcia

rgarcia commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

doesn't work for me
image

this worked:

{
  "mcpServers": {
    "kernel": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@latest",
        "https://mcp.onkernel.com/mcp",
        "--static-oauth-client-metadata",
        "{\"client_name\":\"Antigravity\"}"
      ]
    }
  }
}

also i'd rewrite next steps as:

Next steps:
  1. Go to Settings -> Customizations, scroll to Installed MCP Servers, click the reload button
  2. Complete the OAuth flow that opens in your browser
  3. Verify that Kernel appears connected in Antigravity

@masnwilliams masnwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requesting one change before approval. otherwise the target is scoped and the paired docs cover setup. non-blocking: target metadata is now spread across several lists and switches; a registry would make future targets less error-prone.

Comment thread cmd/mcp/mcp.go Outdated
Replacing mcpServers.kernel wholesale dropped any field a user had added
by hand, including the headers block that carries the API-key workaround,
so rerunning the install silently broke a working config.

Merge into the existing object instead: set serverUrl, and delete only
url and httpUrl, which antigravity ignores.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robertjamesprior

Copy link
Copy Markdown
Author

Blocker addressed in b7b3caa.

installForAntigravity now merges into the existing mcpServers.kernel object instead of replacing it: it sets serverUrl and deletes only url and httpUrl, the two keys antigravity ignores. Anything a user added by hand, including the headers block carrying the API-key workaround, survives a reinstall.

Regression test TestInstallForAntigravityPreservesExistingKernelFields seeds a config with headers plus stale url/httpUrl keys, then asserts the header survives, serverUrl is set, and the two stale keys are gone. Confirmed it fails against the previous code (headers = <nil>, want the existing block preserved) and passes after.

On the non-blocking note: you're right that target metadata is spread across several lists and switches. Every other installer has the same whole-object replacement, so the headers problem isn't unique to antigravity — it's just the first target where a user was likely to have hand-edited fields. I've kept this diff to the target you flagged rather than widening it. Worth its own ticket for a target registry plus a shared merge helper; say the word and I'll file it.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread cmd/mcp/mcp.go
Preserving the headers block means the file can now hold an API key, and
writeJSONFile leaves it world-readable at 0644. Use writePrivateJSONFile,
which already backs the fx target and chmods an existing file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robertjamesprior

Copy link
Copy Markdown
Author

Bugbot caught a real consequence of the previous commit, fixed in 8e7d216.

Merging the existing object means headers now survives a reinstall — which is the point — but it also means this file can hold an API key, and writeJSONFile writes 0644. Before the merge fix the install wiped headers, so the world-readable write never persisted a credential; afterwards it does.

Switched the antigravity path to writePrivateJSONFile, the same writer already backing fx. It writes 0600 and chmods an existing file, so a config previously created at 0644 gets tightened on the next install. It creates the parent directory at 0700 but does not chmod an existing directory.

Extended the regression test to assert 0600. Confirmed it fails against the previous commit (config permissions = 644, want 600) and passes now. Full package green, go vet clean.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8e7d216. Configure here.

Comment thread cmd/mcp/mcp_test.go
Antigravity's remote-server client can complete the OAuth flow and still
send initialize without the bearer token, so the serverUrl config this
target wrote fails on first contact with 401 Unauthorized.

Write the npx mcp-remote stdio entry instead, matching Claude Desktop,
Windsurf and Zed. mcp-remote runs the OAuth flow itself, so the token
never depends on Antigravity's client. Reinstalling over a previous
serverUrl entry strips it along with the other remote-transport keys.

Post-install steps now describe the reload-and-authorize path that the
stdio entry actually takes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robertjamesprior

Copy link
Copy Markdown
Author

Blocker addressed in 554f75b — you're right, and the reasoning in the description was wrong on two counts.

installForAntigravity now writes the stdio entry:

{
  "mcpServers": {
    "kernel": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mcp.onkernel.com/mcp"]
    }
  }
}

Reinstalling over a previous serverUrl entry strips it along with url and httpUrl; the merge and the 0600 write stay.

"It diverges from every other target" was false. Four of the eight — claude, windsurf, goose, zed — already write npx -y mcp-remote <url>. This isn't a divergence, it's the shape we already use for every client whose native remote path doesn't work.

The fx precedent was stale. fx's OAuth was fixed by the authorization-server cutover last week, so fx writes OAuth config because OAuth works there now, not because we knowingly ship a broken path. I was arguing from a state that hadn't been true for five days. (The fx client doc still opens with the old issuer error — separate fix.)

I dropped --static-oauth-client-metadata from your config. It isn't load-bearing: registration returns 200 with or without it, and mcp-remote reaches the same authorize URL either way. All it changes is the client's display name on the consent screen, which the server otherwise defaults to MCP Client. Also left mcp-remote unpinned rather than @latest, to match the other four.

Took your next-steps wording verbatim.

One consequence worth flagging: the merge preserves a hand-added headers block, which under stdio is inert — mcp-remote takes --header arguments, not a headers object. I left it rather than deleting someone's credential config silently; those users land on mcp-remote's OAuth, which works. kernel/docs#623 rewrites that section to the --header form with the key in env.

Verified: the built binary against a throwaway HOME for both a clean install and a reinstall over an existing serverUrl + headers config; the three regression tests fail against the previous commit (command = <nil>, want npx) and pass now; full suite green, go vet and gofmt clean. Not driven inside Antigravity itself — mcp-remote was run directly against the server and reaches the authorization step, but the browser consent and the flow inside the IDE are unverified on my side.

@robertjamesprior

Copy link
Copy Markdown
Author

Two corrections to the comment above, from an accuracy pass. Neither changes this diff.

The API-key form I pointed at was broken. I said kernel/docs#623 rewrites that section to --header with the key in env. That form doesn't work here. mcp-remote stores a --header value literally — parseHeaderLine regex-matches Name: value with no process.env expansion — so the ${VAR} substitution has to come from the client, and Antigravity documents env for stdio servers without documenting substitution inside args. The header would have gone out as the literal placeholder. That page now uses --header-file, which mcp-remote reads itself and which keeps the key out of the process list either way. Checked against 0.14.3: an absolute path logs Loaded 1 header(s), a leading ~ is not expanded and fails ENOENT.

I overstated the fx point. I said fx's OAuth "works there now". What's established is narrower: the issuer mismatch was fixed on the canonical discovery path by the cutover, and the legacy routes on mcp.onkernel.com were deliberately left in place — its /.well-known/oauth-authorization-server still advertises issuer: https://mcp.onkernel.com. I didn't complete an fx authorization to confirm which path it takes. So the honest version is that the fx precedent rests on a state that has since changed and that I didn't verify, not that fx is confirmed working.

The argument doesn't depend on it either way: claude, windsurf, goose and zed already write npx -y mcp-remote <url>, which is four of the eight targets that existed before this one.

@rgarcia

rgarcia commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

add back "--static-oauth-client-metadata", "{\"client_name\":\"Antigravity\"}" because "mcp cli proxy wants to access your kernel account" is not good ux
image

@masnwilliams masnwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the switch to mcp-remote addresses the Antigravity initialize: Unauthorized failure, and the earlier config-preservation blocker is fixed. requesting the remaining OAuth consent identity fix before approval. please also resolve the existing BugBot comment about skipping the POSIX permission assertion on Windows.

Comment thread cmd/mcp/mcp.go Outdated
Without static client metadata, mcp-remote registers as "MCP CLI Proxy",
so the consent screen reads "mcp cli proxy wants to access kernel" and
asks the user to trust that name rather than the application they are
connecting.

Also skip the config permission assertion on Windows, where Mode().Perm()
reports 0666 for a writable file, matching TestInstallForFx.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robertjamesprior

Copy link
Copy Markdown
Author

Both addressed in 631ce29.

Client identity. Flag is back, so the written args are now exactly what you posted:

"args": ["-y", "mcp-remote", "https://mcp.onkernel.com/mcp", "--static-oauth-client-metadata", "{\"client_name\":\"Antigravity\"}"]

Windows. The 0600 assertion is now inside runtime.GOOS != "windows", matching TestInstallForFx.

Retracting what I said earlier — I called that flag "not load-bearing" and that was wrong. I'd checked that registration returned 200 and that mcp-remote reached an authorize URL, and stopped there. I never opened the consent screen. Registering both ways and reading back mcp-remote's stored client_info.json:

registered client_name
without the flag MCP CLI Proxy
with the flag Antigravity

That name is what the grant renders and what the trust warning names, so it's the whole point, not decoration. Verified end to end after the change: ran npx with the exact args the built binary writes, and the registered client comes back Antigravity.

Two things I found while confirming it, neither in this diff:

The other four stdio targets have the same problem. claude, windsurf, goose and zed all run bare npx -y mcp-remote <url>, so every one of those users gets the same "mcp cli proxy wants to access kernel" screen today. Antigravity is just where someone looked.

Retrofitting them only helps new installs. mcp-remote caches client_info.json keyed by server URL and does not re-register when static metadata changes — same config dir, added the flag, ran again, and both client_name and client_id were unchanged. So existing users keep the old name until they clear ~/.mcp-auth/mcp-remote-v1/, which means four client doc pages need a migration note. That's why I didn't fold it into this PR. Filed separately.

kernel/docs#623 now carries the same flag in its manual-config example. Left it out of that page's API-key example, since that path authenticates with the header and never reaches a consent screen.

Full suite green, go vet and gofmt clean.

@masnwilliams masnwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all requested changes are addressed: Antigravity now uses the working mcp-remote path, identifies itself correctly in OAuth consent, preserves existing config safely, and handles the permission assertion portably. checks and BugBot are green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants