@@ -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/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
+ defer 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 (context .Background (),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 )