@@ -207,18 +207,15 @@ func (h *httpBackendClient) defaultClientFactory(ctx context.Context, target *vm
207207 return nil , fmt .Errorf ("failed to start client connection: %w" , err )
208208 }
209209
210- // Initialize the MCP connection
211- if err := initializeClient (ctx , c ); err != nil {
212- _ = c .Close ()
213- return nil , fmt .Errorf ("failed to initialize MCP connection: %w" , err )
214- }
215-
210+ // Note: Initialization is deferred to the caller (e.g., ListCapabilities)
211+ // so that ServerCapabilities can be captured and used for conditional querying
216212 return c , nil
217213}
218214
219- // initializeClient performs MCP protocol initialization handshake.
220- func initializeClient (ctx context.Context , c * client.Client ) error {
221- _ , err := c .Initialize (ctx , mcp.InitializeRequest {
215+ // initializeClient performs MCP protocol initialization handshake and returns server capabilities.
216+ // This allows the caller to determine which optional features the server supports.
217+ func initializeClient (ctx context.Context , c * client.Client ) (* mcp.ServerCapabilities , error ) {
218+ result , err := c .Initialize (ctx , mcp.InitializeRequest {
222219 Params : mcp.InitializeParams {
223220 ProtocolVersion : mcp .LATEST_PROTOCOL_VERSION ,
224221 ClientInfo : mcp.Implementation {
@@ -235,37 +232,88 @@ func initializeClient(ctx context.Context, c *client.Client) error {
235232 },
236233 },
237234 })
238- return err
235+ if err != nil {
236+ return nil , err
237+ }
238+ return & result .Capabilities , nil
239+ }
240+
241+ // queryTools queries tools from a backend if the server advertises tool support.
242+ func queryTools (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListToolsResult , error ) {
243+ if supported {
244+ result , err := c .ListTools (ctx , mcp.ListToolsRequest {})
245+ if err != nil {
246+ return nil , fmt .Errorf ("failed to list tools from backend %s: %w" , backendID , err )
247+ }
248+ return result , nil
249+ }
250+ logger .Debugf ("Backend %s does not advertise tools capability, skipping tools query" , backendID )
251+ return & mcp.ListToolsResult {Tools : []mcp.Tool {}}, nil
252+ }
253+
254+ // queryResources queries resources from a backend if the server advertises resource support.
255+ func queryResources (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListResourcesResult , error ) {
256+ if supported {
257+ result , err := c .ListResources (ctx , mcp.ListResourcesRequest {})
258+ if err != nil {
259+ return nil , fmt .Errorf ("failed to list resources from backend %s: %w" , backendID , err )
260+ }
261+ return result , nil
262+ }
263+ logger .Debugf ("Backend %s does not advertise resources capability, skipping resources query" , backendID )
264+ return & mcp.ListResourcesResult {Resources : []mcp.Resource {}}, nil
265+ }
266+
267+ // queryPrompts queries prompts from a backend if the server advertises prompt support.
268+ func queryPrompts (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListPromptsResult , error ) {
269+ if supported {
270+ result , err := c .ListPrompts (ctx , mcp.ListPromptsRequest {})
271+ if err != nil {
272+ return nil , fmt .Errorf ("failed to list prompts from backend %s: %w" , backendID , err )
273+ }
274+ return result , nil
275+ }
276+ logger .Debugf ("Backend %s does not advertise prompts capability, skipping prompts query" , backendID )
277+ return & mcp.ListPromptsResult {Prompts : []mcp.Prompt {}}, nil
239278}
240279
241280// ListCapabilities queries a backend for its MCP capabilities.
242281// Returns tools, resources, and prompts exposed by the backend.
282+ // Only queries capabilities that the server advertises during initialization.
243283func (h * httpBackendClient ) ListCapabilities (ctx context.Context , target * vmcp.BackendTarget ) (* vmcp.CapabilityList , error ) {
244284 logger .Debugf ("Querying capabilities from backend %s (%s)" , target .WorkloadName , target .BaseURL )
245285
246- // Create a client for this backend
286+ // Create a client for this backend (not yet initialized)
247287 c , err := h .clientFactory (ctx , target )
248288 if err != nil {
249289 return nil , fmt .Errorf ("failed to create client for backend %s: %w" , target .WorkloadID , err )
250290 }
251291 defer c .Close ()
252292
253- // Query tools
254- toolsResp , err := c . ListTools (ctx , mcp. ListToolsRequest {} )
293+ // Initialize the client and get server capabilities
294+ serverCaps , err := initializeClient (ctx , c )
255295 if err != nil {
256- return nil , fmt .Errorf ("failed to list tools from backend %s: %w" , target .WorkloadID , err )
296+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
257297 }
258298
259- // Query resources
260- resourcesResp , err := c .ListResources (ctx , mcp.ListResourcesRequest {})
299+ logger .Debugf ("Backend %s capabilities: tools=%v, resources=%v, prompts=%v" ,
300+ target .WorkloadID , serverCaps .Tools != nil , serverCaps .Resources != nil , serverCaps .Prompts != nil )
301+
302+ // Query each capability type based on server advertisement
303+ // Check for nil BEFORE passing to functions to avoid interface{} nil pointer issues
304+ toolsResp , err := queryTools (ctx , c , serverCaps .Tools != nil , target .WorkloadID )
261305 if err != nil {
262- return nil , fmt . Errorf ( "failed to list resources from backend %s: %w" , target . WorkloadID , err )
306+ return nil , err
263307 }
264308
265- // Query prompts
266- promptsResp , err := c .ListPrompts (ctx , mcp.ListPromptsRequest {})
309+ resourcesResp , err := queryResources (ctx , c , serverCaps .Resources != nil , target .WorkloadID )
267310 if err != nil {
268- return nil , fmt .Errorf ("failed to list prompts from backend %s: %w" , target .WorkloadID , err )
311+ return nil , err
312+ }
313+
314+ promptsResp , err := queryPrompts (ctx , c , serverCaps .Prompts != nil , target .WorkloadID )
315+ if err != nil {
316+ return nil , err
269317 }
270318
271319 // Convert MCP types to vmcp types
@@ -355,6 +403,11 @@ func (h *httpBackendClient) CallTool(
355403 }
356404 defer c .Close ()
357405
406+ // Initialize the client
407+ if _ , err := initializeClient (ctx , c ); err != nil {
408+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
409+ }
410+
358411 // Call the tool
359412 result , err := c .CallTool (ctx , mcp.CallToolRequest {
360413 Params : mcp.CallToolParams {
@@ -426,6 +479,11 @@ func (h *httpBackendClient) ReadResource(ctx context.Context, target *vmcp.Backe
426479 }
427480 defer c .Close ()
428481
482+ // Initialize the client
483+ if _ , err := initializeClient (ctx , c ); err != nil {
484+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
485+ }
486+
429487 // Read the resource
430488 result , err := c .ReadResource (ctx , mcp.ReadResourceRequest {
431489 Params : mcp.ReadResourceParams {
@@ -476,6 +534,11 @@ func (h *httpBackendClient) GetPrompt(
476534 }
477535 defer c .Close ()
478536
537+ // Initialize the client
538+ if _ , err := initializeClient (ctx , c ); err != nil {
539+ return "" , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
540+ }
541+
479542 // Get the prompt
480543 // Convert map[string]any to map[string]string
481544 stringArgs := make (map [string ]string )
0 commit comments