Skip to main content
kRouter
All posts
How kRouter works

Claude Desktop, Antigravity and Copilot through a MITM proxy

Some AI apps have no base URL setting. How kRouter's MITM mode routes Claude Desktop, Antigravity, Copilot and Kiro anyway, and how to undo it cleanly.

Kodelyth · The team behind kRouter
· Updated
10 min read

Most coding tools let you choose where their requests go. In Cline, Codex or Claude Code you set a base URL of http://localhost:20128/v1 and you are done. (Cursor is the odd one out: its requests leave from Cursor's own servers, so localhost never answers and it needs a tunnel -- see why Cursor ignores a localhost base URL.)

A few desktop apps offer no such setting. Claude Desktop, Google Antigravity, GitHub Copilot and Kiro IDE talk to fixed hostnames -- api.anthropic.com, daily-cloudcode-pa.googleapis.com, api.individual.githubcopilot.com, runtime.us-east-1.kiro.dev -- and there is nothing to configure. To send their requests to a different model, you have to catch the traffic on its way out. That is what kRouter's MITM mode does.

This post covers what it changes on your machine, what each app gets, and how to remove all of it afterwards. Updated October 2026: earlier versions described a krouter --uninstall-ca command, a Settings → Security page and a ~/.krouter/certs/ folder. None of those exist; the steps below match kRouter 0.5.163.

How MITM mode works

Four pieces, all on your own machine:

  1. Hosts file. When you start DNS for an app, kRouter adds one line per hostname to /etc/hosts (on Windows, System32\drivers\etc\hosts) pointing it at 127.0.0.1, then flushes the DNS cache. The app now connects to your machine instead of the real service.
  2. A local root certificate. The first time you start the MITM server, kRouter generates a root CA -- a 2048-bit RSA key, valid for 10 years -- and adds it to the system trust store: the System keychain on macOS, the Root store on Windows, the system anchors and Chrome's NSS databases on Linux. It also sets NODE_EXTRA_CA_CERTS, because Electron and other Node-based apps ignore the OS trust store and would otherwise reject the certificate.
  3. A TLS server on port 443. For each hostname the app asks for, kRouter signs a leaf certificate with that CA on the fly. The app sees a valid certificate for api.anthropic.com and carries on.
  4. A decision per request. A chat request for a model you have mapped goes to kRouter, which sends it to the provider you chose. Everything else -- sign-in, settings, telemetry, any model you did not map -- passes through to the real service unchanged.
AppHostnames redirectedRequests re-routed
Claude Desktopapi.anthropic.com/v1/messages, plus its token-count preview
Antigravitydaily-cloudcode-pa.googleapis.com, cloudcode-pa.googleapis.com:generateContent, :streamGenerateContent
GitHub Copilotapi.individual.githubcopilot.com/chat/completions, /v1/messages, /responses
Kiro IDEruntime.us-east-1.kiro.dev, q.us-east-1.amazonaws.com, codewhisperer.us-east-1.amazonaws.comGenerateAssistantResponse

Cursor is not on the list. Cursor interception is not implemented in kRouter; the handler answers 501.

What it writes to your hosts file

Plain lines, one per hostname:

127.0.0.1 api.anthropic.com

Stopping DNS for an app, or stopping the MITM server, removes every line that mentions that app's hostnames and flushes the cache again (dscacheutil -flushcache and killall -HUP mDNSResponder on macOS, resolvectl flush-caches on Linux, ipconfig /flushdns on Windows). There are no begin/end markers: if you had your own entries for those hostnames, they go too.

Editing the hosts file and the trust store needs elevated rights. On macOS and Linux kRouter asks for your sudo password and can keep it encrypted so it does not ask every time. On Windows you start kRouter as Administrator.

Setting it up

MITM only works when kRouter runs on the same machine as the app. Inside Docker it cannot work -- the hosts file and port 443 belong to the container, not your desktop -- and the dashboard says so instead of showing the buttons.

npm install -g @sifxprime/krouter
krouter -t

Then, in the dashboard at http://localhost:20128/dashboard:

  1. Open MITM in the sidebar.
  2. On the MITM Server card, click Start Server. The first start generates the root certificate and trusts it. If something else already holds port 443, the card names the process and asks before stopping it.
  3. Check that the MITM Root Certificate card says "Trusted by system". If it does not, click Install Certificate.
  4. On your app's card, click Start DNS, then pick a kRouter model for each model the app asks for. A model you leave unmapped keeps going to the real service.
  5. Restart the app so it picks up the new DNS entries and certificate.

