@@ -1215,6 +1215,155 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
1215
1215
})
1216
1216
}
1217
1217
1218
+ func TestMCPHTTP_E2E_ChatGPTEndpoint (t * testing.T ) {
1219
+ t .Parallel ()
1220
+
1221
+ // Setup Coder server with authentication
1222
+ coderClient , closer , api := coderdtest .NewWithAPI (t , & coderdtest.Options {
1223
+ IncludeProvisionerDaemon : true ,
1224
+ })
1225
+ defer closer .Close ()
1226
+
1227
+ user := coderdtest .CreateFirstUser (t , coderClient )
1228
+
1229
+ // Create template and workspace for testing search functionality
1230
+ version := coderdtest .CreateTemplateVersion (t , coderClient , user .OrganizationID , nil )
1231
+ coderdtest .AwaitTemplateVersionJobCompleted (t , coderClient , version .ID )
1232
+ template := coderdtest .CreateTemplate (t , coderClient , user .OrganizationID , version .ID )
1233
+
1234
+ // Create MCP client pointing to the ChatGPT endpoint
1235
+ mcpURL := api .AccessURL .String () + "/api/experimental/mcp/http?toolset=chatgpt"
1236
+
1237
+ // Configure client with authentication headers using RFC 6750 Bearer token
1238
+ mcpClient , err := mcpclient .NewStreamableHttpClient (mcpURL ,
1239
+ transport .WithHTTPHeaders (map [string ]string {
1240
+ "Authorization" : "Bearer " + coderClient .SessionToken (),
1241
+ }))
1242
+ require .NoError (t , err )
1243
+ t .Cleanup (func () {
1244
+ if closeErr := mcpClient .Close (); closeErr != nil {
1245
+ t .Logf ("Failed to close MCP client: %v" , closeErr )
1246
+ }
1247
+ })
1248
+
1249
+ ctx , cancel := context .WithTimeout (t .Context (), testutil .WaitLong )
1250
+ defer cancel ()
1251
+
1252
+ // Start client
1253
+ err = mcpClient .Start (ctx )
1254
+ require .NoError (t , err )
1255
+
1256
+ // Initialize connection
1257
+ initReq := mcp.InitializeRequest {
1258
+ Params : mcp.InitializeParams {
1259
+ ProtocolVersion : mcp .LATEST_PROTOCOL_VERSION ,
1260
+ ClientInfo : mcp.Implementation {
1261
+ Name : "test-chatgpt-client" ,
1262
+ Version : "1.0.0" ,
1263
+ },
1264
+ },
1265
+ }
1266
+
1267
+ result , err := mcpClient .Initialize (ctx , initReq )
1268
+ require .NoError (t , err )
1269
+ require .Equal (t , mcpserver .MCPServerName , result .ServerInfo .Name )
1270
+ require .Equal (t , mcp .LATEST_PROTOCOL_VERSION , result .ProtocolVersion )
1271
+ require .NotNil (t , result .Capabilities )
1272
+
1273
+ // Test tool listing - should only have search and fetch tools for ChatGPT
1274
+ tools , err := mcpClient .ListTools (ctx , mcp.ListToolsRequest {})
1275
+ require .NoError (t , err )
1276
+ require .NotEmpty (t , tools .Tools )
1277
+
1278
+ // Verify we have exactly the ChatGPT tools and no others
1279
+ var foundTools []string
1280
+ for _ , tool := range tools .Tools {
1281
+ foundTools = append (foundTools , tool .Name )
1282
+ }
1283
+
1284
+ // ChatGPT endpoint should only expose search and fetch tools
1285
+ assert .Contains (t , foundTools , toolsdk .ToolNameChatGPTSearch , "Should have ChatGPT search tool" )
1286
+ assert .Contains (t , foundTools , toolsdk .ToolNameChatGPTFetch , "Should have ChatGPT fetch tool" )
1287
+ assert .Len (t , foundTools , 2 , "ChatGPT endpoint should only expose search and fetch tools" )
1288
+
1289
+ // Should NOT have other tools that are available in the standard endpoint
1290
+ assert .NotContains (t , foundTools , toolsdk .ToolNameGetAuthenticatedUser , "Should not have authenticated user tool" )
1291
+ assert .NotContains (t , foundTools , toolsdk .ToolNameListWorkspaces , "Should not have list workspaces tool" )
1292
+
1293
+ t .Logf ("ChatGPT endpoint tools: %v" , foundTools )
1294
+
1295
+ // Test search tool - search for templates
1296
+ var searchTool * mcp.Tool
1297
+ for _ , tool := range tools .Tools {
1298
+ if tool .Name == toolsdk .ToolNameChatGPTSearch {
1299
+ searchTool = & tool
1300
+ break
1301
+ }
1302
+ }
1303
+ require .NotNil (t , searchTool , "Expected to find search tool" )
1304
+
1305
+ // Execute search for templates
1306
+ searchReq := mcp.CallToolRequest {
1307
+ Params : mcp.CallToolParams {
1308
+ Name : searchTool .Name ,
1309
+ Arguments : map [string ]any {
1310
+ "query" : "templates" ,
1311
+ },
1312
+ },
1313
+ }
1314
+
1315
+ searchResult , err := mcpClient .CallTool (ctx , searchReq )
1316
+ require .NoError (t , err )
1317
+ require .NotEmpty (t , searchResult .Content )
1318
+
1319
+ // Verify the search result contains our template
1320
+ assert .Len (t , searchResult .Content , 1 )
1321
+ if textContent , ok := searchResult .Content [0 ].(mcp.TextContent ); ok {
1322
+ assert .Equal (t , "text" , textContent .Type )
1323
+ assert .Contains (t , textContent .Text , template .ID .String (), "Search result should contain our test template" )
1324
+ t .Logf ("Search result: %s" , textContent .Text )
1325
+ } else {
1326
+ t .Errorf ("Expected TextContent type, got %T" , searchResult .Content [0 ])
1327
+ }
1328
+
1329
+ // Test fetch tool
1330
+ var fetchTool * mcp.Tool
1331
+ for _ , tool := range tools .Tools {
1332
+ if tool .Name == toolsdk .ToolNameChatGPTFetch {
1333
+ fetchTool = & tool
1334
+ break
1335
+ }
1336
+ }
1337
+ require .NotNil (t , fetchTool , "Expected to find fetch tool" )
1338
+
1339
+ // Execute fetch for the template
1340
+ fetchReq := mcp.CallToolRequest {
1341
+ Params : mcp.CallToolParams {
1342
+ Name : fetchTool .Name ,
1343
+ Arguments : map [string ]any {
1344
+ "id" : fmt .Sprintf ("template:%s" , template .ID .String ()),
1345
+ },
1346
+ },
1347
+ }
1348
+
1349
+ fetchResult , err := mcpClient .CallTool (ctx , fetchReq )
1350
+ require .NoError (t , err )
1351
+ require .NotEmpty (t , fetchResult .Content )
1352
+
1353
+ // Verify the fetch result contains template details
1354
+ assert .Len (t , fetchResult .Content , 1 )
1355
+ if textContent , ok := fetchResult .Content [0 ].(mcp.TextContent ); ok {
1356
+ assert .Equal (t , "text" , textContent .Type )
1357
+ assert .Contains (t , textContent .Text , template .Name , "Fetch result should contain template name" )
1358
+ assert .Contains (t , textContent .Text , template .ID .String (), "Fetch result should contain template ID" )
1359
+ t .Logf ("Fetch result contains template data" )
1360
+ } else {
1361
+ t .Errorf ("Expected TextContent type, got %T" , fetchResult .Content [0 ])
1362
+ }
1363
+
1364
+ t .Logf ("ChatGPT endpoint E2E test successful: search and fetch tools working correctly" )
1365
+ }
1366
+
1218
1367
// Helper function to parse URL safely in tests
1219
1368
func mustParseURL (t * testing.T , rawURL string ) * url.URL {
1220
1369
u , err := url .Parse (rawURL )
0 commit comments