Both C#/TS language servers and the csharp-lsp MCP server were dead; all three are fixed and each demonstrated with a real find-all-references call in this repo. Root causes were one shape — a config naming a path this machine does not have, with nothing checking. None returned a wrong answer; each refused to start: - csharp-ls: MSBuildLocator needs a dotnet root owning host/fxr; Homebrew's bin has none, libexec does. - typescript-language-server: the LSP workspace root is the repo root but `typescript` lives in web/node_modules, and the plugin cannot pass a tsserver path (v5 dropped --tsserver-path; lspServers cannot set initializationOptions). - the csharp-lsp MCP server: .mcp.json named a dotnet install that no longer existed, while ~/.codex/config.toml's copy of the same server had been migrated. Both files are gitignored, so nothing could compare them. Corrects defect-shapes-773.md §5.1: the "workflow agents must use csharp-lsp" note names the MCP server's tools, which subagents DO reach — it was dead because the server could not start, not because agents cannot call it. The LSP tool is the one no subagent has been observed to resolve. Six cold review rounds. Five false greens were found in this PR's own verification code, each introduced by the fix for the previous one — extracted as #796. fixes #777 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be>
4.8 KiB
key, title, status, since, supersedes, superseded-by, rule, signals, mechanics
| key | title | status | since | supersedes | superseded-by | rule | signals | mechanics |
|---|---|---|---|---|---|---|---|---|
| session.local-code-intelligence | 2026-08-14 — Brief subagents at the csharp-lsp MCP tools; no subagent has been observed to reach the LSP tool (#777) | active | 2026-08-14 | none | none | C# and TypeScript find-all-references are available again; brief delegated agents to the `csharp-lsp` MCP tools (`csharp_references`, `csharp_diagnostics`, …) rather than the `LSP` tool, which no dispatched subagent has been observed to resolve (Claude Code 2.1.232, agent types `general-purpose` and `Explore`, 2026-08-14). Preconditions are machine-local — `env.DOTNET_ROOT` in `.claude/settings.local.json` and a root `node_modules/typescript` link — and checkable with `scripts/check-local-lsp.sh`. | find all references, findReferences, csharp-ls, typescript-language-server, LSP tool, csharp-lsp MCP, libhostfxr, MSBuildLocator, DOTNET_ROOT, subagent tool availability · paths: `docs/local-lsp-tooling.md`, `scripts/check-local-lsp.sh`, `.claude/settings.local.json`, `.mcp.json` · issues: #777, #773, #403, #671 | `docs/local-lsp-tooling.md` — surfaces, configuration, traps, verification |
The capability that would address the residue of Family A was configured, enabled, and dead. The
population that testing.guard-derives-population-from-source cannot reach is the one whose members
are sites in code rather than values — #403 (5 of 6 dispatch sites) and #671 (4 of 10 media types).
Find-all-references answers exactly that, and across 811 session transcripts the LSP tool was
invoked zero times, against 23,661 Bash calls over the same corpus. Both C# surfaces failed to
start; nothing reported it, because a language server that cannot initialize is indistinguishable
from one nobody asked.
Two surfaces, and only one of them has been observed to cross the subagent boundary. A dispatched
subagent's ToolSearch returns "No matching deferred tools found" for select:LSP while the same
query resolves in the main session — measured on Claude Code 2.1.232, agent types general-purpose
and Explore, 2026-08-14, plus the independent §5.1 observation. Three observations on one client
version: design around it, but it is measured behaviour, not a guaranteed contract. The MCP side is
positively evidenced — 326 MCP calls from inside subagent turns across four servers in the transcript
corpus — though not yet for csharp-lsp specifically, which only became startable on 2026-08-14. So
the standing note telling workflow agents to use C# code intelligence was unsatisfiable as written
against the LSP tool, and is satisfiable once pointed at the MCP tools. Naming the surface is the
load-bearing part: an agent that cannot resolve the tool substitutes Grep and does not say so.
Both failures were a config naming a path the machine does not have. MSBuildLocator needs a
dotnet root owning host/fxr, which a Homebrew bin/dotnet does not have (libexec does); the MCP
entry named a dotnet install that no longer existed, while ~/.codex/config.toml's copy of the same
server had been migrated. Neither returned a wrong answer — each refused to start, which is the
benign half of environment divergence and the reason it survived so long.
.mcp.json and .mcp/ are gitignored, so the working configuration is not recoverable from the
repo. That is what let one client's copy drift from the other's with nothing to compare against.
docs/local-lsp-tooling.md carries the entry verbatim so a second machine can reconstruct it, and
scripts/check-local-lsp.sh turns every precondition into a check. The script is deliberately wired
to no CI job: every dependency it tests is a developer-machine install, so a red on a runner
would carry no information.
Rejected: making find-all-references a mandatory step before multi-site fixes. Not for
availability reasons — C# is expected to reach delegated agents through the MCP server, so a
mandate would likely be enforceable there (an inference from the MCP boundary generally, not a
measurement of csharp-lsp from a subagent); only the TypeScript route is main-session-bound. The reason is readiness, and it bites each server
separately: csharp-ls answers [] while ErsatzTV.sln loads (minutes), and
typescript-language-server answers with the declaration alone while its own project graph loads —
20 references reported as 1, with nothing marking it incomplete. Mandating the step without a way to prove the server had settled would license treating
that answer as a population — the precise failure the step exists to prevent, now carrying the
authority of a rule. It is documented as available and recommended for the multi-site case, with the
re-issue-and-confirm discipline attached, and the zero-invocation baseline above is what a future
measurement should be compared against.