11package com .akto .hybrid_runtime ;
22
33import com .akto .dao .context .Context ;
4+ import com .akto .data_actor .DataActor ;
45import com .akto .data_actor .DataActorFactory ;
56import com .akto .dto .APIConfig ;
67import com .akto .dto .AccountSettings ;
3233import com .akto .testing .ApiExecutor ;
3334import com .akto .util .Constants ;
3435import com .akto .util .JSONUtils ;
36+ import com .akto .util .McpSseEndpointHelper ;
3537import com .akto .util .Pair ;
3638import com .fasterxml .jackson .databind .ObjectMapper ;
3739import com .fasterxml .jackson .databind .module .SimpleModule ;
@@ -57,11 +59,17 @@ public class McpToolsSyncJobExecutor {
5759
5860 private static final LoggerMaker logger = new LoggerMaker (McpToolsSyncJobExecutor .class , LogDb .RUNTIME );
5961 private static final ObjectMapper mapper = new ObjectMapper ();
62+ public static final DataActor dataActor = DataActorFactory .fetchInstance ();
6063 public static final String MCP_TOOLS_LIST_REQUEST_JSON =
6164 "{\" jsonrpc\" : \" 2.0\" , \" id\" : 1, \" method\" : \" " + McpSchema .METHOD_TOOLS_LIST + "\" , \" params\" : {}}" ;
6265 public static final String MCP_RESOURCE_LIST_REQUEST_JSON =
6366 "{\" jsonrpc\" : \" 2.0\" , \" id\" : 1, \" method\" : \" " + McpSchema .METHOD_RESOURCES_LIST + "\" , \" params\" : {}}" ;
6467 public static final String LOCAL_IP = "127.0.0.1" ;
68+
69+ // MCP Transport types
70+ private static final String TRANSPORT_SSE = "SSE" ;
71+ private static final String TRANSPORT_HTTP = "HTTP" ;
72+
6573 private ServerCapabilities mcpServerCapabilities = null ;
6674
6775 public static final McpToolsSyncJobExecutor INSTANCE = new McpToolsSyncJobExecutor ();
@@ -310,7 +318,7 @@ public static Map<String, Object> generateExampleArguments(JsonSchema inputSchem
310318 public Pair <JSONRPCResponse , HttpResponseParams > getMcpMethodResponse (String host , String mcpMethod ,
311319 String mcpMethodRequestJson , ApiCollection apiCollection ) throws Exception {
312320 OriginalHttpRequest mcpRequest = createRequest (host , mcpMethod , mcpMethodRequestJson );
313- String jsonrpcResponse = sendRequest (mcpRequest );
321+ String jsonrpcResponse = sendRequest (mcpRequest , apiCollection );
314322
315323 JSONRPCResponse rpcResponse = (JSONRPCResponse ) McpSchema .deserializeJsonRpcMessage (mapper , jsonrpcResponse );
316324
@@ -347,13 +355,61 @@ private String buildHeaders(String host) {
347355 return "{\" Content-Type\" :\" application/json\" ,\" Accept\" :\" */*\" ,\" host\" :\" " + host + "\" }" ;
348356 }
349357
350- private String sendRequest (OriginalHttpRequest request ) throws Exception {
358+
359+ private String detectAndSetTransportType (OriginalHttpRequest request , ApiCollection apiCollection ) throws Exception {
360+ // Try SSE first if sseCallbackUrl is set
361+ if (apiCollection .getSseCallbackUrl () != null && !apiCollection .getSseCallbackUrl ().isEmpty ()) {
362+ try {
363+ logger .info ("Attempting to detect transport type for MCP server: {}" , apiCollection .getHostName ());
364+
365+ // Clone request for SSE detection to avoid modifying original
366+ OriginalHttpRequest sseTestRequest = request .copy ();
367+ McpSseEndpointHelper .addSseEndpointHeader (sseTestRequest , apiCollection .getId ());
368+ ApiExecutor .sendRequestWithSse (sseTestRequest , true , null , false ,
369+ new ArrayList <>(), false , true );
370+
371+ // If SSE works, update the collection
372+ dataActor .updateTransportType (apiCollection .getId (), TRANSPORT_SSE );
373+ logger .info ("Detected SSE transport for MCP server: {}" , apiCollection .getHostName ());
374+ return TRANSPORT_SSE ;
375+ } catch (Exception sseException ) {
376+ logger .info ("SSE transport failed, falling back to HTTP transport: {}" , sseException .getMessage ());
377+ // Fall back to HTTP - no need to test, just store it
378+ dataActor .updateTransportType (apiCollection .getId (), TRANSPORT_SSE );
379+ return TRANSPORT_HTTP ;
380+ }
381+ }
382+
383+ // Default to HTTP if no sseCallbackUrl
384+ logger .info ("No SSE callback URL found, using HTTP transport for: {}" , apiCollection .getHostName ());
385+ dataActor .updateTransportType (apiCollection .getId (), TRANSPORT_SSE );
386+ return TRANSPORT_HTTP ;
387+ }
388+ private String sendRequest (OriginalHttpRequest request , ApiCollection apiCollection ) throws Exception {
351389 try {
352- OriginalHttpResponse response = ApiExecutor .sendRequestWithSse (request , true , null , false ,
353- new ArrayList <>(), false , true );
390+ String transportType = apiCollection .getMcpTransportType ();
391+
392+ // If transport type is not set, try to detect it
393+ if (transportType == null || transportType .isEmpty ()) {
394+ transportType = detectAndSetTransportType (request , apiCollection );
395+ }
396+
397+ OriginalHttpResponse response ;
398+ if (TRANSPORT_HTTP .equals (transportType )) {
399+ // Use standard HTTP POST for streamable responses
400+ // Use sendRequestSkipSse to prevent ApiExecutor from trying SSE
401+ logger .info ("Using HTTP transport for MCP server: {}" , apiCollection .getHostName ());
402+ response = ApiExecutor .sendRequestSkipSse (request , true , null , false , new ArrayList <>(), false );
403+ } else {
404+ // Use SSE transport
405+ logger .info ("Using SSE transport for MCP server: {}" , apiCollection .getHostName ());
406+ McpSseEndpointHelper .addSseEndpointHeader (request , apiCollection .getId ());
407+ response = ApiExecutor .sendRequestWithSse (request , true , null , false ,
408+ new ArrayList <>(), false , true );
409+ }
354410 return response .getBody ();
355411 } catch (Exception e ) {
356- logger .error ("Error while making request to MCP server." , e );
412+ logger .error ("Error while making request to MCP server: {}" , e . getMessage () , e );
357413 throw e ;
358414 }
359415 }
0 commit comments