dotnet plugin's Claude manifest references the wrong-shaped LSP file, and version-sync would silently revert any fix
Summary
plugins/dotnet/.claude-plugin/plugin.json declares:
"lspServers": "./lsp.json"
lsp.json uses the Copilot CLI shape. Claude Code reads .claude-plugin/plugin.json and expects a different shape for the referenced file — the one already shipped at plugins/dotnet/.lsp.json (added in #298 / e03f2f2 for exactly this reason).
Copilot CLI shape (lsp.json) |
Claude Code shape (.lsp.json) |
|
|---|---|---|
| Outer wrapper | { "lspServers": { "csharp": {...} } } |
{ "csharp": {...} } (no wrapper) |
| Extension key | fileExtensions |
extensionToLanguage |
| Referenced by | root plugin.json |
.claude-plugin/plugin.json |
Impact
An explicit lspServers reference to the wrong-shaped file takes precedence over Claude Code's own auto-discovery of .lsp.json, so Claude Code registers zero LSP servers for this plugin instead of falling back to the correct file.
Verified locally: pointing .claude-plugin/plugin.json's lspServers at ./.lsp.json fixes LSP registration in Claude Code.
Why this isn't a one-line fix
eng/version/Sync-PluginVersions.ps1 currently treats .claude-plugin/plugin.json as a byte-identical generated copy of the root plugin.json:
[IO.File]::WriteAllText($claudeManifest, [IO.File]::ReadAllText($manifest))
This runs on every /version-bump and the weekly version sync. Since the root manifest must keep referencing ./lsp.json for Copilot CLI, simply editing .claude-plugin/plugin.json's lspServers value would be silently reverted at the next stamp.
Proposed fix
- In
Sync-PluginVersions.ps1, treat the Claude manifest like the Codex manifest: keep only theversionfield in sync (regex-basedSet-ManifestVersion), bootstrapping a missing file as a full copy but never overwriting an existing file's other fields. This step is required regardless of which option below is chosen — without it, any manual edit to.claude-plugin/plugin.jsonis silently reverted at the next/version-bumpor weekly sync. - Update
plugins/dotnet/.claude-plugin/plugin.jsonso Claude Code resolves the correct LSP file, leaving the rootplugin.json(read by Copilot CLI) unchanged at./lsp.json. Two options:- Point
lspServersexplicitly at./.lsp.json— verified locally to work; documents the intent in the manifest itself. - Remove the
lspServersfield entirely — relies on Claude Code's own auto-discovery of.lsp.jsonat the plugin root; one line simpler, but untested here, and leaves the LSP declaration implicit (a future contributor "fixing" the manifests back into sync could more easily reintroduce the bug than if the correct reference is spelled out).
- Point
- Update
eng/version/Test-Sync-PluginVersions.ps1and document the divergence inCONTRIBUTING.md.
Source: dotnet/skills