@@ -12,6 +12,7 @@ import {
1212 ListResourcesRequestSchema ,
1313 ListToolsRequestSchema ,
1414 ListToolsResultSchema ,
15+ ListPromptsRequestSchema ,
1516 CallToolRequestSchema ,
1617 CallToolResultSchema ,
1718 CreateMessageRequestSchema ,
@@ -21,7 +22,9 @@ import {
2122 ErrorCode ,
2223 McpError ,
2324 CreateTaskResultSchema ,
24- Tool
25+ Tool ,
26+ Prompt ,
27+ Resource
2528} from '../types.js' ;
2629import { Transport } from '../shared/transport.js' ;
2730import { Server } from '../server/index.js' ;
@@ -1275,9 +1278,11 @@ test('should handle tool list changed notification with auto refresh', async ()
12751278 version : '1.0.0'
12761279 } ,
12771280 {
1278- toolListChangedOptions : {
1279- onToolListChanged : ( err , tools ) => {
1280- notifications . push ( [ err , tools ] ) ;
1281+ listChanged : {
1282+ tools : {
1283+ onChanged : ( err , tools ) => {
1284+ notifications . push ( [ err , tools ] ) ;
1285+ }
12811286 }
12821287 }
12831288 }
@@ -1361,11 +1366,13 @@ test('should handle tool list changed notification with manual refresh', async (
13611366 version : '1.0.0'
13621367 } ,
13631368 {
1364- toolListChangedOptions : {
1365- autoRefresh : false ,
1366- debounceMs : 0 ,
1367- onToolListChanged : ( err , tools ) => {
1368- notifications . push ( [ err , tools ] ) ;
1369+ listChanged : {
1370+ tools : {
1371+ autoRefresh : false ,
1372+ debounceMs : 0 ,
1373+ onChanged : ( err , tools ) => {
1374+ notifications . push ( [ err , tools ] ) ;
1375+ }
13691376 }
13701377 }
13711378 }
@@ -1394,15 +1401,266 @@ test('should handle tool list changed notification with manual refresh', async (
13941401 } ) ) ;
13951402 await server . sendToolListChanged ( ) ;
13961403
1397- // Wait for the debounced notifications to be processed
1398- await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
1404+ // Wait for the notifications to be processed (no debounce)
1405+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
13991406
14001407 // Should be 1 notification with no tool data because autoRefresh is false
14011408 expect ( notifications ) . toHaveLength ( 1 ) ;
14021409 expect ( notifications [ 0 ] [ 0 ] ) . toBeNull ( ) ;
14031410 expect ( notifications [ 0 ] [ 1 ] ) . toBeNull ( ) ;
14041411} ) ;
14051412
1413+ /***
1414+ * Test: Handle Prompt List Changed Notifications
1415+ */
1416+ test ( 'should handle prompt list changed notification with auto refresh' , async ( ) => {
1417+ const notifications : [ Error | null , Prompt [ ] | null ] [ ] = [ ] ;
1418+
1419+ const server = new Server (
1420+ {
1421+ name : 'test-server' ,
1422+ version : '1.0.0'
1423+ } ,
1424+ {
1425+ capabilities : {
1426+ prompts : {
1427+ listChanged : true
1428+ }
1429+ }
1430+ }
1431+ ) ;
1432+
1433+ // Set up server handlers
1434+ server . setRequestHandler ( InitializeRequestSchema , async request => ( {
1435+ protocolVersion : request . params . protocolVersion ,
1436+ capabilities : {
1437+ prompts : {
1438+ listChanged : true
1439+ }
1440+ } ,
1441+ serverInfo : {
1442+ name : 'test-server' ,
1443+ version : '1.0.0'
1444+ }
1445+ } ) ) ;
1446+
1447+ server . setRequestHandler ( ListPromptsRequestSchema , async ( ) => ( {
1448+ prompts : [ ]
1449+ } ) ) ;
1450+
1451+ // Configure listChanged handler in constructor
1452+ const client = new Client (
1453+ {
1454+ name : 'test-client' ,
1455+ version : '1.0.0'
1456+ } ,
1457+ {
1458+ listChanged : {
1459+ prompts : {
1460+ onChanged : ( err , prompts ) => {
1461+ notifications . push ( [ err , prompts ] ) ;
1462+ }
1463+ }
1464+ }
1465+ }
1466+ ) ;
1467+
1468+ const [ clientTransport , serverTransport ] = InMemoryTransport . createLinkedPair ( ) ;
1469+
1470+ await Promise . all ( [ client . connect ( clientTransport ) , server . connect ( serverTransport ) ] ) ;
1471+
1472+ const result1 = await client . listPrompts ( ) ;
1473+ expect ( result1 . prompts ) . toHaveLength ( 0 ) ;
1474+
1475+ // Update the prompts list
1476+ server . setRequestHandler ( ListPromptsRequestSchema , async ( ) => ( {
1477+ prompts : [
1478+ {
1479+ name : 'test-prompt' ,
1480+ description : 'A test prompt'
1481+ }
1482+ ]
1483+ } ) ) ;
1484+ await server . sendPromptListChanged ( ) ;
1485+
1486+ // Wait for the debounced notifications to be processed
1487+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
1488+
1489+ // Should be 1 notification with 1 prompt because autoRefresh is true
1490+ expect ( notifications ) . toHaveLength ( 1 ) ;
1491+ expect ( notifications [ 0 ] [ 0 ] ) . toBeNull ( ) ;
1492+ expect ( notifications [ 0 ] [ 1 ] ) . toHaveLength ( 1 ) ;
1493+ expect ( notifications [ 0 ] [ 1 ] ?. [ 0 ] . name ) . toBe ( 'test-prompt' ) ;
1494+ } ) ;
1495+
1496+ /***
1497+ * Test: Handle Resource List Changed Notifications
1498+ */
1499+ test ( 'should handle resource list changed notification with auto refresh' , async ( ) => {
1500+ const notifications : [ Error | null , Resource [ ] | null ] [ ] = [ ] ;
1501+
1502+ const server = new Server (
1503+ {
1504+ name : 'test-server' ,
1505+ version : '1.0.0'
1506+ } ,
1507+ {
1508+ capabilities : {
1509+ resources : {
1510+ listChanged : true
1511+ }
1512+ }
1513+ }
1514+ ) ;
1515+
1516+ // Set up server handlers
1517+ server . setRequestHandler ( InitializeRequestSchema , async request => ( {
1518+ protocolVersion : request . params . protocolVersion ,
1519+ capabilities : {
1520+ resources : {
1521+ listChanged : true
1522+ }
1523+ } ,
1524+ serverInfo : {
1525+ name : 'test-server' ,
1526+ version : '1.0.0'
1527+ }
1528+ } ) ) ;
1529+
1530+ server . setRequestHandler ( ListResourcesRequestSchema , async ( ) => ( {
1531+ resources : [ ]
1532+ } ) ) ;
1533+
1534+ // Configure listChanged handler in constructor
1535+ const client = new Client (
1536+ {
1537+ name : 'test-client' ,
1538+ version : '1.0.0'
1539+ } ,
1540+ {
1541+ listChanged : {
1542+ resources : {
1543+ onChanged : ( err , resources ) => {
1544+ notifications . push ( [ err , resources ] ) ;
1545+ }
1546+ }
1547+ }
1548+ }
1549+ ) ;
1550+
1551+ const [ clientTransport , serverTransport ] = InMemoryTransport . createLinkedPair ( ) ;
1552+
1553+ await Promise . all ( [ client . connect ( clientTransport ) , server . connect ( serverTransport ) ] ) ;
1554+
1555+ const result1 = await client . listResources ( ) ;
1556+ expect ( result1 . resources ) . toHaveLength ( 0 ) ;
1557+
1558+ // Update the resources list
1559+ server . setRequestHandler ( ListResourcesRequestSchema , async ( ) => ( {
1560+ resources : [
1561+ {
1562+ uri : 'file:///test.txt' ,
1563+ name : 'test-resource' ,
1564+ description : 'A test resource'
1565+ }
1566+ ]
1567+ } ) ) ;
1568+ await server . sendResourceListChanged ( ) ;
1569+
1570+ // Wait for the debounced notifications to be processed
1571+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
1572+
1573+ // Should be 1 notification with 1 resource because autoRefresh is true
1574+ expect ( notifications ) . toHaveLength ( 1 ) ;
1575+ expect ( notifications [ 0 ] [ 0 ] ) . toBeNull ( ) ;
1576+ expect ( notifications [ 0 ] [ 1 ] ) . toHaveLength ( 1 ) ;
1577+ expect ( notifications [ 0 ] [ 1 ] ?. [ 0 ] . name ) . toBe ( 'test-resource' ) ;
1578+ } ) ;
1579+
1580+ /***
1581+ * Test: Handle Multiple List Changed Handlers
1582+ */
1583+ test ( 'should handle multiple list changed handlers configured together' , async ( ) => {
1584+ const toolNotifications : [ Error | null , Tool [ ] | null ] [ ] = [ ] ;
1585+ const promptNotifications : [ Error | null , Prompt [ ] | null ] [ ] = [ ] ;
1586+
1587+ const server = new Server (
1588+ {
1589+ name : 'test-server' ,
1590+ version : '1.0.0'
1591+ } ,
1592+ {
1593+ capabilities : {
1594+ tools : { listChanged : true } ,
1595+ prompts : { listChanged : true }
1596+ }
1597+ }
1598+ ) ;
1599+
1600+ // Set up server handlers
1601+ server . setRequestHandler ( InitializeRequestSchema , async request => ( {
1602+ protocolVersion : request . params . protocolVersion ,
1603+ capabilities : {
1604+ tools : { listChanged : true } ,
1605+ prompts : { listChanged : true }
1606+ } ,
1607+ serverInfo : {
1608+ name : 'test-server' ,
1609+ version : '1.0.0'
1610+ }
1611+ } ) ) ;
1612+
1613+ server . setRequestHandler ( ListToolsRequestSchema , async ( ) => ( {
1614+ tools : [ { name : 'tool-1' , inputSchema : { type : 'object' } } ]
1615+ } ) ) ;
1616+
1617+ server . setRequestHandler ( ListPromptsRequestSchema , async ( ) => ( {
1618+ prompts : [ { name : 'prompt-1' } ]
1619+ } ) ) ;
1620+
1621+ // Configure multiple listChanged handlers in constructor
1622+ const client = new Client (
1623+ {
1624+ name : 'test-client' ,
1625+ version : '1.0.0'
1626+ } ,
1627+ {
1628+ listChanged : {
1629+ tools : {
1630+ debounceMs : 0 ,
1631+ onChanged : ( err , tools ) => {
1632+ toolNotifications . push ( [ err , tools ] ) ;
1633+ }
1634+ } ,
1635+ prompts : {
1636+ debounceMs : 0 ,
1637+ onChanged : ( err , prompts ) => {
1638+ promptNotifications . push ( [ err , prompts ] ) ;
1639+ }
1640+ }
1641+ }
1642+ }
1643+ ) ;
1644+
1645+ const [ clientTransport , serverTransport ] = InMemoryTransport . createLinkedPair ( ) ;
1646+
1647+ await Promise . all ( [ client . connect ( clientTransport ) , server . connect ( serverTransport ) ] ) ;
1648+
1649+ // Send both notifications
1650+ await server . sendToolListChanged ( ) ;
1651+ await server . sendPromptListChanged ( ) ;
1652+
1653+ // Wait for notifications to be processed
1654+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
1655+
1656+ // Both handlers should have received their respective notifications
1657+ expect ( toolNotifications ) . toHaveLength ( 1 ) ;
1658+ expect ( toolNotifications [ 0 ] [ 1 ] ?. [ 0 ] . name ) . toBe ( 'tool-1' ) ;
1659+
1660+ expect ( promptNotifications ) . toHaveLength ( 1 ) ;
1661+ expect ( promptNotifications [ 0 ] [ 1 ] ?. [ 0 ] . name ) . toBe ( 'prompt-1' ) ;
1662+ } ) ;
1663+
14061664describe ( 'outputSchema validation' , ( ) => {
14071665 /***
14081666 * Test: Validate structuredContent Against outputSchema
0 commit comments