What you're trying to do
gbrain distinguishes trusted local CLI callers (OperationContext.remote = false) from untrusted MCP-facing callers (remote = true), and tightens filesystem access for the latter. Vouch's MCP server doesn't have this distinction — every caller is treated as the same trust level. Once #1 (HTTP transport) lands, this becomes load-bearing: an HTTP-MCP call should not be able to register a source from any path on the host.
Suggested shape
- New
OperationContext dataclass plumbed through every kb.* handler. Fields: remote: bool, caller_kind: "cli" | "mcp_stdio" | "mcp_http" | "jsonl", auth_subject: str | None.
- The CLI sets
remote=false; MCP server sets remote=true; JSONL sets remote=true only when the transport reads from a non-tty (network-facing) source.
kb.register_source_from_path confines the resolved path under kb_root when remote=true; errors with path_outside_kb otherwise.
kb.import_apply requires remote=false (or an explicit --unsafe flag in config) — bundle imports rewrite many files at once and shouldn't run unattended over the network.
Acceptance
- An MCP-stdio call to
kb.register_source_from_path for a path outside kb_root returns path_outside_kb; the same call from CLI succeeds.
- Test fixture proves the confinement holds against
.. traversal and symlink escape.
kb.capabilities surfaces trust_model: {confined: true, methods_requiring_local: [...]}.
Out of scope
What you're trying to do
gbrain distinguishes trusted local CLI callers (
OperationContext.remote = false) from untrusted MCP-facing callers (remote = true), and tightens filesystem access for the latter. Vouch's MCP server doesn't have this distinction — every caller is treated as the same trust level. Once #1 (HTTP transport) lands, this becomes load-bearing: an HTTP-MCP call should not be able to register a source from any path on the host.Suggested shape
OperationContextdataclass plumbed through every kb.* handler. Fields:remote: bool,caller_kind: "cli" | "mcp_stdio" | "mcp_http" | "jsonl",auth_subject: str | None.remote=false; MCP server setsremote=true; JSONL setsremote=trueonly when the transport reads from a non-tty (network-facing) source.kb.register_source_from_pathconfines the resolved path underkb_rootwhenremote=true; errors withpath_outside_kbotherwise.kb.import_applyrequiresremote=false(or an explicit--unsafeflag in config) — bundle imports rewrite many files at once and shouldn't run unattended over the network.Acceptance
kb.register_source_from_pathfor a path outsidekb_rootreturnspath_outside_kb; the same call from CLI succeeds...traversal and symlink escape.kb.capabilitiessurfacestrust_model: {confined: true, methods_requiring_local: [...]}.Out of scope