@actiondock/mcp 2.0.12 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { serveParentIpc } from "@actiondock/core";
3
+ import { resolveTarget } from "./adapter.js";
4
+ try {
5
+ const rawOptions = process.env.ACTIONDOCK_MCP_OPTIONS;
6
+ const options = rawOptions ? JSON.parse(rawOptions) : {};
7
+ const { target } = await resolveTarget(options);
8
+ await serveParentIpc(target);
9
+ }
10
+ catch (err) {
11
+ process.stderr.write(`[MCP Host Error] ${err?.stack || err?.message || String(err)}\n`);
12
+ process.exit(1);
13
+ }
package/dist/stdio.d.ts CHANGED
@@ -1,5 +1,10 @@
1
- import type { ActionDockMcpOptions } from "./types";
1
+ import type { ActionDockMcpOptions } from "./types.js";
2
2
  /**
3
- * Starts an ActionDock MCP server over STDIO transport.
3
+ * 启动 ActionDock MCP STDIO 协议服务。
4
+ * 建立监督进程物理边界:
5
+ * 1. 监督父进程独占标准输入/输出通道,专用于承载 JSON-RPC 协议;
6
+ * 2. 子进程承载 Action 运行时,通过 Node IPC 通信;
7
+ * 3. 子进程输出被重定向并进行限流排空(转入受控诊断流 stderr),彻底杜绝业务 console.log 破坏 MCP STDIO 流;
8
+ * 4. 子进程异常退出时,转换为结构化 JSON-RPC 错误,保障协议稳定性。
4
9
  */
5
10
  export declare function startMcpStdio(options?: ActionDockMcpOptions): Promise<void>;
package/dist/stdio.js ADDED
@@ -0,0 +1,114 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { IpcActionDockTarget } from "@actiondock/core";
6
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
7
+ import { createActionDockMcpServer, resolveTarget } from "./adapter.js";
8
+ /**
9
+ * 启动 ActionDock MCP STDIO 协议服务。
10
+ * 建立监督进程物理边界:
11
+ * 1. 监督父进程独占标准输入/输出通道,专用于承载 JSON-RPC 协议;
12
+ * 2. 子进程承载 Action 运行时,通过 Node IPC 通信;
13
+ * 3. 子进程输出被重定向并进行限流排空(转入受控诊断流 stderr),彻底杜绝业务 console.log 破坏 MCP STDIO 流;
14
+ * 4. 子进程异常退出时,转换为结构化 JSON-RPC 错误,保障协议稳定性。
15
+ */
16
+ export async function startMcpStdio(options = {}) {
17
+ let activeServer;
18
+ let targetToUse;
19
+ let childProcess;
20
+ // 若显式传入了已构造的 target 或不可序列化的内存对象,直接复用或解析目标实例
21
+ if (options.target || options.actions || options.storage || options.app || options.host) {
22
+ targetToUse = options.target ?? (await resolveTarget(options)).target;
23
+ }
24
+ else {
25
+ // 建立隔离的监督子进程
26
+ const currentDir = dirname(fileURLToPath(import.meta.url));
27
+ const hostScript = resolve(currentDir, existsSync(join(currentDir, "stdio-host.ts")) ? "stdio-host.ts" : "stdio-host.js");
28
+ childProcess = spawn(process.execPath, [hostScript], {
29
+ cwd: options.projectRoot || process.cwd(),
30
+ env: {
31
+ ...process.env,
32
+ ACTIONDOCK_MCP_OPTIONS: JSON.stringify({
33
+ projectRoot: options.projectRoot,
34
+ projectRoots: options.projectRoots,
35
+ packageId: options.packageId,
36
+ packageIds: options.packageIds,
37
+ all: options.all,
38
+ customHome: options.customHome,
39
+ configOverrides: options.configOverrides,
40
+ timeoutMs: options.timeoutMs,
41
+ }),
42
+ },
43
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
44
+ });
45
+ // 标准输出物理隔离与受控限流排空转入 stderr 诊断流
46
+ targetToUse = new IpcActionDockTarget({
47
+ childProcess,
48
+ maxDiagnosticBytes: 512 * 1024,
49
+ maxDiagnosticRate: 64 * 1024,
50
+ diagnosticTarget: process.stderr,
51
+ });
52
+ }
53
+ const stdioHandler = serveStdio(async () => {
54
+ const server = await createActionDockMcpServer({
55
+ ...options,
56
+ target: targetToUse,
57
+ });
58
+ activeServer = server;
59
+ targetToUse = targetToUse || server.target;
60
+ return server;
61
+ }, {
62
+ onerror: (err) => {
63
+ process.stderr.write(`[MCP Error] ${err?.message || String(err)}\n`);
64
+ },
65
+ });
66
+ const cleanup = async () => {
67
+ // 清理链路逐层释放,错误不吞没:收集首个异常向上透传,后续层继续尽力释放
68
+ let firstError;
69
+ const swallow = (err) => {
70
+ if (firstError === undefined)
71
+ firstError = err;
72
+ process.stderr.write(`[MCP Cleanup Error] ${err instanceof Error ? err.message : String(err)}\n`);
73
+ };
74
+ if (activeServer) {
75
+ try {
76
+ await activeServer.close();
77
+ }
78
+ catch (err) {
79
+ swallow(err);
80
+ }
81
+ }
82
+ if (targetToUse) {
83
+ try {
84
+ await targetToUse.close();
85
+ }
86
+ catch (err) {
87
+ swallow(err);
88
+ }
89
+ }
90
+ try {
91
+ await stdioHandler.close();
92
+ }
93
+ catch (err) {
94
+ swallow(err);
95
+ }
96
+ if (firstError !== undefined) {
97
+ throw firstError;
98
+ }
99
+ };
100
+ const handleSignal = (signalName) => {
101
+ cleanup()
102
+ .then(() => {
103
+ // 正常关闭退出码为 0
104
+ process.exit(0);
105
+ })
106
+ .catch((err) => {
107
+ // 清理失败退出非零退出码,异常详情已写入 stderr 诊断流
108
+ process.stderr.write(`[MCP ${signalName} Cleanup Failed] ${err instanceof Error ? err.message : String(err)}\n`);
109
+ process.exit(1);
110
+ });
111
+ };
112
+ process.once("SIGINT", () => handleSignal("SIGINT"));
113
+ process.once("SIGTERM", () => handleSignal("SIGTERM"));
114
+ }
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ExecutionManager, RuntimeStorage, ServerRuntimeRegistry } from "@actiondock/core";
1
+ import type { ActionDockApp, ActionDockHost, ActionDockTarget, RuntimeStorage } from "@actiondock/core";
2
2
  import type { ActionDefinition, RunRecord, RunStatus } from "@actiondock/sdk";
