fix(cli): MCP self-hosted discovery + config setup

- deploy.ts: discoverWorkerDirs 掃 mcp worker + 回傳 mcpUrl(對內 /mcp 端點)
- init.ts: initSelfHosted 寫入 config.mcp_url + 重跑 cmdMcpSetup
- config.ts: DEFAULT_MCP_URL 補 /mcp 後綴

Fixes mcp-account-source §3:self-hosted .mcp.json 必須指自己的 mcp worker,避免連官方失敗。

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-06-08 13:23:02 +08:00
parent 5daeede45f
commit 2b46bea764
3 changed files with 25 additions and 2 deletions
+12
View File
@@ -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 URLmcp-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, // 指自己的 MCPmcp-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,讓它指向「自己的」MCPinit 開頭的 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) {
+2 -1
View File
@@ -65,7 +65,8 @@ const ENV_MAP: Record<string, keyof ArcrunConfig> = {
* 平台預設 MCP URLmcp_url 未設時的 fallbackSaaS 用戶用)。
* MCP 搬進 arcrun 主庫後改用 arcrun.dev zonemcp/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';
/**
* 公庫 URLrecipe pull/search/submit-p 的對象,kbdb-base §7.5)。
+11 -1
View File
@@ -53,6 +53,7 @@ export interface DeployContext {
export interface DeployResult {
implemented: boolean;
cypherExecutorUrl?: string;
mcpUrl?: string; // self-hosted 自己的 MCP worker URLmcp-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 URLmcp-account-source §3.mcp.json 指自己)。
// 端點是 /mcpstreamable 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 workermcp-account-source §5ccodeload 主庫即得 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);
}