Skip to content

kekee000/claude-code-gemini-api-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code → Gemini API Proxy

A lightweight Express + TypeScript proxy that speaks the Anthropic Messages API on the front, and talks to Gemini (public or internal gateway) on the back.

Drop it in front of any Claude-compatible client — Claude Code, IDE plugins, your own scripts — and they will transparently run on Gemini.


Highlights

  • API surfacePOST /v1/messages, POST /v1/messages/count_tokens, GET /v1/models
  • Streaming — pseudo-SSE: upstream Gemini is always called in non-stream mode, and the full response is replayed as Anthropic SSE events (see Streaming behavior)
  • Tool calling — bidirectional conversion between Claude tool_use / tool_result and Gemini functionCall / functionResponse
  • Multimodal — text and base64 images
  • Thought-signature cache — LRU (100k entries, 1h TTL) so multi-turn tool use stays coherent
  • Model routing — hard-coded mapping in src/config.ts
  • Local auth — optional shared token for trusted clients

Quick start

npm install
cp .env.example .env       # then edit it
npm run dev                # tsx watch on src/server.ts

Minimal .env:

GEMINI_API_KEY=your_key
PROXY_AUTH_TOKEN=local-dev-key

Get Gemini Api Keys: https://aistudio.google.com/app/api-keys

Optional knobs:

# Point at a custom Gemini endpoint (e.g. an internal gateway)
GEMINI_API_BASE=http://api.gateway.com/v1beta
GEMINI_AUTH_TYPE=bearer

# Fallback model when an incoming model name doesn't match the table below
DEFAULT_GEMINI_MODEL=gemini-3.5-flash

# Verbose logs
DEBUG=false

Connect Claude Code

export ANTHROPIC_BASE_URL="http://127.0.0.1:8318"
export ANTHROPIC_AUTH_TOKEN="local-dev-key"
claude

Some clients read ANTHROPIC_API_KEY instead of ANTHROPIC_AUTH_TOKEN:

export ANTHROPIC_API_KEY="local-dev-key"

Model mapping

Defined in src/config.ts. Anything not listed falls back to DEFAULT_GEMINI_MODEL.

Incoming model Routed to
Kimi-K2.5 DEFAULT_GEMINI_MODEL
Claude Sonnet 4.6 DEFAULT_GEMINI_MODEL
Claude Opus 4.6 DEFAULT_GEMINI_MODEL
gemini-3.5-flash gemini-3.5-flash
gemini-3.1-pro-preview gemini-3.1-pro-preview

DEFAULT_GEMINI_MODEL defaults to gemini-3.5-flash.


Token limits

max_tokens defaults to 32 768 and is clamped to 60 000 before being forwarded to Gemini as maxOutputTokens. Larger requests are silently capped, not rejected.


Streaming behavior

True token-by-token streaming is not supported. When a client sends "stream": true:

  1. The proxy calls Gemini with a non-streaming generateContent request and waits for the full response.
  2. It then replays that response to the client as a sequence of Anthropic SSE events (message_startcontent_block_*message_deltamessage_stop), with periodic ping frames every 15 s to keep the connection alive.

In other words, stream mode is just a wire-format adapter — there is no incremental output. Clients see the answer arrive in one chunk after the upstream call finishes. This trade-off keeps tool-call handling and thoughtSignature bookkeeping simple, at the cost of perceived latency on long generations.


Smoke tests

Streaming, bearer-token auth:

curl -N http://127.0.0.1:8318/v1/messages \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer local-dev-key' \
  -d '{
    "model": "gemini-3.5-flash",
    "max_tokens": 1024,
    "stream": true,
    "messages": [{ "role": "user", "content": "Say hello in one sentence." }]
  }'

x-api-key style (the header set Claude Code uses):

curl http://127.0.0.1:8318/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "max_tokens": 20000,
    "stream": true,
    "messages": [
      { "role": "user", "content": "中国的特大城市有哪些?" }
    ]
  }'

Build & deploy

npm run build              # tsc -> dist/
node dist/server.js        # run

# or, for production
pm2 start pm2.config.cjs

./build.sh packages everything you need to ship:

./build.sh
# produces output/ and output.tar.gz
# (dist/, package.json, pm2.config.cjs, README.md, .env)

Verbose logs:

DEBUG=true node dist/server.js

Notes

This is a compatibility gateway, not a full Anthropic re-implementation. The two parts most worth treating with care are:

  1. Tool-call conversion — Claude Code workflows lean heavily on tool_use / tool_result. Breaking either side breaks the agent loop.
  2. thoughtSignature cache — Gemini requires the original signature to be echoed back on follow-up turns. Don't disable the LRU.

About

A lightweight Express + TypeScript proxy that speaks the **Anthropic Messages API** on the front, and talks to **Gemini** (public or internal gateway) on the back.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors