@@ -242,6 +242,108 @@ func TestToolWithObjectAndArray(t *testing.T) {
242242 assert .Contains (t , required , "books" )
243243}
244244
245+ func TestToolWithAny (t * testing.T ) {
246+ const desc = "Can be any value: string, number, bool, object, or slice"
247+
248+ tool := NewTool ("any-tool" ,
249+ WithDescription ("A tool with an 'any' type property" ),
250+ WithAny ("data" ,
251+ Description (desc ),
252+ Required (),
253+ ),
254+ )
255+
256+ data , err := json .Marshal (tool )
257+ assert .NoError (t , err )
258+
259+ var result map [string ]any
260+ err = json .Unmarshal (data , & result )
261+ assert .NoError (t , err )
262+
263+ assert .Equal (t , "any-tool" , result ["name" ])
264+
265+ schema , ok := result ["inputSchema" ].(map [string ]any )
266+ assert .True (t , ok )
267+ assert .Equal (t , "object" , schema ["type" ])
268+
269+ properties , ok := schema ["properties" ].(map [string ]any )
270+ assert .True (t , ok )
271+
272+ dataProp , ok := properties ["data" ].(map [string ]any )
273+ assert .True (t , ok )
274+ _ , typeExists := dataProp ["type" ]
275+ assert .False (t , typeExists , "The 'any' type property should not have a 'type' field" )
276+ assert .Equal (t , desc , dataProp ["description" ])
277+
278+ required , ok := schema ["required" ].([]any )
279+ assert .True (t , ok )
280+ assert .Contains (t , required , "data" )
281+
282+ type testStruct struct {
283+ A string `json:"A"`
284+ }
285+ testCases := []struct {
286+ description string
287+ arg any
288+ expect any
289+ }{{
290+ description : "string" ,
291+ arg : "hello world" ,
292+ expect : "hello world" ,
293+ }, {
294+ description : "integer" ,
295+ arg : 123 ,
296+ expect : float64 (123 ), // JSON unmarshals numbers to float64
297+ }, {
298+ description : "float" ,
299+ arg : 3.14 ,
300+ expect : 3.14 ,
301+ }, {
302+ description : "boolean" ,
303+ arg : true ,
304+ expect : true ,
305+ }, {
306+ description : "object" ,
307+ arg : map [string ]any {"key" : "value" },
308+ expect : map [string ]any {"key" : "value" },
309+ }, {
310+ description : "slice" ,
311+ arg : []any {1 , "two" , false },
312+ expect : []any {float64 (1 ), "two" , false },
313+ }, {
314+ description : "struct" ,
315+ arg : testStruct {A : "B" },
316+ expect : map [string ]any {"A" : "B" },
317+ }}
318+
319+ for _ , tc := range testCases {
320+ t .Run (fmt .Sprintf ("with_%s" , tc .description ), func (t * testing.T ) {
321+ req := CallToolRequest {
322+ Request : Request {},
323+ Params : CallToolParams {
324+ Name : "any-tool" ,
325+ Arguments : map [string ]any {
326+ "data" : tc .arg ,
327+ },
328+ },
329+ }
330+
331+ // Marshal and unmarshal to simulate a real request
332+ reqBytes , err := json .Marshal (req )
333+ assert .NoError (t , err )
334+
335+ var unmarshaledReq CallToolRequest
336+ err = json .Unmarshal (reqBytes , & unmarshaledReq )
337+ assert .NoError (t , err )
338+
339+ args := unmarshaledReq .GetArguments ()
340+ value , ok := args ["data" ]
341+ assert .True (t , ok )
342+ assert .Equal (t , tc .expect , value )
343+ })
344+ }
345+ }
346+
245347func TestParseToolCallToolRequest (t * testing.T ) {
246348 request := CallToolRequest {}
247349 request .Params .Name = "test-tool"
0 commit comments