1515package http
1616
1717import (
18- "bytes"
18+
1919 "context"
20+ "os"
2021 "encoding/json"
2122 "fmt"
2223 "io"
@@ -325,178 +326,34 @@ func TestHttpToolEndpoints(t *testing.T) {
325326 }
326327
327328 // Run tests
328- tests . RunToolGetTest ( t )
329- tests .RunToolInvokeTest (t , `"hello world"` , tests .DisableArrayTest ())
329+
330+ tests .RunMCPToolInvokeTest (t , `"hello world"` , tests .DisableArrayTest ())
330331 runAdvancedHTTPInvokeTest (t )
331332 runQueryParamInvokeTest (t )
332333}
333334
334- // runQueryParamInvokeTest runs the tool invoke endpoint for the query param test tool
335335func runQueryParamInvokeTest (t * testing.T ) {
336- invokeTcs := []struct {
337- name string
338- api string
339- requestBody io.Reader
340- want string
341- isErr bool
342- }{
343- {
344- name : "invoke query-param-tool (optional omitted)" ,
345- api : "http://127.0.0.1:5000/api/tool/my-query-param-tool/invoke" ,
346- requestBody : bytes .NewBuffer ([]byte (`{"reqId": "test1"}` )),
347- want : `"reqId=test1"` ,
348- },
349- {
350- name : "invoke query-param-tool (some optional nil)" ,
351- api : "http://127.0.0.1:5000/api/tool/my-query-param-tool/invoke" ,
352- requestBody : bytes .NewBuffer ([]byte (`{"reqId": "test2", "page": "5", "filter": null}` )),
353- want : `"page=5\u0026reqId=test2"` , // 'filter' omitted
354- },
355- {
356- name : "invoke query-param-tool (some optional absent)" ,
357- api : "http://127.0.0.1:5000/api/tool/my-query-param-tool/invoke" ,
358- requestBody : bytes .NewBuffer ([]byte (`{"reqId": "test2", "page": "5"}` )),
359- want : `"page=5\u0026reqId=test2"` , // 'filter' omitted
360- },
361- {
362- name : "invoke query-param-tool (required param nil)" ,
363- api : "http://127.0.0.1:5000/api/tool/my-query-param-tool/invoke" ,
364- requestBody : bytes .NewBuffer ([]byte (`{"reqId": null, "page": "1"}` )),
365- want : `{"error":"parameter \"reqId\" is required"}` ,
366- },
367- }
368- for _ , tc := range invokeTcs {
369- t .Run (tc .name , func (t * testing.T ) {
370- // Send Tool invocation request
371- req , err := http .NewRequest (http .MethodPost , tc .api , tc .requestBody )
372- if err != nil {
373- t .Fatalf ("unable to create request: %s" , err )
374- }
375- req .Header .Add ("Content-type" , "application/json" )
376-
377- resp , err := http .DefaultClient .Do (req )
378- if err != nil {
379- t .Fatalf ("unable to send request: %s" , err )
380- }
381- defer resp .Body .Close ()
382-
383- if resp .StatusCode != http .StatusOK {
384- bodyBytes , _ := io .ReadAll (resp .Body )
385- t .Fatalf ("response status code is not 200, got %d: %s" , resp .StatusCode , string (bodyBytes ))
386- }
387-
388- // Check response body
389- var body map [string ]interface {}
390- err = json .NewDecoder (resp .Body ).Decode (& body )
391- if err != nil {
392- t .Fatalf ("error parsing response body: %v" , err )
393- }
394- got , ok := body ["result" ].(string )
395- if ! ok {
396- bodyBytes , _ := json .Marshal (body )
397- t .Fatalf ("unable to find result in response body, got: %s" , string (bodyBytes ))
398- }
399-
400- if got != tc .want {
401- t .Fatalf ("unexpected value: got %q, want %q" , got , tc .want )
402- }
403- })
404- }
336+ t .Run ("invoke query-param-tool (optional omitted)" , func (t * testing.T ) {
337+ tests .RunMCPToolInvokeParametersTest (t , "my-query-param-tool" , []byte (`{"reqId": "test1"}` ), `"reqId=test1"` )
338+ })
339+ t .Run ("invoke query-param-tool (some optional nil)" , func (t * testing.T ) {
340+ tests .RunMCPToolInvokeParametersTest (t , "my-query-param-tool" , []byte (`{"reqId": "test2", "page": "5", "filter": null}` ), `"page=5\u0026reqId=test2"` )
341+ })
342+ t .Run ("invoke query-param-tool (some optional absent)" , func (t * testing.T ) {
343+ tests .RunMCPToolInvokeParametersTest (t , "my-query-param-tool" , []byte (`{"reqId": "test2", "page": "5"}` ), `"page=5\u0026reqId=test2"` )
344+ })
345+ t .Run ("invoke query-param-tool (required param nil)" , func (t * testing.T ) {
346+ tests .RunMCPToolInvokeParametersTest (t , "my-query-param-tool" , []byte (`{"reqId": null, "page": "1"}` ), `parameter "reqId" is required` )
347+ })
405348}
406349
407350func runAdvancedHTTPInvokeTest (t * testing.T ) {
408- // Test HTTP tool invoke endpoint
409- invokeTcs := []struct {
410- name string
411- api string
412- requestHeader map [string ]string
413- requestBody func () io.Reader
414- want string
415- isAgentErr bool
416- }{
417- {
418- name : "invoke my-advanced-tool" ,
419- api : "http://127.0.0.1:5000/api/tool/my-advanced-tool/invoke" ,
420- requestHeader : map [string ]string {},
421- requestBody : func () io.Reader {
422- return bytes .NewBuffer ([]byte (`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 3, "path": "tool3", "country": "US", "X-Other-Header": "test"}` ))
423- },
424- want : `"hello world"` ,
425- isAgentErr : false ,
426- },
427- {
428- name : "invoke my-advanced-tool with wrong params" ,
429- api : "http://127.0.0.1:5000/api/tool/my-advanced-tool/invoke" ,
430- requestHeader : map [string ]string {},
431- requestBody : func () io.Reader {
432- return bytes .NewBuffer ([]byte (`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 4, "path": "tool3", "country": "US", "X-Other-Header": "test"}` ))
433- },
434- want : "error processing request: unexpected status code: 400, response body: Bad Request: Incorrect query parameter: id, actual: [2 1 4]" ,
435- isAgentErr : true ,
436- },
437- }
438-
439- for _ , tc := range invokeTcs {
440- t .Run (tc .name , func (t * testing.T ) {
441- req , err := http .NewRequest (http .MethodPost , tc .api , tc .requestBody ())
442- if err != nil {
443- t .Fatalf ("unable to create request: %s" , err )
444- }
445- req .Header .Add ("Content-type" , "application/json" )
446- for k , v := range tc .requestHeader {
447- req .Header .Add (k , v )
448- }
449-
450- resp , err := http .DefaultClient .Do (req )
451- if err != nil {
452- t .Fatalf ("unable to send request: %s" , err )
453- }
454- defer resp .Body .Close ()
455-
456- // As you noted, the toolbox wraps errors in a 200 OK
457- if resp .StatusCode != http .StatusOK {
458- bodyBytes , _ := io .ReadAll (resp .Body )
459- t .Fatalf ("expected status 200 from toolbox, got %d: %s" , resp .StatusCode , string (bodyBytes ))
460- }
461-
462- // Decode the response body into a map
463- var body map [string ]any
464- if err := json .NewDecoder (resp .Body ).Decode (& body ); err != nil {
465- t .Fatalf ("failed to decode response: %v" , err )
466- }
467-
468- if tc .isAgentErr {
469- resStr , ok := body ["result" ].(string )
470- if ! ok {
471- t .Fatalf ("expected 'result' field as string in response body, got: %v" , body )
472- }
473-
474- var resMap map [string ]any
475- if err := json .Unmarshal ([]byte (resStr ), & resMap ); err != nil {
476- t .Fatalf ("failed to unmarshal result string: %v" , err )
477- }
478-
479- gotErr , ok := resMap ["error" ].(string )
480- if ! ok {
481- t .Fatalf ("expected 'error' field inside result, got: %v" , resMap )
482- }
483-
484- if ! strings .Contains (gotErr , tc .want ) {
485- t .Fatalf ("unexpected error message: got %q, want it to contain %q" , gotErr , tc .want )
486- }
487- } else {
488- got , ok := body ["result" ].(string )
489- if ! ok {
490- resBytes , _ := json .Marshal (body ["result" ])
491- got = string (resBytes )
492- }
493-
494- if got != tc .want {
495- t .Fatalf ("unexpected result: got %q, want %q" , got , tc .want )
496- }
497- }
498- })
499- }
351+ t .Run ("invoke my-advanced-tool" , func (t * testing.T ) {
352+ tests .RunMCPToolInvokeParametersTest (t , "my-advanced-tool" , []byte (`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 3, "path": "tool3", "country": "US", "X-Other-Header": "test"}` ), `"hello world"` )
353+ })
354+ t .Run ("invoke my-advanced-tool with wrong params" , func (t * testing.T ) {
355+ tests .RunMCPToolInvokeParametersTest (t , "my-advanced-tool" , []byte (`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 4, "path": "tool3", "country": "US", "X-Other-Header": "test"}` ), `unexpected status code: 400` )
356+ })
500357}
501358
502359// getHTTPToolsConfig returns a mock HTTP tool's config file
@@ -509,6 +366,11 @@ func getHTTPToolsConfig(sourceConfig map[string]any, toolType string) map[string
509366 otherSourceConfig ["headers" ] = map [string ]string {"X-Custom-Header" : "unexpected" , "Content-Type" : "application/json" }
510367 otherSourceConfig ["queryParams" ] = map [string ]any {"id" : 1 , "name" : "Sid" }
511368
369+ clientId := os .Getenv ("CLIENT_ID" )
370+ if clientId == "" {
371+ clientId = "test-client-id"
372+ }
373+
512374 toolsFile := map [string ]any {
513375 "sources" : map [string ]any {
514376 "my-instance" : sourceConfig ,
@@ -517,7 +379,7 @@ func getHTTPToolsConfig(sourceConfig map[string]any, toolType string) map[string
517379 "authServices" : map [string ]any {
518380 "my-google-auth" : map [string ]any {
519381 "type" : "google" ,
520- "clientId" : tests . ClientId ,
382+ "clientId" : clientId ,
521383 },
522384 },
523385 "tools" : map [string ]any {
0 commit comments