@@ -5,6 +5,7 @@ import (
5 "encoding/json"
5 "encoding/json"
9 "github.com/charmbracelet/crush/internal/config"
10 "github.com/charmbracelet/crush/internal/config"
10 "github.com/charmbracelet/crush/internal/llm/tools"
11 "github.com/charmbracelet/crush/internal/llm/tools"
@@ -154,8 +155,6 @@ func NewMcpTool(name string, tool mcp.Tool, permissions permission.Service, mcpC
157−var mcpTools []tools.BaseTool
159func getTools(ctx context.Context, name string, m config.MCPConfig, permissions permission.Service, c MCPClient, workingDir string) []tools.BaseTool {
158func getTools(ctx context.Context, name string, m config.MCPConfig, permissions permission.Service, c MCPClient, workingDir string) []tools.BaseTool {
160 var stdioTools []tools.BaseTool
159 var stdioTools []tools.BaseTool
161 initRequest := mcp.InitializeRequest{}
160 initRequest := mcp.InitializeRequest{}
@@ -183,50 +182,72 @@ func getTools(ctx context.Context, name string, m config.MCPConfig, permissions
183 return stdioTools
182 return stdioTools
186+ mcpToolsOnce sync.Once
187+ mcpTools []tools.BaseTool
186−func GetMcpTools(ctx context.Context, permissions permission.Service, cfg *config.Config) []tools.BaseTool {
190+func GetMCPTools(ctx context.Context, permissions permission.Service, cfg *config.Config) []tools.BaseTool {
187− if len(mcpTools) > 0 {
191+ mcpToolsOnce.Do(func() {
192+ mcpTools = doGetMCPTools(ctx, permissions, cfg)
188− return mcpTools
194+ return mcpTools
197+func doGetMCPTools(ctx context.Context, permissions permission.Service, cfg *config.Config) []tools.BaseTool {
199+ var wg sync.WaitGroup
200+ var result []tools.BaseTool
190 for name, m := range cfg.MCP {
201 for name, m := range cfg.MCP {
191 if m.Disabled {
202 if m.Disabled {
192 slog.Debug("skipping disabled mcp", "name", name)
203 slog.Debug("skipping disabled mcp", "name", name)
207+ go func(name string, m config.MCPConfig) {
195− switch m.Type {
209+ switch m.Type {
196− case config.MCPStdio:
210+ case config.MCPStdio:
197− c, err := client.NewStdioMCPClient(
211+ c, err := client.NewStdioMCPClient(
198− m.Command,
212+ m.Command,
200− m.Args...,
214+ m.Args...,
217+ slog.Error("error creating mcp client", "error", err)
222+ result = append(result, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
224+ case config.MCPHttp:
225+ c, err := client.NewStreamableHttpClient(
227+ transport.WithHTTPHeaders(m.Headers),
230+ slog.Error("error creating mcp client", "error", err)
234+ result = append(result, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
237+ c, err := client.NewSSEMCPClient(
239+ client.WithHeaders(m.Headers),
202− if err != nil {
241+ if err != nil {
203− slog.Error("error creating mcp client", "error", err)
242+ slog.Error("error creating mcp client", "error", err)
246+ result = append(result, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
207− mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
208− case config.MCPHttp:
209− c, err := client.NewStreamableHttpClient(
211− transport.WithHTTPHeaders(m.Headers),
214− slog.Error("error creating mcp client", "error", err)
217− mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
219− c, err := client.NewSSEMCPClient(
221− client.WithHeaders(m.Headers),
224− slog.Error("error creating mcp client", "error", err)
227− mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c, cfg.WorkingDir())...)
231− return mcpTools
252+ return result