{"record":{"id":"0b67d5a0cd11974e","repo":"gitbutlerapp/gitbutler","slug":"none-of-the-mcp-client-s-filesystem-roots-identify","errorCode":null,"errorMessage":"None of the MCP client's filesystem roots identify a Git repository. {}","messagePattern":"None of the MCP client's filesystem roots identify a Git repository\\. (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/mcp/mod.rs","lineNumber":535,"sourceCode":"        );\n    }\n\n    let mut failures = Vec::new();\n    for root in roots {\n        let path = match root_path(root) {\n            Ok(path) => path,\n            Err(err) => {\n                failures.push(err.to_string());\n                continue;\n            }\n        };\n        match open_repository(&path) {\n            Ok(resolved) => return Ok(resolved),\n            Err(err) => failures.push(format!(\"{}: {err:#}\", path.display())),\n        }\n    }\n\n    bail!(\n        \"None of the MCP client's filesystem roots identify a Git repository. {}\",\n        failures.join(\"; \")\n    )\n}\n\nfn root_path(root: &Root) -> Result<PathBuf> {\n    let url = Url::parse(&root.uri)\n        .with_context(|| format!(\"MCP root is not a valid URI: {}\", root.uri))?;\n    url.to_file_path()\n        .map_err(|()| anyhow::anyhow!(\"MCP root is not a file URI: {}\", root.uri))\n}\n\nfn open_repository(repository: &Path) -> Result<ResolvedRepository> {\n    let repository = repository\n        .canonicalize()\n        .with_context(|| format!(\"Could not resolve repository at {}\", repository.display()))?;\n    let ctx = but_ctx::Context::discover(&repository)\n        .with_context(|| format!(\"Could not open repository at {}\", repository.display()))?;","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/mcp/mod.rs#L517-L553","documentation":"After probing every root with open_repository (crates/but/src/command/mcp/mod.rs:535), none opened as a Git repository (or the root URI was not a valid file URI); each failure string is collected and joined into the message. The client's roots exist but none is, or sits above, a usable .git worktree.","triggerScenarios":"All workspace roots are plain directories with no discoverable .git at or above them; a root is a non-file URI (remote scheme) that Url::to_file_path rejects; sandboxing hides .git from the server.","commonSituations":"Opened a parent folder of several projects where none is at a root level; cloud-hosted root URIs; permissions that block .git discovery.","solutions":["Add a directory that is (or contains) a Git worktree as a root.","Pass the `repository` path argument directly.","Read the joined failure list in the message to see which root failed and why (invalid URI vs. not a repository)."],"exampleFix":"// before: root = file:///home/user/documents (no repo)\n\n// after: root = file:///home/user/documents/project (contains .git)\n// or\n{ \"repository\": \"/home/user/documents/project\", ... }","handlingStrategy":"validation","validationCode":"for root in roots {\n    let path = Url::parse(&root.uri)?.to_file_path().map_err(|()| anyhow::anyhow!(\"not a file URI\"))?;\n    if gix::open(&path).map(|r| r.is_worktree()).unwrap_or(false) {\n        return Ok(path); // a probe-able root exists\n    }\n}\nanyhow::bail!(\"no root is a git repository; pass repository explicitly\");","typeGuard":null,"tryCatchPattern":"match resolve_repository(None, context).await {\n    Err(err) if err.to_string().contains(\"identify a Git repository\") => {\n        // parse the per-root failure details and retry with an explicit path\n    }\n    other => other,\n}","preventionTips":["Open the folder that is the repository (or its parent) as the client root.","Pass `repository` explicitly when roots are cloud or non-file URIs.","Read the joined failure details — they distinguish invalid URIs from missing .git."],"tags":["mcp","roots","git-repository","filesystem"],"backgroundTag":"not-a-git-repository","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}