@@ -9,13 +9,11 @@ package client
99
1010import (
1111 "context"
12- "encoding/json"
1312 "errors"
1413 "fmt"
1514 "io"
1615 "net"
1716 "net/http"
18- "strings"
1917 "time"
2018
2119 "github.com/mark3labs/mcp-go/client"
@@ -28,6 +26,7 @@ import (
2826 vmcpauth "github.com/stacklok/toolhive/pkg/vmcp/auth"
2927 authtypes "github.com/stacklok/toolhive/pkg/vmcp/auth/types"
3028 "github.com/stacklok/toolhive/pkg/vmcp/conversion"
29+ "github.com/stacklok/toolhive/pkg/versions"
3130)
3231
3332const (
@@ -329,7 +328,7 @@ func initializeClient(ctx context.Context, c *client.Client) (*mcp.ServerCapabil
329328 ProtocolVersion : mcp .LATEST_PROTOCOL_VERSION ,
330329 ClientInfo : mcp.Implementation {
331330 Name : "toolhive-vmcp" ,
332- Version : "0.1.0" ,
331+ Version : versions . Version ,
333332 },
334333 Capabilities : mcp.ClientCapabilities {
335334 // Virtual MCP acts as a client to backends
@@ -386,13 +385,6 @@ func queryPrompts(ctx context.Context, c *client.Client, supported bool, backend
386385 return & mcp.ListPromptsResult {Prompts : []mcp.Prompt {}}, nil
387386}
388387
389- // convertContent converts a single mcp.Content item to vmcp.Content.
390- // Delegates to the shared conversion package; kept here for backward compatibility
391- // with tests that call it directly.
392- func convertContent (content mcp.Content ) vmcp.Content {
393- return conversion .ConvertMCPContent (content )
394- }
395-
396388// ListCapabilities queries a backend for its MCP capabilities.
397389// Returns tools, resources, and prompts exposed by the backend.
398390// Only queries capabilities that the server advertises during initialization.
@@ -445,25 +437,10 @@ func (h *httpBackendClient) ListCapabilities(ctx context.Context, target *vmcp.B
445437
446438 // Convert tools
447439 for i , tool := range toolsResp .Tools {
448- // Use a JSON round-trip to capture all schema fields (type, properties,
449- // required, $defs, additionalProperties, etc.) rather than enumerating
450- // them manually. This is forward-safe: any fields the SDK adds in future
451- // versions are preserved automatically.
452- inputSchema := make (map [string ]any )
453- if b , err := json .Marshal (tool .InputSchema ); err == nil {
454- if jsonErr := json .Unmarshal (b , & inputSchema ); jsonErr != nil {
455- logger .Debugf ("Failed to decode tool input schema for %s; using type-only fallback: %v" , tool .Name , jsonErr )
456- inputSchema = map [string ]any {"type" : tool .InputSchema .Type }
457- }
458- } else {
459- logger .Debugf ("Failed to encode tool input schema for %s; using type-only fallback: %v" , tool .Name , err )
460- inputSchema = map [string ]any {"type" : tool .InputSchema .Type }
461- }
462-
463440 capabilities .Tools [i ] = vmcp.Tool {
464441 Name : tool .Name ,
465442 Description : tool .Description ,
466- InputSchema : inputSchema ,
443+ InputSchema : conversion . ConvertToolInputSchema ( tool . InputSchema ) ,
467444 BackendID : target .WorkloadID ,
468445 }
469446 }
@@ -702,11 +679,7 @@ func (h *httpBackendClient) GetPrompt(
702679 logger .Debugf ("Translating prompt name: %s (client-facing) → %s (backend)" , name , backendPromptName )
703680 }
704681
705- // Convert map[string]any to map[string]string
706- stringArgs := make (map [string ]string )
707- for k , v := range arguments {
708- stringArgs [k ] = fmt .Sprintf ("%v" , v )
709- }
682+ stringArgs := conversion .ConvertPromptArguments (arguments )
710683
711684 result , err := c .GetPrompt (ctx , mcp.GetPromptRequest {
712685 Params : mcp.GetPromptParams {
@@ -718,27 +691,9 @@ func (h *httpBackendClient) GetPrompt(
718691 return nil , fmt .Errorf ("prompt get failed on backend %s: %w" , target .WorkloadID , err )
719692 }
720693
721- // Concatenate all prompt messages into a single string.
722- // MCP prompts return messages with role and multi-modal content; only text
723- // chunks are captured (non-text content is silently discarded — Phase 1 limitation).
724- var sb strings.Builder
725- for _ , msg := range result .Messages {
726- if msg .Role != "" {
727- fmt .Fprintf (& sb , "[%s] " , msg .Role )
728- }
729- if textContent , ok := mcp .AsTextContent (msg .Content ); ok {
730- sb .WriteString (textContent .Text )
731- sb .WriteByte ('\n' )
732- }
733- }
734- prompt := sb .String ()
735-
736- // Extract _meta field from backend response
737- meta := conversion .FromMCPMeta (result .Meta )
738-
739694 return & vmcp.PromptGetResult {
740- Messages : prompt ,
695+ Messages : conversion . ConvertPromptMessages ( result . Messages ) ,
741696 Description : result .Description ,
742- Meta : meta ,
697+ Meta : conversion . FromMCPMeta ( result . Meta ) ,
743698 }, nil
744699}
0 commit comments