47 lines
3.1 KiB
Markdown
47 lines
3.1 KiB
Markdown
# context-hub -- MCP initialize Bad Request : 4 causes empilees (30/07/2026)
|
|
|
|
**Symptome initial** : Gemini "Error: calling initialize: sending initialize: Bad Request", connexion MCP impossible.
|
|
|
|
## Cause 1 -- redirection HTTPS vers HTTP
|
|
uvicorn lance sans --proxy-headers, donc il ignore X-Forwarded-Proto du reverse-proxy.
|
|
La redirection Starlette /mcp -> /mcp/ (trailing slash) se construit avec le scheme HTTP percu en interne,
|
|
alors que la requete externe est en HTTPS. Location: http://... au lieu de https://... -- un client MCP
|
|
strict refuse ce downgrade silencieux.
|
|
Fix : CMD Dockerfile -> uvicorn ... --proxy-headers --forwarded-allow-ips=*
|
|
|
|
## Cause 2 -- httpx manquant (revele par --no-cache)
|
|
app/git_sync.py importe httpx directement, jamais dans requirements.txt -- marchait par hasard
|
|
via dependance transitive du package mcp. Un rebuild --no-cache a resolu les dependances a neuf
|
|
et n a pas retire httpx cette fois -> ModuleNotFoundError au chargement de l app, crash loop.
|
|
Fix : httpx>=0.27.0 ajoute explicitement a requirements.txt.
|
|
|
|
## Cause 3 -- mcp 2.0.0 casse l API v1 utilisee par le code
|
|
mcp>=1.2.0 sans plafond -> pip installe 2.0.0 (sorti tres recemment, breaking rewrite officiel).
|
|
Server.list_tools() (API bas niveau v1.x) n existe plus en v2 -> AttributeError au chargement.
|
|
Fix : mcp>=1.2.0,<2.0.0 (recommandation officielle du projet pour qui n a pas migre).
|
|
|
|
## Cause 4 -- transport SSE legacy incompatible clients modernes (LA cause du Bad Request)
|
|
app/routes/mcp.py montait SseServerTransport (spec 2024-11-05, deux endpoints : GET pour ouvrir
|
|
un flux SSE + recuperer un session_id, POST /messages?session_id=... ensuite). Les clients MCP
|
|
recents (Gemini/Antigravity inclus) parlent Streamable HTTP (spec 2025-03-26+) : un seul POST
|
|
direct sans poignee de main prealable. Le serveur recevait ce POST sans session_id -> 400 Bad
|
|
Request (log : "mcp.server.sse: Received request without session_id").
|
|
|
|
Fix : migration vers StreamableHTTPSessionManager (mcp.server.streamable_http_manager, fallback
|
|
import mcp.server.streamable_http si version differente), mode stateless=True (pas de besoin de
|
|
resumabilite/streaming long pour ce service de lookup de regles/ports), json_response=True.
|
|
L auth X-API-Key et le contextvar current_agent_var (lu par tous les handlers call_tool) sont
|
|
preserves a l identique -- seule la couche transport a change.
|
|
Cote main.py : @app.on_event("startup") remplace par un lifespan= unifie (init_db() +
|
|
async with session_manager.run()), necessaire car le session manager doit rester actif toute
|
|
la duree de vie du process, pas juste au demarrage.
|
|
|
|
Comportement residuel attendu, pas un bug : DELETE /mcp/ -> 405 Method Not Allowed en mode
|
|
stateless (pas de session a terminer). Sans impact sur la connexion.
|
|
|
|
## Lecon generale
|
|
Un --no-cache sur un projet avec des bornes de version ouvertes (mcp>=1.2.0 sans plafond,
|
|
requirements.txt incomplet) peut faire remonter plusieurs regressions latentes d un coup.
|
|
Traiter chaque nouvelle erreur de log comme une couche distincte plutot que de chercher un
|
|
fix unique -- ici il a fallu 4 iterations successives avant la resolution complete.
|