on main help sign in
fix(lsp): improve lsp tools (#2089)

With auto discovery, the user configured lsps might be empty, but we might still configure some LSPs. We need to check the proper places, as well as refresh the tool list if LSPs are actually started. This is an alternative implementation to #2079 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

commit4a03cbaf3cf5e96cb5f6ac849817de025558e642 authorCarlos Alexandro Becker <caarlos0@users.noreply.github.com> dateMon 2 Feb 2026, 11:30 (9 months ago) parent00bbf45
4 files changed+18−10
internal/agent/coordinator.go+1−1 internal/agent/tools/mcp/init.go+1 internal/app/app.go+1−4 internal/app/lsp.go+15−5
internal/agent/coordinator.go+1−1
@@ -435,7 +435,7 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan
435435 tools.NewWriteTool(c.lspClients, c.permissions, c.history, c.filetracker, c.cfg.WorkingDir()),
436436 )
437437
438− if len(c.cfg.LSP) > 0 {
438+ if c.lspClients.Len() > 0 {
439439 allTools = append(allTools, tools.NewDiagnosticsTool(c.lspClients), tools.NewReferencesTool(c.lspClients), tools.NewLSPRestartTool(c.lspClients))
440440 }
441441
internal/agent/tools/mcp/init.go+1
@@ -135,6 +135,7 @@ func Close() error {
135135
136136// Initialize initializes MCP clients based on the provided configuration.
137137func Initialize(ctx context.Context, permissions permission.Service, cfg *config.Config) {
138+ slog.Info("Initializing MCP clients")
138139 var wg sync.WaitGroup
139140 // Initialize states for all configured MCPs
140141 for name, m := range cfg.MCP {
internal/app/app.go+1−4
@@ -109,10 +109,7 @@ func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) {
109109 // Check for updates in the background.
110110 go app.checkForUpdates(ctx)
111111
112− go func() {
113− slog.Info("Initializing MCP clients")
114− mcp.Initialize(ctx, app.Permissions, cfg)
115− }()
112+ go mcp.Initialize(ctx, app.Permissions, cfg)
116113
117114 // cleanup database upon app shutdown
118115 app.cleanupFuncs = append(app.cleanupFuncs, conn.Close, mcp.Close)
internal/app/lsp.go+15−5
@@ -5,6 +5,7 @@ import (
55 "log/slog"
66 "os/exec"
77 "slices"
8+ "sync"
89 "time"
910
1011 "github.com/charmbracelet/crush/internal/config"
@@ -58,16 +59,25 @@ func (app *App) initLSPClients(ctx context.Context) {
5859 updateLSPState(name, lsp.StateDisabled, nil, nil, 0)
5960 }
6061 }
62+
63+ var wg sync.WaitGroup
6164 for name, server := range filtered {
6265 if app.config.Options.AutoLSP != nil && !*app.config.Options.AutoLSP && !slices.Contains(userConfiguredLSPs, name) {
6366 slog.Debug("Ignoring non user-define LSP client due to AutoLSP being disabled", "name", name)
6467 continue
6568 }
66− go app.createAndStartLSPClient(
67− ctx, name,
68− toOurConfig(server),
69− slices.Contains(userConfiguredLSPs, name),
70− )
69+ wg.Go(func() {
70+ app.createAndStartLSPClient(
71+ ctx, name,
72+ toOurConfig(server),
73+ slices.Contains(userConfiguredLSPs, name),
74+ )
75+ })
76+ }
77+ wg.Wait()
78+
79+ if err := app.AgentCoordinator.UpdateModels(ctx); err != nil {
80+ slog.Error("Failed to refresh tools after LSP startup", "error", err)
7181 }
7282}
7383