MCP client has no httpx timeout, so the event stream fails after 5 seconds
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 78/100
Direzione di ricerca
Inizia in src/azure_functions_agents/discovery/mcp.py, in _build_http_client, e verifica in cosa differisce il httpx.AsyncClient personalizzato dal client dell'MCP SDK. Aggiungi un timeout esplicito adatto al flusso di eventi di lunga durata, quindi verifica che le sessioni MCP autenticate possano inizializzarsi e completare una chiamata a uno strumento senza il ReadTimeout di cinque secondi.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
_build_http_client in src/azure_functions_agents/discovery/mcp.py creates its httpx.AsyncClient with no timeout. Thus httpx applies its 5 second default to all operations, including the long-lived MCP GET event stream. The stream then fails after 5 seconds, and the MCP session cannot start.
Affected code
src/azure_functions_agents/discovery/mcp.py, lines 88-99:
def _build_http_client(header_provider: Any) -> Any:
if header_provider is None:
return None
from httpx import AsyncClient
async def inject_headers(request: Any) -> None:
headers = await asyncio.to_thread(header_provider, {})
for key, value in headers.items():
request.headers[key] = value
return AsyncClient(follow_redirects=True, event_hooks={"request": [inject_headers]})
The MCP Python SDK builds its own client with sse_read_timeout=300. This client replaces it and loses that value.
Blast radius
_build_http_client returns None when header_provider is None. _build_header_provider returns a provider when the server entry has headers or auth.
Thus every authenticated mcp.json entry hits this defect:
- static headers, for example an Azure Functions system key in
x-functions-key - Entra authentication through
auth.scopeandauth.client_id - both together
Only an unauthenticated mcp.json entry avoids the defect, because then the SDK default client stays in use.
Symptoms
On the MCP server:
GET stream disconnected, reconnecting in 1000ms...
This message repeats.
On the MCP client (the agent app):
MCP server failed to initialize: Cancelled via cancel scope <id>
or:
('Failed to enter context manager.', BrokenResourceError())
or the chat request does not answer at all. A built-in chat API call returns HTTP 500, or it hangs for more than 240 seconds.
The logs do not show the true cause, because the cancel scope message hides the ReadTimeout.
The failure comes late, and it looks like an authentication fault
This is the most confusing part of the defect. Every earlier step succeeds:
| Step | Result |
|---|---|
| Deployment of both apps | Succeeds |
| Host start and function indexing on both apps | Succeeds |
MCP server discovery from mcp.json |
Succeeds |
| HTTP request to the MCP endpoint | Succeeds. The server answers 200 and runs the handler |
| MCP session start and tool call | Fails after about 5 seconds |
Thus nothing looks wrong until an agent tries to use a tool. The error text
names a cancel scope, so a reader first suspects the authentication
configuration, the system key, or the Entra token. It is none of these. The
server-side logs show that the request passed all authentication layers and
that the handler completed.
The ReadTimeout happens on the long-lived GET event stream, not on the POST
that carries the tool call. That is why the request appears to succeed while
the session still fails.
How to reproduce
- Deploy two Azure Functions apps with
azurefunctions-agents-runtime==0.1.0b15. One app exposes an agent throughbuiltin_endpoints.mcp. The other app refers to it inmcp.json. - Give the
mcp.jsonentry an authentication block. Either form is enough:
{
"servers": {
"worker": {
"type": "http",
"url": "https://<host>/runtime/webhooks/mcp",
"headers": { "x-functions-key": "<system key>" }
}
}
}
- Send a chat request to the client app. The request fails as shown above.
Isolated proof
An A/B test separates the transport from all other parts. The test starts the same MCP session twice against the same server, with the same headers. Only the client differs:
| httpx client | Result |
|---|---|
| MCP SDK default | SUCCESS — initialize, tools/list, and tools/call all complete |
Same shape as _build_http_client |
FAILED ReadTimeout -> Cancelled via cancel scope <id>; reason: deadline exceeded |
The failure string of the second row matches the string that the deployed app writes to Application Insights.
The server-side logs also show that the server handler runs and completes. Thus authentication is correct, and the fault is in the client transport only.
Suggested fix
Give the client an explicit timeout. Keep the read budget near the SDK value of sse_read_timeout=300:
from httpx import AsyncClient, Timeout
return AsyncClient(
follow_redirects=True,
timeout=Timeout(300.0, connect=30.0),
event_hooks={"request": [inject_headers]},
)
A configurable value in the mcp.json entry would also help, but a safe default is the important part.
Workaround
Applications can replace the function before they build the app. The replacement must run before create_function_app(), because create_function_app() calls discover_mcp_servers(), and the result goes into _DISCOVERED_MCP_SERVERS_CACHE:
from azure_functions_agents import create_function_app
from azure_functions_agents.discovery import mcp as _mcp_discovery
_mcp_discovery._build_http_client = _build_http_client_with_timeout
app = create_function_app()
This workaround uses a private name. Applications that use it must pin the runtime version.
Environment
azurefunctions-agents-runtime[monitor]==0.1.0b15- Python 3.13
- Azure Functions Flex Consumption (FC1), Linux, Python 3.13 worker
- Two Function Apps, MCP over HTTP between them
- Lingua principale
- Python
- Stelle
- 9
- Fork
- 7
- Merge medio
- 2g 7h
- PR unite (30g)
- 21
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Azure/azure-functions-agents-runtime
-
MCP server headers: unresolved `$VAR` placeholders are sent verbatim instead of failing closed Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
bug
Difficoltà 3/5 1-2 giorni Idoneità per principianti 74/100
Azure/azure-functions-agents-runtime#223 · 1 commento ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 38/100
Tutte le issue di Azure/azure-functions-agents-runtime
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
PolicyEngine/policyengine-us#9559 ·