import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; import { registerAllTools } from "./tools/registry.js"; import { buildLibraryMapInstructions } from "./lib/library-map.js"; import { Env } from "./types.js"; export async function handleMcpRequest( request: Request, env: Env, orgNamespace: string, partnerToken: string, ): Promise { // library-map SDD M4(design §4/§6):連線時把全館藏書地圖嵌進 server instructions, // session 一開就知道館裡有哪些庫(push 零查詢)。builder 內建 timeout+isolate TTL 快取 //(選型理由見 lib/library-map.ts 檔頭);任何失敗回 null → 靜默略過,絕不擋 MCP 連線(鐵律)。 const mapInstructions = await buildLibraryMapInstructions(env); // 2026-07-30(leo 問「人類說『幫我用 arcrun 寫 xxx』,Haiku 會知道要用這些資源嗎? // 如果不會,要寫什麼在外面讓它一聽到就知道?」): // 實測答案是**不會**——AI 只看到 41 個工具名,會自己猜(很可能直接跳到 push_workflow // 瞎編,或去讀 registry/examples 那 8/13 引用不存在零件的壞範例)。 // instructions 是唯一「AI 一連上就必看」的欄位 ⇒ 開場就指路,不依賴任何查詢成功。 // ⚠️ 這段是靜態常數:即使 KBDB 掛了、藏書地圖抓不到,它也必須出現(鐵律:不擋連線)。 const startHere = [ "# Arcrun — 你已經配備了這套工具,別上網找", "", "**Arcrun 是什麼**:跑在 Cloudflare 上的工作流引擎(類 n8n)。你用 `>>` 寫「意圖」,", "系統告訴你有哪些現成零件/recipe 可用,你只要填 payload——**不必自己寫程式**。", "**你現在就有完整能力**:查零件、查 recipe、看實跑過的 workflow、部署、觸發、看執行紀錄。", "⚠️ **不要上網搜 Arcrun 文件**(網路上沒有/會過時)。答案都在下面的工具裡。", "", "【先讀這裡】要在 Arcrun 上做任何事(用戶說「幫我用 Arcrun 做 X」),**照這個順序**:", "", "1. `arcrun_get_skill('write_intent_workflow')` — **必讀第一支**。", " 教你用 `>>` 寫「意圖工作流」。你**不需要先知道有哪些零件**,先寫意圖。", "2. `arcrun_whoami()` — 確認連到哪個帳號(勿自行 curl 猜帳號 URL)。", "3. 把意圖丟 `POST /cypher/search` 或 `arcrun_validate_yaml` — 系統告訴你哪些零件存在。", "4. 卡住/不知道該查什麼 → `arcrun_get_skill('INDEX')`(全館導航:什麼問題查哪裡+已知的坑)。", "5. 缺零件時:缺 API → 寫 recipe(`arcrun_recipe_push`);缺能力 → 投稿零件 PR。", " 🔴 **不要因為查不到零件就改寫成 `code` 節點**——那叫「腹語術」(表面用 Arcrun、", " 實際全寫 JS)。`code` 只用於局部整形(例:剝掉 LLM 回應的雜訊)。", "", "邊:`ON_SUCCESS`(成功往下)、`對每個 <變數>`(FOREACH)、", "以及**條件分支**(2026-08-01 起引擎支援):", "`ON_TRUE`/`ON_FALSE`(配 `if_control`)、`ON_BRANCH`+`branch:` 標籤", "(配 `switch` 的每個 case/`try_catch` 的 try·catch)。", "🔴 **需要判斷時用分支邊,不要寫 code 判斷**——查零件的回應會附 `branch_hint`", "(哪些邊型+可照抄範例),照著接即可。", "🔴 **分支跑完怎麼判斷成功**:看 `verdict`(`arcrun_get_execution_trace` 或", "`GET /workflows//executions`)。**走 true 路時 false 路的節點不出現=正確行為**,", "不是失敗——別因為「只有一條路有輸出」就以為壞掉而改寫成 code(2026-08-01 實撞)。", "第一個節點固定是 `input`。", ].join("\n"); const instructions = mapInstructions ? `${startHere}\n\n---\n\n${mapInstructions}` : startHere; const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); const server = new McpServer( { name: "arcrun-mcp-server", version: "1.0.0" }, { instructions }, ); registerAllTools(server, env, orgNamespace, partnerToken); await server.connect(transport); return transport.handleRequest(request); }