@@ -24,16 +24,6 @@ import (
2424 "github.com/stretchr/testify/require"
2525)
2626
27- // Should be set to opt-in to tests that mutate global state
28- const E2EGlobalMutationOptInEnv = "GITHUB_MCP_SERVER_E2E_MUTATE_GLOBAL_STATE"
29-
30- // skipIfGlobalMutationNotOptedIn skips the test if the opt-in env var is not set
31- func skipIfGlobalMutationNotOptedIn (t * testing.T ) {
32- if os .Getenv (E2EGlobalMutationOptInEnv ) == "" {
33- t .Skipf ("Skipping test: set %s=1 to opt-in to global state mutation tests" , E2EGlobalMutationOptInEnv )
34- }
35- }
36-
3727var (
3828 // Shared variables and sync.Once instances to ensure one-time execution
3929 getTokenOnce sync.Once
@@ -1559,280 +1549,3 @@ func TestListNotifications(t *testing.T) {
15591549 err = json .Unmarshal ([]byte (textContent .Text ), & notifications )
15601550 require .NoError (t , err , "expected to unmarshal text content successfully" )
15611551}
1562-
1563- func TestManageNotificationSubscription (t * testing.T ) {
1564- skipIfGlobalMutationNotOptedIn (t )
1565- t .Parallel ()
1566- client := setupMCPClient (t )
1567- ctx := context .Background ()
1568-
1569- // List notifications to get a valid notificationID
1570- listReq := mcp.CallToolRequest {}
1571- listReq .Params .Name = "list_notifications"
1572- listReq .Params .Arguments = map [string ]any {}
1573- resp , err := client .CallTool (ctx , listReq )
1574- require .NoError (t , err )
1575- require .False (t , resp .IsError )
1576-
1577- textContent , ok := resp .Content [0 ].(mcp.TextContent )
1578- require .True (t , ok )
1579- var notifications []struct {
1580- ID string `json:"id"`
1581- }
1582- err = json .Unmarshal ([]byte (textContent .Text ), & notifications )
1583- require .NoError (t , err )
1584- require .NotEmpty (t , notifications )
1585- if len (notifications ) == 0 {
1586- t .Skip ("No notifications available to test subscription management" )
1587- }
1588- notificationID := notifications [0 ].ID
1589-
1590- // Ignore notification
1591- ignoreReq := mcp.CallToolRequest {}
1592- ignoreReq .Params .Name = "manage_notification_subscription"
1593- ignoreReq .Params .Arguments = map [string ]any {
1594- "notificationID" : notificationID ,
1595- "action" : "ignore" ,
1596- }
1597- resp , err = client .CallTool (ctx , ignoreReq )
1598- require .NoError (t , err )
1599- require .False (t , resp .IsError )
1600- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1601- require .True (t , ok )
1602- require .Contains (t , textContent .Text , "ignored" )
1603-
1604- // Validate with REST client
1605- restClient := getRESTClient (t )
1606- sub , _ , err := restClient .Activity .GetThreadSubscription (ctx , notificationID )
1607- require .NoError (t , err )
1608- require .NotNil (t , sub )
1609- require .True (t , sub .GetIgnored (), "expected notification subscription to be ignored" )
1610-
1611- // Watch notification
1612- watchReq := mcp.CallToolRequest {}
1613- watchReq .Params .Name = "manage_notification_subscription"
1614- watchReq .Params .Arguments = map [string ]any {
1615- "notificationID" : notificationID ,
1616- "action" : "watch" ,
1617- }
1618- resp , err = client .CallTool (ctx , watchReq )
1619- require .NoError (t , err )
1620- require .False (t , resp .IsError )
1621- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1622- require .True (t , ok )
1623- require .Contains (t , textContent .Text , "subscribed" )
1624-
1625- // Validate with REST client
1626- sub , _ , err = restClient .Activity .GetThreadSubscription (ctx , notificationID )
1627- require .NoError (t , err )
1628- require .NotNil (t , sub )
1629- require .False (t , sub .GetIgnored (), "expected notification subscription to not be ignored (watch)" )
1630- require .True (t , sub .GetSubscribed (), "expected notification subscription to be subscribed" )
1631-
1632- // Delete notification subscription
1633- deleteReq := mcp.CallToolRequest {}
1634- deleteReq .Params .Name = "manage_notification_subscription"
1635- deleteReq .Params .Arguments = map [string ]any {
1636- "notificationID" : notificationID ,
1637- "action" : "delete" ,
1638- }
1639- resp , err = client .CallTool (ctx , deleteReq )
1640- require .NoError (t , err )
1641- require .False (t , resp .IsError )
1642- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1643- require .True (t , ok )
1644- require .Contains (t , textContent .Text , "deleted" )
1645-
1646- // Validate with REST client
1647- sub , resp2 , err := restClient .Activity .GetThreadSubscription (ctx , notificationID )
1648- require .NoError (t , err )
1649- require .NotNil (t , sub )
1650- require .False (t , sub .GetSubscribed ())
1651- require .True (t , sub .GetIgnored ())
1652- require .Equal (t , 204 , resp2 .StatusCode )
1653- }
1654-
1655- func TestManageRepositoryNotificationSubscription (t * testing.T ) {
1656- skipIfGlobalMutationNotOptedIn (t )
1657- t .Parallel ()
1658- client := setupMCPClient (t )
1659- ctx := context .Background ()
1660-
1661- // Use a well-known repo for the test (e.g., the user's own repo)
1662- owner := "github"
1663- repo := "github-mcp-server"
1664-
1665- // Ignore repo notifications
1666- ignoreReq := mcp.CallToolRequest {}
1667- ignoreReq .Params .Name = "manage_repository_notification_subscription"
1668- ignoreReq .Params .Arguments = map [string ]any {
1669- "owner" : owner ,
1670- "repo" : repo ,
1671- "action" : "ignore" ,
1672- }
1673- resp , err := client .CallTool (ctx , ignoreReq )
1674- require .NoError (t , err )
1675- require .False (t , resp .IsError )
1676- textContent , ok := resp .Content [0 ].(mcp.TextContent )
1677- require .True (t , ok )
1678- require .Contains (t , textContent .Text , "ignored" )
1679-
1680- // Validate with REST client
1681- restClient := getRESTClient (t )
1682- sub , _ , err := restClient .Activity .GetRepositorySubscription (ctx , owner , repo )
1683- require .NoError (t , err )
1684- require .NotNil (t , sub )
1685- require .True (t , sub .GetIgnored (), "expected repository subscription to be ignored" )
1686-
1687- // Watch repo notifications
1688- watchReq := mcp.CallToolRequest {}
1689- watchReq .Params .Name = "manage_repository_notification_subscription"
1690- watchReq .Params .Arguments = map [string ]any {
1691- "owner" : owner ,
1692- "repo" : repo ,
1693- "action" : "watch" ,
1694- }
1695- resp , err = client .CallTool (ctx , watchReq )
1696- require .NoError (t , err )
1697- require .False (t , resp .IsError )
1698- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1699- require .True (t , ok )
1700- require .Contains (t , textContent .Text , "subscribed" )
1701-
1702- // Validate with REST client
1703- sub , _ , err = restClient .Activity .GetRepositorySubscription (ctx , owner , repo )
1704- require .NoError (t , err )
1705- require .NotNil (t , sub )
1706- require .False (t , sub .GetIgnored (), "expected repository subscription to not be ignored (watch)" )
1707- require .True (t , sub .GetSubscribed (), "expected repository subscription to be subscribed" )
1708-
1709- // Delete repo notification subscription
1710- deleteReq := mcp.CallToolRequest {}
1711- deleteReq .Params .Name = "manage_repository_notification_subscription"
1712- deleteReq .Params .Arguments = map [string ]any {
1713- "owner" : owner ,
1714- "repo" : repo ,
1715- "action" : "delete" ,
1716- }
1717- resp , err = client .CallTool (ctx , deleteReq )
1718- require .NoError (t , err )
1719- require .False (t , resp .IsError )
1720- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1721- require .True (t , ok )
1722- require .Contains (t , textContent .Text , "deleted" )
1723-
1724- // Validate with REST client
1725- sub , resp2 , err := restClient .Activity .GetRepositorySubscription (ctx , owner , repo )
1726- require .NoError (t , err )
1727- require .NotNil (t , sub )
1728- require .False (t , sub .GetSubscribed ())
1729- require .True (t , sub .GetIgnored ())
1730- require .Equal (t , 204 , resp2 .StatusCode )
1731- }
1732-
1733- func TestDismissNotification (t * testing.T ) {
1734- skipIfGlobalMutationNotOptedIn (t )
1735- t .Parallel ()
1736- client := setupMCPClient (t )
1737- ctx := context .Background ()
1738-
1739- // List notifications to get a valid threadID
1740- listReq := mcp.CallToolRequest {}
1741- listReq .Params .Name = "list_notifications"
1742- listReq .Params .Arguments = map [string ]any {}
1743- resp , err := client .CallTool (ctx , listReq )
1744- require .NoError (t , err )
1745- require .False (t , resp .IsError )
1746- textContent , ok := resp .Content [0 ].(mcp.TextContent )
1747- require .True (t , ok )
1748- var notifications []struct {
1749- ID string `json:"id"`
1750- }
1751- err = json .Unmarshal ([]byte (textContent .Text ), & notifications )
1752- require .NoError (t , err )
1753- if len (notifications ) == 0 {
1754- t .Skip ("No notifications available to test dismissal" )
1755- }
1756- require .NotEmpty (t , notifications )
1757- threadID := notifications [0 ].ID
1758-
1759- // Dismiss notification (mark as read)
1760- dismissReq := mcp.CallToolRequest {}
1761- dismissReq .Params .Name = "dismiss_notification"
1762- dismissReq .Params .Arguments = map [string ]any {
1763- "threadID" : threadID ,
1764- "state" : "read" ,
1765- }
1766- resp , err = client .CallTool (ctx , dismissReq )
1767- require .NoError (t , err )
1768- require .False (t , resp .IsError )
1769- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1770- require .True (t , ok )
1771- require .Contains (t , textContent .Text , "read" )
1772- }
1773-
1774- func TestMarkAllNotificationsRead (t * testing.T ) {
1775- skipIfGlobalMutationNotOptedIn (t )
1776- t .Parallel ()
1777- client := setupMCPClient (t )
1778- ctx := context .Background ()
1779-
1780- // Limit to notifications updated within the last hour
1781- oneHourAgo := nowMinusOneHourRFC3339 ()
1782- markAllReq := mcp.CallToolRequest {}
1783- markAllReq .Params .Name = "mark_all_notifications_read"
1784- markAllReq .Params .Arguments = map [string ]any {
1785- "since" : oneHourAgo ,
1786- }
1787- resp , err := client .CallTool (ctx , markAllReq )
1788- require .NoError (t , err )
1789- require .False (t , resp .IsError )
1790- textContent , ok := resp .Content [0 ].(mcp.TextContent )
1791- require .True (t , ok )
1792- require .Contains (t , textContent .Text , "All notifications marked as read" )
1793-
1794- }
1795-
1796- // nowMinusOneHourRFC3339 returns the RFC3339 timestamp for one hour ago from now (UTC)
1797- func nowMinusOneHourRFC3339 () string {
1798- return time .Now ().UTC ().Add (- 1 * time .Hour ).Format (time .RFC3339 )
1799- }
1800-
1801- func TestGetNotificationDetails (t * testing.T ) {
1802- t .Parallel ()
1803- client := setupMCPClient (t )
1804- ctx := context .Background ()
1805-
1806- // List notifications to get a valid notificationID
1807- listReq := mcp.CallToolRequest {}
1808- listReq .Params .Name = "list_notifications"
1809- listReq .Params .Arguments = map [string ]any {}
1810- resp , err := client .CallTool (ctx , listReq )
1811- require .NoError (t , err )
1812- require .False (t , resp .IsError )
1813- textContent , ok := resp .Content [0 ].(mcp.TextContent )
1814- require .True (t , ok )
1815- var notifications []struct {
1816- ID string `json:"id"`
1817- }
1818- err = json .Unmarshal ([]byte (textContent .Text ), & notifications )
1819- require .NoError (t , err )
1820- require .NotEmpty (t , notifications )
1821- if len (notifications ) == 0 {
1822- t .Skip ("No notifications available to test dismissal" )
1823- }
1824- notificationID := notifications [0 ].ID
1825-
1826- // Get notification details
1827- detailsReq := mcp.CallToolRequest {}
1828- detailsReq .Params .Name = "get_notification_details"
1829- detailsReq .Params .Arguments = map [string ]any {
1830- "notificationID" : notificationID ,
1831- }
1832- resp , err = client .CallTool (ctx , detailsReq )
1833- require .NoError (t , err )
1834- require .False (t , resp .IsError )
1835- textContent , ok = resp .Content [0 ].(mcp.TextContent )
1836- require .True (t , ok )
1837- require .Contains (t , textContent .Text , notificationID )
1838- }
0 commit comments