@@ -118,18 +118,15 @@ func defaultClientFactory(ctx context.Context, target *vmcp.BackendTarget) (*cli
118118 return nil , fmt .Errorf ("failed to start client connection: %w" , err )
119119 }
120120
121- // Initialize the MCP connection
122- if err := initializeClient (ctx , c ); err != nil {
123- _ = c .Close ()
124- return nil , fmt .Errorf ("failed to initialize MCP connection: %w" , err )
125- }
126-
121+ // Note: Initialization is deferred to the caller (e.g., ListCapabilities)
122+ // so that ServerCapabilities can be captured and used for conditional querying
127123 return c , nil
128124}
129125
130- // initializeClient performs MCP protocol initialization handshake.
131- func initializeClient (ctx context.Context , c * client.Client ) error {
132- _ , err := c .Initialize (ctx , mcp.InitializeRequest {
126+ // initializeClient performs MCP protocol initialization handshake and returns server capabilities.
127+ // This allows the caller to determine which optional features the server supports.
128+ func initializeClient (ctx context.Context , c * client.Client ) (* mcp.ServerCapabilities , error ) {
129+ result , err := c .Initialize (ctx , mcp.InitializeRequest {
133130 Params : mcp.InitializeParams {
134131 ProtocolVersion : mcp .LATEST_PROTOCOL_VERSION ,
135132 ClientInfo : mcp.Implementation {
@@ -146,37 +143,88 @@ func initializeClient(ctx context.Context, c *client.Client) error {
146143 },
147144 },
148145 })
149- return err
146+ if err != nil {
147+ return nil , err
148+ }
149+ return & result .Capabilities , nil
150+ }
151+
152+ // queryTools queries tools from a backend if the server advertises tool support.
153+ func queryTools (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListToolsResult , error ) {
154+ if supported {
155+ result , err := c .ListTools (ctx , mcp.ListToolsRequest {})
156+ if err != nil {
157+ return nil , fmt .Errorf ("failed to list tools from backend %s: %w" , backendID , err )
158+ }
159+ return result , nil
160+ }
161+ logger .Debugf ("Backend %s does not advertise tools capability, skipping tools query" , backendID )
162+ return & mcp.ListToolsResult {Tools : []mcp.Tool {}}, nil
163+ }
164+
165+ // queryResources queries resources from a backend if the server advertises resource support.
166+ func queryResources (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListResourcesResult , error ) {
167+ if supported {
168+ result , err := c .ListResources (ctx , mcp.ListResourcesRequest {})
169+ if err != nil {
170+ return nil , fmt .Errorf ("failed to list resources from backend %s: %w" , backendID , err )
171+ }
172+ return result , nil
173+ }
174+ logger .Debugf ("Backend %s does not advertise resources capability, skipping resources query" , backendID )
175+ return & mcp.ListResourcesResult {Resources : []mcp.Resource {}}, nil
176+ }
177+
178+ // queryPrompts queries prompts from a backend if the server advertises prompt support.
179+ func queryPrompts (ctx context.Context , c * client.Client , supported bool , backendID string ) (* mcp.ListPromptsResult , error ) {
180+ if supported {
181+ result , err := c .ListPrompts (ctx , mcp.ListPromptsRequest {})
182+ if err != nil {
183+ return nil , fmt .Errorf ("failed to list prompts from backend %s: %w" , backendID , err )
184+ }
185+ return result , nil
186+ }
187+ logger .Debugf ("Backend %s does not advertise prompts capability, skipping prompts query" , backendID )
188+ return & mcp.ListPromptsResult {Prompts : []mcp.Prompt {}}, nil
150189}
151190
152191// ListCapabilities queries a backend for its MCP capabilities.
153192// Returns tools, resources, and prompts exposed by the backend.
193+ // Only queries capabilities that the server advertises during initialization.
154194func (h * httpBackendClient ) ListCapabilities (ctx context.Context , target * vmcp.BackendTarget ) (* vmcp.CapabilityList , error ) {
155195 logger .Debugf ("Querying capabilities from backend %s (%s)" , target .WorkloadName , target .BaseURL )
156196
157- // Create a client for this backend
197+ // Create a client for this backend (not yet initialized)
158198 c , err := h .clientFactory (ctx , target )
159199 if err != nil {
160200 return nil , fmt .Errorf ("failed to create client for backend %s: %w" , target .WorkloadID , err )
161201 }
162202 defer c .Close ()
163203
164- // Query tools
165- toolsResp , err := c . ListTools (ctx , mcp. ListToolsRequest {} )
204+ // Initialize the client and get server capabilities
205+ serverCaps , err := initializeClient (ctx , c )
166206 if err != nil {
167- return nil , fmt .Errorf ("failed to list tools from backend %s: %w" , target .WorkloadID , err )
207+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
168208 }
169209
170- // Query resources
171- resourcesResp , err := c .ListResources (ctx , mcp.ListResourcesRequest {})
210+ logger .Debugf ("Backend %s capabilities: tools=%v, resources=%v, prompts=%v" ,
211+ target .WorkloadID , serverCaps .Tools != nil , serverCaps .Resources != nil , serverCaps .Prompts != nil )
212+
213+ // Query each capability type based on server advertisement
214+ // Check for nil BEFORE passing to functions to avoid interface{} nil pointer issues
215+ toolsResp , err := queryTools (ctx , c , serverCaps .Tools != nil , target .WorkloadID )
172216 if err != nil {
173- return nil , fmt . Errorf ( "failed to list resources from backend %s: %w" , target . WorkloadID , err )
217+ return nil , err
174218 }
175219
176- // Query prompts
177- promptsResp , err := c .ListPrompts (ctx , mcp.ListPromptsRequest {})
220+ resourcesResp , err := queryResources (ctx , c , serverCaps .Resources != nil , target .WorkloadID )
178221 if err != nil {
179- return nil , fmt .Errorf ("failed to list prompts from backend %s: %w" , target .WorkloadID , err )
222+ return nil , err
223+ }
224+
225+ promptsResp , err := queryPrompts (ctx , c , serverCaps .Prompts != nil , target .WorkloadID )
226+ if err != nil {
227+ return nil , err
180228 }
181229
182230 // Convert MCP types to vmcp types
@@ -266,6 +314,11 @@ func (h *httpBackendClient) CallTool(
266314 }
267315 defer c .Close ()
268316
317+ // Initialize the client
318+ if _ , err := initializeClient (ctx , c ); err != nil {
319+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
320+ }
321+
269322 // Call the tool
270323 result , err := c .CallTool (ctx , mcp.CallToolRequest {
271324 Params : mcp.CallToolParams {
@@ -337,6 +390,11 @@ func (h *httpBackendClient) ReadResource(ctx context.Context, target *vmcp.Backe
337390 }
338391 defer c .Close ()
339392
393+ // Initialize the client
394+ if _ , err := initializeClient (ctx , c ); err != nil {
395+ return nil , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
396+ }
397+
340398 // Read the resource
341399 result , err := c .ReadResource (ctx , mcp.ReadResourceRequest {
342400 Params : mcp.ReadResourceParams {
@@ -387,6 +445,11 @@ func (h *httpBackendClient) GetPrompt(
387445 }
388446 defer c .Close ()
389447
448+ // Initialize the client
449+ if _ , err := initializeClient (ctx , c ); err != nil {
450+ return "" , fmt .Errorf ("failed to initialize client for backend %s: %w" , target .WorkloadID , err )
451+ }
452+
390453 // Get the prompt
391454 // Convert map[string]any to map[string]string
392455 stringArgs := make (map [string ]string )
0 commit comments