sipeed/picoclaw · error

failed to load MCP servers: %w

Error message

failed to load MCP servers: %w

What it means

During one-time MCP initialization (ensureMCPInitialized), mcp.Manager.LoadFromMCPConfig starts/connects every enabled server under tools.mcp.servers; any failure is wrapped into this error and stored as the sync.Once init error. From then on every ensureMCPInitialized call — hence every dispatch — returns the same cached error, and the manager is closed so no MCP tools are registered.

Source

Thrown at pkg/agent/agent_mcp.go:119

			findValidServer = true
		}
	}
	if !findValidServer {
		logger.WarnCF("agent", "MCP is enabled but no valid servers are configured, skipping MCP initialization", nil)
		return nil
	}

	al.mcp.initOnce.Do(func() {
		mcpManager := mcp.NewManager(mcp.WithRuntimeEvents(al.runtimeEvents))

		defaultAgent := al.registry.GetDefaultAgent()
		workspacePath := al.cfg.WorkspacePath()
		if defaultAgent != nil && defaultAgent.Workspace != "" {
			workspacePath = defaultAgent.Workspace
		}

		if err := mcpManager.LoadFromMCPConfig(ctx, mcpCfg, workspacePath); err != nil {
			al.mcp.setInitErr(fmt.Errorf("failed to load MCP servers: %w", err))
			logger.WarnCF("agent", "Failed to load MCP servers, MCP tools will not be available",
				map[string]any{
					"error": err.Error(),
				})
			if closeErr := mcpManager.Close(); closeErr != nil {
				logger.ErrorCF("agent", "Failed to close MCP manager",
					map[string]any{
						"error": closeErr.Error(),
					})
			}
			return
		}

		// Register MCP tools for all agents
		servers := mcpManager.GetServers()
		uniqueTools := 0
		totalRegistrations := 0
		agentIDs := al.registry.ListAgentIDs()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the wrapped inner error — it identifies the failing server and cause; fix that tools.mcp.servers entry
  2. Run the server's exact command+args manually in the same environment to reproduce
  3. For url-based servers, verify the URL is reachable and required headers (auth) are set
  4. Temporarily set enabled=false on suspect servers to isolate which one fails, then re-enable one by one
  5. Restart picoclaw after fixing config — the failure is cached by sync.Once and will not retry otherwise

Example fix

// config — before
"tools": { "mcp": { "enabled": true, "servers": {
  "fetch": { "enabled": true, "command": "mcp-fetch" } } } }

// after — command must be an executable, args carry the rest
"tools": { "mcp": { "enabled": true, "servers": {
  "fetch": { "enabled": true, "command": "uvx", "args": ["mcp-server-fetch"] } } } }
Defensive patterns

Strategy: try-catch

Validate before calling

for name, s := range cfg.Tools.MCP.Servers {
    if !s.Enabled {
        continue
    }
    if s.Type == "" || s.Type == "stdio" {
        if s.Command == "" {
            return fmt.Errorf("mcp server %q: stdio server needs a command", name)
        }
        if _, err := exec.LookPath(s.Command); err != nil {
            return fmt.Errorf("mcp server %q: command %q not in PATH: %w", name, s.Command, err)
        }
    } else if s.URL == "" {
        return fmt.Errorf("mcp server %q: %s server needs a url", name, s.Type)
    }
}

Try / catch

if err := al.Run(ctx); err != nil {
    if strings.Contains(err.Error(), "failed to load MCP servers") {
        // one server is broken: log, disable tools.mcp (or the bad server), and restart
        // rather than retrying — init error is cached by sync.Once
        log.Printf("MCP unavailable: %v", err)
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: tools.mcp enabled with at least one enabled server, and a server fails to load: stdio command missing/not executable (command/args in MCPServerConfig), bad env_file, SSE/HTTP type with unreachable URL, failed auth (headers), or invalid transport type.

Common situations: command pointing at npx/uvx/python not installed in PATH (classic in containers/systemd); URL typo or missing auth header for remote servers; server binary changed its CLI args after an upgrade; one broken server poisoning all MCP tools because init is all-or-nothing.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/53ebdacbfa0432c9. Report an issue: GitHub.