@@ -229,7 +229,8 @@ describe('CommercetoolsAgentEssentials (ModelContextProtocol)', () => {
229229
230230 expect ( mockCommercetoolsAPIInstance . run ) . toHaveBeenCalledWith (
231231 toolMethod ,
232- handlerArg
232+ handlerArg ,
233+ undefined
233234 ) ;
234235 expect ( result ) . toEqual ( {
235236 content : [
@@ -419,6 +420,8 @@ describe('CommercetoolsAgentEssentials (ModelContextProtocol)', () => {
419420 } ,
420421 } ;
421422
423+ const getConfig = ( opt : object ) => ( { ..._mockConfiguration , ...opt } ) ;
424+
422425 beforeEach ( ( ) => {
423426 // Reset mocks
424427 ( McpServer as jest . Mock ) . mockClear ( ) ;
@@ -467,7 +470,9 @@ describe('CommercetoolsAgentEssentials (ModelContextProtocol)', () => {
467470 ) ;
468471 } ) ;
469472
470- afterAll ( ( ) => {
473+ afterEach ( ( ) => {
474+ ( McpServer as jest . Mock ) . mockClear ( ) ;
475+ ( CommercetoolsAgentEssentials as unknown as jest . Mock ) . mockClear ( ) ;
471476 _mockCommercetoolsAPIInstance . introspect = jest
472477 . fn ( )
473478 . mockImplementation ( function ( ) {
@@ -512,6 +517,159 @@ describe('CommercetoolsAgentEssentials (ModelContextProtocol)', () => {
512517 ) . rejects . toThrow ( / S i m u l a t e d e r r o r i n t h e i n s t r o p s e c t m e t h o d / ) ;
513518 expect ( CommercetoolsAgentEssentials . create ) . toHaveBeenCalled ( ) ;
514519 } ) ;
520+
521+ describe ( '::CustomTools' , ( ) => {
522+ it ( `should not register custom tools if 'customTools' is not provided` , async ( ) => {
523+ const config = getConfig ( { } ) ;
524+ await CommercetoolsAgentEssentials . create ( {
525+ authConfig : {
526+ clientId : 'id' ,
527+ clientSecret : 'secret' ,
528+ authUrl : 'auth' ,
529+ projectKey : 'key' ,
530+ apiUrl : 'api' ,
531+ type : 'client_credentials' ,
532+ } ,
533+ configuration : config ,
534+ } ) ;
535+
536+ expect ( _mockToolMethod ) . toHaveBeenCalled ( ) ;
537+ expect ( _mockToolMethod ) . toHaveBeenCalledTimes ( 1 ) ;
538+
539+ expect ( _mockToolMethod ) . toHaveBeenCalledWith (
540+ 'mcpTool1' ,
541+ expect . any ( String ) ,
542+ expect . any ( Object ) ,
543+ expect . any ( Function )
544+ ) ;
545+ } ) ;
546+
547+ it ( 'should register custom tools if provided' , async ( ) => {
548+ const customTools = [
549+ {
550+ name : 'custom-tool' ,
551+ method : 'custom-test-tool' ,
552+ description : 'custom tool description' ,
553+ parameters : { shape : { key : 'unique-key' } } ,
554+ execute : jest . fn ( ) ,
555+ } ,
556+ ] ;
557+
558+ const config = getConfig ( { customTools} ) ;
559+
560+ await CommercetoolsAgentEssentials . create ( {
561+ authConfig : {
562+ clientId : 'id' ,
563+ clientSecret : 'secret' ,
564+ authUrl : 'auth' ,
565+ projectKey : 'key' ,
566+ apiUrl : 'api' ,
567+ type : 'client_credentials' ,
568+ } ,
569+ configuration : config ,
570+ } ) ;
571+
572+ expect ( _mockToolMethod ) . toHaveBeenCalled ( ) ;
573+ expect ( _mockToolMethod ) . toHaveBeenCalledTimes ( 2 ) ;
574+ expect ( _mockToolMethod ) . toHaveBeenCalledWith (
575+ 'custom-test-tool' ,
576+ expect . any ( String ) ,
577+ expect . any ( Object ) ,
578+ expect . any ( Function )
579+ ) ;
580+ } ) ;
581+
582+ it ( 'should throw an error if the `customTools` provided is not an array' , ( ) => {
583+ const customTools = { } ;
584+ const config = getConfig ( { customTools} ) ;
585+
586+ jest . spyOn ( CommercetoolsAgentEssentials , 'create' ) ;
587+
588+ expect ( CommercetoolsAgentEssentials . create ) . toHaveBeenCalled ( ) ;
589+ expect (
590+ CommercetoolsAgentEssentials . create ( {
591+ authConfig : {
592+ clientId : 'id' ,
593+ clientSecret : 'secret' ,
594+ authUrl : 'auth' ,
595+ projectKey : 'key' ,
596+ apiUrl : 'api' ,
597+ type : 'client_credentials' ,
598+ } ,
599+ configuration : config ,
600+ } )
601+ ) . rejects . toThrow (
602+ `Tool Error: 'customTools' must be an array of tools`
603+ ) ;
604+ } ) ;
605+
606+ it ( `should throw an error if a tool's 'execute' function is not provided` , ( ) => {
607+ const customTools = [
608+ {
609+ name : 'custom-tool-no-exec-fn' ,
610+ method : 'custom-test-tool-exec-fn' ,
611+ description : 'custom tool description' ,
612+ parameters : { shape : { key : 'unique-key' } } ,
613+ } ,
614+ ] ;
615+
616+ const getConfig = ( opt : object ) => ( { ..._mockConfiguration , ...opt } ) ;
617+ const config = getConfig ( { customTools} ) ;
618+
619+ jest . spyOn ( CommercetoolsAgentEssentials , 'create' ) ;
620+
621+ expect ( CommercetoolsAgentEssentials . create ) . toHaveBeenCalled ( ) ;
622+ expect (
623+ CommercetoolsAgentEssentials . create ( {
624+ authConfig : {
625+ clientId : 'id' ,
626+ clientSecret : 'secret' ,
627+ authUrl : 'auth' ,
628+ projectKey : 'key' ,
629+ apiUrl : 'api' ,
630+ type : 'client_credentials' ,
631+ } ,
632+ configuration : config ,
633+ } )
634+ ) . rejects . toThrow (
635+ `Tool Error: Please provide an 'execute' function for '${ customTools [ 0 ] . name } ' tool.`
636+ ) ;
637+ } ) ;
638+
639+ it ( `should throw an error if a tool's 'execute' property is not a function` , ( ) => {
640+ const customTools = [
641+ {
642+ name : 'custom-tool-no-exec-fn' ,
643+ method : 'custom-test-tool-exec-fn' ,
644+ description : 'custom tool description' ,
645+ parameters : { shape : { key : 'unique-key' } } ,
646+ execute : 'not-a-function' ,
647+ } ,
648+ ] ;
649+
650+ const getConfig = ( opt : object ) => ( { ..._mockConfiguration , ...opt } ) ;
651+ const config = getConfig ( { customTools} ) ;
652+
653+ jest . spyOn ( CommercetoolsAgentEssentials , 'create' ) ;
654+
655+ expect ( CommercetoolsAgentEssentials . create ) . toHaveBeenCalled ( ) ;
656+ expect (
657+ CommercetoolsAgentEssentials . create ( {
658+ authConfig : {
659+ clientId : 'id' ,
660+ clientSecret : 'secret' ,
661+ authUrl : 'auth' ,
662+ projectKey : 'key' ,
663+ apiUrl : 'api' ,
664+ type : 'client_credentials' ,
665+ } ,
666+ configuration : config ,
667+ } )
668+ ) . rejects . toThrow (
669+ `Tool Error: Please provide an 'execute' function for '${ customTools [ 0 ] . name } ' tool.`
670+ ) ;
671+ } ) ;
672+ } ) ;
515673 } ) ;
516674
517675 describe ( '::registerTools with dynamicToolLoadingThreshold' , ( ) => {
0 commit comments