Dart language server burns ~1 CPU core continuously at idle when activated on a monorepo root (rootUri hardcoded to project root; no idle recycling)
Environment
- Serena 1.7.0 (stdio MCP, LSP backend)
- Bundled DartLanguageServer, Dart SDK 3.7.1
- macOS arm64
Symptom
On a large monorepo root (several sub-projects in different languages: Vue/TS, Java, C++, and one Flutter/Dart sub-project), the dart language-server process burns ~1 CPU core continuously for hours with zero requests issued. Measured: 40–48 CPU-seconds per 60s wall-clock at idle, %CPU fluctuating 120–150%, RSS 350–490 MB (peak ~1.1 GB).
All other language servers in the same setup (vue/ts/java/cpp/clangd) consume ~0 CPU at idle (0.03–0.05s per 60s). So the Dart server is a clear outlier.
Note: activating the same Dart SDK via a client that roots it at the real Flutter sub-project directory (which has pubspec.yaml) shows no such behavior — it converges and idles.
Steps to reproduce
- Monorepo root with: no
pubspec.yamlat root; a few hundred.dartfiles scattered under one sub-project that does havepubspec.yaml; hundreds of thousands of files in total (incl.node_modules, build dirs). project.yml:language_servers: [vue, typescript_vts, java, cpp, dart].- Start serena MCP with
--project-from-cwdat the monorepo root. - Wait a few minutes without issuing any request; the
dart language-serverprocess stays at high CPU.
Root cause (confirmed against SDK/source)
- solidlsp unconditionally sets
rootUri= project root in theinitializerequest (DefaultInitializeParamsBuilder._apply_updates), plusworkspaceFoldersfromls_workspace_folders. - The Dart analysis server adds both
workspaceFoldersandrootUrito its analysis roots (no dedup). So the entire monorepo root becomes an analysis root regardless ofls_workspace_folders. - The analysis server then recursively enumerates the whole tree, installs a recursive FSEvents watcher on it, and background-analyzes every
.dartfile. Sub-projects withoutpubspec.yamlfall back toBasicWorkspace(no package resolution), sopackage:imports fail and each file is analyzed in isolation — pure waste. - Active builds in the monorepo continuously generate FS events that keep the watcher busy, so CPU never settles.
- Serena starts all configured language servers eagerly and has no idle timeout / lazy start / recycling until the MCP session ends.
Expected behavior
rootUrishould not be unconditionally set to the project root when explicitworkspaceFoldersare provided (or should be deduped so a folder is not both rootUri and a workspace folder).- Ideally, support per-language workspace folders, e.g. allow each entry in
language_serversto carry arootDir, so the Dart server can be rooted at the actual Flutter sub-project. - Consider idle-based recycling of language servers.
Suggested fixes (in order of preference)
- Per-language
rootDirinlanguage_servers(most general; benefits any language, not just Dart). - Don't set
rootUrito the project root whenworkspaceFoldersare present; or dedupe rootUri against workspaceFolders. - Idle timeout that stops an inactive language server and re-spawns on demand.
Workaround (what we do now)
Remove dart from language_servers and rely on another tool for Dart symbol queries. (The deprecated onlyAnalyzeProjectsWithOpenFiles: true also reduces CPU but is marked deprecated and hurts workspace symbol search.)
Source: oraios/serena