<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cursor | Денис Трофимов</title><link>https://denis-trofimov.github.io/ru/tags/cursor/</link><atom:link href="https://denis-trofimov.github.io/ru/tags/cursor/index.xml" rel="self" type="application/rss+xml"/><description>Cursor</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>ru-RU</language><lastBuildDate>Sat, 18 Jul 2026 00:00:00 +0300</lastBuildDate><image><url>https://denis-trofimov.github.io/media/icon_hu_da05098ef60dc2e7.png</url><title>Cursor</title><link>https://denis-trofimov.github.io/ru/tags/cursor/</link></image><item><title>Выбор semantic code search MCP для агентов на примере Cursor</title><link>https://denis-trofimov.github.io/ru/blog/2026-07-18-choosing-semantic-code-search-mcp-cursor/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0300</pubDate><guid>https://denis-trofimov.github.io/ru/blog/2026-07-18-choosing-semantic-code-search-mcp-cursor/</guid><description>&lt;p&gt;Агентам в Cursor мало одного Grep. Лексический поиск находит строки; он плохо вытаскивает нужный сервис или контроллер, когда запрос — смесь имён и намерения. Локальный semantic / hybrid MCP с &lt;code&gt;search&lt;/code&gt; и &lt;code&gt;find_related&lt;/code&gt; сокращает слепое чтение файлов, которое сжигает токены.&lt;/p&gt;
&lt;p&gt;Выбор такого MCP — задача того же класса, что и раньше на реальных машинах: мерить под свои ограничения, не верить маркетинговым цифрам по RAM, потом делать cutover.&lt;/p&gt;
&lt;h2 id="сначала-ограничения"&gt;Сначала ограничения&lt;/h2&gt;
&lt;p&gt;Хост бенчмарка — не лабораторная станция:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Параметр&lt;/th&gt;
&lt;th&gt;Значение&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;Intel Core i5-6300U @ 2.40 GHz, 4 cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;15 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Клиент&lt;/td&gt;
&lt;td&gt;Cursor MCP по stdio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Корпус&lt;/td&gt;
&lt;td&gt;крупный ERP-класс monorepo для лизинговой / кредитной компании (авто, оборудование, недвижимость), multi-root со вторым API-репо&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Это отсекает тяжёлые transformer forward pass и всё, что тянет Ollama или cloud vector DB на той же машине. Рабочий класс — BM25 плюс статическое embedding в духе Model2Vec: семейство Semble, Ken и их Rust-портов.&lt;/p&gt;
&lt;p&gt;Сам код — классический &lt;strong&gt;PHP / Yii monolith&lt;/strong&gt;: одно толстое дерево приложения, а не рой мелких сервисов. Рядом с controllers, modules и services лежат годы &lt;code&gt;migrations/&lt;/code&gt;, upload- и сгенерированные деревья под &lt;code&gt;web/&lt;/code&gt; (картинки, PDF, собранные ассеты) и крупные статические бандлы, которые не являются исходниками. &lt;code&gt;.gitignore&lt;/code&gt; уже убирает &lt;code&gt;vendor/&lt;/code&gt;, &lt;code&gt;node_modules/&lt;/code&gt;, &lt;code&gt;runtime/&lt;/code&gt; и похожее из VCS — и из инструментов, которые смотрят только на gitignore. Остальной низкосигнальный объём он &lt;strong&gt;не&lt;/strong&gt; отсекает. Для semantic search этот разрыв важен: каждый лишний путь — это файлы на диске для обхода, чанки для embedding, cold start и RSS. С дополнительным ignore в стиле Semble/Sonar fair-индекс на этом корпусе сошёлся примерно в &lt;strong&gt;~4.3k files / ~18.6k chunks&lt;/strong&gt;. Пути, которые отсекает только &lt;code&gt;.sembleignore&lt;/code&gt; / &lt;code&gt;.sonarignore&lt;/code&gt; — &lt;code&gt;migrations/&lt;/code&gt;, &lt;code&gt;web/image|assets|…&lt;/code&gt;, &lt;code&gt;assets/reports|bonds&lt;/code&gt; и рядом — здесь около &lt;strong&gt;~3.6k files / ~340 MiB&lt;/strong&gt; на диске (из них ~1.1k файлов одних миграций). Без исключений шире gitignore индексатор спокойно жуёт эту массу поверх ~4.3k-файлового индекса приложения — почти удваивая обход — по деревьям, которые почти никогда не отвечают на запрос агента.&lt;/p&gt;
&lt;p&gt;
я уже подключал к агентским сценариям (
). Вопрос был — оставлять ли его primary в Cursor.&lt;/p&gt;
&lt;h2 id="кандидаты"&gt;Кандидаты&lt;/h2&gt;
&lt;p&gt;В scope: локальный (или self-hosted) MCP с semantic / hybrid retrieval и drop-in поверхностью &lt;code&gt;search&lt;/code&gt; / &lt;code&gt;find_related&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Инструмент&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Роль в эксперименте&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td&gt;Python / &lt;code&gt;uvx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Был primary в Cursor; baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Drop-in кандидат&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;Drop-in порт; &lt;code&gt;.sonarignore&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;Drop-in + лишние symbol-tools; только gitignore&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;После быстрой проверки отбросил: Bloop как search MCP (archived desktop, другой tool surface), ripgrep MCP как замену Semble (в Cursor уже есть Grep), Livegrep / Zoekt (лексический UI) и стеки с Ollama или удалённой vector DB на этом хосте.&lt;/p&gt;
&lt;h2 id="настройка"&gt;Настройка&lt;/h2&gt;
&lt;p&gt;Ниже — достаточно, чтобы воспроизвести fair MCP-бенч у себя. Пути — плейсхолдеры (&lt;code&gt;~/projects/lease-erp&lt;/code&gt;, &lt;code&gt;~/.local/bin&lt;/code&gt;). Бинарники — в &lt;code&gt;PATH&lt;/code&gt;. После правок &lt;code&gt;mcp.json&lt;/code&gt; перезапустите Cursor. В multi-root workspace агенты должны передавать абсолютный &lt;code&gt;repo&lt;/code&gt; в &lt;code&gt;search&lt;/code&gt; / &lt;code&gt;find_related&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="semble-baseline"&gt;Semble (baseline)&lt;/h3&gt;
&lt;p&gt;Python / &lt;code&gt;uvx&lt;/code&gt;. Был primary в Cursor до cutover; по-прежнему самый простой reference MCP с &lt;code&gt;.sembleignore&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# нужен uv (https://docs.astral.sh/uv/)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uvx --from &lt;span class="s1"&gt;&amp;#39;semble[mcp]&amp;#39;&lt;/span&gt; semble --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;semble&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;uvx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--from&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;semble[mcp]&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;semble&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stdio&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Корневой &lt;code&gt;.sembleignore&lt;/code&gt; — синтаксис как у &lt;code&gt;.gitignore&lt;/code&gt; (см. общий набросок ignore у Sonar).&lt;/p&gt;
&lt;h3 id="ken"&gt;Ken&lt;/h3&gt;
&lt;p&gt;Pure Go drop-in (
). Для бенча — hybrid: &lt;code&gt;KEN_MCP_MODE=hybrid&lt;/code&gt;. Ignore — &lt;strong&gt;только gitignore&lt;/strong&gt; (нет &lt;code&gt;.kenignore&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Go 1.26+ в PATH, либо binary с releases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/townsendmerino/ken/cmd/ken@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/townsendmerino/ken/cmd/ken-mcp@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# $(go env GOPATH)/bin в PATH, либо скопировать в ~/.local/bin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ken download-model &lt;span class="c1"&gt;# potion-code-16M (~60 MB); ken-mcp может скачать сам при первом запуске&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ken&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ken-mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;KEN_MCP_MODE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hybrid&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stdio&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Warm у CLI обманчив: &lt;code&gt;ken search&lt;/code&gt; переиндексирует на каждый вызов. Мерить нужно long-lived &lt;code&gt;ken-mcp&lt;/code&gt;, как в Cursor.&lt;/p&gt;
&lt;h3 id="veles"&gt;Veles&lt;/h3&gt;
&lt;p&gt;Pure Rust (
). Короткий путь — prebuilt installer; MCP — &lt;code&gt;veles serve-mcp&lt;/code&gt;. Обход дерева — &lt;strong&gt;gitignore-only&lt;/strong&gt;, аналога &lt;code&gt;.sembleignore&lt;/code&gt; на этапе индекса нет.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --proto &lt;span class="s1"&gt;&amp;#39;=https&amp;#39;&lt;/span&gt; --tlsv1.2 -LsSf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://github.com/julymetodiev/Veles/releases/latest/download/veles-cli-installer.sh &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# или: cargo install veles-cli&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;veles --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# по желанию: symlink в ~/.local/bin, если установщик положил бинарник в ~/.cargo/bin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;veles&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;veles&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;serve-mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stdio&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Индекс — в &lt;code&gt;&amp;lt;repo&amp;gt;/.veles/&lt;/code&gt;. Для честного cold: &lt;code&gt;veles clean ~/projects/lease-erp&lt;/code&gt; (и убрать остаток &lt;code&gt;.veles/&lt;/code&gt; при необходимости) перед первым MCP &lt;code&gt;search&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="sonar"&gt;Sonar&lt;/h3&gt;
&lt;p&gt;Pure Rust drop-in (
). На момент cutover prebuilt не было — сборка через stable &lt;code&gt;rustup&lt;/code&gt;. Есть &lt;code&gt;.sonarignore&lt;/code&gt; (синтаксис gitignore).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# rustup stable → ~/.cargo/bin в PATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/ooboai/sonar.git ~/src/sonar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/src/sonar &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo build --release
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;install -m &lt;span class="m"&gt;755&lt;/span&gt; target/release/sonar target/release/sonar-mcp ~/.local/bin/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sonar download-model &lt;span class="c1"&gt;# minishlab/potion-code-16M в кэш Sonar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;which sonar-mcp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sonar&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sonar-mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stdio&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cursor-parity с baseline Semble — &lt;code&gt;--content code docs&lt;/code&gt; (по умолчанию у Sonar MCP часто только &lt;code&gt;code&lt;/code&gt;). Smoke: &lt;code&gt;sonar search &amp;quot;SchedulePreviewService&amp;quot; -p ~/projects/lease-erp -k 5&lt;/code&gt;. Перед cold-бенчем очищайте &lt;code&gt;~/.cache/sonar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Общая форма &lt;code&gt;.sonarignore&lt;/code&gt; / &lt;code&gt;.sembleignore&lt;/code&gt; для PHP/Yii ERP (пути &lt;strong&gt;сверх&lt;/strong&gt; того, что уже в &lt;code&gt;.gitignore&lt;/code&gt; — &lt;code&gt;vendor/&lt;/code&gt;, &lt;code&gt;node_modules/&lt;/code&gt;, &lt;code&gt;runtime/&lt;/code&gt; сюда не дублируем):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;reports&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bonds&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;migrations&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_output&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_generated&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="метод-mcp-не-cli"&gt;Метод: MCP, не CLI&lt;/h2&gt;
&lt;p&gt;Я мерил &lt;strong&gt;долгоживущий MCP stdio&lt;/strong&gt; — один процесс на сервер, cold первый &lt;code&gt;search&lt;/code&gt;, затем warm-повторы. Метрики: cold Q1, warm Q1 median (5×), idle RSS / peak HWM, top-1 path на трёх фиксированных запросах и &lt;strong&gt;ignore-parity&lt;/strong&gt; — возможность исключать пути шире &lt;code&gt;.gitignore&lt;/code&gt;, как у &lt;code&gt;.sembleignore&lt;/code&gt;. На PHP/Yii ERP-монолите это не «приятный бонус», а то, что держит индекс на коде приложения, а не на миграциях и массе под &lt;code&gt;web/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Одноразовый CLI здесь ловушка. CLI Ken переиндексирует на каждый вызов, поэтому «warm» CLI — не proxy для Cursor. Честное сравнение чистит кэши перед cold, а для Sonar использует &lt;code&gt;.sonarignore&lt;/code&gt; — копию бывшего &lt;code&gt;.sembleignore&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Cursor-parity у Sonar: &lt;code&gt;--content code docs&lt;/code&gt; (как у Semble в &lt;code&gt;mcp.json&lt;/code&gt;). Ранний прогон только с &lt;code&gt;code&lt;/code&gt; был близко; каноническим считаю rebench с &lt;code&gt;code docs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Чего &lt;strong&gt;не&lt;/strong&gt; мерил: многодневный churn индекса, глубину tree-sitter для PHP, и каждый non-drop-in MCP с другим контрактом tools.&lt;/p&gt;
&lt;h3 id="каркас-бенчмарка"&gt;Каркас бенчмарка&lt;/h3&gt;
&lt;p&gt;Fair-прогон — один долгоживущий MCP-процесс на сервер: очистить кэш индекса, cold &lt;code&gt;search&lt;/code&gt;, затем warm-повторы, параллельно снимая RSS из &lt;code&gt;/proc&lt;/code&gt;. Пути ниже — плейсхолдеры; &lt;code&gt;--repo&lt;/code&gt; указывайте на своё дерево.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Cursor-parity режимы content; бинарники в PATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;BENCH_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/projects/lease-erp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uvx --with mcp --from mcp python bench_fair_mcp.py &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --repo &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BENCH_REPO&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --order ken-first
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uvx --with mcp --from mcp python bench_fair_rust_ports.py &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --repo &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BENCH_REPO&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --servers sonar --sonar-content &lt;span class="s2"&gt;&amp;#34;code docs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ядро цикла замера (Python MCP client SDK):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;BENCH_REPO&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;projects&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;lease-erp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;QUERIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SchedulePreviewService preview&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;ReferenceCacheService&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;actionPreview schedule leasing&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TOP_K&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;search&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;repo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;top_k&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOP_K&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# перед cold — сбросить disk cache этого сервера (зависит от инструмента)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cold_s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;call_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QUERIES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;warm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;call_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QUERIES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;cold_s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cold_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;warm_q1_median_s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;warm&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;RSS / peak HWM берутся из &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/status&lt;/code&gt; воркера (&lt;code&gt;VmRSS&lt;/code&gt;, &lt;code&gt;VmHWM&lt;/code&gt;), с исключением уже живущего Cursor MCP в IDE. В этом и отличие от one-shot CLI, который переиндексирует на каждый вызов.&lt;/p&gt;
&lt;h2 id="результаты"&gt;Результаты&lt;/h2&gt;
&lt;p&gt;Корпус: тот же ERP-класс monorepo лизинга / кредитования. Ken и Semble — fair MCP от 2026-07-17; Sonar / Veles — 2026-07-18 (колонка Sonar = &lt;code&gt;code docs&lt;/code&gt;).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Метрика&lt;/th&gt;
&lt;th&gt;Ken&lt;/th&gt;
&lt;th&gt;Semble&lt;/th&gt;
&lt;th&gt;Sonar&lt;/th&gt;
&lt;th&gt;Veles&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold Q1&lt;/td&gt;
&lt;td&gt;256.6 s&lt;/td&gt;
&lt;td&gt;71.5 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19.5 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm Q1 median&lt;/td&gt;
&lt;td&gt;43 ms&lt;/td&gt;
&lt;td&gt;448 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle RSS&lt;/td&gt;
&lt;td&gt;~2.1 GB&lt;/td&gt;
&lt;td&gt;~0.63 GB&lt;/td&gt;
&lt;td&gt;~0.66 GB&lt;/td&gt;
&lt;td&gt;~0.52 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak HWM&lt;/td&gt;
&lt;td&gt;~2.9 GB&lt;/td&gt;
&lt;td&gt;~0.68 GB&lt;/td&gt;
&lt;td&gt;~0.84 GB&lt;/td&gt;
&lt;td&gt;~0.52 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ignore parity&lt;/td&gt;
&lt;td&gt;нет&lt;/td&gt;
&lt;td&gt;да (&lt;code&gt;.sembleignore&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;да (&lt;code&gt;.sonarignore&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;gitignore-only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Top-1 на трёх запросах: все четыре попали в ожидаемые PHP-сервисы на Q1/Q2. На NL-запросе Q3 (&lt;code&gt;actionPreview schedule leasing&lt;/code&gt;) все четыре промахнулись в один и тот же неверный контроллер — паритет ошибки, не победа Sonar.&lt;/p&gt;
&lt;p&gt;Smoke dual-MCP (тёплый Semble в Cursor плюс cold-старт Sonar) дал суммарный idle около &lt;strong&gt;~1.1 GB&lt;/strong&gt;. Dual на 15 GiB жизнеспособен; после cutover он не понадобился.&lt;/p&gt;
&lt;h2 id="заявки-vs-замер"&gt;Заявки vs замер&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Утверждение (маркетинг / обзоры)&lt;/th&gt;
&lt;th&gt;На этом корпусе&lt;/th&gt;
&lt;th&gt;Вердикт&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Semble RAM «~100–300 MB»&lt;/td&gt;
&lt;td&gt;idle ~633 MB&lt;/td&gt;
&lt;td&gt;Занижено для крупного репо; порядок суб-GB верен&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ken «extremely low» RAM&lt;/td&gt;
&lt;td&gt;idle ~2.1 GB, peak ~2.9 GB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Не подтверждено&lt;/strong&gt; — тяжелее Semble&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm search «дешёвый»&lt;/td&gt;
&lt;td&gt;Ken/Sonar десятки ms; Semble ~0.45 s&lt;/td&gt;
&lt;td&gt;Warm у Ken/Sonar ок; UX ломает &lt;strong&gt;cold&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="решение"&gt;Решение&lt;/h2&gt;
&lt;p&gt;На хосте класса i5 / ≤16 GiB и крупном monorepo важнее &lt;strong&gt;cold start, RAM и контроль ignore&lt;/strong&gt;, чем самый быстрый warm-миллисекунд.&lt;/p&gt;
&lt;p&gt;18 июля 2026 я перевёл primary в Cursor на &lt;strong&gt;Sonar&lt;/strong&gt; (&lt;code&gt;sonar-mcp --content code docs&lt;/code&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sonar&lt;/strong&gt; — cold примерно в 3.5× быстрее Semble, warm примерно в 10×, RAM в той же полосе, плюс &lt;code&gt;.sonarignore&lt;/code&gt; для ignore-parity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Veles&lt;/strong&gt; — лучшие сырые cold/warm/RSS в таблице, но только gitignore. На этом monorepo это не покрывает &lt;code&gt;migrations/&lt;/code&gt;, сгенерированные ассеты и прочие пути вне &lt;code&gt;.gitignore&lt;/code&gt;. Не primary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ken&lt;/strong&gt; — rejected: cold ~257 s, RSS ~2–3 GB, нет ignore-файла; маркетинговый RAM не совпал с замером.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semble&lt;/strong&gt; — снят с primary в Cursor; остаётся полезной точкой отсчёта по контракту tools и модели ignore.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Non-drop-in semantic MCP (другой tool surface, knowledge graph, multi-repo index) — не primary, пока нет отдельной потребности.&lt;/p&gt;
&lt;h2 id="вывод"&gt;Вывод&lt;/h2&gt;
&lt;p&gt;Для агентов Cursor на стеснённых ноутбуках не выбирайте code-search MCP по скриншотам warm-ms. Прогоните fair long-lived MCP-бенч на &lt;strong&gt;своём&lt;/strong&gt; корпусе, проверьте ignore-parity и не путайте CLI-цифры с продуктом для Cursor.&lt;/p&gt;
&lt;p&gt;На этом хосте процесс выбрал Sonar — не потому что он выиграл каждую ячейку, а потому что выиграл те, от которых зависит, останется ли агент usable после cold start.&lt;/p&gt;</description></item></channel></rss>