Claude Desktop

Claude Desktop sends Anthropic Messages requests. The interceptor rewrites only the model field and forwards the body to kRouter's own /v1/messages; kRouter then sends it to the provider you mapped, translating if that provider speaks another format. Sign-in happens on claude.ai, which is not intercepted, so your Claude Desktop login is unaffected.

The card has a slot for each model Claude Desktop requests: Opus 4.7, Opus 4.6, Sonnet 4.6, Sonnet 4.5 and Haiku 4.5. Map Sonnet 4.6 to a Kiro or Copilot model and only those requests move.

From there it is an ordinary kRouter request, and the token savers you have on apply as they would for any client. By default that is only RTK, which compresses tool output such as file listings and logs, not the text you type. When a Claude client talks to a Claude account, kRouter skips the savers so Anthropic's prompt cache keeps working.

A note on "free": Kiro's free plan does include Claude Sonnet 4.5, but as 50 credits a month (Kiro pricing, October 2026). Treat it as a fallback, not a way to run Claude Desktop for nothing.

Two cases where you need none of this. The Claude Code CLI reads ANTHROPIC_BASE_URL, so it never needs interception. And Claude Desktop now has its own third-party inference setting for Cowork, which the Claude Cowork card on kRouter's CLI Tools page writes for you with no certificate involved -- see Claude Desktop Cowork with other models.

Antigravity

Antigravity sends Gemini-format requests to Google's Cloud Code endpoints. The interceptor hands the body to kRouter as it is; kRouter recognises the Antigravity format, translates it for the provider you mapped, and translates the answer back.

Two details:

  • Tab autocomplete is never re-routed. Antigravity's inline-completion models (the ones named tab_...) always pass through to Google. Sending a latency-critical request per keystroke to an external chat model would make typing lag and burn quota.
  • Dropped HTTP/2 streams are retried. Google's load balancer sometimes kills a reused HTTP/2 stream with NGHTTP2_INTERNAL_ERROR. Since v0.5.73 passthrough retries on a fresh HTTP/2 connection before falling back to HTTP/1.1, which Google often rejects with socket hang up.

GitHub Copilot

Copilot's requests are already in OpenAI or Anthropic format, so nothing needs translating on the way in. The interceptor swaps the model and forwards each request to the matching kRouter endpoint -- /v1/chat/completions, /v1/messages or /v1/responses -- and kRouter sends it to the provider you mapped. That covers Copilot Chat in the editor and the Copilot CLI.

