Environment
- SonarQube Server Version: 2026.4.1.126914
- Deployment type zip:
- Client / AI tool using MCP (Claude): SonarQube MCP Server v1.25.0
Description
When using Claude and SonarQube MCP Server almost all calls hang with a timeout sometimes the first calls succeeds. This is wat Claude thinks is happening.
Bug Report: SonarQube MCP Server hangs indefinitely on tool calls (ServerApiHelper.rawGet)
Affected versions: Reproduced on 1.22.0.3040 and 1.25.0.3221 (latest at time of writing) — bug persists across the upgrade.
Environment: Windows Server, standalone sonarqube-mcp-server-<version>.jar process (Java 21+/OpenJDK 25), running alongside a self-hosted SonarQube Server instance. Started with SONARQUBE_TRANSPORT=http, SONARQUBE_HTTP_HOST=127.0.0.1, SONARQUBE_HTTP_PORT=8080. SonarQube Server’s own web tier proxies external /mcp requests (its built-in com.sonar.g.q MCP proxy component) to this local process.
Symptom: Almost every MCP tool call that needs to query the SonarQube Web API (search_my_sonarqube_projects, search_sonar_issues_in_projects, list_pull_requests, etc.) hangs indefinitely and never returns a response. From the client side this surfaces as a 502 Bad Gateway (MCP client timeout). On the SonarQube Server side, web.log shows:
WARN web[...][com.sonar.g.q] MCP proxy failed to forward request to http://127.0.0.1:8080/mcp: Read timed out
The MCP server’s own mcp.log shows the tool being invoked (Tool called: search_my_sonarqube_projects) but never logs a completion or error afterward. Graceful shutdown of the MCP process (Stopping HTTP server...) also hangs indefinitely and never completes — the process has to be force-killed.
Root cause (confirmed via jstack thread dumps, taken during multiple separate hangs): Every hung tool call is a boundedElastic-N reactor thread permanently blocked in the exact same place:
"boundedElastic-N" ... WAITING (parking) on a java.util.concurrent.CompletableFuture$Signaller
at java.util.concurrent.CompletableFuture.waitingGet(CompletableFuture.java:1919)
at java.util.concurrent.CompletableFuture.join(CompletableFuture.java:2138)
at org.sonarsource.sonarqube.mcp.serverapi.ServerApiHelper.rawGet(ServerApiHelper.java:85)
at org.sonarsource.sonarqube.mcp.serverapi.ServerApiHelper.get(ServerApiHelper.java:58)
at org.sonarsource.sonarqube.mcp.serverapi.<...>Api.<method>(...)
at org.sonarsource.sonarqube.mcp.tools.<...>Tool.execute(...)
at org.sonarsource.sonarqube.mcp.tools.ToolExecutor.execute(ToolExecutor.java:105)
This has been observed for at least three different tools/endpoints (ComponentsApi.searchProjects, IssuesApi.search, PullRequestsApi.listPullRequests), all blocking at the identical line ServerApiHelper.java:85 — indicating a shared bug in the internal async HTTP client wrapper (ServerApiHelper.rawGet), not something tool-specific.
Critically, the underlying Apache HttpClient5 async I/O threads (httpclient-main-1, httpclient-dispatch-1) are idle at the time of the hang — sitting in their event loop / thread-pool getTask() wait with no visible in-flight request — suggesting the CompletableFuture returned to the caller is never completed by the HTTP client callback (e.g. a connection lease that’s never granted or released, or a callback that’s silently dropped), rather than the HTTP call itself being slow. A direct curl call from the same machine to the same SonarQube Web API endpoint (with the same token) returns instantly, ruling out network/API-side latency.
Once a call hangs, the blocked thread is never cleaned up — it persists indefinitely (confirmed by re-inspecting a second thread dump minutes later; the earlier stuck threads were still present, alongside new ones from subsequent calls), so hung threads accumulate over the process’s lifetime rather than being reaped or timed out.
Reproducibility: Occasionally the very first tool call after a fresh process restart succeeds, but this is not reliable — reproduced a case where even the first call after restart hung immediately. Once any call hangs, essentially all subsequent tool calls hang as well, making the MCP server effectively unusable without frequent process restarts (each restart at best buys one possibly-successful call).
Ruled out during investigation (so the fix should focus on the async HTTP client / ServerApiHelper, not environment/infra):
- CPU saturation — CPU stayed idle throughout every hang.
HTTP_PROXY/HTTPS_PROXYenvironment variables — none set.- File/OS permissions, running elevated vs. non-elevated — no effect; process reads/writes other files fine.
- Pointing
SONARQUBE_URLat a direct internal address (http://127.0.0.1:9000/) instead of the public HTTPS hostname — no change in behavior, ruling out a reverse-proxy loopback/self-deadlock as the cause. - SonarQube web tier thread pool size (
sonar.web.http.maxThreads=50, default) — far more threads than needed for the observed concurrency, ruling out simple thread-pool exhaustion.
Impact: MCP tool integration with SonarQube Server is effectively broken for any interactive/repeated use — nearly every call times out with a 502, and even a clean server shutdown hangs indefinitely.
Steps to reproduce:
- Run the standalone
sonarqube-mcp-server-<version>.jaragainst a SonarQube Server instance, with the built-in MCP proxy (com.sonar.g.q) forwarding external/mcprequests to it. - From an MCP client, call any tool that queries the SonarQube Web API (e.g.
search_my_sonarqube_projects). - Observe the call hang until the proxy’s read timeout (~10s) is reached, returning
502 Bad Gatewayto the client. - Take a
jstack <pid>thread dump of the MCP server process while the call (or a subsequent one) is in flight/hung — observe aboundedElastic-Nthread blocked inServerApiHelper.rawGetas shown above. - Repeat with further tool calls — observe they also hang, and previously-stuck threads remain in later thread dumps (never cleaned up).