diff --git a/cli/src/commands/init.ts b/cli/src/commands/init.ts index 1d4a382..63395de 100644 --- a/cli/src/commands/init.ts +++ b/cli/src/commands/init.ts @@ -227,6 +227,9 @@ async function initSelfHosted( const deploy = await downloadAndDeploy(deployCtx); const cypherUrl = deploy.cypherExecutorUrl ?? (workerSubdomain ? `https://arcrun-cypher-executor.${workerSubdomain}.workers.dev` : ''); + // self-hosted 自己的 MCP worker URL(mcp-account-source §3:.mcp.json 指自己,不 fallback 官方)。 + const mcpUrl = deploy.mcpUrl + ?? (workerSubdomain ? `https://arcrun-mcp.${workerSubdomain}.workers.dev/mcp` : ''); // 誠實回報部署結果;但**不**用「全部成功」字串 gate 後續 seed(壓測 §4.1: // registry 一個無關 worker 失敗就連坐讓 seed 永遠被跳過)。seed 只看 cypher-executor 是否可達。 const deployFullyOk = /全部成功/.test(deploy.message); @@ -238,6 +241,7 @@ async function initSelfHosted( cloudflare_account_id: accountId, cf_api_token: cfApiToken, cypher_executor_url: cypherUrl, + mcp_url: mcpUrl || undefined, // 指自己的 MCP(mcp-account-source §3),無 subdomain 才留空 fallback 官方 webhooks_kv_namespace_id: kvNamespaceIds['WEBHOOKS'], credentials_kv_namespace_id: kvNamespaceIds['CREDENTIALS_KV'], multi_tenant: false, @@ -245,6 +249,14 @@ async function initSelfHosted( saveConfig(config); createCredentialsYamlIfMissing(); + // 6.5 config 寫好後重寫 .mcp.json,讓它指向「自己的」MCP(init 開頭的 cmdMcpSetup 在 config 前跑, + // 那時 mcp_url 還沒設 → 會 fallback 官方;這裡 config 已含自己的 mcp_url,重跑一次蓋成自己的)。 + try { + cmdMcpSetup(); + } catch (e) { + console.log(chalk.gray(` (.mcp.json 重寫略過:${e instanceof Error ? e.message : e})`)); + } + // 6. seed recipe(薄殼:呼叫 API 的 /init/seed 一次,由 API 灌 API recipe + auth recipe)。 // 只要 cypher-executor 可達就 seed——不被無關 worker(registry)的失敗連坐(壓測 §4.1)。 if (cypherUrl) { diff --git a/cli/src/lib/config.ts b/cli/src/lib/config.ts index 211daa5..a5d2d8a 100644 --- a/cli/src/lib/config.ts +++ b/cli/src/lib/config.ts @@ -65,7 +65,8 @@ const ENV_MAP: Record = { * 平台預設 MCP URL(mcp_url 未設時的 fallback,SaaS 用戶用)。 * MCP 搬進 arcrun 主庫後改用 arcrun.dev zone(mcp/wrangler.toml route = mcp.arcrun.dev)。 */ -export const DEFAULT_MCP_URL = 'https://mcp.arcrun.dev'; +// MCP streamable-http 端點是 /mcp(根路徑 404)。少了 /mcp → client 連線 Failed。 +export const DEFAULT_MCP_URL = 'https://mcp.arcrun.dev/mcp'; /** * 公庫 URL(recipe pull/search/submit-p 的對象,kbdb-base §7.5)。 diff --git a/cli/src/lib/deploy.ts b/cli/src/lib/deploy.ts index 93d0004..4037e01 100644 --- a/cli/src/lib/deploy.ts +++ b/cli/src/lib/deploy.ts @@ -53,6 +53,7 @@ export interface DeployContext { export interface DeployResult { implemented: boolean; cypherExecutorUrl?: string; + mcpUrl?: string; // self-hosted 自己的 MCP worker URL(mcp-account-source §3) message: string; } @@ -132,11 +133,17 @@ export async function downloadAndDeploy(ctx: DeployContext, ref = 'main'): Promi const cypherExecutorUrl = ctx.workerSubdomain ? `https://arcrun-cypher-executor.${ctx.workerSubdomain}.workers.dev` : undefined; + // self-hosted 自己的 MCP worker URL(mcp-account-source §3:.mcp.json 指自己)。 + // 端點是 /mcp(streamable http;根路徑 404)。仿 cypher 用 WORKER_SUBDOMAIN 組。 + const mcpUrl = ctx.workerSubdomain + ? `https://arcrun-mcp.${ctx.workerSubdomain}.workers.dev/mcp` + : undefined; if (failures.length > 0) { return { implemented: true, cypherExecutorUrl, + mcpUrl, message: `部署 ${deployed}/${tier1.length + tier2.length} 成功,${failures.length} 失敗(誠實回報,未假綠):\n` + failures.map(f => ` ✗ ${f}`).join('\n'), @@ -146,6 +153,7 @@ export async function downloadAndDeploy(ctx: DeployContext, ref = 'main'): Promi return { implemented: true, cypherExecutorUrl, + mcpUrl, message: `部署完成:${deployed} 個 Worker 全部成功。`, }; } @@ -211,7 +219,9 @@ function discoverWorkerDirs(root: string): { tier1: string[]; tier2: string[] } } } } - for (const name of ['cypher-executor', 'registry']) { + // self-hosted 也部署自己的 MCP worker(mcp-account-source §5c:codeload 主庫即得 MCP, + // .mcp.json 指自己的 mcp 而非官方 mcp.arcrun.dev)。 + for (const name of ['cypher-executor', 'registry', 'mcp']) { const dir = join(root, name); if (existsSync(join(dir, 'wrangler.toml'))) tier2.push(dir); }