Skip to content

Commit fcbccfe

Browse files
committed
fix: propagate MCPServer CRD timeout to RemoteMCPServer with 30s default
Signed-off-by: skhedim <sebastien.khedim@gmail.com>
1 parent a8ba3e5 commit fcbccfe

6 files changed

Lines changed: 383 additions & 11 deletions

File tree

go/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require (
1414
github.com/gorilla/mux v1.8.1
1515
github.com/hashicorp/go-multierror v1.1.1
1616
github.com/jedib0t/go-pretty/v6 v6.7.8
17-
github.com/kagent-dev/kmcp v0.2.5
17+
github.com/kagent-dev/kmcp v0.2.6-0.20260210193153-3ba0e2e7f39d
1818
github.com/kagent-dev/mockllm v0.0.3
1919
github.com/modelcontextprotocol/go-sdk v1.2.0
2020
github.com/muesli/reflow v0.3.0

go/go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
165165
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
166166
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
167167
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
168-
github.com/kagent-dev/kmcp v0.2.2 h1:uvbKmo9IT6OT9RBNXYwGX0PWyxBLfAW1F9yWd5/wxaI=
169-
github.com/kagent-dev/kmcp v0.2.2/go.mod h1:g7wS/3m2wonRo/1DMwVoHxnilr/urPgV2hwV1DwkwrQ=
170-
github.com/kagent-dev/kmcp v0.2.5 h1:Em5A2vROJuR5JpMe5luSMe2vQJTwxX93AMXJm6Lg/E0=
171-
github.com/kagent-dev/kmcp v0.2.5/go.mod h1:g7wS/3m2wonRo/1DMwVoHxnilr/urPgV2hwV1DwkwrQ=
168+
github.com/kagent-dev/kmcp v0.2.6-0.20260210193153-3ba0e2e7f39d h1:+BN03C8JGZIJ3uMNBopXcNROHpPQdovffYQhY+toBHU=
169+
github.com/kagent-dev/kmcp v0.2.6-0.20260210193153-3ba0e2e7f39d/go.mod h1:g7wS/3m2wonRo/1DMwVoHxnilr/urPgV2hwV1DwkwrQ=
172170
github.com/kagent-dev/mockllm v0.0.3 h1:hk6Oa/vxHoBrGqRig4GCzox8EqRQYXM4c3oFPP/k9Tg=
173171
github.com/kagent-dev/mockllm v0.0.3/go.mod h1:tDLemRsTZa1NdHaDbg3sgFk9cT1QWvMPlBtLVD6I2mA=
174172
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=

go/internal/controller/translator/agent/adk_api_translator.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"slices"
1515
"strconv"
1616
"strings"
17+
"time"
1718

1819
"github.com/kagent-dev/kagent/go/api/v1alpha2"
1920
"github.com/kagent-dev/kagent/go/internal/adk"
@@ -45,6 +46,12 @@ const (
4546
MCPServiceProtocolDefault = v1alpha2.RemoteMCPServerProtocolStreamableHttp
4647

4748
ProxyHostHeader = "x-kagent-host"
49+
50+
// DefaultMCPServerTimeout is the fallback connection timeout applied when
51+
// an MCPServer CRD resource does not have an explicit Timeout set (e.g.
52+
// objects created before the field was introduced). This value mirrors
53+
// the kubebuilder default on MCPServerSpec.Timeout in the kmcp CRD.
54+
DefaultMCPServerTimeout = 30 * time.Second
4855
)
4956

5057
// ValidationError indicates a configuration error that requires user action to fix.
@@ -1259,16 +1266,30 @@ func ConvertMCPServerToRemoteMCPServer(mcpServer *v1alpha1.MCPServer) (*v1alpha2
12591266
return nil, NewValidationError("cannot determine port for MCP server %s", mcpServer.Name)
12601267
}
12611268

1262-
return &v1alpha2.RemoteMCPServer{
1269+
remoteMCP := &v1alpha2.RemoteMCPServer{
12631270
ObjectMeta: metav1.ObjectMeta{
12641271
Name: mcpServer.Name,
12651272
Namespace: mcpServer.Namespace,
12661273
},
12671274
Spec: v1alpha2.RemoteMCPServerSpec{
1268-
URL: fmt.Sprintf("http://%s.%s:%d/mcp", mcpServer.Name, mcpServer.Namespace, mcpServer.Spec.Deployment.Port),
1269-
Protocol: v1alpha2.RemoteMCPServerProtocolStreamableHttp,
1275+
URL: fmt.Sprintf("http://%s.%s:%d/mcp", mcpServer.Name, mcpServer.Namespace, mcpServer.Spec.Deployment.Port),
1276+
Protocol: v1alpha2.RemoteMCPServerProtocolStreamableHttp,
1277+
TerminateOnClose: ptr.To(true),
12701278
},
1271-
}, nil
1279+
}
1280+
1281+
// Propagate the timeout from the MCPServer CRD to the generated
1282+
// RemoteMCPServer spec. Fall back to DefaultMCPServerTimeout for
1283+
// MCPServer objects created before the CRD default was introduced,
1284+
// so the ADK never uses its own 5s built-in which is too short for
1285+
// sidecar gateway cold starts.
1286+
if mcpServer.Spec.Timeout != nil {
1287+
remoteMCP.Spec.Timeout = mcpServer.Spec.Timeout
1288+
} else {
1289+
remoteMCP.Spec.Timeout = &metav1.Duration{Duration: DefaultMCPServerTimeout}
1290+
}
1291+
1292+
return remoteMCP, nil
12721293
}
12731294

