refactor(mcp): u6u_* tool rename → arcrun_* + 前綴收斂單一來源 #20
@@ -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';
|
||||
|
||||
+46
-39
@@ -3,8 +3,7 @@
|
||||
> Arcrun 是 **AI 優先(AI-First)** 的工作流自動化平台。
|
||||
> 跟 AI 描述你的意圖,Arcrun 幫你把它變成可重複執行、不需要 AI 的自動化工作流。
|
||||
>
|
||||
> 註:本指南部分工具仍以舊 `u6u_` 前綴記載(registry/component 管理那組);現役 workflow 工具是
|
||||
> `arcrun_*`(見 `mcp/src/tools/`)。連線設定見 `mcp/README.md`(用 `acr mcp-setup`)。
|
||||
> 註:所有工具一律 `arcrun_*` 前綴(見 `mcp/src/tools/`)。連線設定見 `mcp/README.md`(用 `acr mcp-setup`)。
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +22,7 @@
|
||||
|
||||
## 核心概念:三元組(Triplet)
|
||||
|
||||
u6u 的一切都建立在「三元組」上。三元組是描述業務邏輯的最小單位,格式極度簡單,AI 不會出錯,人也能一眼看懂。
|
||||
Arcrun 的一切都建立在「三元組」上。三元組是描述業務邏輯的最小單位,格式極度簡單,AI 不會出錯,人也能一眼看懂。
|
||||
|
||||
### 格式
|
||||
|
||||
@@ -55,7 +54,7 @@ system sends telegram-notification
|
||||
|
||||
### 為什麼這麼簡單?
|
||||
|
||||
因為 AI 擅長理解意圖,三元組擅長表達意圖。你跟 AI 說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,u6u 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。
|
||||
因為 AI 擅長理解意圖,三元組擅長表達意圖。你跟 AI 說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,Arcrun 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。
|
||||
|
||||
---
|
||||
|
||||
@@ -66,13 +65,15 @@ system sends telegram-notification
|
||||
↓
|
||||
AI 產出 Workflow_Plan_YAML(每次規劃新專案)
|
||||
↓
|
||||
u6u_search_components(查零件庫)
|
||||
arcrun_search_components(查零件庫)
|
||||
↓
|
||||
有缺件?→ AI 產出 Component_Plan_YAML → u6u_publish_component
|
||||
有缺件?→ AI 產出 Component_Plan_YAML → arcrun_publish_component
|
||||
↓
|
||||
u6u_execute_workflow(沙盒測試)
|
||||
arcrun_validate_yaml(部署前 schema 驗證)
|
||||
↓
|
||||
u6u_deploy_workflow(正式部署)
|
||||
arcrun_push_workflow(正式部署)
|
||||
↓
|
||||
arcrun_run_workflow(觸發執行,帶 input)
|
||||
↓
|
||||
(選填)建立 tag,為工作流與零件分類
|
||||
```
|
||||
@@ -214,7 +215,7 @@ workflow:
|
||||
|
||||
## Component_Plan_YAML 格式
|
||||
|
||||
**產出時機:** 只有當 `u6u_search_components` 回報有缺件時,AI 才會產出此 YAML。不是每次都需要。
|
||||
**產出時機:** 只有當 `arcrun_search_components` 回報有缺件時,AI 才會產出此 YAML。不是每次都需要。
|
||||
|
||||
### 格式說明
|
||||
|
||||
@@ -325,7 +326,7 @@ components:
|
||||
|
||||
### 步驟二:確認零件完整性
|
||||
|
||||
呼叫 `u6u_search_components`,傳入所有 triplet:
|
||||
呼叫 `arcrun_search_components`,傳入所有 triplet:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -339,38 +340,45 @@ components:
|
||||
|
||||
回應會告知哪些零件已存在、哪些缺失。若有缺件,先完成[零件開發流程](#零件component開發流程)。
|
||||
|
||||
### 步驟三:沙盒測試
|
||||
### 步驟三:部署前 schema 驗證
|
||||
|
||||
```json
|
||||
// u6u_execute_workflow
|
||||
// arcrun_validate_yaml
|
||||
{
|
||||
"triplets": [
|
||||
"system fetches exchange-rate",
|
||||
"system parses rate-data",
|
||||
"system sends telegram-notification"
|
||||
],
|
||||
"context": {
|
||||
"currency_pair": "USD/TWD",
|
||||
"chat_id": "123456789"
|
||||
}
|
||||
"yaml_content": "workflow:\n name: exchange-rate-notify\n ..."
|
||||
}
|
||||
```
|
||||
|
||||
### 步驟四:正式部署
|
||||
|
||||
```json
|
||||
// u6u_deploy_workflow
|
||||
// arcrun_push_workflow
|
||||
{
|
||||
"api_key": "ak_xxx",
|
||||
"yaml_content": "workflow:\n name: exchange-rate-notify\n ..."
|
||||
}
|
||||
```
|
||||
|
||||
部署成功後,系統回傳 `workflow_id`,並自動記錄 metadata 至 KBDB。
|
||||
|
||||
### 步驟五:加上 Tag(選填)
|
||||
### 步驟五:觸發執行
|
||||
|
||||
```json
|
||||
// u6u_tag_resource
|
||||
// arcrun_run_workflow — 觸發已部署的 workflow,input 帶進 trigger context
|
||||
{
|
||||
"api_key": "ak_xxx",
|
||||
"name": "exchange-rate-notify",
|
||||
"input": {
|
||||
"currency_pair": "USD/TWD",
|
||||
"chat_id": "123456789"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 步驟六:加上 Tag(選填)
|
||||
|
||||
```json
|
||||
// arcrun_tag_resource
|
||||
{
|
||||
"resource_type": "workflow",
|
||||
"resource_id": "wf-abc123",
|
||||
@@ -381,9 +389,8 @@ components:
|
||||
### 查詢已部署的工作流
|
||||
|
||||
```
|
||||
u6u_list_workflows → 列出所有工作流
|
||||
u6u_list_workflows(tag=finance) → 按 tag 篩選
|
||||
u6u_get_workflow(workflow_id) → 取得特定工作流 metadata
|
||||
arcrun_list_workflows → 列出所有工作流
|
||||
arcrun_get_workflow(name) → 取得特定工作流 metadata
|
||||
```
|
||||
|
||||
---
|
||||
@@ -392,12 +399,12 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata
|
||||
|
||||
### 步驟一:確認缺件
|
||||
|
||||
`u6u_search_components` 回報缺件後,AI 產出 Component_Plan_YAML。存入 `components/` 目錄。
|
||||
`arcrun_search_components` 回報缺件後,AI 產出 Component_Plan_YAML。存入 `components/` 目錄。
|
||||
|
||||
### 步驟二:發佈零件
|
||||
|
||||
```json
|
||||
// u6u_publish_component(API Config 方式)
|
||||
// arcrun_publish_component(API Config 方式)
|
||||
{
|
||||
"component_id": "system-fetches-exchange-rate",
|
||||
"api_config": {
|
||||
@@ -408,7 +415,7 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata
|
||||
```
|
||||
|
||||
```json
|
||||
// u6u_publish_component(Gherkin 方式)
|
||||
// arcrun_publish_component(Gherkin 方式)
|
||||
{
|
||||
"component_id": "system-sends-confirmation-email",
|
||||
"gherkin": "Feature: 訂單確認信\n Scenario: ..."
|
||||
@@ -418,7 +425,7 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata
|
||||
### 步驟三:加上 Tag(選填)
|
||||
|
||||
```json
|
||||
// u6u_tag_resource
|
||||
// arcrun_tag_resource
|
||||
{
|
||||
"resource_type": "component",
|
||||
"resource_id": "system-fetches-exchange-rate",
|
||||
@@ -429,9 +436,9 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata
|
||||
### 查詢已發佈的零件
|
||||
|
||||
```
|
||||
u6u_list_components → 列出所有零件
|
||||
u6u_list_components(tag=payment) → 按 tag 篩選
|
||||
u6u_get_component(component_id) → 取得特定零件 metadata
|
||||
arcrun_list_components → 列出所有零件
|
||||
arcrun_list_components(tag=payment) → 按 tag 篩選
|
||||
arcrun_get_component(component_id) → 取得特定零件 metadata
|
||||
```
|
||||
|
||||
---
|
||||
@@ -444,19 +451,19 @@ Tag 是用戶自訂的標籤,可附加至工作流或零件,用於分類與
|
||||
|
||||
```json
|
||||
// 建立 tag
|
||||
// u6u_create_tag
|
||||
// arcrun_create_tag
|
||||
{ "name": "finance", "description": "金融相關" }
|
||||
|
||||
// 列出所有 tag
|
||||
// u6u_list_tags(無需參數)
|
||||
// arcrun_list_tags(無需參數)
|
||||
{}
|
||||
|
||||
// 刪除 tag(不影響已打上此 tag 的資源關聯)
|
||||
// u6u_delete_tag
|
||||
// arcrun_delete_tag
|
||||
{ "tag_name": "deprecated-tag" }
|
||||
|
||||
// 為資源加上 tag
|
||||
// u6u_tag_resource
|
||||
// arcrun_tag_resource
|
||||
{
|
||||
"resource_type": "workflow", // 或 "component"
|
||||
"resource_id": "wf-abc123",
|
||||
@@ -464,7 +471,7 @@ Tag 是用戶自訂的標籤,可附加至工作流或零件,用於分類與
|
||||
}
|
||||
|
||||
// 移除資源的 tag
|
||||
// u6u_untag_resource
|
||||
// arcrun_untag_resource
|
||||
{
|
||||
"resource_type": "component",
|
||||
"resource_id": "system-fetches-exchange-rate",
|
||||
|
||||
+29
-25
@@ -53,40 +53,41 @@ Claude Code 進此資料夾就連對的 MCP。`acr init` 也會自動順帶跑
|
||||
|
||||
| Tool | 說明 |
|
||||
|------|------|
|
||||
| `u6u_get_component_guide` | **開發新零件前必須先呼叫。** 取得 TinyGo 開發指引,包含白名單 import、禁止行為、contract YAML 範例、本地測試指令。 |
|
||||
| `u6u_search_components` | 用自然語言語意搜尋零件庫。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」。回傳零件清單含 canonical_id、描述、評分。 |
|
||||
| `u6u_get_component` | 取得指定零件的完整合約(input_schema、output_schema、gherkin_tests、評分統計等)。 |
|
||||
| `u6u_publish_component` | 提交 TinyGo WASM 零件。需提供 `contract`(合約物件)與 `wasm_base64`(編譯後的 .wasm base64)。Registry 自動執行沙盒驗收。 |
|
||||
| `arcrun_get_component_guide` | **開發新零件前必須先呼叫。** 取得 TinyGo 開發指引,包含白名單 import、禁止行為、contract YAML 範例、本地測試指令。 |
|
||||
| `arcrun_search_components` | 用自然語言語意搜尋零件庫。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」。回傳零件清單含 canonical_id、描述、評分。 |
|
||||
| `arcrun_get_component` | 取得指定零件的完整合約(input_schema、output_schema、gherkin_tests、評分統計等)。 |
|
||||
| `arcrun_publish_component` | 提交 TinyGo WASM 零件。需提供 `contract`(合約物件)與 `wasm_base64`(編譯後的 .wasm base64)。Registry 自動執行沙盒驗收。 |
|
||||
|
||||
### 工作流執行
|
||||
|
||||
| Tool | 說明 |
|
||||
|------|------|
|
||||
| `u6u_execute_workflow` | 在沙盒中執行工作流。輸入 `triplets`(三元組陣列)與 `context`,用於部署前驗證。 |
|
||||
| `u6u_deploy_workflow` | 將工作流 YAML 部署至雲端引擎。輸入 `yaml_content`。 |
|
||||
| `arcrun_validate_yaml` | 部署前驗證工作流 YAML 的 schema。輸入 `yaml_content`。 |
|
||||
| `arcrun_push_workflow` | 將工作流 YAML 部署至雲端引擎。輸入 `api_key` 與 `yaml_content`。 |
|
||||
| `arcrun_run_workflow` | 觸發已部署的工作流執行。輸入 `api_key`、`name`,選填 `input`(帶進 trigger context)。 |
|
||||
|
||||
### 工作流管理
|
||||
|
||||
| Tool | 說明 |
|
||||
|------|------|
|
||||
| `u6u_list_workflows` | 列出已部署的工作流。可傳入選填的 `tag` 參數篩選。 |
|
||||
| `u6u_get_workflow` | 取得指定工作流的 metadata。輸入 `workflow_id`。 |
|
||||
| `arcrun_list_workflows` | 列出已部署的工作流。可傳入選填的 `tag` 參數篩選。 |
|
||||
| `arcrun_get_workflow` | 取得指定工作流的 metadata。輸入 `name`。 |
|
||||
|
||||
### 零件管理
|
||||
|
||||
| Tool | 說明 |
|
||||
|------|------|
|
||||
| `u6u_list_components` | 列出已發佈的零件。可傳入選填的 `tag` 參數篩選。 |
|
||||
| `arcrun_list_components` | 列出已發佈的零件。可傳入選填的 `tag` 參數篩選。 |
|
||||
|
||||
### Tag 管理
|
||||
|
||||
| Tool | 說明 |
|
||||
|------|------|
|
||||
| `u6u_create_tag` | 建立新 tag。輸入 `name`(必填)與 `description`(選填)。 |
|
||||
| `u6u_list_tags` | 列出當前命名空間下所有 tag。 |
|
||||
| `u6u_delete_tag` | 刪除指定 tag。輸入 `tag_name`。 |
|
||||
| `u6u_tag_resource` | 為工作流或零件加上 tag。輸入 `resource_type`、`resource_id`、`tag_name`。 |
|
||||
| `u6u_untag_resource` | 移除工作流或零件的 tag。 |
|
||||
| `arcrun_create_tag` | 建立新 tag。輸入 `name`(必填)與 `description`(選填)。 |
|
||||
| `arcrun_list_tags` | 列出當前命名空間下所有 tag。 |
|
||||
| `arcrun_delete_tag` | 刪除指定 tag。輸入 `tag_name`。 |
|
||||
| `arcrun_tag_resource` | 為工作流或零件加上 tag。輸入 `resource_type`、`resource_id`、`tag_name`。 |
|
||||
| `arcrun_untag_resource` | 移除工作流或零件的 tag。 |
|
||||
|
||||
---
|
||||
|
||||
@@ -97,7 +98,7 @@ Arcrun 的零件是 TinyGo 編譯的 `.wasm`,透過 stdin/stdout JSON 通訊
|
||||
### 步驟一:取得開發指引
|
||||
|
||||
```
|
||||
u6u_get_component_guide
|
||||
arcrun_get_component_guide
|
||||
```
|
||||
|
||||
指引包含:TinyGo 白名單 import、禁止行為、`component.contract.yaml` 完整範例、本地測試指令。
|
||||
@@ -105,7 +106,7 @@ u6u_get_component_guide
|
||||
### 步驟二:搜尋現有零件
|
||||
|
||||
```
|
||||
u6u_search_components("查詢 Google Sheets 資料")
|
||||
arcrun_search_components("查詢 Google Sheets 資料")
|
||||
```
|
||||
|
||||
若已有符合的零件,直接使用,不需要重新開發。
|
||||
@@ -137,7 +138,7 @@ echo '{"input_field":"value"}' | wasmtime my_component.wasm
|
||||
### 步驟四:提交零件
|
||||
|
||||
```
|
||||
u6u_publish_component(
|
||||
arcrun_publish_component(
|
||||
contract={...}, // component.contract.yaml 內容
|
||||
wasm_base64="..." // base64(my_component.wasm)
|
||||
)
|
||||
@@ -152,23 +153,26 @@ Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試)
|
||||
### 步驟一:搜尋零件
|
||||
|
||||
```
|
||||
u6u_search_components("查詢匯率")
|
||||
u6u_search_components("發送 Telegram 訊息")
|
||||
arcrun_search_components("查詢匯率")
|
||||
arcrun_search_components("發送 Telegram 訊息")
|
||||
```
|
||||
|
||||
### 步驟二:沙盒測試
|
||||
### 步驟二:部署前驗證
|
||||
|
||||
```
|
||||
u6u_execute_workflow(
|
||||
triplets=["system >> 查詢匯率 >> get-exchange-rate", ...],
|
||||
context={"currency_pair": "USD/TWD"}
|
||||
)
|
||||
arcrun_validate_yaml(yaml_content="...")
|
||||
```
|
||||
|
||||
### 步驟三:部署
|
||||
|
||||
```
|
||||
u6u_deploy_workflow(yaml_content="...")
|
||||
arcrun_push_workflow(api_key="ak_xxx", yaml_content="...")
|
||||
```
|
||||
|
||||
### 步驟四:觸發執行
|
||||
|
||||
```
|
||||
arcrun_run_workflow(api_key="ak_xxx", name="exchange-rate-notify", input={"currency_pair": "USD/TWD"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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"。內部另留一個 rebrand 過渡 / 單元測試用的覆蓋鉤子
|
||||
* (ARCRUN_TOOL_PREFIX,經 globalThis.process 安全取值)——但 Cloudflare
|
||||
* Workers runtime 沒有 process 全域,部署後此覆蓋「基本不生效」、一律 fallback 到
|
||||
* "arcrun"。**這不是對外 / 用戶可用特性,勿寫進對外文件**;正式 rebrand 請直接改本檔預設值。
|
||||
*/
|
||||
|
||||
const envPrefix = (globalThis as { process?: { env?: Record<string, string | undefined> } })
|
||||
.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}`;
|
||||
@@ -10,7 +10,7 @@ export async function handleMcpRequest(
|
||||
partnerToken: string,
|
||||
): Promise<Response> {
|
||||
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);
|
||||
|
||||
@@ -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 下唯一)"),
|
||||
@@ -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 }) => {
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
+4
-3
@@ -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 {
|
||||
@@ -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。",
|
||||
{
|
||||
@@ -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),
|
||||
|
||||
@@ -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 }) => {
|
||||
@@ -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 () => {
|
||||
@@ -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)"),
|
||||
@@ -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: <canonical_id>。",
|
||||
{
|
||||
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),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 提交新零件。`,
|
||||
}],
|
||||
};
|
||||
}
|
||||
@@ -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}`,
|
||||
}],
|
||||
};
|
||||
}
|
||||
@@ -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。",
|
||||
|
||||
@@ -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"),
|
||||
@@ -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"),
|
||||
@@ -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**(會打到錯帳號)。",
|
||||
{},
|
||||
|
||||
@@ -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),
|
||||
|
||||
+15
-22
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -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 };
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -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<string> | 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 };
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user