feat(mcp): library-map M4 — kbdb_get_map 工具+instructions 注入全館地圖 #73

Merged
Leo merged 1 commits from feat/mcp-library-map-inject into main 2026-07-19 09:13:46 +00:00
Owner

對應 library-map SDD M4system-dev/docs/3-specs/library-map/design.md §4「注入機制」)。關聯 #39。與 #68(kbdb_graph_neighbors)同族薄殼。

內容(design §4 兩件)

1. MCP tool kbdb_get_mapmcp/src/tools/kbdb_map.ts

  • 無參數=全館地圖:每庫一行(library+narrative+top 3 entities+triplet_count)
  • library 參數=該庫詳圖:完整欄位;top_entities/relation_profile/bridges 若為 JSON 字串形(live 曾觀測的 slot 直出形)容錯 JSON.parse 成物件,parse 失敗當空陣列不 crashtriplet_count 字串轉數字
  • description 含「不確定該查什麼時,先呼叫此工具」(任務規格)
  • 404/空庫誠實回報+提示跑 POST /map/recompute?library= backfill(含過渡期 source_prefix 用法)
  • 連線慣例:走既有 KBDB service bindingkbdbFetch,與 kbdb_data.ts 同款)——kbdb base 本來就有 GET /mapGET /map/:library(M2 已 merge),不需繞 cypher proxy。不碰 D1、不新增 binding、D17 kbdb_* 前綴

