Repository: langchain4j/langchain4j (2026-03-18T12:37:14Z)

Issue:
[FEATURE] MCP redirects
**Is your feature request related to a problem? Please describe.**
When trying to connect to an MCP server that has been moved and is issuing a temp redirect status, the client is coded to refuse to follow the redirect. This causes the connection to fail - with no available mitigation strategy. 

**Describe the solution you'd like**
One of:
The ability to specify that the http client follows redirects in the builder.
Redirects on by default (yeah yeah breaking change)
The ability to provide my own httpclient in the builder.

**Describe alternatives you've considered**
Inherit from the StreamableHttpMcpTransport class and roll my own. I'd rather not but this is quite the roadblock for me.

**Additional context**
The issue is in dev.langchain4j.mcp.client.transport.http.StreamableHttpMcpTransport at line 163. 
The sendAsync is getting a 307 in the response status code at line 165 and it ends up down at 222 with java.lang.RuntimeException: Unexpected status code: 307. 

In my case the mcp server is working perfectly but it's been moved. 
It's not mine so I can't do anything about that. 
There's no way to set the httpClient to allow redirects and the default is NEVER.


Discussion:
cc @jmartisk 
This should be trivial to fix, just add a `followRedirects(boolean)` in `StreamableHttpMcpTransport.Builder` and propagate its value when building the HTTP client in `StreamableHttpMcpTransport`'s constructor. Not sure about the default, but probably it should be `false`. Feel free to send a PR, otherwise I will do it later



Patch:
diff --git a/langchain4j-mcp/src/main/java/dev/langchain4j/mcp/client/transport/http/StreamableHttpMcpTransport.java b/langchain4j-mcp/src/main/java/dev/langchain4j/mcp/client/transport/http/StreamableHttpMcpTransport.java
index 2757e55e0b0..f6eedf1569b 100644
--- a/langchain4j-mcp/src/main/java/dev/langchain4j/mcp/client/transport/http/StreamableHttpMcpTransport.java
+++ b/langchain4j-mcp/src/main/java/dev/langchain4j/mcp/client/transport/http/StreamableHttpMcpTransport.java
@@ -76,6 +76,9 @@ public StreamableHttpMcpTransport(StreamableHttpMcpTransport.Builder builder) {
         executor = getOrDefault(builder.executor, DefaultExecutorProvider.getDefaultExecutorService());
         HttpClient.Builder clientBuilder =
                 HttpClient.newBuilder().connectTimeout(timeout).version(httpVersion);
+        if (builder.followRedirects) {
+            clientBuilder.followRedirects(HttpClient.Redirect.NORMAL);
+        }
         if (builder.executor != null) {
             clientBuilder.executor(builder.executor);
         }
@@ -383,6 +386,7 @@ public static class Builder {
         private SSLContext sslContext;
         private boolean forceHttpVersion1_1;
         private boolean subsidiaryChannelEnabled = false;
+        private boolean followRedirects = false;
 
         /**
          * The URL of the MCP server.
@@ -483,6 +487,18 @@ public StreamableHttpMcpTransport.Builder setHttpVersion1_1() {
             return this;
         }
 
+        /**
+         * Enables or disables following HTTP redirects (3xx status codes).
+         * When enabled, the transport will automatically follow redirects
+         * using {@link HttpClient.Redirect#NORMAL} policy (always redirect,
+         * except from HTTPS to HTTP).
+         * Defaults to {@code false}.
+         */
+        public StreamableHttpMcpTransport.Builder followRedirects(boolean followRedirects) {
+            this.followRedirects = followRedirects;
+            return this;
+        }
+
         /**
          * Enables or disables the subsidiary SSE channel. When enabled, the transport
          * will open an HTTP GET-based SSE stream after initialization, allowing the


Test patch:
diff --git a/langchain4j-mcp/src/test/java/dev/langchain4j/mcp/client/transport/StreamableHttpMcpTransportTest.java b/langchain4j-mcp/src/test/java/dev/langchain4j/mcp/client/transport/StreamableHttpMcpTransportTest.java
index 6776ac3dd19..c1b37897b6f 100644
--- a/langchain4j-mcp/src/test/java/dev/langchain4j/mcp/client/transport/StreamableHttpMcpTransportTest.java
+++ b/langchain4j-mcp/src/test/java/dev/langchain4j/mcp/client/transport/StreamableHttpMcpTransportTest.java
@@ -31,6 +31,24 @@ void shouldUseHttp2ByDefault() throws Exception {
         assertThat(extractHttpClient(transport).version()).isEqualTo(HttpClient.Version.HTTP_2);
     }
 
+    @Test
+    void shouldNotFollowRedirectsByDefault() throws Exception {
+        StreamableHttpMcpTransport transport =
+                StreamableHttpMcpTransport.builder().url("http://localhost/mcp").build();
+
+        assertThat(extractHttpClient(transport).followRedirects()).isEqualTo(HttpClient.Redirect.NEVER);
+    }
+
+    @Test
+    void shouldFollowRedirectsWhenEnabled() throws Exception {
+        StreamableHttpMcpTransport transport = StreamableHttpMcpTransport.builder()
+                .url("http://localhost/mcp")
+                .followRedirects(true)
+                .build();
+
+        assertThat(extractHttpClient(transport).followRedirects()).isEqualTo(HttpClient.Redirect.NORMAL);
+    }
+
     @Test
     void shouldForceHttp11ForStreamableTransport() throws Exception {
         StreamableHttpMcpTransport transport = StreamableHttpMcpTransport.builder()