cda1c7b261
leo 兩個洞察:
① 「整個 arcrun instruction 很像 LLM wiki…它會拿到一個 index 把所有文件說明都塞給它,
它不會就可以查,範本全部寫在裡面」
⇒ 對照 wiki 的 push/pull 分法:我原本只做了 push(instructions 開場),
漏了 pull(INDEX 導航)。補 registry/skills/INDEX.md:
什麼症狀查哪支 skill/查現成零件recipe workflow 的九支工具/四個已知的坑/腹語術紅線
② 「它不去查就不知道…如果它去上網搜因為它不知道自己有配備呢?」
⇒ 實測確認 instructions 是 **push**(本 session system prompt 內就有藏書地圖那段)
⇒ AI 不會去上網搜,但原本的 instructions 沒說「你配備了什麼」
⇒ 開場補:Arcrun 是什麼/你現在就有完整能力/不要上網搜(網路上沒有)
驗:tsc 零錯誤。⚠️ 未部署——實測總管 token 只有 account(read),無法部署任何 CF worker。
61 lines
3.7 KiB
TypeScript
61 lines
3.7 KiB
TypeScript
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<Response> {
|
||
// 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)。",
|
||
"**沒有** `ON_TRUE`/`ON_FALSE`/`ON_FAILURE`——引擎目前不支援條件分支。",
|
||
"第一個節點固定是 `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);
|
||
}
|