@@ -71,6 +71,23 @@ The base URL must be reachable **from wherever this code runs**:
7171 variable — do not paste it into chat. (The one exception is the PAT returned by
7272 ` brainkb_create_token ` , which is shown to the user ** once** so they can copy it
7373 into their config — never re-display it afterward.)
74+ - ** Identity must be verified, never assumed — this is the #1 correctness rule.**
75+ Mutations (create space, ingest, add member, grant) are ** attributed to the
76+ authenticated identity permanently** (provenance records who did what). A login
77+ step reporting "Logged in as X" is ** not proof** the next call runs as X: the MCP
78+ silently falls back to a configured ` BRAINKB_EMAIL ` /` BRAINKB_PASSWORD ` ,
79+ ` BRAINKB_TOKEN ` , or an ` Authorization ` header when the session login isn't
80+ carried forward (common on the hosted ` streamable-http ` transport). So:
81+ 1 . After ** every** login, call ` brainkb_whoami() ` and confirm ` email ` == the
82+ intended user.
83+ 2 . ** Immediately before any write/mutation** , call ` brainkb_whoami() ` again and
84+ confirm it still matches. Only proceed if it does.
85+ 3 . If it shows a ** different/unexpected** account (e.g. a shared ` test@… ` ),
86+ ** STOP** — report the mismatch, don't write. The durable fix is a per-call
87+ credential that can't be shadowed: a ** PAT** (` BRAINKB_TOKEN ` /
88+ ` brainkb_use_token ` ) or an ` Authorization: Bearer ` header. A leftover
89+ ` BRAINKB_EMAIL ` /` BRAINKB_PASSWORD ` in the MCP config is the usual culprit and
90+ should be removed on a shared/multi-user MCP.
7491- Confirm before mutating actions (creating a space, ingesting, changing
7592 visibility, adding members). Reads are safe.
7693- ** Authorization is role-based, not just JWT** (see the section below). A ` 403 `
@@ -149,6 +166,21 @@ password unprompted:**
149166 says they have a password account and want to use it. Never prompt for a password
150167 otherwise.
151168
169+ > ** ⚠️ ALWAYS verify identity after logging in — do not trust the login message.**
170+ > Immediately after ` brainkb_finish_login ` / ` brainkb_login ` / ` brainkb_use_token ` ,
171+ > call ** ` brainkb_whoami() ` ** and confirm the returned ` email ` is the account you
172+ > intended. A login step can report "Logged in as X" yet subsequent calls run as a
173+ > ** different** account — because the MCP falls back, silently, to a configured
174+ > ` BRAINKB_EMAIL ` /` BRAINKB_PASSWORD ` (or ` BRAINKB_TOKEN ` , or an ` Authorization `
175+ > header) when the just-established session isn't carried into the next call (this
176+ > is common on the hosted ` streamable-http ` transport, where per-session login may
177+ > not persist between tool calls). ** If ` whoami ` shows a different or unexpected
178+ > account, STOP — the login did not take effect. Do NOT create/ingest/mutate**
179+ > (see the identity rule in "Credentials & safety"). The reliable fix is a
180+ > per-call credential that can't be shadowed: a ** PAT** via ` BRAINKB_TOKEN ` /
181+ > ` brainkb_use_token ` , or an ` Authorization: Bearer ` header — not an in-memory
182+ > session login on a multi-user remote.
183+
152184### 2. Create / choose a workspace (space)
153185- Individual/private workspace (any write-capable role):
154186 ` brainkb_create_space(slug, name, "private", description) ` (space_type defaults to
@@ -169,6 +201,14 @@ password unprompted:**
169201- List what the user can see: ` brainkb_list_spaces() ` .
170202
171203### 3. Ingest
204+ - ** Before ingesting, verify identity: call ` brainkb_whoami() ` and confirm the
205+ ` email ` is the intended user.** Ingest is ** attributed** — the job's ` user_id `
206+ and the provenance (` prov:wasAssociatedWith ` / ` prov:wasAttributedTo ` ) are set to
207+ the authenticated identity, permanently. If ` whoami ` shows the wrong account
208+ (e.g. a fallback ` test@… ` from a stale ` BRAINKB_EMAIL ` ), the data will be
209+ ** mis-attributed and cannot be silently reassigned** — STOP and fix the login
210+ (use a PAT / header) before ingesting. Never ingest "hoping" the earlier login
211+ stuck.
172212- Raw text: ` brainkb_ingest_text(graph_iri, data) ` (Turtle/N-Triples/JSON-LD).
173213- Files: ` brainkb_ingest_files(graph_iri, [paths]) ` .
174214- Both return a ` job_id ` . Tell the user ingestion is running in the background.
0 commit comments