We met Roots as a client capability in the primitives track — the host tells the server which directories it is allowed to operate in. Re-read it now through a security lens: Roots are how a filesystem-touching server avoids accidentally roaming.
Without Roots, a filesystem MCP server has to assume something about its scope: maybe $HOME, maybe the current working directory, maybe whatever a user typed. Every assumption is wrong for some user, and the wrong-for-this-user case is exactly the kind of accident that turns into "the AI wrote my SSH config." With Roots, the host is the one who answers the scope question, derived from whatever the user-facing UX (workspace, opened folder, picker) says is the active context.
The protocol pattern: server lists roots on initialize, optionally subscribes to notifications/roots/listChanged, and refuses any tool call whose argument paths fall outside the current root set. Refuse politely — return a structured error, not a stack trace — so the LLM can correct course on the next turn. "Outside roots" is a contract violation by the model, not a bug in the server.