Skip to content

dotnet plugin's C# LSP never loads in Claude Code — manifest is at root plugin.json, but Claude reads lspServers only from .clau [Content truncated due to length] #846

Description

@hgirma

Summary

The dotnet plugin declares a C# (Roslyn) language server via lspServers, but it never loads in Claude Code: Total LSP servers loaded: 0. The plugin's skills load fine, which masks the problem.

Root cause: Claude Code reads a plugin's manifest — and therefore its lspServers field — only from <pluginRoot>/.claude-plugin/plugin.json. The dotnet plugin instead ships its manifest at the repo-root plugin.json (plus a .codex-plugin/plugin.json for Codex) and has no .claude-plugin/plugin.json. So Claude never sees lspServers. Skills still appear because Claude auto-discovers them from skills/*/SKILL.md frontmatter, independently of the manifest — so only the LSP (the one manifest-only feature) is silently broken.

Environment

  • Claude Code @anthropic-ai/claude-code 2.1.195 (observed on Windows 11, but this is OS-independent)
  • Marketplace dotnet-agent-skills (this repo), plugin dotnet
  • .NET SDK 10.0.301; dnx on PATH; dnx roslyn-language-server --yes --prerelease -- --stdio --autoLoadProjects launches Microsoft.CodeAnalysis.LanguageServer.exe fine when run manually

Repro

  1. Install the dotnet plugin and enable it.
  2. Launch claude --debug with CLAUDE_CODE_DEBUG_LOGS_DIR set, then open/edit a .cs file.
  3. Grep the debug log:
    • Total LSP servers loaded: 0
    • No per-plugin LSP load attempt is logged (none of LSP server(s) from plugin:, Failed to read/parse .lsp.json in plugin, Missing environment variables in plugin LSP config:). The loader never treats dotnet as an LSP source.
    • The dotnet skills do load.
  4. No Microsoft.CodeAnalysis.LanguageServer.exe / dnx process is spawned.

Evidence that the manifest location is the cause

  • Claude Code's plugin loader requires the manifest at .claude-plugin/plugin.json (".claude-plugin/plugin.json is always required"; "No manifest found in directory. Expected .claude-plugin/marketplace.json or .claude-plugin/plugin.json").

  • Every first-party Claude Code plugin (e.g. superpowers, telegram, frontend-design) places its manifest at .claude-plugin/plugin.json and has no root plugin.json.

  • Every dotnet/skills plugin does the opposite — root plugin.json, no .claude-plugin/plugin.json:

    plugin .claude-plugin/plugin.json root plugin.json .codex-plugin/plugin.json lsp.json
    dotnet
    dotnet-ai / -aspnetcore / -blazor / -test / dotnet11
    dotnet-data / -diag / -maui / -msbuild / -nuget / -aspnet

Likely fix (verification in progress)

Ship a .claude-plugin/plugin.json for each plugin — at minimum for dotnet, which declares the LSP — the same way .codex-plugin/plugin.json is already provided for Codex. The content can mirror the existing root plugin.json:

{
  "name": "dotnet",
  "version": "0.1.0",
  "description": "Common everyday C#/.NET coding skills. Expected to be useful to all .NET developers.",
  "skills": ["./skills/"],
  "lspServers": "./lsp.json"
}

I'm validating locally by dropping exactly this .claude-plugin/plugin.json into the installed plugin and checking for Total LSP servers loaded: 1 + a spawned server process; will update this issue with the confirmed result.

Optional hardening: inline the server config under lspServers (record form) instead of the "./lsp.json" string path, e.g.

"lspServers": {
  "csharp": {
    "command": "dnx",
    "args": ["roslyn-language-server", "--yes", "--prerelease", "--", "--stdio", "--autoLoadProjects"],
    "cwd": "${PLUGIN_ROOT}",
    "fileExtensions": { ".cs": "csharp", ".razor": "aspnetcorerazor", ".cshtml": "aspnetcorerazor" },
    "startupTimeout": 120000
  }
}

Impact

Anyone using the dotnet plugin in Claude Code for C# LSP gets no language-server intelligence (diagnostics, go-to-definition, hover, symbols) and no indication why — skills load, so the plugin looks healthy. The same root-level manifest affects all dotnet/skills plugins, but it's only observable for dotnet because that's the only one with manifest-only functionality (lspServers); the rest rely on skills, which auto-discover regardless.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions