@@ -4406,4 +4406,113 @@ describe("elicitInput()", () => {
4406
4406
expect ( toolsResult . tools ) . toHaveLength ( 2 ) ;
4407
4407
expect ( toolsResult . tools . map ( t => t . name ) . sort ( ) ) . toEqual ( [ "test2" , "tool1" ] ) ;
4408
4408
} ) ;
4409
+
4410
+ /***
4411
+ * Test: registerTools() bulk method
4412
+ */
4413
+ test ( "should register multiple tools with single notification using registerTools()" , async ( ) => {
4414
+ const mcpServer = new McpServer ( {
4415
+ name : "test server" ,
4416
+ version : "1.0" ,
4417
+ } ) ;
4418
+
4419
+ // Register first tool to establish capabilities
4420
+ mcpServer . tool ( "initial" , async ( ) => ( {
4421
+ content : [ { type : "text" , text : "Initial" } ]
4422
+ } ) ) ;
4423
+
4424
+ const notifications : Notification [ ] = [ ]
4425
+ const client = new Client ( {
4426
+ name : "test client" ,
4427
+ version : "1.0" ,
4428
+ } ) ;
4429
+ client . fallbackNotificationHandler = async ( notification ) => {
4430
+ notifications . push ( notification )
4431
+ }
4432
+
4433
+ const [ clientTransport , serverTransport ] =
4434
+ InMemoryTransport . createLinkedPair ( ) ;
4435
+
4436
+ await Promise . all ( [
4437
+ client . connect ( clientTransport ) ,
4438
+ mcpServer . connect ( serverTransport ) ,
4439
+ ] ) ;
4440
+
4441
+ // Clear initial notifications
4442
+ notifications . length = 0 ;
4443
+
4444
+ // Register multiple tools at once using the bulk method
4445
+ const tools = mcpServer . registerTools ( [
4446
+ {
4447
+ name : "bulk1" ,
4448
+ config : {
4449
+ title : "Bulk Tool 1" ,
4450
+ description : "First bulk tool"
4451
+ } ,
4452
+ callback : async ( ) => ( {
4453
+ content : [ { type : "text" as const , text : "Bulk 1" } ]
4454
+ } )
4455
+ } ,
4456
+ {
4457
+ name : "bulk2" ,
4458
+ config : {
4459
+ title : "Bulk Tool 2" ,
4460
+ description : "Second bulk tool"
4461
+ } ,
4462
+ callback : async ( ) => ( {
4463
+ content : [ { type : "text" as const , text : "Bulk 2" } ]
4464
+ } )
4465
+ } ,
4466
+ {
4467
+ name : "bulk3" ,
4468
+ config : {
4469
+ description : "Third bulk tool"
4470
+ } ,
4471
+ callback : async ( ) => ( {
4472
+ content : [ { type : "text" as const , text : "Bulk 3" } ]
4473
+ } )
4474
+ }
4475
+ ] ) ;
4476
+
4477
+ // Yield event loop to let notifications process
4478
+ await new Promise ( process . nextTick ) ;
4479
+
4480
+ // Should have sent exactly ONE notification for all three tools
4481
+ expect ( notifications ) . toHaveLength ( 1 ) ;
4482
+ expect ( notifications [ 0 ] ) . toMatchObject ( {
4483
+ method : "notifications/tools/list_changed" ,
4484
+ } ) ;
4485
+
4486
+ // Should return array of registered tools
4487
+ expect ( tools ) . toHaveLength ( 3 ) ;
4488
+ expect ( tools [ 0 ] . title ) . toBe ( "Bulk Tool 1" ) ;
4489
+ expect ( tools [ 1 ] . title ) . toBe ( "Bulk Tool 2" ) ;
4490
+ expect ( tools [ 2 ] . title ) . toBeUndefined ( ) ; // No title provided
4491
+
4492
+ // Verify all tools are registered and functional
4493
+ const toolsResult = await client . request (
4494
+ { method : "tools/list" } ,
4495
+ ListToolsResultSchema ,
4496
+ ) ;
4497
+ expect ( toolsResult . tools ) . toHaveLength ( 4 ) ; // initial + 3 bulk tools
4498
+
4499
+ const toolNames = toolsResult . tools . map ( t => t . name ) . sort ( ) ;
4500
+ expect ( toolNames ) . toEqual ( [ "bulk1" , "bulk2" , "bulk3" , "initial" ] ) ;
4501
+
4502
+ // Test that the tools actually work
4503
+ const callResult = await client . request (
4504
+ {
4505
+ method : "tools/call" ,
4506
+ params : {
4507
+ name : "bulk1" ,
4508
+ arguments : { }
4509
+ }
4510
+ } ,
4511
+ CallToolResultSchema ,
4512
+ ) ;
4513
+ expect ( callResult . content [ 0 ] ) . toMatchObject ( {
4514
+ type : "text" ,
4515
+ text : "Bulk 1"
4516
+ } ) ;
4517
+ } ) ;
4409
4518
} ) ;
0 commit comments