diff --git a/lib/ruby_lsp/test_reporters/lsp_reporter.rb b/lib/ruby_lsp/test_reporters/lsp_reporter.rb
index 613ddbd4c2..dde2e5a332 100644
--- a/lib/ruby_lsp/test_reporters/lsp_reporter.rb
+++ b/lib/ruby_lsp/test_reporters/lsp_reporter.rb
@@ -213,12 +213,9 @@ def at_exit
 
     private
 
-    #: (String) -> TCPSocket
+    #: (String) -> Socket
     def socket(port)
-      # Connect to 127.0.0.1 (IPv4) explicitly since the extension listens on IPv4 only
-      # Using "localhost" hostname can cause connection failures on systems where it resolves
-      # to IPv6 first, but the server is only listening on IPv4
-      socket = TCPSocket.new("127.0.0.1", port)
+      socket = Socket.tcp("localhost", port)
       socket.binmode
       socket.sync = true
       socket
diff --git a/test/test_reporters/lsp_reporter_test.rb b/test/test_reporters/lsp_reporter_test.rb
index 5c263bec10..354574012a 100644
--- a/test/test_reporters/lsp_reporter_test.rb
+++ b/test/test_reporters/lsp_reporter_test.rb
@@ -26,33 +26,40 @@ def test_socket_connection_failure_fallbacks_to_stringio
       assert_kind_of(StringIO, io)
     end
 
-    def test_socket_uses_ipv4_address_not_localhost
+    def test_socket_connects_to_ipv4_server
       server = TCPServer.new("127.0.0.1", 0)
       port = server.addr[1].to_s
 
-      peer_info = nil #: [String, String]?
-      thread = Thread.new do
-        socket = server.accept
-        peer_addr = socket.peeraddr
-        # Store the values to assert outside the thread
-        peer_info = [peer_addr[0], peer_addr[3]] #: [String, String]
-        socket.close
-      end
+      thread = Thread.new { server.accept }
 
       ENV["RUBY_LSP_REPORTER_PORT"] = port
       reporter = LspReporter.new
       io = reporter.instance_variable_get(:@io)
 
-      assert_kind_of(TCPSocket, io)
+      assert_kind_of(Socket, io)
 
-      thread.join(1)
+      accepted = thread.join(1)&.value #: untyped
+      accepted&.close
       io.close
       server.close
+    end
+
+    def test_socket_connects_to_ipv6_server
+      server = TCPServer.new("::1", 0)
+      port = server.addr[1].to_s
 
-      assert(peer_info, "Thread did not complete successfully")
-      family, address = peer_info
-      assert_equal("AF_INET", family)
-      assert_equal("127.0.0.1", address)
+      thread = Thread.new { server.accept }
+
+      ENV["RUBY_LSP_REPORTER_PORT"] = port
+      reporter = LspReporter.new
+      io = reporter.instance_variable_get(:@io)
+
+      assert_kind_of(Socket, io)
+
+      accepted = thread.join(1)&.value #: untyped
+      accepted&.close
+      io.close
+      server.close
     end
 
     def test_coverage_results_are_formatted_as_vscode_expects
diff --git a/test/test_reporters/minitest_reporter_test.rb b/test/test_reporters/minitest_reporter_test.rb
index 6a8882b733..8eab2da4b1 100644
--- a/test/test_reporters/minitest_reporter_test.rb
+++ b/test/test_reporters/minitest_reporter_test.rb
@@ -173,7 +173,7 @@ def test_minitest_spec_output
     def gather_events(uri, output: :stdout)
       plugin_path = File.expand_path("lib/ruby_lsp/test_reporters/minitest_reporter.rb")
 
-      server = TCPServer.new("127.0.0.1", 0)
+      server = TCPServer.new("localhost", 0)
       port = server.addr[1].to_s
       events = []
       socket = nil #: Socket?
diff --git a/test/test_reporters/test_unit_reporter_test.rb b/test/test_reporters/test_unit_reporter_test.rb
index 7b58f3c8bb..36eccbc797 100644
--- a/test/test_reporters/test_unit_reporter_test.rb
+++ b/test/test_reporters/test_unit_reporter_test.rb
@@ -97,7 +97,7 @@ def test_crashing_example
     def gather_events(uri, output: :stdout)
       reporter_path = File.expand_path(File.join("lib", "ruby_lsp", "test_reporters", "test_unit_reporter.rb"))
 
-      server = TCPServer.new("127.0.0.1", 0)
+      server = TCPServer.new("localhost", 0)
       port = server.addr[1].to_s
       events = []
       socket = nil #: Socket?
diff --git a/vscode/src/streamingRunner.ts b/vscode/src/streamingRunner.ts
index 71f39bae44..f632220658 100644
--- a/vscode/src/streamingRunner.ts
+++ b/vscode/src/streamingRunner.ts
@@ -188,7 +188,7 @@ export class StreamingRunner implements vscode.Disposable {
       server.unref();
 
       // eslint-disable-next-line @typescript-eslint/no-misused-promises
-      server.listen(0, "127.0.0.1", async () => {
+      server.listen(0, "localhost", async () => {
         const address = server.address();
 
         if (!address) {
