kotlin-lsp plugin: LSP servers lost during reinitializeLspServerManager (generation 2 overwrites with 0 servers)

Resolved 💬 3 comments Opened Apr 7, 2026 by Gorita Closed Apr 10, 2026

Problem

The official kotlin-lsp plugin from claude-plugins-official marketplace fails to start the LSP server process. The LSP manager initializes correctly on first pass (generation 1) but a subsequent reinitializeLspServerManager() call (generation 2) overwrites the server list with 0 servers.

Debug Log Evidence

Generation 1 (correct):

[LSP MANAGER] Starting async initialization (generation 1)
Loaded 1 LSP server(s) from plugin: kotlin-lsp
Total LSP servers loaded: 2
[LSP SERVER MANAGER] getAllLspServers returned 2 server(s)
LSP manager initialized with 2 servers

Generation 2 (overwrites):

[LSP MANAGER] reinitializeLspServerManager() called
[LSP MANAGER] Starting async initialization (generation 2)
Loaded plugins - Enabled: 4, Disabled: 0, Commands: 2, Agents: 6, Errors: 0
Total LSP servers loaded: 0
[LSP SERVER MANAGER] getAllLspServers returned 0 server(s)
LSP manager initialized with 0 servers

Root Cause Analysis

The lspServers configuration for kotlin-lsp is defined in marketplace.json, not in the cached plugin.json. During generation 1, the LSP manager reads from marketplace.json and correctly finds the LSP server config. However, when reinitializeLspServerManager() is triggered (by file/settings watch changes ~200ms later), it appears to only read from the cached plugin.json, which contains no lspServers field:

Cached plugin.json (~/.claude/plugins/cache/claude-plugins-official/kotlin-lsp/1.0.0/.claude-plugin/plugin.json):

{
  "name": "kotlin-lsp",
  "description": "Kotlin language server for code intelligence",
  "version": "1.0.0",
  "author": {
    "name": "Anthropic",
    "email": "support@anthropic.com"
  }
}

marketplace.json (has the config):

{
  "name": "kotlin-lsp",
  "source": "./plugins/kotlin-lsp",
  "lspServers": {
    "kotlin-lsp": {
      "command": "kotlin-lsp",
      "args": ["--stdio"],
      "extensionToLanguage": {
        ".kt": "kotlin",
        ".kts": "kotlin"
      }
    }
  }
}

The plugin source directory also has no .lsp.json file — only README.md and LICENSE.

Workaround

Created a local marketplace with .lsp.json in the plugin directory, so the LSP config is read from the plugin itself rather than relying on marketplace.json:

kotlin-lsp-local/
├── .claude-plugin/
│   └── marketplace.json
└── plugins/
    └── kotlin-lsp/
        ├── .claude-plugin/
        │   └── plugin.json
        └── .lsp.json          ← LSP config here

This survives reinitialize because the config is in the plugin's own .lsp.json.

Environment

  • Claude Code: 2.1.92
  • OS: macOS 15.7.4 (ARM64)
  • kotlin-lsp binary: installed via brew install JetBrains/utils/kotlin-lsp
  • kotlin-lsp binary works correctly when tested directly with LSP protocol framing

Expected Behavior

The reinitializeLspServerManager() should preserve LSP server configurations from marketplace.json, or the official plugin should include a .lsp.json file so the config is available from the plugin directory itself.

Additional Note

The official docs page (https://code.claude.com/docs/en/discover-plugins#code-intelligence) lists the required binary as kotlin-language-server, while the marketplace.json uses kotlin-lsp as the command. The README says brew install JetBrains/utils/kotlin-lsp. These should be consistent.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