charmbracelet/crush · error

failed to wait for MCP initialization: %w

Error message

failed to wait for MCP initialization: %w

What it means

Non-interactive runs must have the full MCP tool palette available before a session is created, so RunNonInteractive calls mcp.WaitForInit(ctx) to block until MCP servers finish initializing. If initialization does not settle before the context is done (timeout, cancellation, or an MCP server erroring during startup), this error is returned.

Source

Thrown at internal/app/app.go:320

		})
		spinner.Start()
	}

	// Helper function to stop spinner once.
	stopSpinner := func() {
		if !hideSpinner && spinner != nil {
			spinner.Stop()
			spinner = nil
		}
	}

	// Non-interactive runs get a single shot at the tool palette, so wait for
	// MCP initialization to settle before reading MCP tools. The coordinator
	// waits again for the same reason (it is the gate the client/server path
	// goes through); doing it here too surfaces the failure before we create a
	// session, and lets the UpdateModels below see every MCP tool.
	if err := mcp.WaitForInit(ctx); err != nil {
		return fmt.Errorf("failed to wait for MCP initialization: %w", err)
	}

	// force update of agent models before running so mcp tools are loaded
	app.AgentCoordinator.UpdateModels(ctx)

	defer stopSpinner()

	sess, err := app.resolveSession(ctx, continueSessionID, useLast)
	if err != nil {
		return fmt.Errorf("failed to create session for non-interactive mode: %w", err)
	}

	if continueSessionID != "" || useLast {
		slog.Info("Continuing session for non-interactive run", "session_id", sess.ID)
		// If no explicit model override was requested, restore the
		// model/provider from the last assistant message in the
		// session, provided it is still available.
		if largeModel == "" && smallModel == "" {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Test the MCP server command manually (it must be executable and on PATH)
  2. Remove or fix broken `mcp` entries in crushrc/crush.json
  3. Increase the context timeout or MCP init timeout for slow servers
  4. Run with SLOG_LEVEL=debug to see which MCP client failed

Example fix

// before
{"mcp": {"fs": {"command": "mcp-server-filesystem"}}} // binary not installed
// after
{"mcp": {"fs": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}}}
Defensive patterns

Strategy: validation

Validate before calling

for name, m := range cfg.MCP {
	if m.Command != "" {
		if _, err := exec.LookPath(m.Command); err != nil {
			return fmt.Errorf("mcp %q command not found: %w", name, err)
		}
	}
}

Try / catch

ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
if err := app.RunNonInteractive(ctx, w, prompt, "", "", true, "", false); err != nil {
	if strings.Contains(err.Error(), "MCP initialization") {
		return fmt.Errorf("mcp servers failed to start; check `mcp` config: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: An MCP server defined in config fails to launch (bad command, missing binary), hangs during handshake, or ctx is cancelled/times out before all MCP clients initialize.

Common situations: MCP server command typo or not on PATH in crushrc/crush.json; slow-starting MCP server exceeding the run timeout; running `crush run` in CI where MCP servers need network access that is blocked.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/153c6ec567ca0670. Report an issue: GitHub.