12741295
func (a *adkApiTranslator) translateRemoteMCPServerTarget(ctx context.Context, agent *adk.AgentConfig, remoteMcpServer *v1alpha2.RemoteMCPServer, mcpServerTool *v1alpha2.McpServerTool, agentHeaders map[string]string, proxyURL string) error {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
operation: translateAgent
2+
targetObject: agent-with-proxy-mcpserver-timeout
3+
namespace: test
4+
proxyURL: http://proxy.kagent.svc.cluster.local:8080
5+
objects:
6+
- apiVersion: v1
7+
kind: Secret
8+
metadata:
9+
name: openai-secret
10+
namespace: test
11+
data:
12+
api-key: c2stdGVzdC1hcGkta2V5 # base64 encoded "sk-test-api-key"
13+
- apiVersion: kagent.dev/v1alpha2
14+
kind: ModelConfig
15+
metadata:
16+
name: default-model
17+
namespace: test
18+
spec:
19+
provider: OpenAI
20+
model: gpt-4o
21+
apiKeySecret: openai-secret
22+
apiKeySecretKey: api-key
23+
- apiVersion: kagent.dev/v1alpha1
24+
kind: MCPServer
25+
metadata:
26+
name: test-mcp-server
27+
namespace: test
28+
spec:
29+
deployment:
30+
port: 8084
31+
timeout: 60s
32+
- apiVersion: kagent.dev/v1alpha2
33+
kind: Agent
34+
metadata:
35+
name: agent-with-proxy-mcpserver-timeout
36+
namespace: test
37+
spec:
38+
type: Declarative
39+
declarative:
40+
description: An agent with proxy configuration and MCPServer with custom timeout
41+
systemMessage: You are an agent that uses proxies.
42+
modelConfig: default-model
43+
tools:
44+
- type: MCPServer
45+
mcpServer:
46+
name: test-mcp-server
47+
kind: MCPServer
48+
toolNames:
49+
- test-tool

go/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"headers": {
2626
"x-kagent-host": "test-mcp-server.test"
2727
},
28+
"terminate_on_close": true,
29+
"timeout": 30,
2830
"url": "http://proxy.kagent.svc.cluster.local:8080/mcp"
2931
},
3032
"tools": [
@@ -69,7 +71,7 @@
6971
},
7072
"stringData": {
7173
"agent-card.json": "{\"name\":\"agent_with_proxy_mcpserver\",\"description\":\"\",\"url\":\"http://agent-with-proxy-mcpserver.test:8080\",\"version\":\"\",\"capabilities\":{\"streaming\":true,\"pushNotifications\":false,\"stateTransitionHistory\":true},\"defaultInputModes\":[\"text\"],\"defaultOutputModes\":[\"text\"],\"skills\":[]}",
72-
"config.json": "{\"model\":{\"type\":\"openai\",\"model\":\"gpt-4o\",\"base_url\":\"\"},\"description\":\"\",\"instruction\":\"You are an agent that uses proxies.\",\"http_tools\":[{\"params\":{\"url\":\"http://proxy.kagent.svc.cluster.local:8080/mcp\",\"headers\":{\"x-kagent-host\":\"test-mcp-server.test\"}},\"tools\":[\"test-tool\"]}],\"sse_tools\":null,\"remote_agents\":null,\"stream\":false}"
74+
"config.json": "{\"model\":{\"type\":\"openai\",\"model\":\"gpt-4o\",\"base_url\":\"\"},\"description\":\"\",\"instruction\":\"You are an agent that uses proxies.\",\"http_tools\":[{\"params\":{\"url\":\"http://proxy.kagent.svc.cluster.local:8080/mcp\",\"headers\":{\"x-kagent-host\":\"test-mcp-server.test\"},\"timeout\":30,\"terminate_on_close\":true},\"tools\":[\"test-tool\"]}],\"sse_tools\":null,\"remote_agents\":null,\"stream\":false}"
7375
}
7476
},
7577
{
@@ -138,7 +140,7 @@
138140
"template": {
139141
"metadata": {
140142
"annotations": {
141-
"kagent.dev/config-hash": "4693175952507523169"
143+
"kagent.dev/config-hash": "6152451571408999755"
142144
},
143145
"labels": {
144146
"app": "kagent",

0 commit comments

Comments
 (0)