unity-mcp-cli 0.71.0 → 0.72.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to `unity-mcp-cli` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - **`runTool` / `runSystemTool` library functions.** The HTTP-tool
13
+ invocation paths previously available only as the `run-tool` /
14
+ `run-system-tool` CLI commands are now first-class library exports:
15
+
16
+ ```ts
17
+ import { runTool, runSystemTool } from 'unity-mcp-cli';
18
+
19
+ const result = await runTool({
20
+ toolName: 'tool-list',
21
+ unityProjectPath: '/path/to/Unity/project',
22
+ input: { regexSearch: 'gameobject', includeDescription: true },
23
+ });
24
+ if (result.kind === 'success') {
25
+ // result.data === parsed JSON body from the Unity plugin
26
+ }
27
+ ```
28
+
29
+ Same URL/token resolution priority as the CLI commands (explicit
30
+ override → project config → deterministic localhost port). Returns
31
+ a discriminated `{ kind: 'success' | 'failure', ... }` union; never
32
+ throws past the public boundary; emits no console output.
33
+
34
+ ### Changed
35
+
36
+ - **`run-tool` / `run-system-tool` commands** now delegate to the new
37
+ library functions internally. CLI behaviour is unchanged.
38
+
8
39
  ## [0.67.0] - 2026-04-21
9
40
 
10
41
  ### Added
