diff --git a/CHANGELOG.md b/CHANGELOG.md
index d82f3ae1..b773b546 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+- Fixed MCP connection to localhost being routed through an active HTTP_PROXY/HTTPS_PROXY; NO_PROXY is now automatically extended with localhost and 127.0.0.1 when a proxy is configured
- Fixed terminal scrollbar disappearing when Claude shows a choice/confirmation prompt (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/22)
- Fixed Cancel button sending Ctrl+C instead of Esc, making it impossible to exit /usage and similar screens
- Fixed Default profile settings not saving in Tools → Options → Profiles (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/31)
diff --git a/pom.xml b/pom.xml
index 49db55d5..b64609c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.nbclaudecodegui
netbeans-claude-code-gui
- 0.20.8-SNAPSHOT
+ 0.20.9-SNAPSHOT
nbm
Netbeans Claude Code GUI
NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.
diff --git a/src/main/java/io/github/nbclaudecodegui/process/ClaudeProcess.java b/src/main/java/io/github/nbclaudecodegui/process/ClaudeProcess.java
index 1977f2cc..f422fcca 100644
--- a/src/main/java/io/github/nbclaudecodegui/process/ClaudeProcess.java
+++ b/src/main/java/io/github/nbclaudecodegui/process/ClaudeProcess.java
@@ -136,7 +136,10 @@ public PtyProcess start(String workingDir, ClaudeProfile profile, String extraCl
+ ", apiKeyHelper=" + (apiKeyHelper ? "SET" : "NOT SET")
+ ", ANTHROPIC_AUTH_TOKEN=" + (!env.getOrDefault("ANTHROPIC_AUTH_TOKEN", "").isBlank() ? "SET" : "NOT SET")
+ ", ANTHROPIC_BASE_URL=" + env.getOrDefault("ANTHROPIC_BASE_URL", "(not set)")
- + ", CLAUDE_CONFIG_DIR=" + env.getOrDefault("CLAUDE_CONFIG_DIR", "(inherited)"));
+ + ", CLAUDE_CONFIG_DIR=" + env.getOrDefault("CLAUDE_CONFIG_DIR", "(inherited)")
+ + ", HTTP_PROXY=" + env.getOrDefault("HTTP_PROXY", env.getOrDefault("http_proxy", "(not set)"))
+ + ", HTTPS_PROXY=" + env.getOrDefault("HTTPS_PROXY", env.getOrDefault("https_proxy", "(not set)"))
+ + ", NO_PROXY=" + env.getOrDefault("NO_PROXY", env.getOrDefault("no_proxy", "(not set)")));
List cmd = new ArrayList<>();
cmd.add(executable);
@@ -587,9 +590,36 @@ static Map buildEnv(ClaudeProfile profile, java.nio.file.Path pr
env.putAll(profile.toEnvVars());
}
+ // Ensure localhost is excluded from proxy to protect MCP SSE server
+ ensureLocalhostInNoProxy(env);
+
return env;
}
+ private static void ensureLocalhostInNoProxy(Map env) {
+ // Normalize lowercase no_proxy → NO_PROXY (Linux systems may use either)
+ if (!env.containsKey("NO_PROXY") && env.containsKey("no_proxy")) {
+ env.put("NO_PROXY", env.get("no_proxy"));
+ }
+
+ String httpProxy = env.getOrDefault("HTTP_PROXY", env.getOrDefault("http_proxy", ""));
+ String httpsProxy = env.getOrDefault("HTTPS_PROXY", env.getOrDefault("https_proxy", ""));
+ if (httpProxy.isBlank() && httpsProxy.isBlank()) return; // no proxy active, nothing to do
+
+ String noProxy = env.getOrDefault("NO_PROXY", "");
+ List required = List.of("localhost", "127.0.0.1");
+ List missing = required.stream()
+ .filter(h -> !noProxy.contains(h))
+ .collect(java.util.stream.Collectors.toList());
+ if (missing.isEmpty()) return;
+
+ String updated = noProxy.isBlank()
+ ? String.join(",", missing)
+ : noProxy + "," + String.join(",", missing);
+ env.put("NO_PROXY", updated);
+ LOG.fine("Auto-added to NO_PROXY: " + missing + " → NO_PROXY=" + updated);
+ }
+
/**
* Builds a minimal {@code settings.local.json} from scratch for the given port.
* Used as a fallback when the existing file cannot be parsed.
diff --git a/src/test/java/io/github/nbclaudecodegui/process/ClaudeProcessProfileTest.java b/src/test/java/io/github/nbclaudecodegui/process/ClaudeProcessProfileTest.java
index 1b506b61..72d36126 100644
--- a/src/test/java/io/github/nbclaudecodegui/process/ClaudeProcessProfileTest.java
+++ b/src/test/java/io/github/nbclaudecodegui/process/ClaudeProcessProfileTest.java
@@ -127,6 +127,49 @@ void buildEnv_systemManagedProxy_noProxyVarsAdded() {
}
}
+ // -------------------------------------------------------------------------
+ // NO_PROXY auto-injection
+ // -------------------------------------------------------------------------
+
+ @Test
+ void buildEnv_customProxy_noProxyBlank_injectsLocalhost() {
+ ClaudeProfile p = ClaudeProfile.createNamed("CustomProxyNoNP");
+ p.setProxyMode(ProxyMode.CUSTOM);
+ p.setHttpProxy("http://proxy:3128");
+ p.setHttpsProxy("");
+ p.setNoProxy("");
+ Map env = ClaudeProcess.buildEnv(p, PROFILES_DIR);
+ String noProxy = env.getOrDefault("NO_PROXY", "");
+ assertTrue(noProxy.contains("localhost"), "NO_PROXY should contain localhost, was: " + noProxy);
+ assertTrue(noProxy.contains("127.0.0.1"), "NO_PROXY should contain 127.0.0.1, was: " + noProxy);
+ }
+
+ @Test
+ void buildEnv_customProxy_noProxyHasLocalhost_notDuplicated() {
+ ClaudeProfile p = ClaudeProfile.createNamed("CustomProxyHasNP");
+ p.setProxyMode(ProxyMode.CUSTOM);
+ p.setHttpProxy("http://proxy:3128");
+ p.setHttpsProxy("");
+ p.setNoProxy("localhost,127.0.0.1");
+ Map env = ClaudeProcess.buildEnv(p, PROFILES_DIR);
+ String noProxy = env.getOrDefault("NO_PROXY", "");
+ // Should not contain duplicates
+ int localhostCount = noProxy.split("localhost", -1).length - 1;
+ assertEquals(1, localhostCount, "localhost should appear exactly once in NO_PROXY: " + noProxy);
+ }
+
+ @Test
+ void buildEnv_noProxyActive_noLocalhostInjected() {
+ ClaudeProfile p = ClaudeProfile.createNamed("CustomNoProxyActive");
+ p.setProxyMode(ProxyMode.NO_PROXY);
+ Map env = ClaudeProcess.buildEnv(p, PROFILES_DIR);
+ // NO_PROXY should be empty (explicitly cleared by NO_PROXY mode)
+ // and since no proxy is set, ensureLocalhostInNoProxy should not add anything
+ String noProxy = env.getOrDefault("NO_PROXY", "");
+ assertFalse(noProxy.contains("localhost"),
+ "With no proxy active, localhost should not be injected: " + noProxy);
+ }
+
// -------------------------------------------------------------------------
// Extra env vars
// -------------------------------------------------------------------------