From 5fc7277c3ce8cfccc1e53aee6990fe99b11f80a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Jul 2026 05:21:34 +0000 Subject: [PATCH] =?UTF-8?q?refactor(mcp):=20u6u=5F*=20tool=20=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=20rename=20=E7=82=BA=20arcrun=5F*=20+=20=E5=89=8D?= =?UTF-8?q?=E7=B6=B4=E6=94=B6=E6=96=82=E5=96=AE=E4=B8=80=E4=BE=86=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 零 u6u 洩漏(leo 要求 1):connector tool 清單只剩 arcrun_*,並移除壞掉/ 重複的 u6u_ workflow tool(deploy/execute/get/list_workflows 由 arcrun_ push/run/get/list_workflows 取代);MCP server name 也由 u6u-mcp-server 改 arcrun-mcp-server。 前綴單一真相源(leo 要求 2):新增 mcp/src/brand.ts(TOOL_PREFIX + toolName() helper),所有 server.tool() 註冊一律走 toolName("suffix"),前綴不再明碼散寫。 未來 rebrand 只改 brand.ts 一行。 - 12 個獨有能力 tool rename(component/tag/gui/search_workflows) - 4 個重複/壞掉 tool 移除 - inter-tool hint、描述字串、註解內 u6u_ 名字全數更新 - tsc exit 0;vitest 19/19 綠 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk --- cli/src/commands/list.ts | 2 +- mcp/src/brand.ts | 25 ++++++ mcp/src/mcp-handler.ts | 2 +- ...u6u_create_tag.ts => arcrun_create_tag.ts} | 3 +- ...u6u_delete_tag.ts => arcrun_delete_tag.ts} | 3 +- ...t_component.ts => arcrun_get_component.ts} | 7 +- ...guide.ts => arcrun_get_component_guide.ts} | 7 +- ...i_context.ts => arcrun_get_gui_context.ts} | 3 +- mcp/src/tools/arcrun_introspection.ts | 9 ++- ...omponents.ts => arcrun_list_components.ts} | 3 +- .../{u6u_list_tags.ts => arcrun_list_tags.ts} | 3 +- ...mponent.ts => arcrun_publish_component.ts} | 9 ++- mcp/src/tools/arcrun_recipe.ts | 13 +-- mcp/src/tools/arcrun_report_feedback.ts | 6 +- ...ponents.ts => arcrun_search_components.ts} | 7 +- ...orkflows.ts => arcrun_search_workflows.ts} | 9 ++- mcp/src/tools/arcrun_skills_examples.ts | 11 +-- ...tag_resource.ts => arcrun_tag_resource.ts} | 3 +- ...g_resource.ts => arcrun_untag_resource.ts} | 3 +- mcp/src/tools/arcrun_whoami.ts | 3 +- mcp/src/tools/arcrun_workflow_crud.ts | 21 +++-- mcp/src/tools/registry.ts | 37 ++++----- mcp/src/tools/u6u_deploy_workflow.ts | 81 ------------------- mcp/src/tools/u6u_execute_workflow.ts | 54 ------------- mcp/src/tools/u6u_get_workflow.ts | 33 -------- mcp/src/tools/u6u_list_workflows.ts | 62 -------------- 26 files changed, 111 insertions(+), 308 deletions(-) create mode 100644 mcp/src/brand.ts rename mcp/src/tools/{u6u_create_tag.ts => arcrun_create_tag.ts} (96%) rename mcp/src/tools/{u6u_delete_tag.ts => arcrun_delete_tag.ts} (95%) rename mcp/src/tools/{u6u_get_component.ts => arcrun_get_component.ts} (90%) rename mcp/src/tools/{u6u_get_component_guide.ts => arcrun_get_component_guide.ts} (78%) rename mcp/src/tools/{u6u_get_gui_context.ts => arcrun_get_gui_context.ts} (97%) rename mcp/src/tools/{u6u_list_components.ts => arcrun_list_components.ts} (96%) rename mcp/src/tools/{u6u_list_tags.ts => arcrun_list_tags.ts} (94%) rename mcp/src/tools/{u6u_publish_component.ts => arcrun_publish_component.ts} (92%) rename mcp/src/tools/{u6u_search_components.ts => arcrun_search_components.ts} (92%) rename mcp/src/tools/{u6u_search_workflows.ts => arcrun_search_workflows.ts} (91%) rename mcp/src/tools/{u6u_tag_resource.ts => arcrun_tag_resource.ts} (97%) rename mcp/src/tools/{u6u_untag_resource.ts => arcrun_untag_resource.ts} (96%) delete mode 100644 mcp/src/tools/u6u_deploy_workflow.ts delete mode 100644 mcp/src/tools/u6u_execute_workflow.ts delete mode 100644 mcp/src/tools/u6u_get_workflow.ts delete mode 100644 mcp/src/tools/u6u_list_workflows.ts diff --git a/cli/src/commands/list.ts b/cli/src/commands/list.ts index 7903b42..8b6bc91 100644 --- a/cli/src/commands/list.ts +++ b/cli/src/commands/list.ts @@ -4,7 +4,7 @@ * thin-shell-alignment P1(issue #11):原本直連 CF KV 讀 `workflow:` 前綴(CfKvClient), * 有兩個漂移:① 前綴對不上(部署寫 `{apiKey}:wf:` → 永遠列不到新部署)② 薄殼直碰底層儲存 * (self-hosted 用戶需 CF API token 才能 list)。改走 cypher `GET /webhooks/named`(KV 源,與 - * MCP u6u_list_workflows 同源),薄殼不再直連 KV、key 前綴 bug 自然消失。 + * MCP arcrun_list_workflows 同源),薄殼不再直連 KV、key 前綴 bug 自然消失。 */ import chalk from 'chalk'; import ora from 'ora'; diff --git a/mcp/src/brand.ts b/mcp/src/brand.ts new file mode 100644 index 0000000..1b600bb --- /dev/null +++ b/mcp/src/brand.ts @@ -0,0 +1,25 @@ +/** + * brand.ts — MCP tool 名前綴的單一真相源(single source of truth)。 + * + * 為什麼存在(leo 硬要求 2): + * 歷史上 tool 名前綴(早期 "u6u_"、對外改名後應為 "arcrun_")被明碼散寫在 + * ~39 個 tool 檔裡,每次 rebrand 都得逐檔手改、極易漏 → u6u 洩漏給用戶。 + * 收斂成這一個常數後,未來再 rebrand「只改這一行」。 + * + * 用法: + * import { toolName } from "../brand.js"; + * server.tool(toolName("push_workflow"), ...) // → "arcrun_push_workflow" + * + * 語意後綴(push_workflow / list_tags …)保留可讀,只有「品牌前綴」被變數化。 + * + * 可用環境變數 ARCRUN_TOOL_PREFIX 覆蓋(測試 / 未來 rebrand 過渡用),預設 "arcrun"。 + * (Workers runtime 無 process 全域,故用 globalThis 安全取值,取不到就 fallback。) + */ + +const envPrefix = (globalThis as { process?: { env?: Record } }) + .process?.env?.ARCRUN_TOOL_PREFIX; + +export const TOOL_PREFIX = envPrefix || "arcrun"; + +/** 把語意後綴組成完整 tool 名,例:toolName("whoami") → "arcrun_whoami"。 */ +export const toolName = (suffix: string): string => `${TOOL_PREFIX}_${suffix}`; diff --git a/mcp/src/mcp-handler.ts b/mcp/src/mcp-handler.ts index c5f17fa..d062552 100644 --- a/mcp/src/mcp-handler.ts +++ b/mcp/src/mcp-handler.ts @@ -10,7 +10,7 @@ export async function handleMcpRequest( partnerToken: string, ): Promise { const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); - const server = new McpServer({ name: "u6u-mcp-server", version: "1.0.0" }); + const server = new McpServer({ name: "arcrun-mcp-server", version: "1.0.0" }); registerAllTools(server, env, orgNamespace, partnerToken); await server.connect(transport); diff --git a/mcp/src/tools/u6u_create_tag.ts b/mcp/src/tools/arcrun_create_tag.ts similarity index 96% rename from mcp/src/tools/u6u_create_tag.ts rename to mcp/src/tools/arcrun_create_tag.ts index 21e3091..0dc9e60 100644 --- a/mcp/src/tools/u6u_create_tag.ts +++ b/mcp/src/tools/arcrun_create_tag.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerCreateTag(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_create_tag", + toolName("create_tag"), "在當前命名空間下建立新的 tag,用於分類工作流與零件。", { name: z.string().describe("Tag 名稱(在當前 org_namespace 下唯一)"), diff --git a/mcp/src/tools/u6u_delete_tag.ts b/mcp/src/tools/arcrun_delete_tag.ts similarity index 95% rename from mcp/src/tools/u6u_delete_tag.ts rename to mcp/src/tools/arcrun_delete_tag.ts index 8627ea5..3b0ccf8 100644 --- a/mcp/src/tools/u6u_delete_tag.ts +++ b/mcp/src/tools/arcrun_delete_tag.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerDeleteTag(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_delete_tag", + toolName("delete_tag"), "刪除當前命名空間下的指定 tag。", { tag_name: z.string().describe("要刪除的 Tag 名稱") }, async ({ tag_name }) => { diff --git a/mcp/src/tools/u6u_get_component.ts b/mcp/src/tools/arcrun_get_component.ts similarity index 90% rename from mcp/src/tools/u6u_get_component.ts rename to mcp/src/tools/arcrun_get_component.ts index 92cf23a..d2f9e6c 100644 --- a/mcp/src/tools/u6u_get_component.ts +++ b/mcp/src/tools/arcrun_get_component.ts @@ -1,14 +1,15 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_get_component — 取得零件完整合約 + * arcrun_get_component — 取得零件完整合約 * 呼叫 Component Registry GET /components/:id */ export function registerGetComponent(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_component", + toolName("get_component"), "取得指定零件的完整合約,包含 canonical_id、display_name、category、version、stability、input_schema、output_schema、gherkin_tests、評分統計等。", { canonical_id: z.string().describe("零件 canonical_id(如 validate_json)"), @@ -29,7 +30,7 @@ export function registerGetComponent(server: McpServer, env: Env, orgNamespace: if (response.status === 404) { return { - content: [{ type: "text", text: `零件 '${canonical_id}' 不存在。可用 u6u_search_components 搜尋相似零件。` }], + content: [{ type: "text", text: `零件 '${canonical_id}' 不存在。可用 arcrun_search_components 搜尋相似零件。` }], isError: true, }; } diff --git a/mcp/src/tools/u6u_get_component_guide.ts b/mcp/src/tools/arcrun_get_component_guide.ts similarity index 78% rename from mcp/src/tools/u6u_get_component_guide.ts rename to mcp/src/tools/arcrun_get_component_guide.ts index c3b753d..c1e8fea 100644 --- a/mcp/src/tools/u6u_get_component_guide.ts +++ b/mcp/src/tools/arcrun_get_component_guide.ts @@ -1,15 +1,16 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; /** - * u6u_get_component_guide — 取得零件開發指引 + * arcrun_get_component_guide — 取得零件開發指引 * 呼叫 Component Registry GET /components/guide * AI 在開發新零件前應先讀取此指引 */ export function registerGetComponentGuide(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_component_guide", - "取得 u6u 零件開發指引(Markdown 格式)。包含 TinyGo 白名單 import、禁止行為、component.contract.yaml 完整範例、本地測試指令。開發新零件前必須先讀取此指引。", + toolName("get_component_guide"), + "取得 arcrun 零件開發指引(Markdown 格式)。包含 TinyGo 白名單 import、禁止行為、component.contract.yaml 完整範例、本地測試指令。開發新零件前必須先讀取此指引。", {}, async () => { try { diff --git a/mcp/src/tools/u6u_get_gui_context.ts b/mcp/src/tools/arcrun_get_gui_context.ts similarity index 97% rename from mcp/src/tools/u6u_get_gui_context.ts rename to mcp/src/tools/arcrun_get_gui_context.ts index 7955128..e1584a2 100644 --- a/mcp/src/tools/u6u_get_gui_context.ts +++ b/mcp/src/tools/arcrun_get_gui_context.ts @@ -1,4 +1,5 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -17,7 +18,7 @@ interface ActionLogRecord { export function registerGetGuiContext(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_gui_context", + toolName("get_gui_context"), "查詢用戶在 GUI 上的最近操作記錄,了解用戶的當前意圖與操作上下文。" + "回傳最近 N 條操作記錄(從新到舊),以及用戶當前所在頁面和正在編輯的 Workflow ID。", { diff --git a/mcp/src/tools/arcrun_introspection.ts b/mcp/src/tools/arcrun_introspection.ts index 9beabb5..f7ab4f8 100644 --- a/mcp/src/tools/arcrun_introspection.ts +++ b/mcp/src/tools/arcrun_introspection.ts @@ -11,6 +11,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -20,7 +21,7 @@ const apiKeyDesc = export function registerValidateYaml(server: McpServer, env: Env) { server.tool( - "arcrun_validate_yaml", + toolName("validate_yaml"), "Dry-run YAML 校驗。不部署、無 side effect。回 {valid, errors?, nodeCount, edgeCount}。**永遠先 call 此 tool 再 push_workflow**,避免反覆 deploy 失敗。", { api_key: z.string().describe(apiKeyDesc), @@ -73,7 +74,7 @@ export function registerValidateYaml(server: McpServer, env: Env) { export function registerListPausedExecutions(server: McpServer, env: Env) { server.tool( - "arcrun_list_paused_executions", + toolName("list_paused_executions"), "列當前 api_key 下所有 paused workflow(等 daemon callback resume 的)。給 debug 用:claude_api 等 async 零件會把 workflow 暫停,此 tool 告訴你哪些還沒回來。", { api_key: z.string().describe(apiKeyDesc), @@ -108,7 +109,7 @@ export function registerListPausedExecutions(server: McpServer, env: Env) { export function registerGetExecutionTrace(server: McpServer, env: Env) { server.tool( - "arcrun_get_execution_trace", + toolName("get_execution_trace"), "看單一 paused workflow 的 state 細節(trace、graph、context、pending_result)。task_id 從 paused 錯誤訊息或 list_paused_executions 取得。", { api_key: z.string().describe(apiKeyDesc), @@ -156,7 +157,7 @@ export function registerGetExecutionTrace(server: McpServer, env: Env) { export function registerListRecentExecutions(server: McpServer, env: Env) { server.tool( - "arcrun_list_recent_executions", + toolName("list_recent_executions"), "列某 workflow 最近 N 次執行 verdict(成功 / 失敗 / duration)。資料來源是 ANALYTICS_KV 90 天保留期。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/u6u_list_components.ts b/mcp/src/tools/arcrun_list_components.ts similarity index 96% rename from mcp/src/tools/u6u_list_components.ts rename to mcp/src/tools/arcrun_list_components.ts index 2f136fa..a715621 100644 --- a/mcp/src/tools/u6u_list_components.ts +++ b/mcp/src/tools/arcrun_list_components.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerListComponents(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_list_components", + toolName("list_components"), "列出當前命名空間下所有已發佈的零件,可選擇按 tag 篩選。", { tag: z.string().optional().describe("按 tag 名稱篩選(選填)") }, async ({ tag }) => { diff --git a/mcp/src/tools/u6u_list_tags.ts b/mcp/src/tools/arcrun_list_tags.ts similarity index 94% rename from mcp/src/tools/u6u_list_tags.ts rename to mcp/src/tools/arcrun_list_tags.ts index 2674c1b..0244f6e 100644 --- a/mcp/src/tools/u6u_list_tags.ts +++ b/mcp/src/tools/arcrun_list_tags.ts @@ -1,10 +1,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerListTags(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_list_tags", + toolName("list_tags"), "列出當前命名空間下所有的 tag。", {}, async () => { diff --git a/mcp/src/tools/u6u_publish_component.ts b/mcp/src/tools/arcrun_publish_component.ts similarity index 92% rename from mcp/src/tools/u6u_publish_component.ts rename to mcp/src/tools/arcrun_publish_component.ts index eb1c88a..4332703 100644 --- a/mcp/src/tools/u6u_publish_component.ts +++ b/mcp/src/tools/arcrun_publish_component.ts @@ -1,20 +1,21 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_publish_component — 提交 TinyGo WASM 零件至 Component Registry + * arcrun_publish_component — 提交 TinyGo WASM 零件至 Component Registry * * AI 工作流: - * 1. 先呼叫 u6u_get_component_guide 取得開發指引 + * 1. 先呼叫 arcrun_get_component_guide 取得開發指引 * 2. 依指引用 TinyGo 撰寫零件(stdin/stdout JSON I/O) * 3. 編譯為 .wasm,base64 編碼後提交 * 4. Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試) */ export function registerPublishComponent(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_publish_component", - "提交 TinyGo WASM 零件至 Component Registry。需提供 component.contract.yaml 內容與編譯後的 .wasm base64。提交前請先呼叫 u6u_get_component_guide 取得開發規範。", + toolName("publish_component"), + "提交 TinyGo WASM 零件至 Component Registry。需提供 component.contract.yaml 內容與編譯後的 .wasm base64。提交前請先呼叫 arcrun_get_component_guide 取得開發規範。", { contract: z.object({ canonical_id: z.string().describe("零件功能名稱(小寫底線,如 validate_json)"), diff --git a/mcp/src/tools/arcrun_recipe.ts b/mcp/src/tools/arcrun_recipe.ts index e90d497..e7c97cc 100644 --- a/mcp/src/tools/arcrun_recipe.ts +++ b/mcp/src/tools/arcrun_recipe.ts @@ -11,6 +11,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -30,7 +31,7 @@ export function registerAllRecipeTools(server: McpServer, env: Env) { /** arcrun_recipe_search — 搜尋公庫 recipe(同名可多作者,附市場數據)。落空回創作引導。 */ export function registerRecipeSearch(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_search", + toolName("recipe_search"), "搜尋公庫 recipe(API 整合配方)。同 canonical_id 可有多作者版本,各附市場數據(成功/失敗次數),依數據選最佳。找不到時會提示可自己做一個 recipe 投稿成為作者。", { api_key: z.string().describe(apiKeyDesc), @@ -58,7 +59,7 @@ export function registerRecipeSearch(server: McpServer, env: Env) { /** arcrun_recipe_pull — 從公庫取一份 recipe 寫進自己私庫。 */ export function registerRecipePull(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_pull", + toolName("recipe_pull"), "從公庫取一份 recipe 寫進自己私庫(按需取用,非全量同步)。不指定 author 取市場最佳版本。取回後可在 workflow 用 component: 。", { api_key: z.string().describe(apiKeyDesc), @@ -108,7 +109,7 @@ export function registerRecipePull(server: McpServer, env: Env) { /** arcrun_recipe_submit_p — 把私庫某 recipe 投稿到公庫(新增作者版本)。 */ export function registerRecipeSubmitP(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_submit_p", + toolName("recipe_submit_p"), "把私庫某 recipe 投稿到公庫(app-store 模型:新增一個作者版本,不覆蓋別人的)。投稿 = 把 recipe 暴露給全網,需帶 exposure_consent 明示同意。別人能搜到並 pull,市場數據決定它被不被選用。", { api_key: z.string().describe(apiKeyDesc), @@ -160,7 +161,7 @@ export function registerRecipeSubmitP(server: McpServer, env: Env) { /** arcrun_recipe_push — 上傳/更新私庫 recipe(就地更新自己的版本)。 */ export function registerRecipePush(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_push", + toolName("recipe_push"), "上傳一份 recipe 到自己私庫(或就地更新自己既有版本)。recipe = 「http_request + 參數模板」的具名封裝,不需 deploy Worker。要投稿到公庫用 arcrun_recipe_submit_p。", { api_key: z.string().describe(apiKeyDesc), @@ -192,7 +193,7 @@ export function registerRecipePush(server: McpServer, env: Env) { /** arcrun_recipe_list — 列出自己私庫的 recipe。 */ export function registerRecipeList(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_list", + toolName("recipe_list"), "列出自己私庫(本部署)的 recipe。要找公庫的用 arcrun_recipe_search。", { api_key: z.string().describe(apiKeyDesc), @@ -213,7 +214,7 @@ export function registerRecipeList(server: McpServer, env: Env) { /** arcrun_recipe_delete — 刪除私庫某 recipe。 */ export function registerRecipeDelete(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_delete", + toolName("recipe_delete"), "刪除自己私庫某 recipe(canonical_id / rec_hash / uuid)。不影響公庫別人的版本。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/arcrun_report_feedback.ts b/mcp/src/tools/arcrun_report_feedback.ts index 6f61fe1..1041d11 100644 --- a/mcp/src/tools/arcrun_report_feedback.ts +++ b/mcp/src/tools/arcrun_report_feedback.ts @@ -8,11 +8,11 @@ * * 後續 M4 weekly_review workflow 聚合這些 block 產出 arcrun-roadmap。 * - * 命名注意:M5 全面 rename u6u → arcrun 前,本 tool 直接用新名 arcrun_ prefix - * 立下範例。其他 u6u_* tool 等 M5 一次切。 + * tool 名前綴走 brand.ts 的 toolName() helper(single source of truth)。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -28,7 +28,7 @@ const ISSUE_TYPES = [ export function registerReportFeedback(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "arcrun_report_feedback", + toolName("report_feedback"), "AI agent 完成 workflow 任務 / 卡住 / 解掉問題後 **必須** call 此 tool 回報。即使順利也要 call (issue_type=success_story),那是告訴平台「這 pattern 已 work,可推廣」。回饋會寫進 KBDB type=agent-feedback,週報自動聚合產出平台改善 roadmap。", { issue_type: z.enum(ISSUE_TYPES).describe( diff --git a/mcp/src/tools/u6u_search_components.ts b/mcp/src/tools/arcrun_search_components.ts similarity index 92% rename from mcp/src/tools/u6u_search_components.ts rename to mcp/src/tools/arcrun_search_components.ts index 96896f8..9286561 100644 --- a/mcp/src/tools/u6u_search_components.ts +++ b/mcp/src/tools/arcrun_search_components.ts @@ -1,14 +1,15 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_search_components — 語意搜尋零件庫 + * arcrun_search_components — 語意搜尋零件庫 * 呼叫 Component Registry GET /components/search?q=... */ export function registerSearchComponents(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_search_components", + toolName("search_components"), "用自然語言語意搜尋零件庫,找出符合需求的零件。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」、「驗證 JSON 格式」。回傳零件清單含 canonical_id、描述、評分。", { query: z.string().describe("自然語言搜尋詞,如「查詢 Google Sheets 資料」"), @@ -43,7 +44,7 @@ export function registerSearchComponents(server: McpServer, env: Env, orgNamespa return { content: [{ type: "text", - text: `找不到符合「${query}」的零件。可以用 u6u_publish_component 提交新零件。`, + text: `找不到符合「${query}」的零件。可以用 arcrun_publish_component 提交新零件。`, }], }; } diff --git a/mcp/src/tools/u6u_search_workflows.ts b/mcp/src/tools/arcrun_search_workflows.ts similarity index 91% rename from mcp/src/tools/u6u_search_workflows.ts rename to mcp/src/tools/arcrun_search_workflows.ts index fb68881..2ec83fd 100644 --- a/mcp/src/tools/u6u_search_workflows.ts +++ b/mcp/src/tools/arcrun_search_workflows.ts @@ -1,15 +1,16 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_search_workflows — 用自然語言找現成工作流(workflow-discovery R2) + * arcrun_search_workflows — 用自然語言找現成工作流(workflow-discovery R2) * * 北極星入口:AI 先查「有沒有現成工作流能做這件事」→ 找到就執行,別重造。 * 呼叫 cypher GET /workflows/search → 轉發 KBDB /entries/search(entry_type=workflow + 本租戶)。 * 優先語意搜尋;KBDB 未開 Vectorize → 自動降級關鍵字 + 回 capability_hint(不假裝語義)。 * - * 薄殼(rule 07):只做參數轉換 + 呼叫 + 格式化,零業務邏輯。形態對齊 u6u_search_components。 + * 薄殼(rule 07):只做參數轉換 + 呼叫 + 格式化,零業務邏輯。形態對齊 arcrun_search_components。 * flag 安全:AI 收到意圖時主動 call 一次,無輪詢/排程。 */ export function registerSearchWorkflows( @@ -19,7 +20,7 @@ export function registerSearchWorkflows( partnerToken: string, ) { server.tool( - "u6u_search_workflows", + toolName("search_workflows"), "用自然語言找現成的工作流(先查有沒有現成的能做這件事,找到就用,別重造)。例如:「把資料寫進 Google Sheets」、「每天抓 RSS 發通知」、「webhook 轉發到別的 API」。回傳本帳號下符合的工作流清單。", { query: z.string().describe("自然語言描述要找的工作流,如「把資料寫進 Google Sheets」"), @@ -60,7 +61,7 @@ export function registerSearchWorkflows( return { content: [{ type: "text", - text: `找不到符合「${query}」的現成工作流。可以用 u6u_deploy_workflow 部署一個新的。${hint}`, + text: `找不到符合「${query}」的現成工作流。可以用 arcrun_push_workflow 部署一個新的。${hint}`, }], }; } diff --git a/mcp/src/tools/arcrun_skills_examples.ts b/mcp/src/tools/arcrun_skills_examples.ts index 943ea92..5ac1539 100644 --- a/mcp/src/tools/arcrun_skills_examples.ts +++ b/mcp/src/tools/arcrun_skills_examples.ts @@ -25,6 +25,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -68,7 +69,7 @@ function parseTags(tagsJson?: string): string[] { export function registerListSkills(server: McpServer, env: Env) { server.tool( - "arcrun_list_skills", + toolName("list_skills"), "列所有 agent-skill blocks(從 arcrun/registry/skills/ 同步進 KBDB)。每個 skill 是個 markdown playbook,描述 AI 面對 X 問題該怎麼想 + 該用哪個 example。回 [{slug, title, tags}]。call get_skill(slug) 拿完整內文。", { tag: z.string().optional().describe("optional 標籤過濾。如 'rag' / 'watcher' / 'debug'"), @@ -115,7 +116,7 @@ export function registerListSkills(server: McpServer, env: Env) { export function registerGetSkill(server: McpServer, env: Env) { server.tool( - "arcrun_get_skill", + toolName("get_skill"), "拿單一 agent-skill 完整 markdown playbook。slug 從 list_skills 取得。", { slug: z.string().describe("skill slug,例如 'build_watcher_workflow' / 'rag_with_arcrun'"), @@ -153,7 +154,7 @@ export function registerGetSkill(server: McpServer, env: Env) { export function registerListExamples(server: McpServer, env: Env) { server.tool( - "arcrun_list_examples", + toolName("list_examples"), "列所有 workflow-example blocks(從 arcrun/registry/examples/ 同步進 KBDB)。每個 example 是可直接 push 的 workflow YAML 範本 + description。回 [{slug, tags}]。call get_example / search_examples 拿細節。", { tag: z.string().optional().describe("optional 標籤過濾。如 'rag' / 'cron' / 'llm' / 'webhook'"), @@ -194,7 +195,7 @@ export function registerListExamples(server: McpServer, env: Env) { export function registerGetExample(server: McpServer, env: Env) { server.tool( - "arcrun_get_example", + toolName("get_example"), "拿單一 workflow-example 完整 YAML + description。slug 從 list_examples / search_examples 取得。可直接拿 YAML 改成你自己的 → push。", { slug: z.string().describe("example slug,例如 'rag-search-answer' / 'cron-watcher'"), @@ -243,7 +244,7 @@ export function registerGetExample(server: McpServer, env: Env) { export function registerSearchExamples(server: McpServer, env: Env) { server.tool( - "arcrun_search_examples", + toolName("search_examples"), "用 use case 關鍵字搜 workflow examples,回最相關 N 個。" + "注意:基本盤目前是 D1 LIKE 關鍵字搜尋(非語義 embedding;語義是 kbdb-base Phase 1 的 embed 模組,尚未上)。" + "→ 用具體詞('email'、'cron'、'rag')比整句自然語言命中率高。也會比對 slug/tag。", diff --git a/mcp/src/tools/u6u_tag_resource.ts b/mcp/src/tools/arcrun_tag_resource.ts similarity index 97% rename from mcp/src/tools/u6u_tag_resource.ts rename to mcp/src/tools/arcrun_tag_resource.ts index 40adc2f..6844b79 100644 --- a/mcp/src/tools/u6u_tag_resource.ts +++ b/mcp/src/tools/arcrun_tag_resource.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerTagResource(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_tag_resource", + toolName("tag_resource"), "為當前命名空間下的工作流或零件加上 tag 標籤。", { resource_type: z.enum(["workflow", "component"]).describe("資源類型:workflow 或 component"), diff --git a/mcp/src/tools/u6u_untag_resource.ts b/mcp/src/tools/arcrun_untag_resource.ts similarity index 96% rename from mcp/src/tools/u6u_untag_resource.ts rename to mcp/src/tools/arcrun_untag_resource.ts index 6f58632..b8bcc95 100644 --- a/mcp/src/tools/u6u_untag_resource.ts +++ b/mcp/src/tools/arcrun_untag_resource.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerUntagResource(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_untag_resource", + toolName("untag_resource"), "移除當前命名空間下工作流或零件的 tag 標籤。", { resource_type: z.enum(["workflow", "component"]).describe("資源類型:workflow 或 component"), diff --git a/mcp/src/tools/arcrun_whoami.ts b/mcp/src/tools/arcrun_whoami.ts index eba73c1..24ee23c 100644 --- a/mcp/src/tools/arcrun_whoami.ts +++ b/mcp/src/tools/arcrun_whoami.ts @@ -8,11 +8,12 @@ * 薄殼:只回報 MCP 已解析的 orgNamespace(綁哪個帳號)+ cypher binding 連向,無業務邏輯。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; export function registerWhoami(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "arcrun_whoami", + toolName("whoami"), "回報這個 MCP 連線目前生效的身份:綁哪個帳號 / namespace、cypher 連向哪。" + "部署 / 觸發 / 查 workflow 前先 call 此 tool 確認帳號,**不要自己 curl 猜帳號 URL**(會打到錯帳號)。", {}, diff --git a/mcp/src/tools/arcrun_workflow_crud.ts b/mcp/src/tools/arcrun_workflow_crud.ts index e56836e..96d2553 100644 --- a/mcp/src/tools/arcrun_workflow_crud.ts +++ b/mcp/src/tools/arcrun_workflow_crud.ts @@ -3,9 +3,8 @@ * * 對應 .agents/specs/llm-interface/ Milestone 2.2。 * - * 取代既有 u6u_deploy_workflow(呼叫 /workflows/deploy — 該 endpoint 不存在, - * 是壞掉的 tool)+ u6u_list_workflows / u6u_get_workflow 透過 KBDB 撈 metadata - * 而非直接問 cypher-executor 的真實狀態。 + * 取代早期壞掉的 deploy_workflow(呼叫 /workflows/deploy — 該 endpoint 不存在), + * 以及舊的 list/get workflow(透過 KBDB 撈 metadata 而非直接問 cypher-executor 真實狀態)。 * * 新 tool 直打 cypher-executor /webhooks/named*: * - arcrun_push_workflow @@ -14,11 +13,11 @@ * - arcrun_delete_workflow * - arcrun_run_workflow * - * 舊 u6u_* 待 M5 一次 rename + 退場(leo 2026-05-16 拍板)。在此之前, - * AI 看到兩套 tool — 用 arcrun_* 為主,u6u_* 有 deprecation hint。 + * tool 名前綴一律走 brand.ts 的 toolName() helper(single source of truth)。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -34,8 +33,8 @@ const apiKeyDesc = */ export function registerPushWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_push_workflow", - "部署 workflow 到 arcrun(取代 u6u_deploy_workflow,後者打不存在的 endpoint)。輸入可以是 YAML 字串或 graph 物件。**建議先 call arcrun_validate_yaml 確認 schema**。", + toolName("push_workflow"), + "部署 workflow 到 arcrun。輸入可以是 YAML 字串或 graph 物件。**建議先 call arcrun_validate_yaml 確認 schema**。", { api_key: z.string().describe(apiKeyDesc), yaml_content: z.string().optional().describe( @@ -147,7 +146,7 @@ export function registerPushWorkflow(server: McpServer, env: Env) { export function registerListWorkflows(server: McpServer, env: Env) { server.tool( - "arcrun_list_workflows", + toolName("list_workflows"), "列出你 (api_key 對應 namespace) 已部署的所有 workflow。回 [{name}]。", { api_key: z.string().describe(apiKeyDesc), @@ -185,7 +184,7 @@ export function registerListWorkflows(server: McpServer, env: Env) { export function registerGetWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_get_workflow", + toolName("get_workflow"), "看單一 workflow 的完整定義(graph + config)。", { api_key: z.string().describe(apiKeyDesc), @@ -248,7 +247,7 @@ export function registerGetWorkflow(server: McpServer, env: Env) { export function registerDeleteWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_delete_workflow", + toolName("delete_workflow"), "刪除 workflow。**不可逆,確認後再做**。會清掉對應 cron index 與 webhook URL。", { api_key: z.string().describe(apiKeyDesc), @@ -292,7 +291,7 @@ export function registerDeleteWorkflow(server: McpServer, env: Env) { export function registerRunWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_run_workflow", + toolName("run_workflow"), "觸發 workflow 執行。input 物件帶進 trigger context。回 {success, data, trace?, duration_ms}。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/registry.ts b/mcp/src/tools/registry.ts index d333296..3790ab4 100644 --- a/mcp/src/tools/registry.ts +++ b/mcp/src/tools/registry.ts @@ -1,21 +1,17 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { Env } from "../types.js"; -import { registerSearchComponents } from "./u6u_search_components.js"; -import { registerExecuteWorkflow } from "./u6u_execute_workflow.js"; -import { registerDeployWorkflow } from "./u6u_deploy_workflow.js"; -import { registerPublishComponent } from "./u6u_publish_component.js"; -import { registerListWorkflows } from "./u6u_list_workflows.js"; -import { registerGetWorkflow } from "./u6u_get_workflow.js"; -import { registerSearchWorkflows } from "./u6u_search_workflows.js"; -import { registerListComponents } from "./u6u_list_components.js"; -import { registerGetComponent } from "./u6u_get_component.js"; -import { registerGetComponentGuide } from "./u6u_get_component_guide.js"; -import { registerCreateTag } from "./u6u_create_tag.js"; -import { registerListTags } from "./u6u_list_tags.js"; -import { registerDeleteTag } from "./u6u_delete_tag.js"; -import { registerTagResource } from "./u6u_tag_resource.js"; -import { registerUntagResource } from "./u6u_untag_resource.js"; -import { registerGetGuiContext } from "./u6u_get_gui_context.js"; +import { registerSearchComponents } from "./arcrun_search_components.js"; +import { registerPublishComponent } from "./arcrun_publish_component.js"; +import { registerSearchWorkflows } from "./arcrun_search_workflows.js"; +import { registerListComponents } from "./arcrun_list_components.js"; +import { registerGetComponent } from "./arcrun_get_component.js"; +import { registerGetComponentGuide } from "./arcrun_get_component_guide.js"; +import { registerCreateTag } from "./arcrun_create_tag.js"; +import { registerListTags } from "./arcrun_list_tags.js"; +import { registerDeleteTag } from "./arcrun_delete_tag.js"; +import { registerTagResource } from "./arcrun_tag_resource.js"; +import { registerUntagResource } from "./arcrun_untag_resource.js"; +import { registerGetGuiContext } from "./arcrun_get_gui_context.js"; import { registerReportFeedback } from "./arcrun_report_feedback.js"; import { registerAllIntrospectionTools } from "./arcrun_introspection.js"; import { registerAllWorkflowCrudTools } from "./arcrun_workflow_crud.js"; @@ -26,11 +22,7 @@ import { registerWhoami } from "./arcrun_whoami.js"; export function registerAllTools(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { registerSearchComponents(server, env, orgNamespace); - registerExecuteWorkflow(server, env, orgNamespace, partnerToken); - registerDeployWorkflow(server, env, orgNamespace); registerPublishComponent(server, env, orgNamespace); - registerListWorkflows(server, env, orgNamespace, partnerToken); // thin-shell-alignment P1: list 改讀 /webhooks/named - registerGetWorkflow(server, env, orgNamespace); registerSearchWorkflows(server, env, orgNamespace, partnerToken); // workflow-discovery R2 registerListComponents(server, env, orgNamespace); registerGetComponent(server, env, orgNamespace); @@ -41,12 +33,13 @@ export function registerAllTools(server: McpServer, env: Env, orgNamespace: stri registerTagResource(server, env, orgNamespace); registerUntagResource(server, env, orgNamespace); registerGetGuiContext(server, env, orgNamespace); - // LI SDD M1.3: explicit feedback tool (新命名規範 arcrun_*) + // LI SDD M1.3: explicit feedback tool(arcrun_* 命名規範) registerReportFeedback(server, env, orgNamespace); // LI SDD M2.2: introspection tools (validate / paused / trace / recent executions) registerAllIntrospectionTools(server, env); // LI SDD M2.2: workflow CRUD (push / list / get / delete / run) - // 取代既有 u6u_deploy_workflow (打不存在的 /workflows/deploy endpoint) + // 取代早期壞掉的 deploy_workflow(打不存在的 /workflows/deploy endpoint), + // 以及重複的 list/get workflow(改直問 cypher-executor 真實狀態,不從 KBDB 撈 metadata)。 registerAllWorkflowCrudTools(server, env); // LI SDD M3.2: skills + examples lookup(KBDB-backed) // 走 sync-registry-to-kbdb.py 把 registry/{skills,examples} 同步進 KBDB diff --git a/mcp/src/tools/u6u_deploy_workflow.ts b/mcp/src/tools/u6u_deploy_workflow.ts deleted file mode 100644 index a2ef9ac..0000000 --- a/mcp/src/tools/u6u_deploy_workflow.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -export function registerDeployWorkflow(server: McpServer, env: Env, orgNamespace: string) { - server.tool( - "u6u_deploy_workflow", - "將工作流 YAML 配置正式部署至雲端引擎,完成註冊與排程設定。", - { - yaml_content: z.string().describe("工作流的 YAML 配置內容") - }, - async ({ yaml_content }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { - content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], - isError: true - }; - } - - const response = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/workflows/deploy", { - method: "POST", - headers: { "Content-Type": "application/yaml" }, - body: yaml_content - }); - - if (!response.ok) { - const errorText = await response.text(); - return { - content: [{ type: "text", text: `Deployment failed: ${errorText}` }], - isError: true - }; - } - - const result = await response.json<{ workflow_id?: string; [key: string]: unknown }>(); - const workflowId = result.workflow_id ?? crypto.randomUUID(); - - // Parse workflow name from YAML - const nameMatch = yaml_content.match(/^name:\s*(.+)$/m); - const workflowName = nameMatch ? nameMatch[1].trim() : workflowId; - - // Store workflow metadata in KBDB - if (env.KBDB) { - const kbdbResp = await kbdbFetch(env, "/records", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - template: "workflow_metadata", - record_id: `wf-${workflowId}`, - user_id: orgNamespace, - values: { - workflow_id: workflowId, - name: workflowName, - deployed_at: new Date().toISOString(), - org_namespace: orgNamespace - } - }) - }); - - if (!kbdbResp.ok) { - const errText = await kbdbResp.text(); - return { - content: [{ type: "text", text: `Deployment succeeded but failed to store metadata: ${errText}` }], - isError: true - }; - } - } - - return { - content: [{ type: "text", text: `Successfully deployed workflow: ${JSON.stringify(result, null, 2)}` }] - }; - } catch (error) { - return { - content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], - isError: true - }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_execute_workflow.ts b/mcp/src/tools/u6u_execute_workflow.ts deleted file mode 100644 index 0164643..0000000 --- a/mcp/src/tools/u6u_execute_workflow.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; - -export function registerExecuteWorkflow(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { - server.tool( - "u6u_execute_workflow", - "在沙盒環境中即時執行工作流,驗證 triplets 邏輯是否正確。每個 config 鍵對應 triplets 中的節點名,內含 component(零件 canonical_id)、recipe(prompt_recipe:xxx,選用)、與該節點的其他靜態參數。", - { - triplets: z.array(z.string()).describe("工作流三元組,例:['input >> 完成後 >> synth']"), - context: z.record(z.string(), z.any()).describe("初始變數(測試資料 / 上游節點輸出模擬)"), - config: z.record(z.string(), z.record(z.string(), z.any())).optional().describe("每節點配置:{ node_name: { component, recipe?, ...params } }") - }, - async ({ triplets, context, config }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { - content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], - isError: true - }; - } - - // KI-12 修:改打 /cypher/execute(吃 triplets+config),原 /execute 是吃完整 graph 的舊路徑 - // KI-15 修:轉發 partner token 給 cypher-executor,讓 recipe expander 能用 ak_ key 抓 KBDB - const response = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/cypher/execute", { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-Arcrun-API-Key": partnerToken - }, - body: JSON.stringify({ triplets, context, config }) - }); - - if (!response.ok) { - const errorText = await response.text(); - return { - content: [{ type: "text", text: `Execution failed: ${errorText}` }], - isError: true - }; - } - - const result = await response.json(); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }] - }; - } catch (error) { - return { - content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], - isError: true - }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_get_workflow.ts b/mcp/src/tools/u6u_get_workflow.ts deleted file mode 100644 index 4f261dc..0000000 --- a/mcp/src/tools/u6u_get_workflow.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -export function registerGetWorkflow(server: McpServer, env: Env, orgNamespace: string) { - server.tool( - "u6u_get_workflow", - "取得指定工作流的 metadata,包含名稱、部署時間與 tag 列表。", - { workflow_id: z.string().describe("工作流 ID") }, - async ({ workflow_id }) => { - try { - if (!env.KBDB) { - return { content: [{ type: "text", text: "Error: KBDB service binding unavailable" }], isError: true }; - } - const resp = await kbdbFetch(env, `/records/wf-${encodeURIComponent(workflow_id)}`); - if (resp.status === 404) { - return { content: [{ type: "text", text: `Error: Workflow '${workflow_id}' not found` }], isError: true }; - } - if (!resp.ok) { - return { content: [{ type: "text", text: `Error querying workflow: ${await resp.text()}` }], isError: true }; - } - const record = await resp.json<{ slots: { workflow_id: string; name: string; deployed_at: string; org_namespace: string } }>(); - if (record.slots.org_namespace !== orgNamespace) { - return { content: [{ type: "text", text: `Error: Workflow '${workflow_id}' not found` }], isError: true }; - } - return { content: [{ type: "text", text: JSON.stringify(record.slots, null, 2) }] }; - } catch (error) { - return { content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_list_workflows.ts b/mcp/src/tools/u6u_list_workflows.ts deleted file mode 100644 index c7197c3..0000000 --- a/mcp/src/tools/u6u_list_workflows.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -/** - * u6u_list_workflows — 列出本帳號已部署的工作流 - * - * thin-shell-alignment P1(issue #11):原讀 KBDB `/records?template=workflow_metadata`, - * 與 CLI `acr list`(讀 KV)不同源 → 列出的東西不一樣。改讀 cypher `GET /webhooks/named` - * (KV 源,與 CLI 收斂同源)。job 分:list 讀 KV(部署寫入處,權威),search 讀 KBDB entry。 - * tag 過濾仍走 KBDB resource_tag(另一維度,非 workflow 清單來源)。 - */ -export function registerListWorkflows(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { - server.tool( - "u6u_list_workflows", - "列出當前命名空間下所有已部署的工作流,可選擇按 tag 篩選。", - { tag: z.string().optional().describe("按 tag 名稱篩選(選填)") }, - async ({ tag }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], isError: true }; - } - - // tag 過濾(選填):先從 KBDB resource_tag 查出該 tag 下的 workflow_id 白名單。 - let tagFilter: Set | null = null; - if (tag) { - if (!env.KBDB) { - return { content: [{ type: "text", text: "Error: KBDB service binding unavailable (tag 過濾需要)" }], isError: true }; - } - const tagResp = await kbdbFetch(env, `/records/search?template=resource_tag&user_id=${encodeURIComponent(orgNamespace)}&tag_name=${encodeURIComponent(tag)}&resource_type=workflow`); - if (!tagResp.ok) { - return { content: [{ type: "text", text: `Error querying tags: ${await tagResp.text()}` }], isError: true }; - } - const tagData = await tagResp.json<{ records: Array<{ slots: { resource_id: string } }> }>(); - tagFilter = new Set(tagData.records.map(r => r.slots.resource_id)); - if (tagFilter.size === 0) return { content: [{ type: "text", text: JSON.stringify([], null, 2) }] }; - } - - // 主清單:讀 cypher GET /webhooks/named(KV 源,與 CLI acr list 同源)。 - const resp = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/webhooks/named", { - method: "GET", - headers: { "X-Arcrun-API-Key": partnerToken }, - }); - if (!resp.ok) { - return { content: [{ type: "text", text: `Error listing workflows: ${await resp.text()}` }], isError: true }; - } - const data = await resp.json<{ workflows: Array<{ name: string; description?: string; created_at?: string; webhook_url?: string }> }>(); - let workflows = data.workflows ?? []; - // tag 過濾用 name 比對(KV 源主鍵=name)。 - // ⚠️ 語意債(SDD §4 記):舊 tag 的 resource_id 可能存 UUID(舊 workflow_metadata workflow_id) - // 或 name,語意不明確。方向①收斂到 KV(主鍵=name)後,resource_id 應統一為 name。 - // 過渡期先用 name 比對(KV 源唯一鍵);舊用 UUID tag 的會在 backfill/re-tag 後對齊。待總管確認 tag 收斂。 - if (tagFilter !== null) workflows = workflows.filter(w => tagFilter!.has(w.name)); - - return { content: [{ type: "text", text: JSON.stringify(workflows, null, 2) }] }; - } catch (error) { - return { content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; - } - } - ); -}