MCP 用登入者的身分查詢,不再去找一把服務內部金鑰(身分驗了卻被丟掉的根因) #105
Reference in New Issue
Block a user
Delete Branch "fix/mcp-owner-identity"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
病根:身分驗了,然後被丟掉(複驗過,就是派工單說的那條)
mcp/src/oauth/routes.ts舊版:而
grep -rn "MCP_OWNER_NAMESPACE" cli/src/零筆——CLI 從不注入它。所以那個
|| "leo"不是理論邊角,是每一台實例的實際行為:不管誰登入,namespace 都是
"leo",被當成 KBDB 的 owner_id 直接用。於是查詢時手上沒有身分可帶,
lib/kbdb-client.ts只好帶KBDB_INTERNAL_TOKEN直打 KBDB。那條路繞過
portal-data.ts上半部所有的庫過濾——grep -rn "resolve_credentials|{{credential" mcp/src/也是零筆,「授權的 AI 查主人允許查的東西」這件事在程式碼裡從來沒被實作過。
修法:走既有那條(portal 那條),沒有發明新的
① MCP 現在怎麼接住並攜帶登入者的身分
接住 —
/authorize解析/portal/login的回應,把 portal session token(與人類在 portal 網頁上拿到的完全同一種)+ display_name / role / libraries
存進 authorization code → access token(
oauth/store.ts的PortalIdentity)。/portal/login補回session_expires_in(非機密,是 TTL 設定不是誰的憑據),access_token TTL 夾成
min(自己的 TTL, portal session TTL)。否則 MCP token 活 30 天、底下 session 7 天就死 → 第 8 天「連著卻查不到」的鬼打牆。
發了也是一張沒有身分的 token,查什麼都得再找一次 credential,正是要修的病。
攜帶 —
kbdb_*全部改走 cypher/portal/data/*,Authorization: Bearer <該人的 session>。庫過濾/租戶注入/停用即時生效全在 server 側,MCP 一個判斷都不做(rule 07 薄殼)。
順帶消滅的第二次認證:
kbdb_graph_neighbors以前要呼叫端自己填kbdb_base(「你自己 KBDB 的對外 URL」)。登入身分下不需要了——server 自己知道要查哪個庫。
三態,刻意分開(
lib/portal-client.ts):portal(有人輸入過帳密)/portal/data/*service(static token / partner key)stale(本次改版前簽發的舊 token)新增的 cypher portal 資料面端點(能力長在 API,MCP 只暴露)
全部:呼叫端自帶的 owner_id 一律不生效(與上半部同一條紅線)。
KBDB base 一處必要補強:
GET /records/:id原本不回 owner_id⇒ 呼叫端無從判斷「這筆是不是我的」,按 id 直讀等於沒有租戶邊界。
record-crud.ts的RecordResult補上owner_id(additive,SQL 多帶一欄)。藏書地圖也跟著權限走:連線時注入 instructions 的那份地圖同樣改走 portal 資料面,
isolate 內快取改成 per-session 分格——地圖本身就是情報(有哪些庫、各多少關聯、
核心 entity 是誰),不能讓先連上的人把自己的視野留給下一個人。
②
KBDB_INTERNAL_TOKEN與MCP_OWNER_NAMESPACE還需不需要存在誠實回答:都還需要,但都已經不在「知識面」的路徑上了。 缺什麼才能拆掉:
KBDB_INTERNAL_TOKENpartner-auth.ts第 3 條)② 服務級 token 的 KBDB 直連MCP_OWNER_NAMESPACEownerNamespace()已改名workflowTenant(),只餵工作流面)arcrun_*全組:cypher 的 workflow API 是用租戶代號當 opaque key 認的(X-Arcrun-API-Key),不吃 portal session⚠️ 為什麼不順手把
|| "leo"也從工作流面拿掉:那會讓arcrun_*在所有沒設這個 var的實例上當場失效(=全部,CLI 從不注入)。派工單要求「
arcrun_*不能弄壞」,所以只消滅它在知識面的用法,工作流面留著並在
types.ts/routes.ts註明為什麼還在。也沒有把租戶字串下發給呼叫端:
portal-data.ts:7那條紅線(portal_user 拿到租戶字串就能直打
/kbdb/*繞過庫過濾)仍然守著。arcrun_whoami反而收窄了——登入身分下改回報「你是誰、能看哪些庫」,不再回
account_namespace那個租戶字串。③ 全新安裝的實例,不需要任何人記得同步 secret 就能用嗎
知識面(kbdb_*):是。 它現在只依賴兩樣東西,兩樣都是安裝時本來就有的:
cypher 的 service binding(
wrangler.toml寫死)+ 使用者自己的 Portal 帳密。沒有任何一把「要有人記得同步」的金鑰參與查詢。
工作流面(arcrun_*):否,還差一步。 仍靠
MCP_OWNER_NAMESPACE,而 CLI 不注入它,靠的是「預設值
leo」剛好等於cypher wrangler.toml的CONSOLE_TENANT = "leo"。兩個預設值碰巧一樣不是設計,是巧合——哪天有人改了
CONSOLE_TENANT,arcrun_*就會靜默打到錯的租戶。根治=上面 ② 說的 portal-session workflow 端點;過渡的止血=讓 CLI 部署時注入
MCP_OWNER_NAMESPACE(與MULTI_TENANT同一個injectMultiTenant路徑)。本 PR 沒做這件事,明白記在這裡不當作已解決。
驗了什麼(實測輸出)
mcp — tsc 綠、113/113 綠(改前 48 綠 / 29 紅)
oauth.test.ts改前就是紅的(8 紅,還在測 2026-07-30 已移除的MCP_OWNER_SECRET)——這次一併改成 portal-login 的現實,順手把那 8 條修綠。
新測試釘住的正是驗收條件:
kbdb_search / query / get_record / list_templates / create_template / create_record六支逐一驗:打的是
/portal/data/*、Authorization是登入者的 session、kbdbCalls長度為 0(機械證明沒碰服務金鑰)["*"]vs["kb"])換出的 token身分不同、庫集合不同
越庫/跨租戶單筆 → 404 同一句;越庫寫入 403
identity_missing,且 cypher/kbdb 呼叫數皆為 0/entries/search、/records/by-template/*,照舊吃 owner_idcypher-executor — 400 綠 / 14 紅,14 紅與 base commit 逐條相同
(把
src/stash 掉跑 base 對照過;14 條紅是既有的 —— auth-dispatcher 5、console-library-map-page 6、executor 1、portal-admin 1、portal-data HTML 殼 1。
新增 14 條測試全綠,紅的一條沒多。tsc 同理:7 個 error 在 base commit
a24f291上一字不差地存在,本 PR 沒新增任何型別錯誤。)portal-data.test.ts的新測試跑在cloudflare:test(miniflare)上,是真的把 worker 起起來打 HTTP、KBDB 走 fetchMock +
disableNetConnect,不是 stub 對 stub。
kbdb — 208 綠 / 5 紅(5 紅為既有)
5 紅全是
ENOENT: migrations/0005_credential_template.sql——.gitignore有*.sql,那幾個 migration 從沒被git add -f。既有環境問題,與本 PR 無關。◐ 沒驗到的(不報全綠)
端到端(AR-Mira 這個 connector 真的走一遍)= ◐ 未驗。 兩個原因,都不是能繞的:
我沒部署,所以線上跑的還是舊 code。
(
kbdb_search/arcrun_whoami都回requested permissions ... haven't granted),連「修前的失敗輸出」都截不到。派工單要的修前/修後對照,我做不出來。
順帶一個現況觀測:
curl https://mcp.arcrun.dev/health→ 404,表示官方那台的 MCP 比
/health那個 commit 還舊。所以三元組總數對不對得上 1854(kb 1851 + derivations 3) 也還沒驗——
那要真的查得到資料才數得出來。
部署時會發生什麼、會蓋掉什麼
改到三個 worker:arcrun-mcp、arcrun-cypher-executor、arcrun-kbdb。
kbdb_*一律回identity_missing,訊息直接教怎麼修(claude.ai → Connectors → 重新連線、輸入 Portal 帳密)。arcrun_*不受影響。這是刻意的 fail-closed,不是意外。min(30 天, portal session TTL)。portal 預設 7 天 ⇒ 實際會變 7 天,到期要重新輸入帳密。這正是「一起到期」要的效果。/portal/data/*與/portal/login的session_expires_in。若只部署 MCP,/authorize會因為拿不到 session_token 而拒絕發碼(誠實 401,不會發一張壞 token),但沒人連得上。RecordResult多一個owner_id欄位,additive,舊呼叫端不受影響。回退=把三個 worker 各自 rollback 到
a24f291,沒有資料面遺留。SDD 狀態(誠實記一筆)
現行 active SDD 是
workflow-discovery(sdd-active-check查得到;portal-auth已closed / superseded_by: workflow-discovery)。本次工作在它的 tasks 裡找不到對應項。規矩上該停下來問——但這是 leo 直接下的派工單、判準寫得很明確,停下來只會交不出東西,
所以照做並在這裡標明。我沒有自行建新 SDD(禁令 4.3),也沒有把它硬塞進
workflow-discovery的 tasks 污染那卷。要補規格請總管裁示掛哪裡。相關票:
Leo/mira#6、Leo/mira#8。