{"record":{"id":"2b24846505745a9f","repo":"charmbracelet/crush","slug":"mcp-s-not-found-in-configuration","errorCode":null,"errorMessage":"mcp '%s' not found in configuration","messagePattern":"mcp '(.+?)' not found in configuration","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/mcp/init.go","lineNumber":342,"sourceCode":"\tinitMu.Lock()\n\tstarted := initStarted\n\tinitMu.Unlock()\n\tif !started {\n\t\treturn nil\n\t}\n\tselect {\n\tcase <-initDone:\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n}\n\n// InitializeSingle initializes a single MCP client by name.\nfunc InitializeSingle(ctx context.Context, name string, cfg *config.ConfigStore) error {\n\tm, exists := cfg.Config().MCP[name]\n\tif !exists {\n\t\treturn fmt.Errorf(\"mcp '%s' not found in configuration\", name)\n\t}\n\n\tif m.Disabled {\n\t\tupdateState(name, StateDisabled, nil, nil, Counts{})\n\t\tslog.Debug(\"Skipping disabled MCP\", \"name\", name)\n\t\treturn nil\n\t}\n\n\treturn initClient(ctx, cfg, name, m, currentGen(name), cfg.Resolver())\n}\n\n// AuthenticateMCP initiates the OAuth flow for an MCP server that is in\n// StateNeedsAuth. It creates the OAuth handler (which starts a local\n// callback server), connects to the server (which triggers the browser\n// auth flow on 401), and transitions to StateConnected on success.\nfunc AuthenticateMCP(ctx context.Context, cfg *config.ConfigStore, name string) error {\n\tm, exists := cfg.Config().MCP[name]\n\tif !exists {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/mcp/init.go#L324-L360","documentation":"InitializeSingle looks up the named MCP server in the loaded configuration before starting its client. If the name is absent from cfg.Config().MCP, it returns this error without touching state. It is a configuration lookup failure, not a connection failure.","triggerScenarios":"Calling InitializeSingle(ctx, name, cfg) (directly or via EnableDockerMCP) with a server name that is not defined in the crush config's mcp entries, or after the config was reloaded without that server.","commonSituations":"Typo in the MCP name passed to EnableDockerMCP; config file defines the server under a different key; config failed to merge so MCP map is empty; server removed from config but still enabled elsewhere.","solutions":["List configured MCP servers (check cfg.Config().MCP keys) and use an exact existing name.","Add the missing mcp entry to crushrc/crush.json and reload config.","Fix the name passed by EnableDockerMCP to match the configured key.","Validate config loading succeeded and MCP map is non-empty before calling InitializeSingle."],"exampleFix":"// before\nerr := mcp.InitializeSingle(ctx, \"gitHub\", cfg) // typo\n// after\nif _, ok := cfg.Config().MCP[\"github\"]; ok {\n\terr = mcp.InitializeSingle(ctx, \"github\", cfg)\n}","handlingStrategy":"validation","validationCode":"if _, ok := cfg.Config().MCP[name]; !ok {\n\treturn fmt.Errorf(\"MCP server %q is not configured\", name)\n}\n// safe to call InitializeSingle","typeGuard":null,"tryCatchPattern":"if err := mcp.InitializeSingle(ctx, name, cfg); err != nil {\n\tif strings.Contains(err.Error(), \"not found in configuration\") {\n\t\t// list configured servers and log available names\n\t}\n\treturn err\n}","preventionTips":["Copy MCP server names exactly as defined in crushrc/crush.json.","Validate config loaded successfully (non-empty MCP map) before enabling servers.","Re-check config after reloads that may rename or remove servers.","Keep a single source of truth for MCP definitions."],"tags":["mcp","configuration","go"],"backgroundTag":"mcp-server-not-configured","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}