@@ -1,2 +1 @@
1
- import { Command } from 'commander';
2
- export declare const runSystemToolCommand: Command;
1
+ export declare const runSystemToolCommand: import("commander").Command;
@@ -1,132 +1,13 @@
1
- import { Command } from 'commander';
2
- import * as ui from '../utils/ui.js';
3
- import { verbose } from '../utils/ui.js';
4
- import { resolveAndValidateProjectPath, resolveConnection } from '../utils/connection.js';
5
- import { parseInput } from '../utils/input.js';
6
- export const runSystemToolCommand = new Command('run-system-tool')
7
- .description('Execute a system tool via the HTTP API (not exposed to MCP clients)')
8
- .argument('<tool-name>', 'Name of the system tool to execute')
9
- .argument('[path]', 'Unity project path (used for config and auto port detection)')
10
- .option('--path <path>', 'Unity project path (config and auto port detection)')
11
- .option('--url <url>', 'Direct server URL override (bypasses config)')
12
- .option('--token <token>', 'Bearer token override (bypasses config)')
13
- .option('--input <json>', 'JSON string of tool arguments')
14
- .option('--input-file <file>', 'Read JSON arguments from file')
15
- .option('--raw', 'Output raw JSON (no formatting)')
16
- .option('--timeout <ms>', 'Request timeout in milliseconds (default: 60000)', '60000')
17
- .action(async (toolName, positionalPath, options) => {
18
- const projectPath = resolveAndValidateProjectPath(positionalPath, options);
19
- const { url: baseUrl, token } = resolveConnection(projectPath, options);
20
- const body = parseInput(options);
21
- const endpoint = `${baseUrl}/api/system-tools/${encodeURIComponent(toolName)}`;
22
- verbose(`System tool: ${toolName}`);
23
- verbose(`Endpoint: ${endpoint}`);
24
- verbose(`Body: ${body}`);
25
- const headers = {
26
- 'Content-Type': 'application/json',
27
- };
28
- if (token) {
29
- headers['Authorization'] = `Bearer ${token}`;
30
- verbose(`Authorization header set (source: ${options.token ? '--token flag' : 'config'})`);
31
- }
32
- const authSource = options.token ? '--token flag' : 'config';
33
- if (!options.raw) {
34
- ui.heading('Run System Tool');
35
- ui.label('Tool', toolName);
36
- ui.label('URL', endpoint);
37
- if (token) {
38
- ui.label('Auth', `from ${authSource}`);
39
- }
40
- ui.divider();
41
- }
42
- const spinner = options.raw ? null : ui.startSpinner(`Calling ${toolName}...`);
43
- const timeoutMs = parseInt(options.timeout ?? '60000', 10);
44
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
45
- ui.error(`Invalid --timeout value: "${options.timeout}". Must be a positive integer (milliseconds).`);
46
- process.exit(1);
47
- }
48
- const controller = new AbortController();
49
- const fetchTimeout = setTimeout(() => controller.abort(), timeoutMs);
50
- try {
51
- const response = await fetch(endpoint, {
52
- method: 'POST',
53
- headers,
54
- body,
55
- signal: controller.signal,
56
- });
57
- const responseText = await response.text();
58
- let responseData;
59
- try {
60
- responseData = JSON.parse(responseText);
61
- }
62
- catch {
63
- responseData = responseText;
64
- }
65
- if (!response.ok) {
66
- spinner?.stop();
67
- if (options.raw) {
68
- process.stdout.write(responseText);
69
- }
70
- else {
71
- ui.error(`HTTP ${response.status}: ${response.statusText}`);
72
- if (responseData) {
73
- ui.info(typeof responseData === 'string'
74
- ? responseData
75
- : JSON.stringify(responseData, null, 2));
76
- }
77
- }
78
- process.exit(1);
79
- }
80
- spinner?.success(`${toolName} completed`);
81
- if (options.raw) {
82
- process.stdout.write(responseText);
83
- }
84
- else {
85
- ui.success('Response:');
86
- console.log(typeof responseData === 'string'
87
- ? responseData
88
- : JSON.stringify(responseData, null, 2));
89
- }
90
- }
91
- catch (err) {
92
- spinner?.stop();
93
- const isTimeout = err instanceof Error && err.name === 'AbortError';
94
- const cause = err instanceof Error && 'cause' in err ? err.cause : null;
95
- const causeCode = cause?.code ?? '';
96
- const rootMessage = cause?.message || causeCode || (err instanceof Error ? err.message : String(err));
97
- const errorSignature = `${rootMessage} ${causeCode}`;
98
- const isConnectionRefused = errorSignature.includes('ECONNREFUSED');
99
- const isConnectionReset = errorSignature.includes('ECONNRESET');
100
- const isNetworkError = errorSignature.includes('EAI_AGAIN') || errorSignature.includes('ENOTFOUND');
101
- let displayMessage;
102
- if (isTimeout) {
103
- displayMessage = `System tool call timed out after ${timeoutMs / 1000} seconds: ${toolName}`;
104
- }
105
- else if (isConnectionRefused) {
106
- displayMessage = `Connection refused at ${endpoint}. Is the MCP server running? Start Unity Editor with the MCP plugin first.`;
107
- }
108
- else if (isConnectionReset) {
109
- displayMessage = `Connection was reset by the server at ${endpoint}. The server may have crashed or restarted.`;
110
- }
111
- else if (isNetworkError) {
112
- displayMessage = `Cannot reach ${endpoint}. Check your network connection and server URL.`;
113
- }
114
- else {
115
- displayMessage = `${rootMessage}`;
116
- if (cause && cause.message !== rootMessage) {
117
- displayMessage += ` (${cause.message})`;
118
- }
119
- }
120
- if (options.raw) {
121
- process.stderr.write(displayMessage + '\n');
122
- }
123
- else {
124
- ui.error(`Failed to call system tool: ${displayMessage}`);
125
- }
126
- process.exit(1);
127
- }
128
- finally {
129
- clearTimeout(fetchTimeout);
130
- }
1
+ import { runSystemTool } from '../lib/run-tool.js';
2
+ import { buildRunToolCommand } from './run-tool-builder.js';
3
+ export const runSystemToolCommand = buildRunToolCommand({
4
+ name: 'run-system-tool',
5
+ description: 'Execute a system tool via the HTTP API (not exposed to MCP clients)',
6
+ argDescription: 'Name of the system tool to execute',
7
+ routePrefix: '/api/system-tools',
8
+ verboseLabel: 'System tool',
9
+ headingLabel: 'Run System Tool',
10
+ errorNoun: 'system tool',
11
+ invoke: runSystemTool,
131
12
  });
132
13
  //# sourceMappingURL=run-system-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-system-tool.js","sourceRoot":"","sources":["../../src/commands/run-system-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-system-tool.js","sourceRoot":"","sources":["../../src/commands/run-system-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;IACtD,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,qEAAqE;IAClF,cAAc,EAAE,oCAAoC;IACpD,WAAW,EAAE,mBAAmB;IAChC,YAAY,EAAE,aAAa;IAC3B,YAAY,EAAE,iBAAiB;IAC/B,SAAS,EAAE,aAAa;IACxB,MAAM,EAAE,aAAa;CACtB,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { Command } from 'commander';
2
+ import type { RunToolOptions, RunToolResult } from '../lib/types.js';
3
+ interface BuilderOptions {
4
+ /** CLI subcommand name, e.g. `'run-tool'`. */
5
+ name: string;
6
+ /** `description()` text for the commander command. */
7
+ description: string;
8
+ /** Description shown next to the `<tool-name>` argument. */
9
+ argDescription: string;
10
+ /** URL path prefix the lib function targets, e.g. `'/api/tools'`. */
11
+ routePrefix: string;
12
+ /** Verbose-log label, e.g. `'Tool'` or `'System tool'`. */
13
+ verboseLabel: string;
14
+ /** Heading printed by `ui.heading`, e.g. `'Run Tool'`. */
15
+ headingLabel: string;
16
+ /**
17
+ * Lower-case noun used in user-facing failure copy:
18
+ * `Failed to call <noun>:` and `<Capitalized> call timed out…`.
19
+ */
20
+ errorNoun: string;
21
+ /** Library function — `runTool` or `runSystemTool`. */
22
+ invoke: (opts: RunToolOptions) => Promise<RunToolResult>;
23
+ }
24
+ export declare function buildRunToolCommand(cfg: BuilderOptions): Command;
25
+ export {};
@@ -0,0 +1,125 @@
1
+ import { Command } from 'commander';
2
+ import * as ui from '../utils/ui.js';
3
+ import { verbose } from '../utils/ui.js';
4
+ import { resolveAndValidateProjectPath, resolveConnection } from '../utils/connection.js';
5
+ import { parseInput } from '../utils/input.js';
6
+ export function buildRunToolCommand(cfg) {
7
+ return new Command(cfg.name)
8
+ .description(cfg.description)
9
+ .argument('<tool-name>', cfg.argDescription)
10
+ .argument('[path]', 'Unity project path (used for config and auto port detection)')
11
+ .option('--path <path>', 'Unity project path (config and auto port detection)')
12
+ .option('--url <url>', 'Direct server URL override (bypasses config)')
13
+ .option('--token <token>', 'Bearer token override (bypasses config)')
14
+ .option('--input <json>', 'JSON string of tool arguments')
15
+ .option('--input-file <file>', 'Read JSON arguments from file')
16
+ .option('--raw', 'Output raw JSON (no formatting)')
17
+ .option('--timeout <ms>', 'Request timeout in milliseconds (default: 60000)', '60000')
18
+ .action(async (toolName, positionalPath, options) => {
19
+ // Validate --timeout first so a bad value short-circuits before
20
+ // we read --input-file or hit the network.
21
+ const timeoutMs = parseInt(options.timeout, 10);
22
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
23
+ ui.error(`Invalid --timeout value: "${options.timeout}". Must be a positive integer (milliseconds).`);
24
+ process.exit(1);
25
+ }
26
+ // Resolve path + connection up front so the heading and verbose
27
+ // output reflect the final endpoint before the HTTP call fires.
28
+ const projectPath = resolveAndValidateProjectPath(positionalPath, options);
29
+ const { url: baseUrl, token } = resolveConnection(projectPath, options);
30
+ const body = parseInput(options);
31
+ const endpoint = `${baseUrl}${cfg.routePrefix}/${encodeURIComponent(toolName)}`;
32
+ const authSource = options.token ? '--token flag' : 'config';
33
+ verbose(`${cfg.verboseLabel}: ${toolName}`);
34
+ verbose(`Endpoint: ${endpoint}`);
35
+ verbose(`Body: ${body}`);
36
+ if (token)
37
+ verbose(`Authorization header set (source: ${authSource})`);
38
+ if (!options.raw) {
39
+ ui.heading(cfg.headingLabel);
40
+ ui.label('Tool', toolName);
41
+ ui.label('URL', endpoint);
42
+ if (token)
43
+ ui.label('Auth', `from ${authSource}`);
44
+ ui.divider();
45
+ }
46
+ const spinner = options.raw ? null : ui.startSpinner(`Calling ${toolName}...`);
47
+ // The CLI already resolved url/token, so passing them explicitly
48
+ // makes the lib's resolver a no-op rather than re-reading config.
49
+ const result = await cfg.invoke({
50
+ toolName,
51
+ url: baseUrl,
52
+ ...(token ? { token } : {}),
53
+ input: body,
54
+ timeoutMs,
55
+ });
56
+ if (result.kind === 'success') {
57
+ spinner?.success(`${toolName} completed`);
58
+ if (options.raw) {
59
+ process.stdout.write(stringifyForRaw(result.data));
60
+ }
61
+ else {
62
+ ui.success('Response:');
63
+ console.log(typeof result.data === 'string'
64
+ ? result.data
65
+ : JSON.stringify(result.data, null, 2));
66
+ }
67
+ return;
68
+ }
69
+ spinner?.stop();
70
+ handleFailure(result, {
71
+ toolName,
72
+ endpoint,
73
+ raw: options.raw,
74
+ timeoutMs,
75
+ errorNoun: cfg.errorNoun,
76
+ });
77
+ });
78
+ }
79
+ function stringifyForRaw(data) {
80
+ if (typeof data === 'string')
81
+ return data;
82
+ if (data === undefined)
83
+ return '';
84
+ return JSON.stringify(data);
85
+ }
86
+ function handleFailure(failure, ctx) {
87
+ if (failure.reason === 'http-error') {
88
+ if (ctx.raw) {
89
+ process.stdout.write(stringifyForRaw(failure.data));
90
+ }
91
+ else {
92
+ ui.error(`HTTP ${failure.httpStatus}: ${failure.message}`);
93
+ if (failure.data !== undefined) {
94
+ ui.info(typeof failure.data === 'string'
95
+ ? failure.data
96
+ : JSON.stringify(failure.data, null, 2));
97
+ }
98
+ }
99
+ process.exit(1);
100
+ }
101
+ const message = buildFailureMessage(failure, ctx);
102
+ if (ctx.raw)
103
+ process.stderr.write(message + '\n');
104
+ else
105
+ ui.error(`Failed to call ${ctx.errorNoun}: ${message}`);
106
+ process.exit(1);
107
+ }
108
+ function buildFailureMessage(failure, ctx) {
109
+ switch (failure.reason) {
110
+ case 'timeout':
111
+ return `${capitalize(ctx.errorNoun)} call timed out after ${ctx.timeoutMs / 1000} seconds: ${ctx.toolName}`;
112
+ case 'connection-refused':
113
+ return `Connection refused at ${ctx.endpoint}. Is the MCP server running? Start Unity Editor with the MCP plugin first.`;
114
+ case 'connection-reset':
115
+ return `Connection was reset by the server at ${ctx.endpoint}. The server may have crashed or restarted.`;
116
+ case 'network-error':
117
+ return `Cannot reach ${ctx.endpoint}. Check your network connection and server URL.`;
118
+ default:
119
+ return failure.message;
120
+ }
121
+ }
122
+ function capitalize(s) {
123
+ return s.length === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1);
124
+ }
125
+ //# sourceMappingURL=run-tool-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tool-builder.js","sourceRoot":"","sources":["../../src/commands/run-tool-builder.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1 @@
1
- import { Command } from 'commander';
2
- export declare const runToolCommand: Command;
1
+ export declare const runToolCommand: import("commander").Command;
@@ -1,132 +1,13 @@
1
- import { Command } from 'commander';
2
- import * as ui from '../utils/ui.js';
3
- import { verbose } from '../utils/ui.js';
4
- import { resolveAndValidateProjectPath, resolveConnection } from '../utils/connection.js';
5
- import { parseInput } from '../utils/input.js';
6
- export const runToolCommand = new Command('run-tool')
7
- .description('Execute an MCP tool via the HTTP API')
8
- .argument('<tool-name>', 'Name of the MCP tool to execute')
9
- .argument('[path]', 'Unity project path (used for config and auto port detection)')
10
- .option('--path <path>', 'Unity project path (config and auto port detection)')
11
- .option('--url <url>', 'Direct server URL override (bypasses config)')
12
- .option('--token <token>', 'Bearer token override (bypasses config)')
13
- .option('--input <json>', 'JSON string of tool arguments')
14
- .option('--input-file <file>', 'Read JSON arguments from file')
15
- .option('--raw', 'Output raw JSON (no formatting)')
16
- .option('--timeout <ms>', 'Request timeout in milliseconds (default: 60000)', '60000')
17
- .action(async (toolName, positionalPath, options) => {
18
- const projectPath = resolveAndValidateProjectPath(positionalPath, options);
19
- const { url: baseUrl, token } = resolveConnection(projectPath, options);
20
- const body = parseInput(options);
21
- const endpoint = `${baseUrl}/api/tools/${encodeURIComponent(toolName)}`;
22
- verbose(`Tool: ${toolName}`);
23
- verbose(`Endpoint: ${endpoint}`);
24
- verbose(`Body: ${body}`);
25
- const headers = {
26
- 'Content-Type': 'application/json',
27
- };
28
- if (token) {
29
- headers['Authorization'] = `Bearer ${token}`;
30
- verbose(`Authorization header set (source: ${options.token ? '--token flag' : 'config'})`);
31
- }
32
- const authSource = options.token ? '--token flag' : 'config';
33
- if (!options.raw) {
34
- ui.heading('Run Tool');
35
- ui.label('Tool', toolName);
36
- ui.label('URL', endpoint);
37
- if (token) {
38
- ui.label('Auth', `from ${authSource}`);
39
- }
40
- ui.divider();
41
- }
42
- const spinner = options.raw ? null : ui.startSpinner(`Calling ${toolName}...`);
43
- const timeoutMs = parseInt(options.timeout ?? '60000', 10);
44
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
45
- ui.error(`Invalid --timeout value: "${options.timeout}". Must be a positive integer (milliseconds).`);
46
- process.exit(1);
47
- }
48
- const controller = new AbortController();
49
- const fetchTimeout = setTimeout(() => controller.abort(), timeoutMs);
50
- try {
51
- const response = await fetch(endpoint, {
52
- method: 'POST',
53
- headers,
54
- body,
55
- signal: controller.signal,
56
- });
57
- const responseText = await response.text();
58
- let responseData;
59
- try {
60
- responseData = JSON.parse(responseText);
61
- }
62
- catch {
63
- responseData = responseText;
64
- }
65
- if (!response.ok) {
66
- spinner?.stop();
67
- if (options.raw) {
68
- process.stdout.write(responseText);
69
- }
70
- else {
71
- ui.error(`HTTP ${response.status}: ${response.statusText}`);
72
- if (responseData) {
73
- ui.info(typeof responseData === 'string'
74
- ? responseData
75
- : JSON.stringify(responseData, null, 2));
76
- }
77
- }
78
- process.exit(1);
79
- }
80
- spinner?.success(`${toolName} completed`);
81
- if (options.raw) {
82
- process.stdout.write(responseText);
83
- }
84
- else {
85
- ui.success('Response:');
86
- console.log(typeof responseData === 'string'
87
- ? responseData
88
- : JSON.stringify(responseData, null, 2));
89
- }
90
- }
91
- catch (err) {
92
- spinner?.stop();
93
- const isTimeout = err instanceof Error && err.name === 'AbortError';
94
- const cause = err instanceof Error && 'cause' in err ? err.cause : null;
95
- const causeCode = cause?.code ?? '';
96
- const rootMessage = cause?.message || causeCode || (err instanceof Error ? err.message : String(err));
97
- const errorSignature = `${rootMessage} ${causeCode}`;
98
- const isConnectionRefused = errorSignature.includes('ECONNREFUSED');
99
- const isConnectionReset = errorSignature.includes('ECONNRESET');
100
- const isNetworkError = errorSignature.includes('EAI_AGAIN') || errorSignature.includes('ENOTFOUND');
101
- let displayMessage;
102
- if (isTimeout) {
103
- displayMessage = `Tool call timed out after ${timeoutMs / 1000} seconds: ${toolName}`;
104
- }
105
- else if (isConnectionRefused) {
106
- displayMessage = `Connection refused at ${endpoint}. Is the MCP server running? Start Unity Editor with the MCP plugin first.`;
107
- }
108
- else if (isConnectionReset) {
109
- displayMessage = `Connection was reset by the server at ${endpoint}. The server may have crashed or restarted.`;
110
- }
111
- else if (isNetworkError) {
112
- displayMessage = `Cannot reach ${endpoint}. Check your network connection and server URL.`;
113
- }
114
- else {
115
- displayMessage = `${rootMessage}`;
116
- if (cause && cause.message !== rootMessage) {
117
- displayMessage += ` (${cause.message})`;
118
- }
119
- }
120
- if (options.raw) {
121
- process.stderr.write(displayMessage + '\n');
122
- }
123
- else {
124
- ui.error(`Failed to call tool: ${displayMessage}`);
125
- }
126
- process.exit(1);
127
- }
128
- finally {
129
- clearTimeout(fetchTimeout);
130
- }
1
+ import { runTool } from '../lib/run-tool.js';
2
+ import { buildRunToolCommand } from './run-tool-builder.js';
3
+ export const runToolCommand = buildRunToolCommand({
4
+ name: 'run-tool',
5
+ description: 'Execute an MCP tool via the HTTP API',
6
+ argDescription: 'Name of the MCP tool to execute',
7
+ routePrefix: '/api/tools',
8
+ verboseLabel: 'Tool',
9
+ headingLabel: 'Run Tool',
10
+ errorNoun: 'tool',
11
+ invoke: runTool,
131
12
  });
132
13
  //# sourceMappingURL=run-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-tool.js","sourceRoot":"","sources":["../../src/commands/run-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-tool.js","sourceRoot":"","sources":["../../src/commands/run-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;IAChD,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,sCAAsC;IACnD,cAAc,EAAE,iCAAiC;IACjD,WAAW,EAAE,YAAY;IACzB,YAAY,EAAE,MAAM;IACpB,YAAY,EAAE,UAAU;IACxB,SAAS,EAAE,MAAM;IACjB,MAAM,EAAE,OAAO;CAChB,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { RunToolOptions, RunToolResult } from './types.js';
2
+ /**
3
+ * Invoke a regular MCP tool over the Unity plugin's HTTP API.
4
+ *
5
+ * URL/token resolution priority: explicit override → project config →
6
+ * deterministic localhost port. POSTs to `/api/tools/{name}`. No
7
+ * console output, no `process.exit`; errors are returned in the
8
+ * `kind: 'failure'` variant.
9
+ */
10
+ export declare function runTool(opts: RunToolOptions): Promise<RunToolResult>;
11
+ /**
12
+ * Invoke a system tool (internal tool not exposed to MCP clients) over
13
+ * the Unity plugin's HTTP API. POSTs to `/api/system-tools/{name}`.
14
+ */
15
+ export declare function runSystemTool(opts: RunToolOptions): Promise<RunToolResult>;
@@ -0,0 +1,228 @@
1
+ // Library-safe `runTool` / `runSystemTool` implementations.
2
+ //
3
+ // Constraints (same contract as the rest of `lib/*.ts`):
4
+ // - No commander, no spinners, no process.exit, no console output.
5
+ // - Errors are returned in `{ kind: 'failure', success: false, ... }`,
6
+ // never thrown past the public boundary.
7
+ import { readConfig, resolveConnectionFromConfig } from '../utils/config.js';
8
+ import { generatePortFromDirectory } from '../utils/port.js';
9
+ import { requireProjectPath } from './validation.js';
10
+ const DEFAULT_TIMEOUT_MS = 60000;
11
+ /**
12
+ * Invoke a regular MCP tool over the Unity plugin's HTTP API.
13
+ *
14
+ * URL/token resolution priority: explicit override → project config →
15
+ * deterministic localhost port. POSTs to `/api/tools/{name}`. No
16
+ * console output, no `process.exit`; errors are returned in the
17
+ * `kind: 'failure'` variant.
18
+ */
19
+ export async function runTool(opts) {
20
+ return invokeTool('/api/tools', opts);
21
+ }
22
+ /**
23
+ * Invoke a system tool (internal tool not exposed to MCP clients) over
24
+ * the Unity plugin's HTTP API. POSTs to `/api/system-tools/{name}`.
25
+ */
26
+ export async function runSystemTool(opts) {
27
+ return invokeTool('/api/system-tools', opts);
28
+ }
29
+ async function invokeTool(routePrefix, opts) {
30
+ const validationFailure = validateOptions(opts);
31
+ if (validationFailure)
32
+ return validationFailure;
33
+ const resolved = resolveConnection(opts);
34
+ if (resolved.kind === 'failure')
35
+ return resolved;
36
+ const { url, token } = resolved;
37
+ const body = serializeInput(opts.input);
38
+ if ('error' in body) {
39
+ return makeFailure({
40
+ endpoint: '',
41
+ reason: 'invalid-input',
42
+ message: body.error.message,
43
+ error: body.error,
44
+ });
45
+ }
46
+ const endpoint = `${url}${routePrefix}/${encodeURIComponent(opts.toolName)}`;
47
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
48
+ const timeoutMs = typeof opts.timeoutMs === 'number' && opts.timeoutMs > 0 ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
49
+ const controller = new AbortController();
50
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
51
+ const externalAbort = () => controller.abort();
52
+ if (opts.signal) {
53
+ if (opts.signal.aborted)
54
+ controller.abort();
55
+ else
56
+ opts.signal.addEventListener('abort', externalAbort, { once: true });
57
+ }
58
+ const headers = { 'Content-Type': 'application/json' };
59
+ if (token)
60
+ headers['Authorization'] = `Bearer ${token}`;
61
+ try {
62
+ const response = await fetchImpl(endpoint, {
63
+ method: 'POST',
64
+ headers,
65
+ body: body.json,
66
+ signal: controller.signal,
67
+ });
68
+ const text = await safeReadText(response);
69
+ const data = parseJsonOrText(text);
70
+ if (!response.ok) {
71
+ return makeFailure({
72
+ endpoint,
73
+ reason: 'http-error',
74
+ httpStatus: response.status,
75
+ data,
76
+ message: response.statusText || `HTTP ${response.status}`,
77
+ });
78
+ }
79
+ const success = {
80
+ kind: 'success',
81
+ success: true,
82
+ endpoint,
83
+ httpStatus: response.status,
84
+ data,
85
+ };
86
+ return success;
87
+ }
88
+ catch (err) {
89
+ return classifyFetchError(err, endpoint, timeoutMs);
90
+ }
91
+ finally {
92
+ clearTimeout(timer);
93
+ opts.signal?.removeEventListener('abort', externalAbort);
94
+ }
95
+ }
96
+ function validateOptions(opts) {
97
+ if (!opts || typeof opts !== 'object') {
98
+ return makeFailure({
99
+ endpoint: '',
100
+ reason: 'invalid-input',
101
+ message: 'options object is required.',
102
+ });
103
+ }
104
+ if (typeof opts.toolName !== 'string' || opts.toolName.trim().length === 0) {
105
+ return makeFailure({
106
+ endpoint: '',
107
+ reason: 'invalid-input',
108
+ message: 'toolName is required and must be a non-empty string.',
109
+ });
110
+ }
111
+ const hasUrl = typeof opts.url === 'string' && opts.url.length > 0;
112
+ const hasProjectPath = typeof opts.unityProjectPath === 'string' && opts.unityProjectPath.trim().length > 0;
113
+ if (!hasUrl && !hasProjectPath) {
114
+ return makeFailure({
115
+ endpoint: '',
116
+ reason: 'invalid-input',
117
+ message: 'Either unityProjectPath or url must be provided.',
118
+ });
119
+ }
120
+ return null;
121
+ }
122
+ function resolveConnection(opts) {
123
+ if (opts.url) {
124
+ return { kind: 'success', url: opts.url.replace(/\/$/, ''), token: opts.token };
125
+ }
126
+ // `unityProjectPath` is library-only — does NOT require an `Assets/`
127
+ // folder, unlike the CLI's `resolveAndValidateProjectPath`. The
128
+ // deterministic-port fallback works against the path string alone.
129
+ const validated = requireProjectPath(opts.unityProjectPath);
130
+ if (!validated.ok) {
131
+ return makeFailure({
132
+ endpoint: '',
133
+ reason: 'invalid-input',
134
+ message: validated.error.message,
135
+ error: validated.error,
136
+ });
137
+ }
138
+ const projectPath = validated.projectPath;
139
+ const config = readConfig(projectPath);
140
+ const fromConfig = config
141
+ ? resolveConnectionFromConfig(config)
142
+ : { url: undefined, token: undefined };
143
+ const url = fromConfig.url
144
+ ? fromConfig.url.replace(/\/$/, '')
145
+ : `http://localhost:${generatePortFromDirectory(projectPath)}`;
146
+ return { kind: 'success', url, token: opts.token ?? fromConfig.token };
147
+ }
148
+ function serializeInput(input) {
149
+ if (input === undefined || input === null)
150
+ return { json: '{}' };
151
+ if (typeof input === 'string') {
152
+ // Validate the round-trip so the server never sees malformed bodies.
153
+ try {
154
+ JSON.parse(input);
155
+ return { json: input };
156
+ }
157
+ catch (err) {
158
+ return {
159
+ error: new Error(`input string is not valid JSON: ${err instanceof Error ? err.message : String(err)}`),
160
+ };
161
+ }
162
+ }
163
+ if (typeof input !== 'object') {
164
+ return {
165
+ error: new Error('input must be a plain object, JSON string, undefined, or null.'),
166
+ };
167
+ }
168
+ try {
169
+ return { json: JSON.stringify(input) };
170
+ }
171
+ catch (err) {
172
+ return {
173
+ error: new Error(`input could not be serialized to JSON: ${err instanceof Error ? err.message : String(err)}`),
174
+ };
175
+ }
176
+ }
177
+ async function safeReadText(response) {
178
+ try {
179
+ return await response.text();
180
+ }
181
+ catch {
182
+ return '';
183
+ }
184
+ }
185
+ function parseJsonOrText(text) {
186
+ if (text.length === 0)
187
+ return undefined;
188
+ try {
189
+ return JSON.parse(text);
190
+ }
191
+ catch {
192
+ return text;
193
+ }
194
+ }
195
+ function getCause(err) {
196
+ if (!(err instanceof Error) || !('cause' in err))
197
+ return undefined;
198
+ return err.cause;
199
+ }
200
+ function classifyFetchError(err, endpoint, timeoutMs) {
201
+ if (err instanceof Error && err.name === 'AbortError') {
202
+ return makeFailure({
203
+ endpoint,
204
+ reason: 'timeout',
205
+ message: `Tool call timed out after ${timeoutMs}ms.`,
206
+ error: err,
207
+ });
208
+ }
209
+ const error = err instanceof Error ? err : new Error(String(err));
210
+ const causeCode = getCause(err)?.code;
211
+ let reason = 'unknown';
212
+ if (causeCode === 'ECONNREFUSED')
213
+ reason = 'connection-refused';
214
+ else if (causeCode === 'ECONNRESET')
215
+ reason = 'connection-reset';
216
+ else if (causeCode === 'ENOTFOUND' || causeCode === 'EAI_AGAIN')
217
+ reason = 'network-error';
218
+ return makeFailure({
219
+ endpoint,
220
+ reason,
221
+ message: error.message,
222
+ error,
223
+ });
224
+ }
225
+ function makeFailure(fields) {
226
+ return { kind: 'failure', success: false, ...fields };
227
+ }
228
+ //# sourceMappingURL=run-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tool.js","sourceRoot":"","sources":["../../src/lib/run-tool.ts"],"names":[],"mappings":"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"}
@@ -376,3 +376,107 @@ export interface OpenEnvInputs {
376
376
  transport?: OpenProjectOptions['transport'];
377
377
  startServer?: OpenProjectOptions['startServer'];
378
378
  }
379
+ /**
380
+ * Coarse failure category for {@link RunToolFailure}. Mirrors the
381
+ * branches the CLI's `run-tool` command surfaces in its error path so
382
+ * library consumers can render the same diagnostics without re-deriving
383
+ * them from the underlying `Error`.
384
+ */
385
+ export type RunToolFailureReason = 'invalid-input' | 'connection-refused' | 'connection-reset' | 'network-error' | 'timeout' | 'http-error' | 'unknown';
386
+ /**
387
+ * Options accepted by both {@link runTool} and {@link runSystemTool}.
388
+ *
389
+ * Either `unityProjectPath` (preferred — resolves URL + token from the
390
+ * project's `UserSettings/AI-Game-Developer-Config.json`, falling back
391
+ * to a deterministic localhost port when the file is absent) or `url`
392
+ * (explicit endpoint override) MUST be provided.
393
+ */
394
+ export interface RunToolOptions {
395
+ /**
396
+ * Tool name to invoke. Forwarded as the `{name}` segment of the
397
+ * route — the function URL-encodes it before issuing the request.
398
+ */
399
+ toolName: string;
400
+ /**
401
+ * Absolute or relative path to the Unity project. Used to read the
402
+ * project's config (host + token) and, as a last resort, to derive
403
+ * the deterministic localhost port mirroring the C# plugin's hash.
404
+ */
405
+ unityProjectPath?: string;
406
+ /** Explicit base URL override (no trailing slash required). */
407
+ url?: string;
408
+ /** Bearer token override. */
409
+ token?: string;
410
+ /**
411
+ * Tool arguments, serialized as the JSON request body. When omitted,
412
+ * the body is `{}`. Anything other than `undefined` / `null` /
413
+ * `object` is rejected with a `kind: 'failure'` result.
414
+ */
415
+ input?: unknown;
416
+ /**
417
+ * Per-request timeout in milliseconds. Defaults to `60000` (matching
418
+ * the CLI command's `--timeout` default). Values <= 0 are treated as
419
+ * the default to keep accidental "0 = disable" mistakes from
420
+ * stalling polling callers.
421
+ */
422
+ timeoutMs?: number;
423
+ /**
424
+ * Optional abort signal. When fired, the in-flight fetch is
425
+ * cancelled and the result resolves to a `kind: 'failure'` with
426
+ * `reason: 'timeout'`.
427
+ */
428
+ signal?: AbortSignal;
429
+ /**
430
+ * Optional injection point so tests can swap the `fetch`
431
+ * implementation. Defaults to the global `fetch`.
432
+ */
433
+ fetchImpl?: typeof fetch;
434
+ }
435
+ /** Successful `runTool` / `runSystemTool` outcome. Narrow with `kind === 'success'`. */
436
+ export interface RunToolSuccess {
437
+ kind: 'success';
438
+ /** Always `true` for the success variant. Wire-compatible alias for `kind === 'success'`. */
439
+ success: true;
440
+ /** Resolved endpoint URL that was hit (post URL/token resolution). */
441
+ endpoint: string;
442
+ /** HTTP status code returned by the Unity plugin. */
443
+ httpStatus: number;
444
+ /**
445
+ * Parsed response body. The Unity plugin returns
446
+ * `{ status: "success", structured?: <tool output>, content?: <text blocks[]> }`
447
+ * — consumers typically read `data.structured` or `data.content`
448
+ * depending on whether the invoked tool returns structured content.
449
+ * Non-JSON responses surface the raw text string.
450
+ */
451
+ data: unknown;
452
+ }
453
+ /** Failed `runTool` / `runSystemTool` outcome. Narrow with `kind === 'failure'`. */
454
+ export interface RunToolFailure {
455
+ kind: 'failure';
456
+ /** Always `false` for the failure variant. Wire-compatible alias for `kind === 'failure'`. */
457
+ success: false;
458
+ /**
459
+ * Resolved endpoint URL. Empty string when the failure is
460
+ * `reason: 'invalid-input'` and resolution never happened.
461
+ */
462
+ endpoint: string;
463
+ /** Coarse cause — see {@link RunToolFailureReason}. */
464
+ reason: RunToolFailureReason;
465
+ /** HTTP status code when `reason === 'http-error'`. */
466
+ httpStatus?: number;
467
+ /**
468
+ * Response body for diagnostics on `http-error` (parsed JSON when the
469
+ * server returned JSON, otherwise the raw text). Omitted on transport
470
+ * failures where no response was received.
471
+ */
472
+ data?: unknown;
473
+ /** Human-readable failure summary; never thrown past the public boundary. */
474
+ message: string;
475
+ /** Captured error, when applicable. */
476
+ error?: Error;
477
+ }
478
+ export type RunToolResult = RunToolSuccess | RunToolFailure;
479
+ export type RunSystemToolOptions = RunToolOptions;
480
+ export type RunSystemToolResult = RunToolResult;
481
+ export type RunSystemToolSuccess = RunToolSuccess;
482
+ export type RunSystemToolFailure = RunToolFailure;
package/dist/lib.d.ts CHANGED
@@ -3,4 +3,5 @@ export { removePlugin } from './lib/remove-plugin.js';
3
3
  export { configure } from './lib/configure.js';
4
4
  export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
5
5
  export { openProject } from './lib/open.js';
6
- export type { ProgressEvent, ProgressCallback, ResultKind, InstallPluginOptions, InstallResult, InstallSuccess, InstallFailure, RemovePluginOptions, RemoveResult, RemoveSuccess, RemoveFailure, ConfigureOptions, ConfigureResult, ConfigureSuccess, ConfigureFailure, ConfigureSnapshot, FeatureAction, McpFeatureSnapshot, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, McpTransport, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectTransport, } from './lib/types.js';
6
+ export { runTool, runSystemTool } from './lib/run-tool.js';
7
+ export type { ProgressEvent, ProgressCallback, ResultKind, InstallPluginOptions, InstallResult, InstallSuccess, InstallFailure, RemovePluginOptions, RemoveResult, RemoveSuccess, RemoveFailure, ConfigureOptions, ConfigureResult, ConfigureSuccess, ConfigureFailure, ConfigureSnapshot, FeatureAction, McpFeatureSnapshot, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, McpTransport, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectTransport, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, } from './lib/types.js';
package/dist/lib.js CHANGED
@@ -20,4 +20,5 @@ export { removePlugin } from './lib/remove-plugin.js';
20
20
  export { configure } from './lib/configure.js';
21
21
  export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
22
22
  export { openProject } from './lib/open.js';
23
+ export { runTool, runSystemTool } from './lib/run-tool.js';
23
24
  //# sourceMappingURL=lib.js.map
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,qDAAqD;AACrD,iEAAiE;AACjE,sEAAsE;AACtE,oDAAoD;AACpD,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,iEAAiE;AACjE,oEAAoE;AACpE,2BAA2B;AAC3B,EAAE;AACF,sEAAsE;AACtE,sDAAsD;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,qDAAqD;AACrD,iEAAiE;AACjE,sEAAsE;AACtE,oDAAoD;AACpD,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,iEAAiE;AACjE,oEAAoE;AACpE,2BAA2B;AAC3B,EAAE;AACF,sEAAsE;AACtE,sDAAsD;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unity-mcp-cli",
3
- "version": "0.71.0",
3
+ "version": "0.72.0",
4
4
  "description": "Cross-platform CLI tool for AI Game Developer (Skills & MCP). Full AI develop and test loop. Efficient token usage, advanced tools. Creates Unity project, installs plugins, configures tools, and manages HTTP connection with Unity Editor and a game made with Unity. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.",
5
5
  "type": "module",
6
6
  "main": "dist/lib.js",