3
3
  /**
4
4
  * MCP 任务状态枚举(兼容 Model Context Protocol Task 规范)。
@@ -26,8 +26,15 @@ export declare function toMcpTaskStatus(status: RunStatus): McpTaskStatus;
26
26
  export declare function toMcpTaskPayload(run: RunRecord): McpTaskPayload;
27
27
  /**
28
28
  * ActionDock MCP 适配层初始化选项。
29
+ * 统一以 target(及可选 host, app)为核心。
29
30
  */
30
31
  export interface ActionDockMcpOptions {
32
+ /** 目标 ActionDockTarget 门面实例(最高优先级) */
33
+ target?: ActionDockTarget;
34
+ /** 目标 ActionDockHost 宿主实例 */
35
+ host?: ActionDockHost;
36
+ /** 目标 ActionDockApp 应用实例 */
37
+ app?: ActionDockApp;
31
38
  /** 单个目标项目根目录 */
32
39
  projectRoot?: string;
33
40
  /** 多个项目根目录(用于多包聚合提供) */
@@ -44,14 +51,28 @@ export interface ActionDockMcpOptions {
44
51
  configOverrides?: Record<string, unknown>;
45
52
  /** 单个 Tool 执行超时时间(毫秒) */
46
53
  timeoutMs?: number;
47
- /** 预加载的 Action 映射表 */
48
- actions?: Map<string, ActionDefinition>;
49
- /** 底层存储实例 */
54
+ /** 预加载的 Action 集合(单元测试或内存模式使用) */
55
+ actions?: Map<string, ActionDefinition> | Array<{
56
+ id: string;
57
+ action: ActionDefinition;
58
+ } | (ActionDefinition & {
59
+ id: string;
60
+ })> | Record<string, ActionDefinition>;
61
+ /** 底层存储实例(单元测试或特定场景注入) */
50
62
  storage?: RuntimeStorage;
51
- /** 服务端运行时注册表 */
52
- runtimeRegistry?: ServerRuntimeRegistry;
53
- /** 活跃执行任务管理器 */
54
- executionManager?: ExecutionManager;
63
+ /**
64
+ * 是否由适配层接管外部注入 storage 的生命周期。
65
+ * 默认 false:外部注入的 storage 由注入方自行管理,适配层不具各 close 语义;
66
+ * 置为 true 时透传原始实例,随 target.close() 级联关闭。
67
+ */
68
+ ownStorageLifecycle?: boolean;
69
+ /**
70
+ * 实例 close 是否级联关闭 target 门面。
71
+ * 默认 false:适配层产物可能被 SDK 传输层按请求(或按连接)创建与销毁,
72
+ * 级联语义会误杀共享 target,生命周期统一由外层入口的 stop/cleanup 收敛;
73
+ * 仅在调用方自行持有实例并需要一次 close 同时释放 target 时置 true。
74
+ */
75
+ cascadeTargetClose?: boolean;
55
76
  }
56
77
  /**
57
78
  * HTTP 传输协议安全配置项。
@@ -61,14 +82,18 @@ export interface HttpSecurityOptions {
61
82
  port?: number;
62
83
  token?: string;
63
84
  allowInsecureNoAuth?: boolean;
85
+ allowQueryToken?: boolean;
86
+ allowInsecureHttp?: boolean;
64
87
  corsOrigins?: string[];
65
88
  maxBodyBytes?: number;
66
89
  }
67
- export interface ActionDockMcpHttpOptions extends ActionDockMcpOptions, HttpSecurityOptions {
90
+ export interface ActionDockMcpHttpOptions extends Omit<ActionDockMcpOptions, "host">, Omit<HttpSecurityOptions, "host"> {
91
+ host?: string | ActionDockHost;
68
92
  }
69
93
  export interface ActionDockMcpHttpServerInstance {
70
94
  port: number;
71
95
  host: string;
72
96
  url: string;
97
+ target?: ActionDockTarget;
73
98
  stop: () => Promise<void>;
74
99
  }
package/dist/types.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 将 ActionDock 内部的 RunStatus 转换为 MCP 标准的 TaskStatus。
3
+ */
4
+ export function toMcpTaskStatus(status) {
5
+ switch (status) {
6
+ case "running":
7
+ return "working";
8
+ case "success":
9
+ return "completed";
10
+ case "failed":
11
+ case "timed_out":
12
+ case "interrupted":
13
+ return "failed";
14
+ case "cancelled":
15
+ return "cancelled";
16
+ default:
17
+ return "failed";
18
+ }
19
+ }
20
+ /**
21
+ * 将内部 RunRecord 实体转换为向 MCP 客户端暴露的 McpTaskPayload。
22
+ */
23
+ export function toMcpTaskPayload(run) {
24
+ return {
25
+ taskId: run.id,
26
+ status: toMcpTaskStatus(run.status),
27
+ createdAt: run.startedAt,
28
+ finishedAt: run.finishedAt,
29
+ input: run.input,
30
+ output: run.output,
31
+ error: run.error,
32
+ };
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actiondock/mcp",
3
- "version": "2.0.12",
3
+ "version": "2.2.0",
4
4
  "description": "ActionDock MCP Adapter for exposing Actions as Model Context Protocol (MCP) Tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,19 +18,19 @@
18
18
  "README.md"
19
19
  ],
20
20
  "engines": {
21
- "node": ">=22.13.0"
21
+ "node": ">=24.12.0"
22
22
  },
23
23
  "publishConfig": {
24
24
  "access": "public",
25
25
  "registry": "https://registry.npmjs.org/"
26
26
  },
27
27
  "scripts": {
28
- "build": "bun run ../../scripts/build.ts",
29
- "test": "bun test"
28
+ "build": "node ../../scripts/build.ts",
29
+ "test": "node ../../scripts/run-tests.ts"
30
30
  },
31
31
  "dependencies": {
32
- "@actiondock/core": "^2.0.12",
33
- "@actiondock/sdk": "^2.0.12",
32
+ "@actiondock/core": "^2.2.0",
33
+ "@actiondock/sdk": "^2.2.0",
34
34
  "@modelcontextprotocol/server": "^2.0.0"
35
35
  },
36
36
  "devDependencies": {