Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion internal/common/config/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type (

ToolConfig struct {
Name string `json:"name" yaml:"name"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Method string `json:"method" yaml:"method"`
Endpoint string `json:"endpoint" yaml:"endpoint"`
Expand All @@ -71,6 +72,7 @@ type (
RequestBody string `json:"requestBody" yaml:"requestBody"`
ResponseBody string `json:"responseBody" yaml:"responseBody"`
InputSchema map[string]any `json:"inputSchema,omitempty" yaml:"inputSchema,omitempty"`
OutputSchema map[string]any `json:"outputSchema,omitempty" yaml:"outputSchema,omitempty"`
}

MCPServerConfig struct {
Expand Down Expand Up @@ -186,15 +188,26 @@ func (t *ToolConfig) ToToolSchema() mcp.ToolSchema {
}
}

return mcp.ToolSchema{
result := mcp.ToolSchema{
Name: t.Name,
Title: t.Title,
Description: t.Description,
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: properties,
Required: required,
},
}

// Add output schema if provided
if t.OutputSchema != nil {
result.OutputSchema = &mcp.ToolInputSchema{
Type: "object",
Properties: t.OutputSchema,
}
}

return result
}

// ToPromptSchema converts a PromptConfig to a PromptSchema
Expand Down
139 changes: 139 additions & 0 deletions internal/common/config/mcp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestToolConfigToToolSchema(t *testing.T) {
// Test ToolConfig with Title and OutputSchema
toolConfig := ToolConfig{
Name: "get_weather_data",
Title: "Weather Data Retriever",
Description: "Get current weather data for a location",
Method: "GET",
Endpoint: "https://api.weather.com/data",
Args: []ArgConfig{
{
Name: "location",
Type: "string",
Description: "City name or zip code",
Required: true,
},
},
OutputSchema: map[string]any{
"temperature": map[string]any{
"type": "number",
"description": "Temperature in celsius",
},
"conditions": map[string]any{
"type": "string",
"description": "Weather conditions description",
},
"humidity": map[string]any{
"type": "number",
"description": "Humidity percentage",
},
},
}

toolSchema := toolConfig.ToToolSchema()

// Verify basic fields
assert.Equal(t, "get_weather_data", toolSchema.Name)
assert.Equal(t, "Weather Data Retriever", toolSchema.Title)
assert.Equal(t, "Get current weather data for a location", toolSchema.Description)

// Verify InputSchema
assert.Equal(t, "object", toolSchema.InputSchema.Type)
assert.Len(t, toolSchema.InputSchema.Properties, 1)
assert.Contains(t, toolSchema.InputSchema.Properties, "location")
assert.Equal(t, []string{"location"}, toolSchema.InputSchema.Required)

// Verify OutputSchema
assert.NotNil(t, toolSchema.OutputSchema)
assert.Equal(t, "object", toolSchema.OutputSchema.Type)
assert.Len(t, toolSchema.OutputSchema.Properties, 3)
assert.Contains(t, toolSchema.OutputSchema.Properties, "temperature")
assert.Contains(t, toolSchema.OutputSchema.Properties, "conditions")
assert.Contains(t, toolSchema.OutputSchema.Properties, "humidity")
}

func TestToolConfigToToolSchemaWithoutOutputSchema(t *testing.T) {
// Test ToolConfig without Title and OutputSchema (backward compatibility)
toolConfig := ToolConfig{
Name: "simple_tool",
Description: "A simple tool",
Method: "POST",
Endpoint: "https://api.example.com/tool",
Args: []ArgConfig{
{
Name: "param1",
Type: "string",
Required: false,
},
},
}

toolSchema := toolConfig.ToToolSchema()

// Verify basic fields
assert.Equal(t, "simple_tool", toolSchema.Name)
assert.Equal(t, "", toolSchema.Title) // Should be empty when not provided
assert.Equal(t, "A simple tool", toolSchema.Description)

// Verify InputSchema
assert.Equal(t, "object", toolSchema.InputSchema.Type)
assert.Len(t, toolSchema.InputSchema.Properties, 1)
assert.Contains(t, toolSchema.InputSchema.Properties, "param1")
assert.Empty(t, toolSchema.InputSchema.Required) // No required args

// Verify OutputSchema is nil
assert.Nil(t, toolSchema.OutputSchema)
}

func TestToolConfigToToolSchemaWithInputSchema(t *testing.T) {
// Test ToolConfig that combines Args with explicit InputSchema
toolConfig := ToolConfig{
Name: "mixed_tool",
Title: "Mixed Tool",
Description: "A tool with both Args and InputSchema",
Method: "POST",
Endpoint: "https://api.example.com/mixed",
Args: []ArgConfig{
{
Name: "arg1",
Type: "string",
Description: "First argument",
Required: true,
},
},
InputSchema: map[string]any{
"custom_field": map[string]any{
"type": "number",
"description": "Custom field from InputSchema",
},
},
OutputSchema: map[string]any{
"result": map[string]any{
"type": "string",
},
},
}

toolSchema := toolConfig.ToToolSchema()

// Verify both arg-generated and explicit InputSchema properties are present
assert.Equal(t, "object", toolSchema.InputSchema.Type)
assert.Len(t, toolSchema.InputSchema.Properties, 2)
assert.Contains(t, toolSchema.InputSchema.Properties, "arg1")
assert.Contains(t, toolSchema.InputSchema.Properties, "custom_field")
assert.Equal(t, []string{"arg1"}, toolSchema.InputSchema.Required)

// Verify OutputSchema
assert.NotNil(t, toolSchema.OutputSchema)
assert.Equal(t, "object", toolSchema.OutputSchema.Type)
assert.Len(t, toolSchema.OutputSchema.Properties, 1)
assert.Contains(t, toolSchema.OutputSchema.Properties, "result")
}
8 changes: 5 additions & 3 deletions internal/core/mcpproxy/sse.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ func (t *SSETransport) FetchTools(ctx context.Context) ([]mcp.ToolSchema, error)
}

tools[i] = mcp.ToolSchema{
Name: schema.Name,
Description: schema.Description,
InputSchema: inputSchema,
Name: schema.Name,
Title: "", // Will be supported when mcpgo library updates
Description: schema.Description,
InputSchema: inputSchema,
OutputSchema: nil, // Will be supported when mcpgo library updates
}
}

Expand Down
8 changes: 5 additions & 3 deletions internal/core/mcpproxy/stdio.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,11 @@ func (t *StdioTransport) FetchTools(ctx context.Context) ([]mcp.ToolSchema, erro
}

tools[i] = mcp.ToolSchema{
Name: schema.Name,
Description: schema.Description,
InputSchema: inputSchema,
Name: schema.Name,
Title: "", // Will be supported when mcpgo library updates
Description: schema.Description,
InputSchema: inputSchema,
OutputSchema: nil, // Will be supported when mcpgo library updates
}
}

Expand Down
8 changes: 5 additions & 3 deletions internal/core/mcpproxy/streamable.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ func (t *StreamableTransport) FetchTools(ctx context.Context) ([]mcp.ToolSchema,
}

tools[i] = mcp.ToolSchema{
Name: schema.Name,
Description: schema.Description,
InputSchema: inputSchema,
Name: schema.Name,
Title: "", // Will be supported when mcpgo library updates
Description: schema.Description,
InputSchema: inputSchema,
OutputSchema: nil, // Will be supported when mcpgo library updates
}
}

Expand Down
8 changes: 5 additions & 3 deletions internal/core/sse.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,11 @@ func (s *Server) handlePostMessage(c *gin.Context, conn session.Connection) {
toolSchemas := make([]mcp.ToolSchema, len(tools))
for i, tool := range tools {
toolSchemas[i] = mcp.ToolSchema{
Name: tool.Name,
Description: tool.Description,
InputSchema: tool.InputSchema,
Name: tool.Name,
Title: tool.Title,
Description: tool.Description,
InputSchema: tool.InputSchema,
OutputSchema: tool.OutputSchema,
}
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/mcp/server_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ type (
ToolSchema struct {
// The name of the tool
Name string `json:"name"`
// A human-readable title for the tool (optional)
Title string `json:"title,omitempty"`
// A human-readable description of the tool
Description string `json:"description"`
// A JSON Schema object defining the expected parameters for the tool
InputSchema ToolInputSchema `json:"inputSchema"`
// A JSON Schema object defining the expected output of the tool (optional)
OutputSchema *ToolInputSchema `json:"outputSchema,omitempty"`
}

ToolInputSchema struct {
Expand Down
Loading