diff --git a/mcp/tools.go b/mcp/tools.go index a0278e263..83b6582fd 100644 --- a/mcp/tools.go +++ b/mcp/tools.go @@ -72,7 +72,7 @@ type Tool struct { // A human-readable description of the tool. Description string `json:"description,omitempty"` // A JSON Schema object defining the expected parameters for the tool. - InputSchema ToolInputSchema `json:"-"` // Hide this from JSON marshaling + InputSchema ToolInputSchema `json:"inputSchema"` // Alternative to InputSchema - allows arbitrary JSON Schema to be provided RawInputSchema json.RawMessage `json:"-"` // Hide this from JSON marshaling } diff --git a/mcp/tools_test.go b/mcp/tools_test.go index 38791f3c1..25bfb7827 100644 --- a/mcp/tools_test.go +++ b/mcp/tools_test.go @@ -73,3 +73,72 @@ func TestToolWithRawSchema(t *testing.T) { assert.True(t, ok) assert.Contains(t, required, "query") } + +func TestUnmarshalToolWithRawSchema(t *testing.T) { + // Create a complex raw schema + rawSchema := json.RawMessage(`{ + "type": "object", + "properties": { + "query": {"type": "string", "description": "Search query"}, + "limit": {"type": "integer", "minimum": 1, "maximum": 50} + }, + "required": ["query"] + }`) + + // Create a tool with raw schema + tool := NewToolWithRawSchema("search-tool", "Search API", rawSchema) + + // Marshal to JSON + data, err := json.Marshal(tool) + assert.NoError(t, err) + + // Unmarshal to verify the structure + var toolUnmarshalled Tool + err = json.Unmarshal(data, &toolUnmarshalled) + assert.NoError(t, err) + + // Verify tool properties + assert.Equal(t, tool.Name, toolUnmarshalled.Name) + assert.Equal(t, tool.Description, toolUnmarshalled.Description) + + // Verify schema was properly included + assert.Equal(t, "object", toolUnmarshalled.InputSchema.Type) + assert.Contains(t, toolUnmarshalled.InputSchema.Properties, "query") + assert.Subset(t, toolUnmarshalled.InputSchema.Properties["query"], map[string]interface{}{ + "type": "string", + "description": "Search query", + }) + assert.Contains(t, toolUnmarshalled.InputSchema.Properties, "limit") + assert.Subset(t, toolUnmarshalled.InputSchema.Properties["limit"], map[string]interface{}{ + "type": "integer", + "minimum": 1.0, + "maximum": 50.0, + }) + assert.Subset(t, toolUnmarshalled.InputSchema.Required, []string{"query"}) +} + +func TestUnmarshalToolWithoutRawSchema(t *testing.T) { + // Create a tool with both schemas set + tool := NewTool("dual-schema-tool", + WithDescription("A tool with both schemas set"), + WithString("input", Description("Test input")), + ) + + data, err := json.Marshal(tool) + assert.Nil(t, err) + + // Unmarshal to verify the structure + var toolUnmarshalled Tool + err = json.Unmarshal(data, &toolUnmarshalled) + assert.NoError(t, err) + + // Verify tool properties + assert.Equal(t, tool.Name, toolUnmarshalled.Name) + assert.Equal(t, tool.Description, toolUnmarshalled.Description) + assert.Subset(t, toolUnmarshalled.InputSchema.Properties["input"], map[string]interface{}{ + "type": "string", + "description": "Test input", + }) + assert.Empty(t, toolUnmarshalled.InputSchema.Required) + assert.Empty(t, toolUnmarshalled.RawInputSchema) +} \ No newline at end of file