Skip to content

Commit e17cd6e

Browse files
papagalaEItanya
andauthored
fix: make A2A client timeout configurable in MCP handler (#1617)
## fix: make A2A client timeout configurable in MCP handler ### Problem The MCP handler's `invoke_agent` tool uses an A2A client with a **hardcoded 30-second timeout** (`mcp_handler.go:212`). When an agent performs multi-step work — schema exploration, multiple tool calls, LLM reasoning — the total round-trip easily exceeds 30 seconds. The A2A client times out and returns: ``` Failed to send A2A message: a2aClient.SendMessage: a2aClient.doRequest: http request failed: context deadline exceeded (Client.Timeout exceeded while awaiting headers) ``` The agent itself completes successfully (visible in pod logs), but the caller never receives the response. ### Root Cause Other A2A call sites already use configurable timeouts: | Call site | Timeout source | |---|---| | `a2a_registrar.go` | `cfg.Streaming.Timeout` (default 600s) ✅ | | CLI `agent invoke` | `cfg.Config.Timeout` ✅ | | CLI `agent run` | `cfg.Config.Timeout` ✅ | | **`mcp_handler.go`** | **Hardcoded `30 * time.Second`** ❌ | The MCP handler was the only place with a hardcoded value. ### Fix - Add `a2aTimeout time.Duration` parameter to `NewMCPHandler()` - Pass `cfg.Streaming.Timeout` from `app.go` (same source as the A2A registrar) - Fall back to 60s if a zero/negative value is passed - No new config keys — uses the existing `STREAMING_TIMEOUT` env var / `--streaming-timeout` flag ### Changes - `go/core/internal/mcp/mcp_handler.go` — new field, new constructor param, use `h.a2aTimeout` instead of hardcoded value - `go/core/pkg/app/app.go` — pass `cfg.Streaming.Timeout` to `NewMCPHandler()` ### Testing - `go build ./core/...` passes - Manually verified with a kagent agent performing 5+ tool calls (~40s total) — `invoke_agent` now returns successfully Signed-off-by: Oswaldo Gomez <papagala@users.noreply.github.com> Co-authored-by: Oswaldo Gomez <papagala@users.noreply.github.com> Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
1 parent 1bf4617 commit e17cd6e

2 files changed

Lines changed: 12 additions & 2 deletions

File tree

go/core/internal/mcp/mcp_handler.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
type MCPHandler struct {
2626
kubeClient client.Client
2727
a2aBaseURL string
28+
a2aTimeout time.Duration
2829
authenticator auth.AuthProvider
2930
httpHandler *mcpsdk.StreamableHTTPHandler
3031
server *mcpsdk.Server
@@ -55,12 +56,20 @@ type InvokeAgentOutput struct {
5556
ContextID string `json:"context_id,omitempty"`
5657
}
5758

59+
// defaultA2ATimeout is the fallback timeout for A2A client calls and should match
60+
// the configured default streaming timeout.
61+
const defaultA2ATimeout = 10 * time.Minute
62+
5863
// NewMCPHandler creates a new MCP handler
5964
// Wraps the StreamableHTTPHandler and adds A2A bridging and context management.
60-
func NewMCPHandler(kubeClient client.Client, a2aBaseURL string, authenticator auth.AuthProvider) (*MCPHandler, error) {
65+
func NewMCPHandler(kubeClient client.Client, a2aBaseURL string, authenticator auth.AuthProvider, a2aTimeout time.Duration) (*MCPHandler, error) {
66+
if a2aTimeout <= 0 {
67+
a2aTimeout = defaultA2ATimeout
68+
}
6169
handler := &MCPHandler{
6270
kubeClient: kubeClient,
6371
a2aBaseURL: a2aBaseURL,
72+
a2aTimeout: a2aTimeout,
6473
authenticator: authenticator,
6574
}
6675

@@ -209,7 +218,7 @@ func (h *MCPHandler) handleInvokeAgent(ctx context.Context, req *mcpsdk.CallTool
209218
if a2aClient == nil {
210219
// Build A2A client options with authentication propagation
211220
a2aOpts := []a2aclient.Option{
212-
a2aclient.WithTimeout(30 * time.Second),
221+
a2aclient.WithTimeout(h.a2aTimeout),
213222
a2aclient.WithHTTPReqHandler(
214223
authimpl.A2ARequestHandler(
215224
h.authenticator,

go/core/pkg/app/app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ func Start(getExtensionConfig GetExtensionConfig) {
533533
mgr.GetClient(),
534534
cfg.A2ABaseUrl+httpserver.APIPathA2A,
535535
extensionCfg.Authenticator,
536+
cfg.Streaming.Timeout,
536537
)
537538
if err != nil {
538539
setupLog.Error(err, "unable to create MCP handler")

0 commit comments

Comments
 (0)