[FEATURE] Improve LSP client compatibility with Roslyn language server (C#/.NET)
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
The official Microsoft Roslyn language server (Microsoft.CodeAnalysis.LanguageServer) only partially works with Claude Code's LSP client. Some operations succeed (hover, documentSymbol, goToDefinition, findReferences) but others fail or return empty results (workspaceSymbol, goToImplementation), and indexing is unreliable — operations called shortly after startup often fail.
This issue focuses on Roslyn-specific protocol requirements that go beyond the generic LSP gaps already tracked in other issues.
What works
hover— returns type infodocumentSymbol— lists symbols in a filegoToDefinition— navigates to definitions within the workspacefindReferences— finds references (once indexing completes)
What doesn't work
goToImplementation— Roslyn won't enable this withouttextDocument.implementationin client capabilities (see #32502)workspaceSymbol— requires aqueryparameter the LSP tool doesn't expose (see #38198), andworkspace.symbolis missing from client capabilitiescallHierarchy/incomingCalls/outgoingCalls— Roslyn doesn't implementtextDocument/prepareCallHierarchy; this is a server limitation, not a Claude Code bug- Indexing is unreliable — operations fail with empty results when called before Roslyn finishes indexing
Root causes (from binary analysis + Serena comparison)
I compared Claude Code's LSP client behavior (extracted from the compiled binary) against Serena's Roslyn implementation, which has a fully working Roslyn integration.
1. Missing client capabilities
Claude Code declares:
capabilities: {
workspace: { configuration: false, workspaceFolders: false },
textDocument: {
hover: {}, definition: {}, references: {},
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
callHierarchy: {},
// Missing: implementation, typeDefinition, signatureHelp
},
// Missing: workspace.symbol
}
Roslyn only enables server-side features when the client declares support for them. The missing textDocument.implementation capability is why goToImplementation fails silently.
Related: #32502
2. No Roslyn-specific solution/project notifications
After initialization, Roslyn expects solution/open and project/open notifications to know which solution and projects to load. Without these, it relies on --autoLoadProjects, which is less reliable and slower.
Serena sends these explicitly:
self.server.notify.send_notification("solution/open", {"solution": solution_uri})
self.server.notify.send_notification("project/open", {"projects": project_uris})
Claude Code sends neither.
3. No readiness wait
Roslyn emits a workspace/projectInitializationComplete notification when indexing is done. Serena waits up to 30 seconds for this before considering the server ready. Claude Code doesn't wait for any readiness signal, so operations called early in a session often fail.
4. workspace/configuration returns null for everything
When Roslyn pulls configuration via workspace/configuration, Claude Code returns null for every item. Serena returns sensible defaults (analysis scope, member insertion location, etc.). While Roslyn tolerates null responses, returning proper defaults improves behavior.
Related: #16360, #33552
Proposed Solution
For the plugin system (generic, benefits all LSP servers)
- Add
textDocument.implementationandworkspace.symbolto client capabilities — these are standard LSP features (#32502) - Use plugin
settingsto respond toworkspace/configurationpull requests — currently settings are only sent viadidChangeConfigurationpush, not used for pull responses (#33552)
For Roslyn specifically (could be solved generically)
- Support post-initialization notifications in plugin config — a new field like
postInitNotificationsin.lsp.jsonwould let plugins send custom notifications afterinitialized. This is generic enough to benefit other servers too:
{
"roslyn": {
"command": "roslyn-language-server.cmd",
"postInitNotifications": [
{ "method": "solution/open", "params": { "solution": "${WORKSPACE_SOLUTION_URI}" } }
]
}
}
- Support a readiness notification in plugin config — a new field like
readyNotificationthat tells the LSP client to wait for a specific notification before marking the server as ready:
{
"roslyn": {
"readyNotification": "workspace/projectInitializationComplete"
}
}
Related Issues
- #32502 — Expand LSP tool to support more protocol methods
- #32595 — LSP client does not respond to client/registerCapability
- #33552 — settings field not sent via workspace/didChangeConfiguration
- #38198 — workspaceSymbol missing query parameter
- #16360 — C# LSP missing workspace/configuration and other request handlers
Additional Context
- Roslyn version tested: 5.5.0-2.26103.6 (installed as dotnet global tool
roslyn-language-server) - Plugin config: custom local plugin with
--stdio --autoLoadProjectsargs - Project size: ~60 projects in a .slnx solution (large WPF application)
- Platform: Windows 11, Claude Code latest
- Reference implementation: Serena's CSharpLanguageServer demonstrates a fully working Roslyn integration with all the above features
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