sipeed/picoclaw · error

failed to connect to MCP server %q: %w

Error message

failed to connect to MCP server %q: %w

What it means

Wrapper around every probe failure in picoclaw mcp show <name>. The command builds a one-server Manager (Enabled forced true), calls LoadFromMCPConfig — which spawns the server process and performs the MCP initialize handshake — and any failure there is reported under this message with %w, so the underlying cause stays visible. The whole probe runs under the --timeout flag, default 10s.

Source

Thrown at cmd/picoclaw/internal/mcp/show.go:174

			name := args[0]
			server, exists := cfg.Tools.MCP.Servers[name]
			if !exists {
				return fmt.Errorf("MCP server %q not found", name)
			}

			serverInfo := buildServerInfo(name, server, cfg.Tools.MCP.Discovery.Enabled)

			if !server.Enabled {
				cliui.PrintMCPShow(cmd.OutOrStdout(), serverInfo, nil, true)
				return nil
			}

			ctx, cancel := context.WithTimeout(context.Background(), timeout)
			defer cancel()

			details, err := serverShowProbe(ctx, name, server, cfg.WorkspacePath())
			if err != nil {
				return fmt.Errorf("failed to connect to MCP server %q: %w", name, err)
			}

			tools := make([]cliui.MCPShowTool, 0, len(details))
			for _, d := range details {
				params := make([]cliui.MCPShowParam, 0, len(d.Parameters))
				for _, p := range d.Parameters {
					params = append(params, cliui.MCPShowParam{
						Name:        p.Name,
						Type:        p.Type,
						Description: p.Description,
						Required:    p.Required,
					})
				}
				tools = append(tools, cliui.MCPShowTool{
					Name:        d.Name,
					Description: d.Description,
					Parameters:  params,
				})

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Re-run with a bigger budget: picoclaw mcp show <name> --timeout 60s
  2. Run the configured command by hand with the same env and args and watch its stderr
  3. Check the server's env and env_file entries supply every secret the server needs
  4. For local commands verify the path exists and is executable; for URLs, curl the endpoint
  5. Read the wrapped error text — it names the actual transport, spawn, or handshake failure

Example fix

# before
$ picoclaw mcp show weather --timeout 10s
failed to connect to MCP server "weather": failed to connect to server weather: context deadline exceeded

# after
$ picoclaw mcp show weather --timeout 60s
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight before probing a stdio server
if cmd := server.Command; cmd != "" && strings.ContainsRune(cmd, os.PathSeparator) {
  if info, err := os.Stat(cmd); err != nil {
    return fmt.Errorf("command %s missing: %w", cmd, err)
  } else if info.IsDir() || (runtime.GOOS != "windows" && info.Mode()&0o111 == 0) {
    return fmt.Errorf("command %s not executable", cmd)
  }
}
for k := range server.Env {
  if strings.HasPrefix(server.Env[k], "$") {
    return fmt.Errorf("env %s looks like an unresolved variable", k)
  }
}

Type guard

func isConnectFailure(err error) bool {
  return err != nil && strings.Contains(err.Error(), "failed to connect to MCP server")
}

func isProbeTimeout(err error) bool {
  return errors.Is(err, context.DeadlineExceeded) // works through the %w chain
}

Try / catch

details, err := serverShowProbe(ctx, name, server, ws)
if err != nil {
  if errors.Is(err, context.DeadlineExceeded) {
    // retry once with a longer --timeout (default is 10s)
    ctx2, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()
    details, err = serverShowProbe(ctx2, name, server, ws)
  }
  if err != nil {
    return fmt.Errorf("failed to connect to MCP server %q: %w", name, err)
  }
}

Prevention

When it happens

Trigger: Server binary exits immediately (missing env vars such as API keys, bad args, missing runtime); local command path missing or not executable (validateLocalCommandPath failures bubble up here); remote URL refused or unreachable; initialize handshake or tools listing exceeding the 10s default on slow-starting servers.

Common situations: Server secrets present in the user's shell but absent from the config env/env_file map; first start of heavy servers (python/uvx resolving packages) blowing the default timeout; moved or deleted binaries; wrong base URL for remote MCP servers.

Related errors


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