Skip to content

Latest commit

 

History

History
55 lines (46 loc) · 2.89 KB

File metadata and controls

55 lines (46 loc) · 2.89 KB

MCP Roots Support

MCP Roots let clients tell the server which filesystem areas are in scope. mcp-bash uses the standard roots/list flow and exposes the resulting roots to tools.

How it works

  • During initialize, the lifecycle handler records whether the client advertises roots and roots.listChanged.
  • After initialized, the server sends roots/list to the client. Responses are matched via the RPC callback registry.
  • If a client emits notifications/roots/list_changed, the server re-requests roots (debounced).
  • While a refresh is in flight, the cached roots remain available; client responses replace the cache on success.
  • Timeouts or client errors keep the existing roots (no noisy warnings); malformed client payloads are ignored.

Tool environment

Every tool receives these env vars (populated once roots are ready):

  • MCP_ROOTS_JSON – JSON array of roots with uri, name, and normalized path.
  • MCP_ROOTS_PATHS – newline-separated list of normalized absolute paths.
  • MCP_ROOTS_COUNT – number of roots.

SDK helpers in sdk/tool-sdk.sh:

  • mcp_roots_list – prints MCP_ROOTS_PATHS.
  • mcp_roots_count – prints the count.
  • mcp_roots_contains <path> – returns 0 if the path is within any root.

Fallbacks (when the client doesn’t supply roots or times out)

Priority (highest to lowest):

  1. --roots flag to mcp-bash run-tool (run-tool only; comma-separated)
  2. MCPBASH_ROOTS=/path/one:/path/two (colon-separated; absolute or relative to MCPBASH_PROJECT_ROOT)
  3. config/roots.json in your project:
    {
      "roots": [
        { "path": "./data", "name": "Data" },
        { "path": "/shared/media", "name": "Media" }
      ]
    }
  4. Default: MCPBASH_PROJECT_ROOT (implicit single root)

Behavior:

  • --roots / MCPBASH_ROOTS fail fast on invalid paths (non-existent or unreadable).
  • config/roots.json warns and skips invalid entries but keeps valid ones.
  • Client roots replace the current cache on success; malformed client payloads keep the previous roots.

Try it

  • Run ./examples/run 04-roots-basics and call example.roots.read with ./data/sample.txt (allowed) and /etc/passwd (denied).
  • In the advanced ffmpeg-studio example, paths are scoped by client roots; if none are provided, it falls back to the bundled ./media.

Path requirements

  • All roots must exist and be readable; mcp-bash will not create directories.
  • Paths are canonicalized (symlinks resolved where possible) before comparison, and drive letters are normalized on Windows/MSYS.
  • Only file:// URIs are accepted from clients; non-local authorities are rejected.
  • Relative paths in MCPBASH_ROOTS or config/roots.json resolve against MCPBASH_PROJECT_ROOT.

Logging and safety

  • Paths are percent-decoded, normalized via realpath, and deduplicated before use.
  • Late/stale responses are dropped using a generation counter so they cannot overwrite newer roots.