Skip to content

Commit 0523523

Browse files
Add AdditionalProperties to ToolInputSchema (#678)
- Add AdditionalProperties field to ToolArgumentsSchema struct - Update MarshalJSON to include additionalProperties in output - Add WithSchemaAdditionalProperties ToolOption function - Add comprehensive tests for marshal/unmarshal and ToolOption Fixes #672
1 parent a2e00ab commit 0523523

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

mcp/tools.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,10 +635,11 @@ func (t Tool) MarshalJSON() ([]byte, error) {
635635

636636
// ToolArgumentsSchema represents a JSON Schema for tool arguments.
637637
type ToolArgumentsSchema struct {
638-
Defs map[string]any `json:"$defs,omitempty"`
639-
Type string `json:"type"`
640-
Properties map[string]any `json:"properties,omitempty"`
641-
Required []string `json:"required,omitempty"`
638+
Defs map[string]any `json:"$defs,omitempty"`
639+
Type string `json:"type"`
640+
Properties map[string]any `json:"properties,omitempty"`
641+
Required []string `json:"required,omitempty"`
642+
AdditionalProperties any `json:"additionalProperties,omitempty"`
642643
}
643644

644645
type ToolInputSchema ToolArgumentsSchema // For retro-compatibility
@@ -662,6 +663,10 @@ func (tis ToolArgumentsSchema) MarshalJSON() ([]byte, error) {
662663
m["required"] = tis.Required
663664
}
664665

666+
if tis.AdditionalProperties != nil {
667+
m["additionalProperties"] = tis.AdditionalProperties
668+
}
669+
665670
return json.Marshal(m)
666671
}
667672

@@ -919,6 +924,15 @@ func WithOpenWorldHintAnnotation(value bool) ToolOption {
919924
}
920925
}
921926

927+
// WithSchemaAdditionalProperties sets the additionalProperties field on the tool's input schema.
928+
// It accepts false (disallow extra properties), true (allow any), or a schema map
929+
// to validate additional properties against.
930+
func WithSchemaAdditionalProperties(schema any) ToolOption {
931+
return func(t *Tool) {
932+
t.InputSchema.AdditionalProperties = schema
933+
}
934+
}
935+
922936
//
923937
// Common Property Options
924938
//

mcp/tools_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,3 +1693,75 @@ func TestWithToolIcons(t *testing.T) {
16931693

16941694
assert.Equal(t, icons, tool.Icons)
16951695
}
1696+
1697+
func TestToolArgumentsSchema_UnmarshalWithAdditionalPropertiesFalse(t *testing.T) {
1698+
jsonData := `{
1699+
"type": "object",
1700+
"properties": {
1701+
"name": {"type": "string"}
1702+
},
1703+
"additionalProperties": false
1704+
}`
1705+
1706+
var schema ToolArgumentsSchema
1707+
err := json.Unmarshal([]byte(jsonData), &schema)
1708+
assert.NoError(t, err)
1709+
1710+
assert.Equal(t, "object", schema.Type)
1711+
assert.Contains(t, schema.Properties, "name")
1712+
assert.Equal(t, false, schema.AdditionalProperties)
1713+
}
1714+
1715+
func TestToolArgumentsSchema_UnmarshalWithAdditionalPropertiesSchema(t *testing.T) {
1716+
jsonData := `{
1717+
"type": "object",
1718+
"properties": {
1719+
"name": {"type": "string"}
1720+
},
1721+
"additionalProperties": {"type": "string"}
1722+
}`
1723+
1724+
var schema ToolArgumentsSchema
1725+
err := json.Unmarshal([]byte(jsonData), &schema)
1726+
assert.NoError(t, err)
1727+
1728+
assert.Equal(t, "object", schema.Type)
1729+
additionalProps, ok := schema.AdditionalProperties.(map[string]any)
1730+
assert.True(t, ok)
1731+
assert.Equal(t, "string", additionalProps["type"])
1732+
}
1733+
1734+
func TestToolArgumentsSchema_MarshalWithAdditionalProperties(t *testing.T) {
1735+
schema := ToolArgumentsSchema{
1736+
Type: "object",
1737+
AdditionalProperties: false,
1738+
}
1739+
1740+
data, err := json.Marshal(schema)
1741+
assert.NoError(t, err)
1742+
assert.Contains(t, string(data), `"additionalProperties":false`)
1743+
}
1744+
1745+
func TestToolArgumentsSchema_MarshalOmitsNilAdditionalProperties(t *testing.T) {
1746+
schema := ToolArgumentsSchema{
1747+
Type: "object",
1748+
AdditionalProperties: nil,
1749+
}
1750+
1751+
data, err := json.Marshal(schema)
1752+
assert.NoError(t, err)
1753+
assert.NotContains(t, string(data), "additionalProperties")
1754+
}
1755+
1756+
func TestWithSchemaAdditionalProperties(t *testing.T) {
1757+
tool := NewTool(
1758+
"strict-tool",
1759+
WithSchemaAdditionalProperties(false),
1760+
)
1761+
1762+
assert.Equal(t, false, tool.InputSchema.AdditionalProperties)
1763+
1764+
data, err := json.Marshal(tool)
1765+
assert.NoError(t, err)
1766+
assert.Contains(t, string(data), `"additionalProperties":false`)
1767+
}

0 commit comments

Comments
 (0)