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
- Read the wrapped inner error — it identifies the failing server and cause; fix that tools.mcp.servers entry
- Run the server's exact command+args manually in the same environment to reproduce
- For url-based servers, verify the URL is reachable and required headers (auth) are set
- Temporarily set enabled=false on suspect servers to isolate which one fails, then re-enable one by one
- 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
- Smoke-test each MCP server command (exec.LookPath / dry run) in CI with the production config
- Pin tool versions in args (e.g. npx -y package@1.2.3) so upstream releases cannot break startup
- Remember the init error is cached: fixing config requires a restart, not a retry
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
- tool discovery is enabled but neither 'use_bm25' nor 'use_re
- must be in range 1-65535
- channel %s not found
- no default agent for heartbeat
- no agent available for route (agent_id=%s)
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/53ebdacbfa0432c9.
Report an issue: GitHub.