MiMo Code 是小米的 AI 编码工具,有免费额度。但使用 MiMo Code 才能使用,分析一下
认证逆向
MiMo Code 的免费 API 不需要登录。认证通过一个 bootstrap 接口完成:
POST https://api.xiaomimimo.com/api/free-ai/bootstrap
Body: {"client": "<设备指纹>"}
Response: {"jwt": "eyJhbG..."}
请求抓包就能看到。没有 OAuth、没有 API key、没有 session——一个 POST 拿 JWT,用它调 chat 接口
设备指纹
client 参数是设备指纹,由客户端本地生成:
import hashlib, platform, os
def get_fingerprint() -> str:
raw = "|".join([
platform.node(), # hostname
platform.system().lower(), # darwin / linux / windows
platform.machine(), # arm64 / x86_64
platform.processor() or "unknown-cpu", # CPU 型号
os.environ.get("USER") or "unknown", # 用户名
])
return hashlib.sha256(raw.encode()).hexdigest()
指纹会持久化到 ~/.local/share/mimocode/mimo-free-client,保证同一台机器每次 bootstrap 拿到同一个 token:
from pathlib import Path
FINGERPRINT_FILE = Path.home() / ".local/share/mimocode/mimo-free-client"
def get_fingerprint() -> str:
if FINGERPRINT_FILE.exists():
return FINGERPRINT_FILE.read_text().strip()
fp = hashlib.sha256(...).hexdigest()
FINGERPRINT_FILE.parent.mkdir(parents=True, exist_ok=True)
FINGERPRINT_FILE.write_text(fp)
FINGERPRINT_FILE.chmod(0o600)
return fp
JWT 解析
bootstrap 返回的 JWT 需要解析 exp 字段来判断过期时间:
def _parse_jwt_exp(jwt: str) -> float:
# JWT payload 是 base64url 编码的 JSON
parts = jwt.split(".")
pad = 4 - len(parts[1]) % 4
payload = json.loads(base64.urlsafe_b64decode(parts[1] + "=" * pad))
return payload.get("exp", time.time() + 3600) * 1000 # 毫秒
proxy 在过期前 5 分钟自动刷新:
async def get_token(self) -> str:
if self._jwt and self._exp - time.time() * 1000 > 300_000: # 还有 5 分钟
return self._jwt
# ... bootstrap 获取新 token
并发安全
多个并发请求同时发现 token 过期时,只触发一次 bootstrap:
async def get_token(self) -> str:
if self._bootstrapping: # 有请求正在 bootstrap
return (await self._bootstrapping)[0] # 等它完成,复用结果
self._bootstrapping = asyncio.ensure_future(self._bootstrap())
try:
self._jwt, self._exp = await self._bootstrapping
return self._jwt
finally:
self._bootstrapping = None
请求转发
拿到 token 后,转发到 chat 接口:
POST https://api.xiaomimimo.com/api/free-ai/openai/chat
Headers:
Authorization: Bearer <jwt>
X-Mimo-Source: mimocode-cli-free
User-Agent: mimocode/0.1.0 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14
Body: <OpenAI 格式 JSON>
但不能直接透传——客户端发的请求和标准 OpenAI 格式有差异
请求改写
def _prepare_body(body: bytes) -> bytes:
payload = json.loads(body)
messages = payload.get("messages", [])
normalized = []
has_system_prompt = False
for msg in messages:
item = dict(msg)
# MiMo Code 用 developer role,标准格式是 system
if item.get("role") == "developer":
item["role"] = "system"
# 检测是否已有 system prompt
if item.get("role") == "system" and isinstance(item.get("content"), str):
if item["content"].startswith("You are MiMoCode"):
has_system_prompt = True
normalized.append(item)
# 没有 system prompt 时自动注入 MiMo Code 的默认 prompt
if not has_system_prompt:
normalized.insert(0, {
"role": "system",
"content": "You are MiMoCode, an interactive CLI tool..."
})
payload["messages"] = normalized
# stream 请求自动加 stream_options(MiMo 要求的)
if payload.get("stream"):
payload.setdefault("stream_options", {"include_usage": True})
return json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode()
错误重试
token 过期时自动重新 bootstrap:
resp = await client.send(req)
if resp.status_code in (401, 403):
await jwt_mgr.invalidate() # 作废旧 token
token = await jwt_mgr.get_token() # bootstrap 拿新的
resp = await client.send(req) # 重试
流式响应透传
SSE 流直接 pipe,不解码不改写:
async def _send_streaming(body: bytes):
token = await jwt_mgr.get_token()
client = httpx.AsyncClient(timeout=120)
resp = await client.send(
client.build_request("POST", CHAT_URL, headers=_build_headers(token), content=body),
stream=True,
)
async def stream():
try:
async for chunk in resp.aiter_bytes():
yield chunk
finally:
await resp.aclose()
await client.aclose()
return StreamingResponse(stream(), media_type="text/event-stream")
MiMo 的流式响应本身就是标准 SSE 格式,直接透传就行