Connecting CodeNavi (WSL2) to Antigravity on Windows¶
How to use a CodeNavi instance running inside WSL2 from Antigravity (Google's agentic IDE) on the Windows host.
When to use this guide¶
You're running CodeNavi in Docker inside a WSL2 distro (Ubuntu, etc.) that you manage yourself (Docker --network=host), and you want Antigravity — installed on Windows — to call CodeNavi's MCP tools (semantic_search, read_file, …). Because that WSL2 VM can't always be reached on localhost out of the box, this guide covers the networking bridge, the Antigravity config, and — most importantly — the privacy trade-offs of connecting a local code index to a cloud IDE.
Installed on Windows via Docker Desktop (the trial installer /
setup.ps1)? The networking bridge below does not apply to you — Docker Desktop publishes the port to Windows, sohttp://localhost:8765/mcp/<codebase>already works with no port proxy. Skip Steps 1–2 and go straight to Step 3 — Configure Antigravity — but read Privacy first on the way. Thenetshbridge is only for the self-managed--network=hostcase above.Read Privacy first before you connect. Antigravity runs its agent in Google's cloud. Anything CodeNavi returns to it leaves your machine.
How it works¶
WSL2 (Linux VM) Windows host Google Cloud
┌───────────────────────────┐ ┌──────────────────┐
│ Docker (--network=host) │ │ netsh portproxy │ ┌─────────────┐
│ CodeNavi MCP :8765 │◀───────│ 127.0.0.1:8765 │◀─────│ Antigravity │──▶ Gemini
│ bound to 0.0.0.0 │ eth0 IP│ → <WSL_IP>:8765 │ MCP │ agent │ (cloud)
└───────────────────────────┘ └──────────────────┘ └─────────────┘
Three things have to line up:
- CodeNavi listens on all interfaces (
0.0.0.0), not just127.0.0.1. - Windows forwards
localhost:8765to the WSL VM's IP (anetshport proxy). - Antigravity is pointed at
http://localhost:8765/mcp/<your-codebase>.
Privacy first¶
Antigravity is a cloud agentic IDE — its agent runs on Google's servers. Every time that agent calls a CodeNavi tool, the chunks CodeNavi returns are placed into the model's prompt and sent to Google. Connecting CodeNavi to Antigravity means the code CodeNavi retrieves leaves your machine.
There are two distinct exposure surfaces, and they behave differently on a scoped endpoint (/mcp/<codebase>):
| Surface | Behaviour on a scoped endpoint |
|---|---|
| Code contents (search results, file reads, symbols) | Locked to the scoped codebase. The transport injects the codebase into every tool call and rejects any attempt to query a different one. The agent cannot read another codebase's code. |
Codebase metadata (list_codebases, /health) |
Still visible. list_codebases takes no codebase parameter, so it lists every configured codebase's name, path, and size regardless of scope. |
Recommendations:
- Always point Antigravity at a scoped endpoint (
/mcp/<codebase>), never the unscoped/mcp. Scoping is fail-safe; the unscoped endpoint can search every index — including any you add later. - Only scope it to codebases you're comfortable sending to Google. Treat anything proprietary as off-limits unless you've accepted that trade-off.
- If even the names and paths of your other codebases are sensitive, run a dedicated single-codebase instance (see Full isolation) so there's nothing else to enumerate.
- Review Antigravity's own data-use settings — prefer a plan/configuration where prompts aren't retained for model training, and disable telemetry.
Prerequisites¶
- CodeNavi running in Docker inside WSL2, reachable at
http://localhost:8765/healthfrom inside the distro. - Antigravity installed on Windows.
- An admin PowerShell on Windows (for the port proxy).
- Node.js on Windows only if you use the
mcp-remotefallback (Step 3, Option B).
Step 1 — Confirm CodeNavi is listening on all interfaces¶
The port proxy connects to the WSL VM's eth0 IP, so uvicorn itself must be bound to 0.0.0.0, not 127.0.0.1. Under --network=host there's no Docker port-publish step, so the variable that actually controls this is CODENAVI_BIND (the in-container uvicorn bind) — not CODENAVI_HOST, which only affects the port mapping in bridge-mode deployments. CODENAVI_BIND already defaults to 0.0.0.0, so most installs need no .env change here — just verify:
cd ~/codenavi/deploy && docker compose up -d
ss -tlnp | grep 8765 # want 0.0.0.0:8765, NOT 127.0.0.1:8765
If it shows 127.0.0.1:8765, something overrode the default — set CODENAVI_BIND=0.0.0.0 explicitly in deploy/.env and restart.
Step 2 — Bridge Windows → WSL2¶
Find the WSL VM's IP (inside WSL):
ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
# e.g. 172.23.247.28
In an admin PowerShell on Windows, forward the port:
netsh interface portproxy add v4tov4 `
listenport=8765 listenaddress=127.0.0.1 `
connectport=8765 connectaddress=<WSL_IP>
⚠️ The WSL IP changes on reboot. If the connection breaks later, re-check
eth0and re-add the rule.connectaddress=localhostdoes not work here — you must use the eth0 IP.Delete the rule with:
netsh interface portproxy delete v4tov4 listenport=8765 listenaddress=127.0.0.1For a setup that survives reboots, see Hardening.
Verify from Windows PowerShell:
curl http://localhost:8765/health # should return JSON
/health is plain HTTP and is the right smoke test. A raw curl http://localhost:8765/mcp will not return anything useful — /mcp speaks the MCP Streamable-HTTP protocol, not REST.
Step 3 — Configure Antigravity¶
Running
agyinside the distro rather than the Windows IDE? Use the bundle instead — it wires the server, theusing-codenaviskill and the statusline in one go: connecting-antigravity.md.
In Antigravity: open the MCP panel (the … menu in the prompt editor) → Manage MCP Servers → View raw config. This opens mcp_config.json.
Option A — Native HTTP (recommended)¶
Antigravity supports remote MCP servers directly via serverUrl:
{
"mcpServers": {
"codenavi": {
"serverUrl": "http://localhost:8765/mcp/<your-codebase>"
}
}
}
Replace <your-codebase> with the codebase you want to expose (run list_codebases or check /health for the names).
Option B — mcp-remote bridge (fallback)¶
If Antigravity rejects a plain-http serverUrl, use the Node bridge instead:
{
"mcpServers": {
"codenavi": {
"command": "npx",
"args": ["mcp-remote", "http://localhost:8765/mcp/<your-codebase>"]
}
}
}
Save the config. The CodeNavi tools should appear in Antigravity's MCP tool list.
Step 4 — Verify¶
In an Antigravity chat, ask the agent to run a search:
Use
semantic_searchto find where requests are authenticated.
- Tools listed but every call times out → it's the network bridge (Step 2), not Antigravity.
- Tools never appear → transport mismatch; switch between Option A and Option B.
Full isolation (optional)¶
Scoping protects code but still leaks codebase names and paths via list_codebases and /health. For hard isolation, run a second CodeNavi instance configured with only the codebase you want to share:
- Give it its own
CODEBASE_CONFIGcontaining a single codebase. - Run it on a different port (e.g.
8766) with its own port-proxy rule. - Point Antigravity at that instance.
Then there is nothing else for list_codebases to enumerate.
Resource note: each instance loads its own embedding + reranker models into GPU memory. Two model-loaded instances may not fit on a single mid-range GPU. Plan VRAM accordingly, or run the isolated instance on CPU if its codebase is small.
Hardening / stable URL¶
The netsh proxy is brittle (the WSL IP changes on reboot) and the MCP port is only as private as your network. A single move fixes both: put Tailscale in front of CodeNavi.
- Stable
https://<host>.ts.netURL — no more re-runningnetshafter reboots. - Real TLS, which is the prerequisite for enabling the auth token.
- Set
CODENAVI_AUTH_TOKENindeploy/.envand pass it from Antigravity via a header.
Full walkthrough: remote-access.md (the auth-token + Funnel steps; only the client config differs).
Windows gotcha: if you pass an auth header through the
mcp-remotefallback on Windows, the space inBearer <token>can get mangled bycmd.exe. Prefer Option A'sserverUrlwith aheadersblock, or the native connector flow.
For serverUrl with auth:
{
"mcpServers": {
"codenavi": {
"serverUrl": "https://<host>.ts.net/mcp/<your-codebase>",
"headers": { "Authorization": "Bearer <your-token>" }
}
}
}
Operational notes¶
- One heavy client at a time. Searches serialize on their GPU phases, so a second client's searches queue behind the first; running another MCP client (or a reindex) against the same instance concurrently can also exhaust memory. Don't point two busy agents at one instance.
- Cosmetic reconnects. With the
mcp-remotefallback you may see SSE "reconnect" notices after each tool call (stateless_http=True). Results still return; ignore them.
Troubleshooting¶
| Symptom | Likely cause / fix |
|---|---|
curl …/health fails from Windows but works in WSL |
Port proxy missing or pointing at a stale WSL IP. Re-run Step 2 with the current eth0 IP. |
ss shows 127.0.0.1:8765 |
CODENAVI_BIND overridden away from its 0.0.0.0 default. Set CODENAVI_BIND=0.0.0.0 in deploy/.env, restart (Step 1). |
| Tools listed in Antigravity but calls time out | Network bridge, not Antigravity. Re-verify Steps 1–2. |
| Tools never appear | Transport mismatch. Switch between Option A and Option B (Step 3). |
Codebase scope mismatch … 400 |
The agent passed a different codebase than the scoped endpoint allows. Expected — leave the call's codebase empty, or use that codebase's own scoped URL. |
401 Unauthorized |
Auth token enabled but the header doesn't match (or got mangled — see the Windows gotcha above). |
Startup log: Refusing to start: bound to non-loopback address … with no CODENAVI_AUTH_TOKEN |
Auth is required by default on a network bind.1 This setup binds 0.0.0.0, so pick one: set CODENAVI_AUTH_TOKEN (recommended — setup.sh generates one), or set CODENAVI_ALLOW_NO_AUTH=1 to acknowledge the risk on a trusted single-user laptop. |
Security & privacy notes¶
- Antigravity is cloud. Connecting CodeNavi exports whatever it retrieves to Google. Scope tightly; never expose proprietary code you haven't cleared for cloud use.
- Scope, don't trust. Use
/mcp/<codebase>, never bare/mcp. The scoped endpoint enforces the boundary at the transport; the unscoped one does not. - A tokenless network bind now refuses to start (fail-closed). This setup binds
0.0.0.0, so CodeNavi requires a token by default: setCODENAVI_AUTH_TOKEN(setup.shgenerates one) and put it in the client's headers. Bound to the WSL VM network the port is only reachable from the host and other distros — fine for a single-user laptop, not for shared or exposed networks; add TLS before exposing it anywhere. If you accept the risk on a trusted single-user laptop,CODENAVI_ALLOW_NO_AUTH=1acknowledges it and lets the server start tokenless. - Metadata still leaks under scoping.
list_codebases//healthreveal all configured codebase names and paths. Use a dedicated single-codebase instance if that matters.
See also: setup.md · claude-desktop-connectors.md · claude-integration.md
-
Vendor change reference CN-354. ↩