Skip to content

Commit 3d1bfca

Browse files
authored
fix(tool): Do not return empty outputSchema (#573)
* fix(tool): Do not return empty `outputSchema` If the output schema is not specify, we do not return it as we break the MCP specification that are expecting the following format: ```json "outputSchema": { "type": "object", "properties": {}, "required": [] } ``` * fix(tool): typo in test
1 parent 35fc389 commit 3d1bfca

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

mcp/tools.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ func (t Tool) MarshalJSON() ([]byte, error) {
607607
return nil, fmt.Errorf("tool %s has both OutputSchema and RawOutputSchema set: %w", t.Name, errToolSchemaConflict)
608608
}
609609
m["outputSchema"] = t.RawOutputSchema
610-
} else {
610+
} else if t.OutputSchema.Type != "" { // If no output schema is specified, do not return anything
611611
m["outputSchema"] = t.OutputSchema
612612
}
613613

mcp/tools_test.go

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -586,27 +586,51 @@ func TestToolWithOutputSchema(t *testing.T) {
586586
Email string `json:"email,omitempty" jsonschema_description:"Email address"`
587587
}
588588

589-
tool := NewTool("test_tool",
590-
WithDescription("Test tool with output schema"),
591-
WithOutputSchema[TestOutput](),
592-
WithString("input", Required()),
593-
)
594-
595-
// Check that RawOutputSchema was set
596-
assert.NotNil(t, tool.OutputSchema)
589+
tests := []struct {
590+
name string
591+
tool Tool
592+
expectedOutputSchema bool
593+
}{
594+
{
595+
name: "default behavior",
596+
tool: NewTool("test_tool",
597+
WithDescription("Test tool with output schema"),
598+
WithOutputSchema[TestOutput](),
599+
WithString("input", Required()),
600+
),
601+
expectedOutputSchema: true,
602+
},
603+
{
604+
name: "no output schema is set",
605+
tool: NewTool("test_tool",
606+
WithDescription("Test tool with no output schema"),
607+
WithString("input", Required()),
608+
),
609+
expectedOutputSchema: false,
610+
},
611+
}
597612

598-
// Marshal and verify structure
599-
data, err := json.Marshal(tool)
600-
assert.NoError(t, err)
613+
for _, tt := range tests {
614+
t.Run(tt.name, func(t *testing.T) {
615+
// Marshal and verify structure
616+
data, err := json.Marshal(tt.tool)
617+
assert.NoError(t, err)
601618

602-
var toolData map[string]any
603-
err = json.Unmarshal(data, &toolData)
604-
assert.NoError(t, err)
619+
var toolData map[string]any
620+
err = json.Unmarshal(data, &toolData)
621+
assert.NoError(t, err)
605622

606-
// Verify outputSchema exists
607-
outputSchema, exists := toolData["outputSchema"]
608-
assert.True(t, exists)
609-
assert.NotNil(t, outputSchema)
623+
// Verify outputSchema exists
624+
outputSchema, exists := toolData["outputSchema"]
625+
if tt.expectedOutputSchema {
626+
assert.True(t, exists)
627+
assert.NotNil(t, outputSchema)
628+
} else {
629+
assert.False(t, exists)
630+
assert.Nil(t, outputSchema)
631+
}
632+
})
633+
}
610634
}
611635

612636
// TestNewToolResultStructured tests that the NewToolResultStructured function

0 commit comments

Comments
 (0)