2. server instructions 注入(mcp/src/lib/library-map.tsmcp/src/mcp-handler.ts

  • 連線時拉 GET /map,渲染成每庫一行:{library}:{narrative}|核心:{top3}|{triplet_count} triplets,嵌入 instructions(design §6:session 啟動 push 零查詢)。總量控制:narrative 截 60 字、庫數上限 30 行(數百 token 內,R3)
  • 快取選型=isolate 內 TTL 快取(成功 5min/失敗 1min),不是每次現拉。理由:本 MCP 用 stateless StreamableHTTP(sessionIdGenerator: undefined),每個 HTTP request 都重建 McpServer——「每次現拉」實際上是每個 tool call 都多打一次 /map,不只 initialize;地圖只在 ingest recompute 後才變,5 分鐘 staleness 無害。isolate 回收即自然失效
  • 拉不到(timeout 1.5s/HTTP 錯/空庫/壞 JSON)=回 null 靜默略過,絕不擋 MCP 連線(鐵律:地圖是加分不是依賴),instructions 沒地圖照常可用

測試(誠實回報)

  • pnpm vitest run76/76 過(新增 mcp/tests/unit/tools/kbdb-map.test.ts 17 測,假 KBDB binding 比照 kbdb-graph.test.ts 手法:全館/詳圖路徑與 auth header、JSON 字串 slot 容錯、404/空庫誠實訊息、instructions 失敗靜默、快取命中不重打)
  • tsc --noEmit:乾淨
  • live 端點形狀已對照 https://arcrun-kbdb.leo21c.workers.dev/map(leo21c backfill 後)核實

部署

merge 後需 gated redeploy arcrun-mcp(leo 閘)。純 code 變更,無 wrangler.toml/binding/migration 改動。

關聯 #39。

對應 **library-map SDD M4**(`system-dev/docs/3-specs/library-map/design.md` §4「注入機制」)。關聯 #39。與 #68(kbdb_graph_neighbors)同族薄殼。 ## 內容(design §4 兩件) ### 1. MCP tool `kbdb_get_map`(`mcp/src/tools/kbdb_map.ts`) - **無參數=全館地圖**:每庫一行(library+narrative+top 3 entities+triplet_count) - **帶 `library` 參數=該庫詳圖**:完整欄位;`top_entities`/`relation_profile`/`bridges` 若為 JSON 字串形(live 曾觀測的 slot 直出形)容錯 `JSON.parse` 成物件,**parse 失敗當空陣列不 crash**;`triplet_count` 字串轉數字 - description 含「**不確定該查什麼時,先呼叫此工具**」(任務規格) - 404/空庫**誠實回報**+提示跑 `POST /map/recompute?library=` backfill(含過渡期 `source_prefix` 用法) - 連線慣例:走**既有 KBDB service binding**(`kbdbFetch`,與 kbdb_data.ts 同款)——kbdb base 本來就有 `GET /map`/`GET /map/:library`(M2 已 merge),不需繞 cypher proxy。不碰 D1、不新增 binding、D17 `kbdb_*` 前綴 ### 2. server instructions 注入(`mcp/src/lib/library-map.ts`+`mcp/src/mcp-handler.ts`) - 連線時拉 `GET /map`,渲染成每庫一行:`{library}:{narrative}|核心:{top3}|{triplet_count} triplets`,嵌入 instructions(design §6:session 啟動 push 零查詢)。總量控制:narrative 截 60 字、庫數上限 30 行(數百 token 內,R3) - **快取選型=isolate 內 TTL 快取(成功 5min/失敗 1min),不是每次現拉**。理由:本 MCP 用 stateless StreamableHTTP(`sessionIdGenerator: undefined`),**每個 HTTP request 都重建 McpServer**——「每次現拉」實際上是每個 tool call 都多打一次 /map,不只 initialize;地圖只在 ingest recompute 後才變,5 分鐘 staleness 無害。isolate 回收即自然失效 - **拉不到(timeout 1.5s/HTTP 錯/空庫/壞 JSON)=回 null 靜默略過,絕不擋 MCP 連線**(鐵律:地圖是加分不是依賴),instructions 沒地圖照常可用 ## 測試(誠實回報) - `pnpm vitest run`:**76/76 過**(新增 `mcp/tests/unit/tools/kbdb-map.test.ts` 17 測,假 KBDB binding 比照 kbdb-graph.test.ts 手法:全館/詳圖路徑與 auth header、JSON 字串 slot 容錯、404/空庫誠實訊息、instructions 失敗靜默、快取命中不重打) - `tsc --noEmit`:乾淨 - live 端點形狀已對照 `https://arcrun-kbdb.leo21c.workers.dev/map`(leo21c backfill 後)核實 ## 部署 **merge 後需 gated redeploy arcrun-mcp(leo 閘)**。純 code 變更,無 wrangler.toml/binding/migration 改動。 關聯 #39。
Leo added 1 commit 2026-07-19 09:12:21 +00:00
library-map SDD M4(design §4,源頭 #39)。兩件:

1. kbdb_get_map(tools/kbdb_map.ts,與 #68 kbdb_graph_neighbors 同族薄殼):
   - 無參數=全館地圖(每庫一行:library+narrative+top 3 entities+triplet_count)
   - 帶 library=該庫詳圖;top_entities/relation_profile/bridges 若為 JSON 字串形
     容錯 parse 成物件(parse 失敗當空陣列,不 crash)
   - 404/空庫誠實回報+POST /map/recompute backfill 指引
   - 走既有 KBDB service binding(kbdbFetch),不碰 D1、不新增 binding

2. instructions 注入(lib/library-map.ts+mcp-handler.ts):
   - 連線時拉 GET /map,渲染成緊湊文字({library}:{narrative}|核心:{top3}|{n} triplets)
     嵌 server instructions(design §6:session 啟動 push 零查詢)
   - 快取選型:isolate 內 TTL 快取(成功 5min/失敗 1min)——stateless StreamableHTTP
     每個 HTTP request 重建 McpServer,「每次現拉」實際是每個 tool call 都多打一次 /map
   - timeout 1.5s;任何失敗(超時/HTTP錯/空庫/壞JSON)回 null 靜默略過,絕不擋 MCP 連線(鐵律)

測試:假 KBDB binding(比照 kbdb-graph.test.ts)17 新測,pnpm vitest run 76/76 過、tsc --noEmit 乾淨。
merge 後需 gated redeploy arcrun-mcp(leo 閘)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
Author
Owner

總管審過 merge。一項 D21「記錄不阻擋」留檔:instructions 注入的 module 快取為全域、/map 未帶 owner 過濾——MULTI_TENANT=true 部署時=跨租戶把全館地圖注入所有人 instructions。現行單租戶(D21 唯一目標)無虞;未來多租戶啟用前必須:快取按 namespace 分 key+/map 帶 owner 過濾。其餘:注入失敗路徑 null-safe 不擋連線 、timeout 1.5s 、工具 owner_id 透傳 、76/76 綠。

總管審過 merge。一項 D21「記錄不阻擋」留檔:**instructions 注入的 module 快取為全域、/map 未帶 owner 過濾——MULTI_TENANT=true 部署時=跨租戶把全館地圖注入所有人 instructions**。現行單租戶(D21 唯一目標)無虞;未來多租戶啟用前必須:快取按 namespace 分 key+/map 帶 owner 過濾。其餘:注入失敗路徑 null-safe 不擋連線 ✅、timeout 1.5s ✅、工具 owner_id 透傳 ✅、76/76 綠。
Leo merged commit 289cd495b4 into main 2026-07-19 09:13:46 +00:00
Sign in to join this conversation.