{"record":{"id":"09c0eee8b6cfa6cb","repo":"charmbracelet/crush","slug":"mcp-http-config-requires-a-non-empty-url-field","errorCode":null,"errorMessage":"mcp http config requires a non-empty 'url' field","messagePattern":"mcp http config requires a non-empty 'url' field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/mcp/init.go","lineNumber":1070,"sourceCode":"\t\t}\n\t\tcmd := exec.CommandContext(ctx, home.Long(command), args...)\n\t\tcmd.Env = append(os.Environ(), envs...)\n\t\t// Run the child in its own process group and kill the whole group when\n\t\t// the session context is cancelled. A stdio server often spawns its own\n\t\t// children (signal-mcp launches signal-cli); os/exec's default\n\t\t// cancellation kills only the direct child, orphaning the rest with\n\t\t// PPID 1 — production accumulated 15+ such zombies over two days.\n\t\tconfigureStdioProcess(cmd)\n\t\treturn &mcp.CommandTransport{\n\t\t\tCommand: cmd,\n\t\t}, nil, nil\n\tcase config.MCPHttp:\n\t\turl, err := m.ResolvedURL(resolver)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif strings.TrimSpace(url) == \"\" {\n\t\t\treturn nil, nil, fmt.Errorf(\"mcp http config requires a non-empty 'url' field\")\n\t\t}\n\n\t\t// OAuth-enabled HTTP transport. The handler persists the token\n\t\t// (and the client registration/endpoints needed to refresh it)\n\t\t// on every exchange and refresh via this saver.\n\t\tif m.OAuth {\n\t\t\ttokenSaver := func(tok *oauth.Token) {\n\t\t\t\tif err := cfg.SetConfigField(config.ScopeGlobal, fmt.Sprintf(\"mcp.%s.oauth_token\", name), tok); err != nil {\n\t\t\t\t\tslog.Warn(\"Failed to persist MCP OAuth token\", \"name\", name, \"error\", err)\n\t\t\t\t} else {\n\t\t\t\t\tslog.Info(\"Persisted MCP OAuth token\", \"name\", name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A pre-registered client is required for servers that do not\n\t\t\t// support dynamic client registration (e.g. GitHub, Slack).\n\t\t\t// Resolve the credentials through the shell like other config\n\t\t\t// values so $VAR and $(cmd) work.","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/mcp/init.go#L1052-L1088","documentation":"For MCP HTTP-type servers, createTransport resolves the 'url' field and rejects empty/whitespace values. An HTTP transport cannot be constructed without an endpoint, so init fails with this message.","triggerScenarios":"An MCP config with type http whose 'url' field is missing, empty, or resolves to an empty string through the variable resolver.","commonSituations":"URL stored in an env var that is unset (e.g. $MY_MCP_URL); config entry converted from stdio to http without filling in url; trailing typo leaving the field blank.","solutions":["Provide a non-empty url (http:// or https://) for the http-type MCP server","If the URL comes from an env var, ensure it is set in the runtime environment","Switch the type to stdio if this server is actually a local command","Check ResolvedURL resolution errors wrapped earlier in the log"],"exampleFix":"// before\nmcp api type http url ''\n// after\nmcp api type http url 'https://api.example.com/mcp'","handlingStrategy":"validation","validationCode":"u := os.Getenv(\"MY_MCP_URL\")\nif strings.TrimSpace(u) == \"\" {\n    return errors.New(\"MY_MCP_URL must be set for http-type mcp servers\")\n}\nif _, err := url.Parse(u); err != nil {\n    return fmt.Errorf(\"invalid mcp url: %w\", err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set a full http(s) URL for http-type MCP entries","Export any env vars referenced in the url field","Validate config after converting entries between stdio and http","Test the endpoint with curl before wiring it into config"],"tags":["mcp","http","config","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}