The card has slots for the models Copilot actually requests: GPT-5 mini (the Copilot CLI default), GPT-5.4 nano (which Copilot's "Auto" picks for light tasks), Claude Haiku 4.5, GPT-4o and GPT-4.1. Only api.individual.githubcopilot.com is redirected.

If you use Copilot Chat in VS Code, check whether you need interception at all: recent releases let it use a model endpoint you supply, depending on your plan. Any model in GitHub Copilot Chat walks through that route.

Kiro IDE

Kiro speaks AWS's CodeWhisperer format and expects answers as binary AWS EventStream frames, so this is the one app where the interceptor does real work. It converts each chat request, tools included, into an OpenAI chat request for kRouter, then re-encodes kRouter's streamed answer as EventStream frames. If the provider fails, Kiro gets an EventStream exception frame carrying the real error rather than "Truncated event message received".

Kiro IDE 1.0.228 moved its chat calls: they now go to runtime.us-east-1.kiro.dev as POST / with an x-amz-target header, not to a /generateAssistantResponse path. Until v0.5.137 the interceptor matched on the path only, so MITM looked enabled while every chat turn went straight to AWS. If Kiro seems to ignore your mappings, check you are on v0.5.137 or later.

One fix matters if you map Kiro IDE back to a Kiro account. Kiro's Claude backends only accept tool IDs matching ^[a-zA-Z0-9_-]+$, and IDs produced by Gemini or OpenAI models can contain dots, colons or slashes. Since v0.5.74 kRouter rewrites them before any request reaches Kiro's service, whichever client sent it.

The anti-loop guard

kRouter itself calls some of the same hostnames: api.anthropic.com for a Claude account, Google's Cloud Code endpoints for an Antigravity account, AWS for a Kiro account. With the hosts file redirected, those calls would land back on the interceptor.

So every outbound request kRouter makes carries an x-request-source: local header, and the interceptor passes anything carrying it straight through. Passthrough does not use the hosts file: it looks up the real address through Google's public DNS (8.8.8.8). One consequence is that on a network that blocks outside DNS, passthrough fails.

The guard has broken before, which is why it is worth knowing about. v0.5.47 added that header to a list of headers scrubbed from Antigravity requests; kRouter's own calls to Google re-entered the interceptor and died with NGHTTP2_INTERNAL_ERROR, and v0.5.55 reverted it. In v0.5.74 the header became mandatory for every provider, after the Kiro, GitHub and Cursor executors turned out to build their headers without it.

Cleaning up

There is no CLI command for this. It is all on the MITM page.

  1. Click Stop DNS on each app's card, or Stop Server on the MITM Server card. Stopping the server removes every hosts entry kRouter added and unsets NODE_EXTRA_CA_CERTS.
  2. On the MITM Root Certificate card, click Uninstall. That removes the certificate from the system trust store.
  3. Uninstall leaves the files on disk. If you are done with MITM for good, delete them. On Windows they are in %APPDATA%\krouter\mitm\; if you set DATA_DIR, they are in $DATA_DIR/mitm/.
rm ~/.krouter/mitm/rootCA.key ~/.krouter/mitm/rootCA.crt
  1. On macOS or Linux, confirm the hosts file is clean. No output means nothing is left:
grep -E 'anthropic|cloudcode-pa|githubcopilot|kiro\.dev|codewhisperer|q\.us-east-1' /etc/hosts

When it goes wrong

  • Every request from the app fails with "fetch failed", and the MITM server is stopped. The hosts entries outlived the server, so the app is talking to nothing. Since v0.5.134 kRouter checks for this at start, tries to remove them, and says so if it cannot. Click Stop DNS for the app, or delete the lines by hand.
  • kRouter keeps crashing after you enable MITM. Since v0.5.159 (v0.5.161 for krouter -t), a server that crashes repeatedly turns MITM off itself and restarts.
  • A Node or Electron app rejects the certificate. It started before NODE_EXTRA_CA_CERTS was set. Quit and reopen it. On Linux, an app launched from the desktop menu may need you to log out and back in.
  • You want to see the traffic. Request dumps are off by default; DEBUG_MITM=1 or MITM_FILE_LOG=1 turns them on, with auth headers redacted. Before v0.5.120 they were always on and kept bearer tokens on disk, so upgrade if you are older than that.

Platform-specific fixes for macOS and Windows are in Troubleshooting.

Security implications

Running a local root CA is a real security decision.

  1. The key can sign for any domain. rootCA.key can mint a certificate your machine will trust for any HTTPS site. Do not copy it, back it up to shared storage, or commit your kRouter data directory anywhere.
  2. It is machine-wide. The hosts file and the trust store belong to the whole machine, not your user account. On a shared computer, every user's traffic to those hostnames is redirected.
  3. It only works where the app runs. MITM on a VPS does nothing for the editor on your laptop; it intercepts the server's own traffic and nothing else. For a remote kRouter, point clients at its base URL instead.
  4. Vendors can object. The MITM page warns that intercepting these apps may break their terms of service and can get the account restricted. That goes for all four. If you also connect a Google account to kRouter as an Antigravity provider, read why Antigravity accounts get flagged first.
  5. Uninstall when you are done. The steps are above.

Common questions

Does kRouter's MITM mode work with Cursor?

No. Cursor interception is not implemented; the handler answers 501. Cursor does accept a custom OpenAI base URL, but because its requests come from Cursor's servers, it needs a public URL such as kRouter's tunnel rather than localhost.

Do I need MITM for Claude Code?

No. The Claude Code CLI reads ANTHROPIC_BASE_URL, so you point it at http://localhost:20128/v1 and nothing is intercepted. MITM is for Claude Desktop, which has no such setting.

Can I run MITM mode in Docker?

No. The hosts file and port 443 it needs belong to the container, while the apps you want to intercept run on the host. Run kRouter directly on the machine where the app runs.

What happens to models I don't map?

They go to the real service exactly as before. Only chat requests for a mapped model are re-routed; sign-in, settings and everything else always pass through.

Where is the certificate stored?

In kRouter's data directory: ~/.krouter/mitm/rootCA.crt and rootCA.key on macOS and Linux, %APPDATA%\krouter\mitm\ on Windows. In your keychain or certificate store it appears as "9Router MITM Root CA", a name inherited from the project kRouter is forked from.

Kodelyth · The team behind kRouter

Published by Kodelyth, the team that builds kRouter. Posts are drafted with AI assistance and reviewed by a person before they go out. kRouter is free and MIT licensed.

Install kRouter