From 159d0f0fb64b5b76285c2b2b9adff3fd9ee26110 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Jul 2026 11:19:47 +0000 Subject: [PATCH] =?UTF-8?q?MCP=20kbdb=5Fcreate=5Frecord=20=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=20org=5Fnamespace=20=E7=82=BA=20owner=5Fid=EF=BC=8C?= =?UTF-8?q?=E9=85=8D=E5=90=88=20base=20owner-mandatory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Ck8bjuBTLFkiFxqLGHMpqG --- mcp/src/tools/kbdb_data.ts | 38 +++++++++++++++++++++++++++++++------- mcp/src/tools/registry.ts | 3 ++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/mcp/src/tools/kbdb_data.ts b/mcp/src/tools/kbdb_data.ts index 793b066..488f303 100644 --- a/mcp/src/tools/kbdb_data.ts +++ b/mcp/src/tools/kbdb_data.ts @@ -26,11 +26,18 @@ import type { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; import { errorResponse, successResponse } from "../lib/cypher-client.js"; -/** 註冊全部 KBDB 資料層工具(kbdb-base Phase 9.1)。不含建表/SQL tool(鐵律)。 */ -export function registerAllKbdbDataTools(server: McpServer, env: Env) { +/** + * 註冊全部 KBDB 資料層工具(kbdb-base Phase 9.1)。不含建表/SQL tool(鐵律)。 + * + * D28(owner-mandatory):base 的 `POST /records` 已把 owner_id 設必填(缺 → 400)。 + * MCP 是薄殼、是 caller——owner **由機制注入**(org namespace),不靠 AI 記得帶。 + * 仿 arcrun_report_feedback:把 orgNamespace 傳進寫入 tool,寫入時當 owner_id。 + * 送到 base 的 owner_id 一定非空 → AI 漏不了。 + */ +export function registerAllKbdbDataTools(server: McpServer, env: Env, orgNamespace: string) { registerCreateTemplate(server, env); registerListTemplates(server, env); - registerCreateRecord(server, env); + registerCreateRecord(server, env, orgNamespace); registerGetRecord(server, env); registerQuery(server, env); registerSearch(server, env); @@ -92,8 +99,16 @@ export function registerListTemplates(server: McpServer, env: Env) { ); } -/** kbdb_create_record — 依某 template 填一筆 record(slot → 內容)。 */ -export function registerCreateRecord(server: McpServer, env: Env) { +/** + * kbdb_create_record — 依某 template 填一筆 record(slot → 內容)。 + * + * D28(owner-mandatory):base 的 `POST /records` owner_id 必填(缺 → 400)。 + * owner_id 由 MCP **機制注入**(orgNamespace),不靠 AI 帶: + * - AI 傳的 owner_id 當「選填覆寫」(想歸到別的租戶/專案時才用)。 + * - AI 沒傳 → 用注入的 orgNamespace。 + * - 兩者皆空 → 直接回錯(不送必然 400 的請求),保證送到 base 的 owner_id 一定非空。 + */ +export function registerCreateRecord(server: McpServer, env: Env, orgNamespace: string) { server.tool( "kbdb_create_record", "依某 template 填一筆 record(一列資料)。values 是 {slot名: 內容},slot 名要對得上 template 的 slots。" + @@ -101,14 +116,23 @@ export function registerCreateRecord(server: McpServer, env: Env) { { template: z.string().min(1).describe("template 的 name 或 id"), values: z.record(z.string()).describe("欄位內容 {slot名: 字串內容},如 {name:'Leo', email:'leo@x.com'}"), - owner_id: z.string().optional().describe("資料歸屬標記(選填,如專案 id / 用戶 id)"), + owner_id: z.string().optional().describe("資料歸屬標記(選填;預設用你的 org namespace,想歸到別的租戶/專案才傳)"), }, async ({ template, values, owner_id }) => { try { + // 機制注入:AI 傳的 owner_id 覆寫,缺則用 orgNamespace。兩者皆空 → 拒送(避免必然 400)。 + const resolvedOwner = (owner_id && owner_id.trim()) || orgNamespace; + if (!resolvedOwner) { + return errorResponse( + "owner_missing", + "無法決定 owner_id:AI 未傳 owner_id 且 org namespace 為空", + ["確認 MCP 連線帶了有效的 Authorization(org namespace)", "或明確傳入 owner_id"], + ); + } const res = await kbdbFetch(env, "/records", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ template, values, owner_id }), + body: JSON.stringify({ template, values, owner_id: resolvedOwner }), }); if (!res.ok) { return errorResponse("create_record_failed", `填 record 失敗`, [ diff --git a/mcp/src/tools/registry.ts b/mcp/src/tools/registry.ts index d333296..d791121 100644 --- a/mcp/src/tools/registry.ts +++ b/mcp/src/tools/registry.ts @@ -55,7 +55,8 @@ export function registerAllTools(server: McpServer, env: Env, orgNamespace: stri registerAllRecipeTools(server, env); // kbdb-base Phase 9.1: KBDB 資料層薄殼(template/record/query/search,HANDOFF §2) // 鐵律:不提供建表/SQL tool,AI 只有 template+slot 可用(類 Supabase 萬用表) - registerAllKbdbDataTools(server, env); + // D28: 傳 orgNamespace,寫入 record 時機制注入 owner_id(base owner-mandatory,AI 漏不了) + registerAllKbdbDataTools(server, env, orgNamespace); // §7.8 P1 D2: whoami(與 CLI acr whoami 對齊,AI 不繞 CLI 自己 curl 猜帳號) registerWhoami(server, env, orgNamespace); }