Skip to main content
Glama

sonarless-mcp

Local SonarQube for any project, built for AI agents: one shared SonarQube server and one shared SonarQube MCP server per machine, used by every client — Claude Code, Cursor, opencode, VS Code, Codex — at once. Single binary for Linux, macOS and Windows.

Standing on the shoulders of gitricko/sonarless. sonarless had the great idea: SonarQube without a hosted server, just Docker and one command. sonarless-mcp is a Go rewrite of that idea, reshaped around agents using SonarQube through MCP. If you just want scans in a shell or a GitHub Action, use the original — and give it a ⭐.

What's different from sonarless

sonarless

sonarless-mcp

Runs on

bash + jq + curl (Linux/macOS)

single Go binary (Linux/macOS/Windows)

MCP

—

sonarless-mcp mcp: one shared MCP container for all clients, project key filled in per workspace

Project key

directory name

sonar-project.properties, .sonarcloud.properties, Maven, Gradle (Groovy/Kotlin), pyproject.toml, .NET, CI pipelines, package.json

Scanner

sonar-scanner CLI

CLI, Maven, Gradle or dotnet-sonarscanner, picked per project

Resources

server runs until stopped

stops itself after 30 min unused, resumes on next use

Server version

fixed in script

SONARLESS_SONARQUBE_VERSION in a config file (e.g. to match your CI)

Scan history

lost when the container is recreated

kept in per-version named volumes

Related MCP server: sonarqube-mcp

Install

One installer for Linux, macOS and Windows — tell your AI agent:

Install sonarless-mcp: https://raw.githubusercontent.com/BrainerVirus/sonarless-mcp/main/install

or run it yourself — same script, copy the line for your shell:

Linux / macOS

curl -fsSL https://raw.githubusercontent.com/BrainerVirus/sonarless-mcp/main/install | sh

Windows (PowerShell)

irm https://raw.githubusercontent.com/BrainerVirus/sonarless-mcp/main/install | iex

install is a single file that is valid in both sh and PowerShell; it hands off to the platform installer, which detects your CPU, downloads the matching release, verifies its SHA-256 checksum, installs the binary (~/.local/bin or %LOCALAPPDATA%\Programs\sonarless-mcp, added to your PATH), then opens the client picker (run by an agent, it lists the detected clients and the command to register them instead):

Register the SonarQube MCP server in:

  Select all available
  Clear all

› [x] Claude Code · detected
  [x] Cursor · already configured
  [ ] VS Code · not installed
  [x] opencode · detected
  [ ] Codex · not installed

↑/↓ move · space toggle · a all · n none · enter confirm · esc cancel

If ~/.local/bin isn't on your PATH yet, the installer adds it for every shell it finds — ~/.profile, ~/.bashrc (and ~/.bash_profile on macOS), zsh's .zshenv, fish's conf.d — with one guarded, marked line each, so reruns change nothing (SONARLESS_MCP_NO_MODIFY_PATH=1 opts out). On Windows it goes on your user PATH. In a terminal that was already open, the new command may not be recognized (or highlighted) yet: in zsh run rehash, in bash hash -r; fish notices on its own; Warp reads PATH only when a tab starts, so open a new tab there. The installer detects your shell and terminal and prints the one that applies.

Installed clients are preselected; untick any you don't want, or clear them all. Run it again any time with sonarless-mcp setup (--remove to unregister, --yes / --clients claude,cursor for scripts). Installer options: SONARLESS_MCP_VERSION=v1.2.3 pins a release, SONARLESS_MCP_INSTALL_DIR changes the target, SONARLESS_MCP_NO_SETUP=1 skips the picker.

Or with Go: go install github.com/BrainerVirus/sonarless-mcp/cmd/sonarless-mcp@latest.

Requires Docker (Docker Desktop on macOS/Windows).

Updating

Installed binaries keep themselves current: once a day, starting the MCP shim, start or scan checks GitHub Releases in the background, downloads a newer release, verifies its checksum, smoke-tests it and swaps it in, so the next start runs it. The same check pulls the latest SonarQube MCP image, which the shared container picks up the next time it starts from stopped (never mid-session). Run sonarless-mcp update to do it now; SONARLESS_AUTO_UPDATE=false turns the daily check off. Log: <cache dir>/sonarless-mcp/update.log.

Use with AI agents

sonarless-mcp setup registers a sonarqube MCP server in each client (Claude Code via claude mcp add, Cursor ~/.cursor/mcp.json, opencode opencode.json, VS Code user mcp.json, Codex config.toml), editing only that entry. If a client already has a different sonarqube server (say, your company's remote SonarQube), it is left untouched and sonarless-mcp registers as sonarqube-local instead. To do it by hand, sonarless-mcp mcp-config <client> prints the snippet.

How it works:

Claude Code ─┐                      ┌──────────────────────────┐   ┌──────────────┐
Cursor ──────┼─ sonarless-mcp mcp ──▶ sonarless-mcp container  ├──▶│ SonarQube    │
opencode ────┘  (tiny stdio shim,   │ (SonarQube MCP, HTTP,    │   │ (one server) │
                 one per client)    │  127.0.0.1:9235)         │   └──────────────┘
                                    └──────────────────────────┘
  • Each client runs a few-MB shim instead of its own Java MCP container.

  • The shim starts or resumes the shared containers, keeps one token valid (regenerated under a lock, so clients never revoke each other's), and answers initialize/tools/list from cache during a cold start so clients don't time out.

  • Tools that take a projectKey default to the workspace's project (only when that project exists on the server), and the agent is told which project it is.

  • After SONARLESS_IDLE_TIMEOUT (default 30m) without MCP calls, scans or web UI traffic, a background watcher stops both containers. The next request resumes them, history intact.

What agents get

Besides SonarQube's own tools, the sonarqube MCP server offers sonarless-mcp's features as tools, so any client can use them without knowing the CLI:

Tool

Does

sonarless_status

local containers, remotes and whether they're reachable

sonarless_project

detected project key/name, its source, which servers have it

sonarless_scan

scan the workspace locally and report the quality gate

sonarless_remote_sync

align local rules with a remote (CI) — when remotes exist

Anything that needs a token (adding a remote, changing its token) stays a terminal command: the tools tell the agent the exact command to give you, and a token never passes through the chat. SONARLESS_MCP_AGENT_TOOLS=false hides them.

sonarless-mcp setup also installs a sonarless-mcp skill for clients with skills (Claude Code, Cursor, opencode, Codex) — a short guide the agent loads when you ask about SonarQube or sonarless, kept current by updates and never written over a skill of yours with the same name.

Remote SonarQube servers

Next to the local server you can add any number of remote ones — typically your company's CI server — and ask the agent about either:

sonarless-mcp remote add work --url http://sonar.internal:9000 --branch develop   # token: hidden prompt
sonarless-mcp remote update work --token                # new token (hidden prompt); keeps url/branch
sonarless-mcp remote update work --url http://10.0.0.5:9000   # server moved; keeps token
sonarless-mcp remote update work --branch main                # CI now analyzes main; keeps url/token
sonarless-mcp remote list        # name, reachable/unreachable, url, default branch
sonarless-mcp remote import work --branch develop   # reuse a SonarQube MCP entry another client already has
sonarless-mcp remote sync work   # make local scans judge this project like CI (gate, rule sets, new code)
sonarless-mcp remote remove work

Use a User token (squ_…, My Account → Security): analysis tokens (sqa_/sqp_) can only submit scans, not read results, so they're refused.

Every MCP tool then takes an optional server argument: local (default — your working copy, scanned in real time) or a remote's name (what CI found, e.g. on develop). The workspace's project key and the remote's branch are filled in.

Judge local scans like CI

sonarless-mcp remote sync work (run in a project) copies the remote's quality gate, the quality profiles (rule sets) the project uses there and its new-code definition to your local server, and applies them to the project — so a local scan fails on the same conditions CI would (e.g. 80% coverage, 3% duplication) before you push. Copies are named work: <name>; nothing built-in is changed, and built-in profiles that are identical on both servers (same SonarQube version) are left as is. Run it again to pick up changes on the remote.

Remotes are built to stay out of the way:

  • Nothing touches a remote unless a tool call asks for it: startup, initialize and the tool list only use the local server.

  • Before a remote call, a 3-second reachability check (cached 30s) runs; if the server is down or you're off the VPN, the agent gets a clear tool error and keeps using the local server. Reconnect and the next call works.

  • A remote's MCP container only starts on its first successful use and stops with the rest when idle, so configured-but-unused remotes cost nothing.

  • Tokens are stored per remote in a private file (remotes/<name>.token, 0600), never in remotes.json; a remote can be added while offline and is verified on first use.

Scan from the command line

sonarless-mcp scan            # detect, start server, scan, wait for the quality gate
sonarless-mcp results         # key metrics, saved to sonar-metrics.json
sonarless-mcp project         # what was detected and where it came from
sonarless-mcp status | start | stop
sonarless-mcp reset --yes     # wipe this version's history and start fresh

Scanners: Maven projects use ./mvnw → mvn → a Maven container; Gradle projects use ./gradlew → gradle → a Gradle container (the SonarQube plugin is applied by an init script if the build doesn't declare it); .NET uses dotnet-sonarscanner; everything else uses the sonar-scanner CLI container. Build-based scans skip tests unless --tests (needed for coverage).

Project key detection

First match wins:

  1. SONARLESS_PROJECT_KEY (env or .sonarless.env)

  2. sonar-project.properties, then .sonarcloud.properties

  3. explicit build config: pom.xml <properties>, Gradle sonar { properties { ... } } / gradle.properties, package.json "sonar"

  4. pyproject.toml [tool.sonar]

  5. .NET SonarQube.Analysis.xml / Directory.Build.props

  6. CI pipelines (GitHub Actions, GitLab CI, Jenkinsfile, Azure Pipelines, Bitbucket, CircleCI): -Dsonar.projectKey=…, /k:…, projectKey: — so local keys match CI

  7. build defaults: Maven groupId:artifactId, Gradle group:rootProject.name, .sln name, package.json name

  8. the directory name

The project root is the topmost Maven/Gradle/Sonar root under the git root, so running from inside a module scans the whole build.

Configuration

sonarless-mcp config prints every setting and where it came from. Layers, lowest first:

  1. built-in defaults

  2. user file: ~/.config/sonarless-mcp/config.env (Linux), ~/Library/Application Support/sonarless-mcp/config.env (macOS), %AppData%\sonarless-mcp\config.env (Windows)

  3. project file .sonarless.env (scan settings only — the server is shared)

  4. environment variables

# config.env — match the SonarQube version your CI uses
SONARLESS_SONARQUBE_VERSION=26.6.0.123539-community
SONARLESS_IDLE_TIMEOUT=30m

Setting

Default

SONARLESS_SONARQUBE_VERSION

26.6.0.123539-community

sonarqube image tag

SONARLESS_SERVER_PORT

9234

web UI/API port (127.0.0.1)

SONARLESS_ADMIN_USER / SONARLESS_ADMIN_PASS

admin / admin

local admin

SONARLESS_MCP_PORT / SONARLESS_MCP_IMAGE

9235 / sonarsource/sonarqube-mcp:latest

shared MCP server

SONARLESS_MCP_TOOLSETS / SONARLESS_MCP_READ_ONLY

server defaults / false

passed to the MCP server

SONARLESS_IDLE_TIMEOUT

30m

0 keeps everything running

SONARLESS_INSTANCE

sonarless

names the containers (-server, -mcp), network and volumes

SONARLESS_AUTO_UPDATE

true

daily background update check (binary + MCP image)

SONARLESS_MCP_AGENT_TOOLS

true

expose the sonarless_* tools to agents

SONARLESS_PLUGINS_DIR

<config dir>/plugins

extra plugin jars (a shellcheck binary there is mounted into CLI scans)

SONARLESS_PROJECT_KEY / SONARLESS_PROJECT_NAME

detected

per project

SONARLESS_SCANNER / SONARLESS_SCAN_TESTS

auto / false

per project

SONARLESS_SOURCES / SONARLESS_SCANNER_IMAGE / SONARLESS_METRICS_FILE

. / sonarsource/sonar-scanner-cli:12.1 / sonar-metrics.json

per project

About SonarQube versions

SonarQube's embedded database can't be upgraded across versions, so each version keeps its own data volumes: a new version starts with fresh history, and switching back restores the old one. sonarless-mcp reset --yes wipes the current version's history.

Contributing

Conventional Commits drive fully automated releases (semantic-release + GoReleaser); see AGENTS.md for layout, testing rules and the release flow.

Credits

MIT licensed; see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    An MCP server for SonarQube that enables LLM agents to discover projects, analyze code quality metrics, check Quality Gate status, search issues with filters, and rank projects by worst-performing metrics. It provides read-only, safe access to SonarQube instances with structured outputs and error handling.
    5
    48 PyPI
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server that exposes SonarQube data as AI agent tools, enabling project discovery, quality gates, measures, issues, hotspots, rule explanations, source code, and raw API access.
    4
    -