unity-mcp-cli 0.51.6

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.
Files changed (38) hide show
  1. package/bin/unity-mcp.js +2 -0
  2. package/dist/commands/configure.d.ts +2 -0
  3. package/dist/commands/configure.js +83 -0
  4. package/dist/commands/configure.js.map +1 -0
  5. package/dist/commands/connect.d.ts +2 -0
  6. package/dist/commands/connect.js +64 -0
  7. package/dist/commands/connect.js.map +1 -0
  8. package/dist/commands/create-project.d.ts +2 -0
  9. package/dist/commands/create-project.js +28 -0
  10. package/dist/commands/create-project.js.map +1 -0
  11. package/dist/commands/install-editor.d.ts +2 -0
  12. package/dist/commands/install-editor.js +46 -0
  13. package/dist/commands/install-editor.js.map +1 -0
  14. package/dist/commands/install-plugin.d.ts +2 -0
  15. package/dist/commands/install-plugin.js +26 -0
  16. package/dist/commands/install-plugin.js.map +1 -0
  17. package/dist/commands/open.d.ts +2 -0
  18. package/dist/commands/open.js +33 -0
  19. package/dist/commands/open.js.map +1 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +26 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/utils/config.d.ts +51 -0
  24. package/dist/utils/config.js +118 -0
  25. package/dist/utils/config.js.map +1 -0
  26. package/dist/utils/manifest.d.ts +17 -0
  27. package/dist/utils/manifest.js +134 -0
  28. package/dist/utils/manifest.js.map +1 -0
  29. package/dist/utils/port.d.ts +6 -0
  30. package/dist/utils/port.js +19 -0
  31. package/dist/utils/port.js.map +1 -0
  32. package/dist/utils/unity-editor.d.ts +14 -0
  33. package/dist/utils/unity-editor.js +180 -0
  34. package/dist/utils/unity-editor.js.map +1 -0
  35. package/dist/utils/unity-hub.d.ts +21 -0
  36. package/dist/utils/unity-hub.js +90 -0
  37. package/dist/utils/unity-hub.js.map +1 -0
  38. package/package.json +44 -0
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const configureCommand: Command;
@@ -0,0 +1,83 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { getOrCreateConfig, writeConfig, updateFeatures } from '../utils/config.js';
5
+ function parseCommaSeparated(value) {
6
+ return value.split(',').map((s) => s.trim()).filter(Boolean);
7
+ }
8
+ export const configureCommand = new Command('configure')
9
+ .description('Configure MCP tools, prompts, and resources in AI-Game-Developer-Config.json')
10
+ .requiredOption('--project-path <path>', 'Path to the Unity project')
11
+ .option('--enable-tools <names>', 'Enable specific tools (comma-separated)', parseCommaSeparated)
12
+ .option('--disable-tools <names>', 'Disable specific tools (comma-separated)', parseCommaSeparated)
13
+ .option('--enable-all-tools', 'Enable all tools')
14
+ .option('--disable-all-tools', 'Disable all tools')
15
+ .option('--enable-prompts <names>', 'Enable specific prompts (comma-separated)', parseCommaSeparated)
16
+ .option('--disable-prompts <names>', 'Disable specific prompts (comma-separated)', parseCommaSeparated)
17
+ .option('--enable-all-prompts', 'Enable all prompts')
18
+ .option('--disable-all-prompts', 'Disable all prompts')
19
+ .option('--enable-resources <names>', 'Enable specific resources (comma-separated)', parseCommaSeparated)
20
+ .option('--disable-resources <names>', 'Disable specific resources (comma-separated)', parseCommaSeparated)
21
+ .option('--enable-all-resources', 'Enable all resources')
22
+ .option('--disable-all-resources', 'Disable all resources')
23
+ .option('--list', 'List current configuration')
24
+ .action(async (options) => {
25
+ const projectPath = path.resolve(options.projectPath);
26
+ if (!fs.existsSync(projectPath)) {
27
+ console.error(`Error: Project path does not exist: ${projectPath}`);
28
+ process.exit(1);
29
+ }
30
+ const config = getOrCreateConfig(projectPath);
31
+ if (options.list) {
32
+ console.log('\nCurrent configuration:');
33
+ console.log(` Host: ${config.host ?? 'not set'}`);
34
+ console.log(` Keep Connected: ${config.keepConnected ?? false}`);
35
+ console.log(` Transport: ${config.transportMethod ?? 'streamableHttp'}`);
36
+ console.log(` Auth: ${config.authOption ?? 'none'}`);
37
+ const printFeatures = (label, features) => {
38
+ if (!features || features.length === 0) {
39
+ console.log(`\n ${label}: (none configured - all enabled by default)`);
40
+ return;
41
+ }
42
+ console.log(`\n ${label}:`);
43
+ for (const f of features) {
44
+ const status = f.enabled ? '[enabled]' : '[disabled]';
45
+ console.log(` ${status} ${f.name}`);
46
+ }
47
+ };
48
+ printFeatures('Tools', config.tools);
49
+ printFeatures('Prompts', config.prompts);
50
+ printFeatures('Resources', config.resources);
51
+ return;
52
+ }
53
+ // Apply tool changes
54
+ if (options.enableTools || options.disableTools || options.enableAllTools || options.disableAllTools) {
55
+ updateFeatures(config, 'tools', {
56
+ enableNames: options.enableTools,
57
+ disableNames: options.disableTools,
58
+ enableAll: options.enableAllTools,
59
+ disableAll: options.disableAllTools,
60
+ });
61
+ }
62
+ // Apply prompt changes
63
+ if (options.enablePrompts || options.disablePrompts || options.enableAllPrompts || options.disableAllPrompts) {
64
+ updateFeatures(config, 'prompts', {
65
+ enableNames: options.enablePrompts,
66
+ disableNames: options.disablePrompts,
67
+ enableAll: options.enableAllPrompts,
68
+ disableAll: options.disableAllPrompts,
69
+ });
70
+ }
71
+ // Apply resource changes
72
+ if (options.enableResources || options.disableResources || options.enableAllResources || options.disableAllResources) {
73
+ updateFeatures(config, 'resources', {
74
+ enableNames: options.enableResources,
75
+ disableNames: options.disableResources,
76
+ enableAll: options.enableAllResources,
77
+ disableAll: options.disableAllResources,
78
+ });
79
+ }
80
+ writeConfig(projectPath, config);
81
+ console.log('Configuration updated successfully.');
82
+ });
83
+ //# sourceMappingURL=configure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/commands/configure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const connectCommand: Command;
@@ -0,0 +1,64 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { findEditorPath, getProjectEditorVersion, launchEditor } from '../utils/unity-editor.js';
5
+ export const connectCommand = new Command('connect')
6
+ .description('Open Unity and enforce MCP connection to a specified server URL via environment variables')
7
+ .requiredOption('--project-path <path>', 'Path to the Unity project')
8
+ .requiredOption('--url <url>', 'MCP server URL to connect to')
9
+ .option('--tools <names>', 'Comma-separated list of tools to enable (sets UNITY_MCP_TOOLS)')
10
+ .option('--token <token>', 'Auth token (sets UNITY_MCP_TOKEN)')
11
+ .option('--auth <option>', 'Auth option: none or required (sets UNITY_MCP_AUTH_OPTION)')
12
+ .option('--keep-connected', 'Force keep connected (sets UNITY_MCP_KEEP_CONNECTED=true)')
13
+ .option('--editor-version <version>', 'Specific Unity Editor version to use')
14
+ .action(async (options) => {
15
+ const projectPath = path.resolve(options.projectPath);
16
+ if (!fs.existsSync(projectPath)) {
17
+ console.error(`Error: Project path does not exist: ${projectPath}`);
18
+ process.exit(1);
19
+ }
20
+ // Determine editor version
21
+ let version = options.editorVersion;
22
+ if (!version) {
23
+ version = getProjectEditorVersion(projectPath) ?? undefined;
24
+ if (version) {
25
+ console.log(`Detected editor version from project: ${version}`);
26
+ }
27
+ }
28
+ const editorPath = findEditorPath(version);
29
+ if (!editorPath) {
30
+ const versionMsg = version ? ` (version ${version})` : '';
31
+ console.error(`Error: Unity Editor not found${versionMsg}. Install it with: unity-mcp install-editor --version <version>`);
32
+ process.exit(1);
33
+ }
34
+ // Build environment variables for MCP connection
35
+ const env = {
36
+ UNITY_MCP_HOST: options.url,
37
+ };
38
+ if (options.keepConnected) {
39
+ env['UNITY_MCP_KEEP_CONNECTED'] = 'true';
40
+ }
41
+ if (options.tools) {
42
+ env['UNITY_MCP_TOOLS'] = options.tools;
43
+ }
44
+ if (options.token) {
45
+ env['UNITY_MCP_TOKEN'] = options.token;
46
+ }
47
+ if (options.auth) {
48
+ if (options.auth !== 'none' && options.auth !== 'required') {
49
+ console.error('Error: --auth must be "none" or "required"');
50
+ process.exit(1);
51
+ }
52
+ env['UNITY_MCP_AUTH_OPTION'] = options.auth;
53
+ }
54
+ console.log(`Connecting to MCP server: ${options.url}`);
55
+ console.log('Environment variables:');
56
+ for (const [key, value] of Object.entries(env)) {
57
+ const display = key === 'UNITY_MCP_TOKEN' ? '***' : value;
58
+ console.log(` ${key}=${display}`);
59
+ }
60
+ console.log(`\nOpening project: ${projectPath}`);
61
+ console.log(`Using editor: ${editorPath}`);
62
+ launchEditor(editorPath, projectPath, env);
63
+ });
64
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const createProjectCommand: Command;
@@ -0,0 +1,28 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import { findUnityHub, createProject, listInstalledEditors } from '../utils/unity-hub.js';
4
+ export const createProjectCommand = new Command('create-project')
5
+ .description('Create a new Unity project')
6
+ .requiredOption('--path <path>', 'Path where the project will be created')
7
+ .option('--editor-version <version>', 'Unity Editor version to use')
8
+ .action(async (options) => {
9
+ const hubPath = findUnityHub();
10
+ if (!hubPath) {
11
+ console.error('Error: Unity Hub not found. Please install Unity Hub first.');
12
+ process.exit(1);
13
+ }
14
+ let editorVersion = options.editorVersion;
15
+ if (!editorVersion) {
16
+ // Use the latest installed editor
17
+ const editors = listInstalledEditors(hubPath);
18
+ if (editors.length === 0) {
19
+ console.error('Error: No Unity editors installed. Install one with: unity-mcp install-editor --version <version>');
20
+ process.exit(1);
21
+ }
22
+ editorVersion = editors[0].version;
23
+ console.log(`No editor version specified, using latest installed: ${editorVersion}`);
24
+ }
25
+ const projectPath = path.resolve(options.path);
26
+ createProject(hubPath, projectPath, editorVersion);
27
+ });
28
+ //# sourceMappingURL=create-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-project.js","sourceRoot":"","sources":["../../src/commands/create-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE1F,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;KAC9D,WAAW,CAAC,4BAA4B,CAAC;KACzC,cAAc,CAAC,eAAe,EAAE,wCAAwC,CAAC;KACzE,MAAM,CAAC,4BAA4B,EAAE,6BAA6B,CAAC;KACnE,MAAM,CAAC,KAAK,EAAE,OAAiD,EAAE,EAAE;IAClE,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAE1C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,kCAAkC;QAClC,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,mGAAmG,CAAC,CAAC;YACnH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,wDAAwD,aAAa,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const installEditorCommand: Command;
@@ -0,0 +1,46 @@
1
+ import { Command } from 'commander';
2
+ import { findUnityHub, installEditor, listInstalledEditors } from '../utils/unity-hub.js';
3
+ import { getProjectEditorVersion } from '../utils/unity-editor.js';
4
+ export const installEditorCommand = new Command('install-editor')
5
+ .description('Install Unity Editor via Unity Hub')
6
+ .option('--version <version>', 'Unity Editor version to install')
7
+ .option('--project-path <path>', 'Read version from an existing Unity project')
8
+ .action(async (options) => {
9
+ const hubPath = findUnityHub();
10
+ if (!hubPath) {
11
+ console.error('Error: Unity Hub not found. Please install Unity Hub first.');
12
+ process.exit(1);
13
+ }
14
+ let version = options.version;
15
+ if (!version && options.projectPath) {
16
+ version = getProjectEditorVersion(options.projectPath) ?? undefined;
17
+ if (version) {
18
+ console.log(`Detected editor version from project: ${version}`);
19
+ }
20
+ else {
21
+ console.error('Error: Could not read editor version from ProjectSettings/ProjectVersion.txt');
22
+ process.exit(1);
23
+ }
24
+ }
25
+ if (!version) {
26
+ console.error('Error: Please specify --version or --project-path');
27
+ // Show installed editors as a hint
28
+ const editors = listInstalledEditors(hubPath);
29
+ if (editors.length > 0) {
30
+ console.log('\nCurrently installed editors:');
31
+ for (const editor of editors) {
32
+ console.log(` ${editor.version} - ${editor.path}`);
33
+ }
34
+ }
35
+ process.exit(1);
36
+ }
37
+ // Check if already installed
38
+ const editors = listInstalledEditors(hubPath);
39
+ const alreadyInstalled = editors.find((e) => e.version === version);
40
+ if (alreadyInstalled) {
41
+ console.log(`Unity Editor ${version} is already installed at: ${alreadyInstalled.path}`);
42
+ return;
43
+ }
44
+ installEditor(hubPath, version);
45
+ });
46
+ //# sourceMappingURL=install-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-editor.js","sourceRoot":"","sources":["../../src/commands/install-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;KAC9D,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,qBAAqB,EAAE,iCAAiC,CAAC;KAChE,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,OAAmD,EAAE,EAAE;IACpE,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAE9B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC;QACpE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;YAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAEnE,mCAAmC;QACnC,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAC9C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,OAAO,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IACpE,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,6BAA6B,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IAED,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const installPluginCommand: Command;
@@ -0,0 +1,26 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { addPluginToManifest, resolveLatestVersion } from '../utils/manifest.js';
5
+ export const installPluginCommand = new Command('install-plugin')
6
+ .description('Install Unity-MCP plugin into a Unity project')
7
+ .requiredOption('--project-path <path>', 'Path to the Unity project')
8
+ .option('--plugin-version <version>', 'Plugin version to install (default: latest)')
9
+ .action(async (options) => {
10
+ const projectPath = path.resolve(options.projectPath);
11
+ // Validate project exists
12
+ const manifestPath = path.join(projectPath, 'Packages', 'manifest.json');
13
+ if (!fs.existsSync(manifestPath)) {
14
+ console.error(`Error: Not a valid Unity project (missing Packages/manifest.json): ${projectPath}`);
15
+ process.exit(1);
16
+ }
17
+ // Resolve version
18
+ let version = options.pluginVersion;
19
+ if (!version) {
20
+ version = await resolveLatestVersion();
21
+ }
22
+ console.log(`Installing Unity-MCP plugin v${version} into: ${projectPath}`);
23
+ addPluginToManifest(projectPath, version);
24
+ console.log('Done! Open the project in Unity Editor to complete installation.');
25
+ });
26
+ //# sourceMappingURL=install-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-plugin.js","sourceRoot":"","sources":["../../src/commands/install-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;KAC9D,WAAW,CAAC,+CAA+C,CAAC;KAC5D,cAAc,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;KACpE,MAAM,CAAC,4BAA4B,EAAE,6CAA6C,CAAC;KACnF,MAAM,CAAC,KAAK,EAAE,OAAwD,EAAE,EAAE;IACzE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEtD,0BAA0B;IAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACzE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,sEAAsE,WAAW,EAAE,CAAC,CAAC;QACnG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;IACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,MAAM,oBAAoB,EAAE,CAAC;IACzC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,UAAU,WAAW,EAAE,CAAC,CAAC;IAC5E,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;AAClF,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const openCommand: Command;
@@ -0,0 +1,33 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { findEditorPath, getProjectEditorVersion, launchEditor } from '../utils/unity-editor.js';
5
+ export const openCommand = new Command('open')
6
+ .description('Open a Unity project in Unity Editor')
7
+ .requiredOption('--project-path <path>', 'Path to the Unity project')
8
+ .option('--editor-version <version>', 'Specific Unity Editor version to use')
9
+ .action(async (options) => {
10
+ const projectPath = path.resolve(options.projectPath);
11
+ if (!fs.existsSync(projectPath)) {
12
+ console.error(`Error: Project path does not exist: ${projectPath}`);
13
+ process.exit(1);
14
+ }
15
+ // Determine editor version
16
+ let version = options.editorVersion;
17
+ if (!version) {
18
+ version = getProjectEditorVersion(projectPath) ?? undefined;
19
+ if (version) {
20
+ console.log(`Detected editor version from project: ${version}`);
21
+ }
22
+ }
23
+ const editorPath = findEditorPath(version);
24
+ if (!editorPath) {
25
+ const versionMsg = version ? ` (version ${version})` : '';
26
+ console.error(`Error: Unity Editor not found${versionMsg}. Install it with: unity-mcp install-editor --version <version>`);
27
+ process.exit(1);
28
+ }
29
+ console.log(`Opening project: ${projectPath}`);
30
+ console.log(`Using editor: ${editorPath}`);
31
+ launchEditor(editorPath, projectPath);
32
+ });
33
+ //# sourceMappingURL=open.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAEjG,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,sCAAsC,CAAC;KACnD,cAAc,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;KACpE,MAAM,CAAC,4BAA4B,EAAE,sCAAsC,CAAC;KAC5E,MAAM,CAAC,KAAK,EAAE,OAAwD,EAAE,EAAE;IACzE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,uCAAuC,WAAW,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,2BAA2B;IAC3B,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;IACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,uBAAuB,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC;QAC5D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,KAAK,CAAC,gCAAgC,UAAU,iEAAiE,CAAC,CAAC;QAC3H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;IAC3C,YAAY,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { Command } from 'commander';
2
+ import { createRequire } from 'module';
3
+ import { createProjectCommand } from './commands/create-project.js';
4
+ import { installEditorCommand } from './commands/install-editor.js';
5
+ import { openCommand } from './commands/open.js';
6
+ import { installPluginCommand } from './commands/install-plugin.js';
7
+ import { configureCommand } from './commands/configure.js';
8
+ import { connectCommand } from './commands/connect.js';
9
+ const require = createRequire(import.meta.url);
10
+ const pkg = require('../package.json');
11
+ const program = new Command();
12
+ program
13
+ .name('unity-mcp')
14
+ .description('Cross-platform CLI tool for Unity-MCP operations')
15
+ .version(pkg.version);
16
+ program.addCommand(createProjectCommand);
17
+ program.addCommand(installEditorCommand);
18
+ program.addCommand(openCommand);
19
+ program.addCommand(installPluginCommand);
20
+ program.addCommand(configureCommand);
21
+ program.addCommand(connectCommand);
22
+ program.parseAsync().catch((error) => {
23
+ console.error(error);
24
+ process.exit(1);
25
+ });
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAExB,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,51 @@
1
+ export interface McpFeature {
2
+ name: string;
3
+ enabled: boolean;
4
+ }
5
+ export interface UnityConnectionConfig {
6
+ host?: string;
7
+ token?: string;
8
+ keepConnected?: boolean;
9
+ logLevel?: number;
10
+ timeoutMs?: number;
11
+ keepServerRunning?: boolean;
12
+ transportMethod?: string;
13
+ authOption?: string;
14
+ connectionMode?: string;
15
+ cloudServerUrl?: string;
16
+ cloudToken?: string;
17
+ tools?: McpFeature[];
18
+ prompts?: McpFeature[];
19
+ resources?: McpFeature[];
20
+ [key: string]: unknown;
21
+ }
22
+ /**
23
+ * Create a default config for a Unity project.
24
+ */
25
+ export declare function createDefaultConfig(projectPath: string): UnityConnectionConfig;
26
+ /**
27
+ * Read the AI-Game-Developer-Config.json from a Unity project.
28
+ * Returns null if the file doesn't exist.
29
+ */
30
+ export declare function readConfig(projectPath: string): UnityConnectionConfig | null;
31
+ /**
32
+ * Write the AI-Game-Developer-Config.json to a Unity project.
33
+ * Creates the UserSettings directory if needed.
34
+ */
35
+ export declare function writeConfig(projectPath: string, config: UnityConnectionConfig): void;
36
+ /**
37
+ * Read config or create with defaults if it doesn't exist.
38
+ */
39
+ export declare function getOrCreateConfig(projectPath: string): UnityConnectionConfig;
40
+ /**
41
+ * Update features (tools, prompts, or resources) in the config.
42
+ * - enableNames: set these to enabled=true
43
+ * - disableNames: set these to enabled=false
44
+ * - enableAll/disableAll: override all features
45
+ */
46
+ export declare function updateFeatures(config: UnityConnectionConfig, featureType: 'tools' | 'prompts' | 'resources', options: {
47
+ enableNames?: string[];
48
+ disableNames?: string[];
49
+ enableAll?: boolean;
50
+ disableAll?: boolean;
51
+ }): void;
@@ -0,0 +1,118 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { generatePortFromDirectory } from './port.js';
4
+ const CONFIG_RELATIVE_PATH = 'UserSettings/AI-Game-Developer-Config.json';
5
+ function getConfigPath(projectPath) {
6
+ return path.join(projectPath, CONFIG_RELATIVE_PATH);
7
+ }
8
+ /**
9
+ * Create a default config for a Unity project.
10
+ */
11
+ export function createDefaultConfig(projectPath) {
12
+ const port = generatePortFromDirectory(projectPath);
13
+ return {
14
+ host: `http://localhost:${port}`,
15
+ keepConnected: false,
16
+ logLevel: 3,
17
+ timeoutMs: 10000,
18
+ keepServerRunning: false,
19
+ transportMethod: 'streamableHttp',
20
+ authOption: 'none',
21
+ connectionMode: 'Custom',
22
+ cloudServerUrl: 'https://ai-game.dev',
23
+ tools: [],
24
+ prompts: [],
25
+ resources: [],
26
+ };
27
+ }
28
+ /**
29
+ * Read the AI-Game-Developer-Config.json from a Unity project.
30
+ * Returns null if the file doesn't exist.
31
+ */
32
+ export function readConfig(projectPath) {
33
+ const configPath = getConfigPath(projectPath);
34
+ if (!fs.existsSync(configPath)) {
35
+ return null;
36
+ }
37
+ const json = fs.readFileSync(configPath, 'utf-8');
38
+ try {
39
+ return JSON.parse(json);
40
+ }
41
+ catch (err) {
42
+ if (err instanceof SyntaxError) {
43
+ console.error(`Malformed JSON in config file: ${configPath}\n${err.message}`);
44
+ }
45
+ return null;
46
+ }
47
+ }
48
+ /**
49
+ * Write the AI-Game-Developer-Config.json to a Unity project.
50
+ * Creates the UserSettings directory if needed.
51
+ */
52
+ export function writeConfig(projectPath, config) {
53
+ const configPath = getConfigPath(projectPath);
54
+ const dir = path.dirname(configPath);
55
+ if (!fs.existsSync(dir)) {
56
+ fs.mkdirSync(dir, { recursive: true });
57
+ }
58
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
59
+ }
60
+ /**
61
+ * Read config or create with defaults if it doesn't exist.
62
+ */
63
+ export function getOrCreateConfig(projectPath) {
64
+ const existing = readConfig(projectPath);
65
+ if (existing)
66
+ return existing;
67
+ const config = createDefaultConfig(projectPath);
68
+ writeConfig(projectPath, config);
69
+ return config;
70
+ }
71
+ /**
72
+ * Update features (tools, prompts, or resources) in the config.
73
+ * - enableNames: set these to enabled=true
74
+ * - disableNames: set these to enabled=false
75
+ * - enableAll/disableAll: override all features
76
+ */
77
+ export function updateFeatures(config, featureType, options) {
78
+ const rawFeatures = config[featureType];
79
+ const features = Array.isArray(rawFeatures)
80
+ ? rawFeatures.filter((f) => typeof f === 'object' && f !== null && typeof f.name === 'string' && typeof f.enabled === 'boolean')
81
+ : [];
82
+ if (options.enableAll) {
83
+ for (const f of features)
84
+ f.enabled = true;
85
+ config[featureType] = features;
86
+ return;
87
+ }
88
+ if (options.disableAll) {
89
+ for (const f of features)
90
+ f.enabled = false;
91
+ config[featureType] = features;
92
+ return;
93
+ }
94
+ if (options.enableNames) {
95
+ for (const name of options.enableNames) {
96
+ const existing = features.find((f) => f.name === name);
97
+ if (existing) {
98
+ existing.enabled = true;
99
+ }
100
+ else {
101
+ features.push({ name, enabled: true });
102
+ }
103
+ }
104
+ }
105
+ if (options.disableNames) {
106
+ for (const name of options.disableNames) {
107
+ const existing = features.find((f) => f.name === name);
108
+ if (existing) {
109
+ existing.enabled = false;
110
+ }
111
+ else {
112
+ features.push({ name, enabled: false });
113
+ }
114
+ }
115
+ }
116
+ config[featureType] = features;
117
+ }
118
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Resolve the latest plugin version. Tries OpenUPM API first, falls back to hardcoded version.
3
+ */
4
+ export declare function resolveLatestVersion(): Promise<string>;
5
+ /**
6
+ * Determines if the version should be updated.
7
+ * Only update if the new version is higher than the current version.
8
+ * Ports the C# Installer.ShouldUpdateVersion() logic.
9
+ */
10
+ export declare function shouldUpdateVersion(currentVersion: string, newVersion: string): boolean;
11
+ /**
12
+ * Add Unity-MCP plugin to a Unity project's Packages/manifest.json.
13
+ * Ports the C# Installer.Manifest.cs logic:
14
+ * - Adds OpenUPM scoped registry with required scopes
15
+ * - Adds/updates the plugin dependency (never downgrades)
16
+ */
17
+ export declare function addPluginToManifest(projectPath: string, version: string): void;
@@ -0,0 +1,134 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import semver from 'semver';
4
+ const PACKAGE_ID = 'com.ivanmurzak.unity.mcp';
5
+ const REGISTRY_NAME = 'package.openupm.com';
6
+ const REGISTRY_URL = 'https://package.openupm.com';
7
+ const REQUIRED_SCOPES = [
8
+ 'com.ivanmurzak',
9
+ 'extensions.unity',
10
+ 'org.nuget.com.ivanmurzak',
11
+ 'org.nuget.microsoft',
12
+ 'org.nuget.system',
13
+ 'org.nuget.r3',
14
+ ];
15
+ // Hardcoded fallback version (updated on each release)
16
+ const FALLBACK_VERSION = '0.51.6';
17
+ /**
18
+ * Resolve the latest plugin version. Tries OpenUPM API first, falls back to hardcoded version.
19
+ */
20
+ export async function resolveLatestVersion() {
21
+ try {
22
+ const controller = new AbortController();
23
+ const timeout = setTimeout(() => controller.abort(), 5000);
24
+ try {
25
+ const res = await fetch(`https://package.openupm.com/${PACKAGE_ID}`, {
26
+ signal: controller.signal,
27
+ headers: { Accept: 'application/json' },
28
+ });
29
+ if (res.ok) {
30
+ const data = (await res.json());
31
+ const latest = data?.['dist-tags']?.latest;
32
+ if (latest) {
33
+ console.log(`Resolved latest version from OpenUPM: ${latest}`);
34
+ return latest;
35
+ }
36
+ }
37
+ }
38
+ finally {
39
+ clearTimeout(timeout);
40
+ }
41
+ }
42
+ catch {
43
+ // Network error or timeout — fall through to hardcoded version
44
+ }
45
+ console.log(`Using fallback version: ${FALLBACK_VERSION}`);
46
+ return FALLBACK_VERSION;
47
+ }
48
+ /**
49
+ * Determines if the version should be updated.
50
+ * Only update if the new version is higher than the current version.
51
+ * Ports the C# Installer.ShouldUpdateVersion() logic.
52
+ */
53
+ export function shouldUpdateVersion(currentVersion, newVersion) {
54
+ if (!currentVersion)
55
+ return true;
56
+ if (!newVersion)
57
+ return false;
58
+ // Skip automatic update for non-semver specs (file:, git+, http, etc.)
59
+ const nonSemverPrefixes = ['file:', 'git+', 'http:', 'https:'];
60
+ if (nonSemverPrefixes.some((prefix) => currentVersion.startsWith(prefix))) {
61
+ return false;
62
+ }
63
+ const current = semver.valid(semver.coerce(currentVersion));
64
+ const target = semver.valid(semver.coerce(newVersion));
65
+ if (current && target) {
66
+ return semver.gt(target, current);
67
+ }
68
+ // Fallback to string comparison
69
+ return newVersion.localeCompare(currentVersion) > 0;
70
+ }
71
+ /**
72
+ * Add Unity-MCP plugin to a Unity project's Packages/manifest.json.
73
+ * Ports the C# Installer.Manifest.cs logic:
74
+ * - Adds OpenUPM scoped registry with required scopes
75
+ * - Adds/updates the plugin dependency (never downgrades)
76
+ */
77
+ export function addPluginToManifest(projectPath, version) {
78
+ const manifestPath = path.join(projectPath, 'Packages', 'manifest.json');
79
+ if (!fs.existsSync(manifestPath)) {
80
+ throw new Error(`manifest.json not found at: ${manifestPath}`);
81
+ }
82
+ const rawJson = fs.readFileSync(manifestPath, 'utf-8');
83
+ const manifest = JSON.parse(rawJson);
84
+ let modified = false;
85
+ // --- Ensure scopedRegistries array exists
86
+ if (!manifest.scopedRegistries) {
87
+ manifest.scopedRegistries = [];
88
+ modified = true;
89
+ }
90
+ // --- Find or create the OpenUPM registry
91
+ let openUpmRegistry = manifest.scopedRegistries.find((r) => r.name === REGISTRY_NAME);
92
+ if (!openUpmRegistry) {
93
+ openUpmRegistry = {
94
+ name: REGISTRY_NAME,
95
+ url: REGISTRY_URL,
96
+ scopes: [],
97
+ };
98
+ manifest.scopedRegistries.push(openUpmRegistry);
99
+ modified = true;
100
+ }
101
+ // --- Add missing scopes
102
+ if (!openUpmRegistry.scopes) {
103
+ openUpmRegistry.scopes = [];
104
+ modified = true;
105
+ }
106
+ for (const scope of REQUIRED_SCOPES) {
107
+ if (!openUpmRegistry.scopes.includes(scope)) {
108
+ openUpmRegistry.scopes.push(scope);
109
+ modified = true;
110
+ }
111
+ }
112
+ // --- Add/update dependency (version-aware, never downgrade)
113
+ if (!manifest.dependencies) {
114
+ manifest.dependencies = {};
115
+ modified = true;
116
+ }
117
+ const currentVersion = manifest.dependencies[PACKAGE_ID];
118
+ if (!currentVersion || shouldUpdateVersion(currentVersion, version)) {
119
+ manifest.dependencies[PACKAGE_ID] = version;
120
+ modified = true;
121
+ }
122
+ else {
123
+ console.log(`Plugin already at version ${currentVersion} (>= ${version}). Skipping version update.`);
124
+ }
125
+ // --- Write back
126
+ if (modified) {
127
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
128
+ console.log(`Updated ${manifestPath}`);
129
+ }
130
+ else {
131
+ console.log('manifest.json is already up to date.');
132
+ }
133
+ }
134
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generate a deterministic port from a directory path.
3
+ * Ports the C# UnityMcpPlugin.GeneratePortFromDirectory() logic.
4
+ * SHA256 hash of lowercased directory → first 4 bytes as uint32 → modulo 10000 + 50000.
5
+ */
6
+ export declare function generatePortFromDirectory(dir: string): number;
@@ -0,0 +1,19 @@
1
+ import { createHash } from 'crypto';
2
+ const MIN_PORT = 50000;
3
+ const MAX_PORT = 59999;
4
+ const PORT_RANGE = MAX_PORT - MIN_PORT + 1;
5
+ /**
6
+ * Generate a deterministic port from a directory path.
7
+ * Ports the C# UnityMcpPlugin.GeneratePortFromDirectory() logic.
8
+ * SHA256 hash of lowercased directory → first 4 bytes as uint32 → modulo 10000 + 50000.
9
+ */
10
+ export function generatePortFromDirectory(dir) {
11
+ const hash = createHash('sha256')
12
+ .update(dir.toLowerCase())
13
+ .digest();
14
+ // Read first 4 bytes as little-endian int32, then treat as unsigned
15
+ const int32 = hash.readInt32LE(0);
16
+ const uint32 = int32 >>> 0;
17
+ return MIN_PORT + (uint32 % PORT_RANGE);
18
+ }
19
+ //# sourceMappingURL=port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../../src/utils/port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,MAAM,QAAQ,GAAG,KAAK,CAAC;AACvB,MAAM,QAAQ,GAAG,KAAK,CAAC;AACvB,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAAW;IACnD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC;SAC9B,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;SACzB,MAAM,EAAE,CAAC;IAEZ,oEAAoE;IACpE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,KAAK,CAAC,CAAC;IAE3B,OAAO,QAAQ,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Read the Unity editor version from a project's ProjectSettings/ProjectVersion.txt.
3
+ */
4
+ export declare function getProjectEditorVersion(projectPath: string): string | null;
5
+ /**
6
+ * Find the Unity Editor binary path for a specific version.
7
+ * Uses Unity Hub to locate installed editors.
8
+ */
9
+ export declare function findEditorPath(version?: string): string | null;
10
+ /**
11
+ * Launch Unity Editor with the given project path.
12
+ * Spawns a detached process and returns immediately.
13
+ */
14
+ export declare function launchEditor(editorPath: string, projectPath: string, env?: Record<string, string>): void;
@@ -0,0 +1,180 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { spawn } from 'child_process';
4
+ import { platform } from 'os';
5
+ import { findUnityHub, listInstalledEditors } from './unity-hub.js';
6
+ /**
7
+ * Compare two Unity version strings with numeric-aware sorting.
8
+ * Parses components like "2022.3.62f3" into [2022, 3, 62, "f", 3].
9
+ * Returns negative if a < b, positive if a > b, 0 if equal.
10
+ */
11
+ function compareUnityVersions(a, b) {
12
+ const parseVersion = (v) => {
13
+ const parts = [];
14
+ for (const segment of v.split(/([.\-])/)) {
15
+ // Split each segment further into numeric and alpha tokens
16
+ const tokens = segment.match(/(\d+|[a-zA-Z]+)/g);
17
+ if (tokens) {
18
+ for (const token of tokens) {
19
+ const num = parseInt(token, 10);
20
+ parts.push(isNaN(num) ? token : num);
21
+ }
22
+ }
23
+ }
24
+ return parts;
25
+ };
26
+ const aParts = parseVersion(a);
27
+ const bParts = parseVersion(b);
28
+ const len = Math.max(aParts.length, bParts.length);
29
+ for (let i = 0; i < len; i++) {
30
+ const ap = aParts[i];
31
+ const bp = bParts[i];
32
+ if (ap === undefined && bp === undefined)
33
+ return 0;
34
+ if (ap === undefined)
35
+ return -1;
36
+ if (bp === undefined)
37
+ return 1;
38
+ if (typeof ap === 'number' && typeof bp === 'number') {
39
+ if (ap !== bp)
40
+ return ap - bp;
41
+ }
42
+ else {
43
+ const cmp = String(ap).localeCompare(String(bp));
44
+ if (cmp !== 0)
45
+ return cmp;
46
+ }
47
+ }
48
+ return 0;
49
+ }
50
+ /**
51
+ * Read the Unity editor version from a project's ProjectSettings/ProjectVersion.txt.
52
+ */
53
+ export function getProjectEditorVersion(projectPath) {
54
+ const versionFile = path.join(projectPath, 'ProjectSettings', 'ProjectVersion.txt');
55
+ if (!fs.existsSync(versionFile)) {
56
+ return null;
57
+ }
58
+ const content = fs.readFileSync(versionFile, 'utf-8');
59
+ const match = content.match(/m_EditorVersion:\s*(.+)/);
60
+ return match ? match[1].trim() : null;
61
+ }
62
+ /**
63
+ * Find the Unity Editor binary path for a specific version.
64
+ * Uses Unity Hub to locate installed editors.
65
+ */
66
+ export function findEditorPath(version) {
67
+ const hubPath = findUnityHub();
68
+ if (!hubPath) {
69
+ // Try common default locations
70
+ return findEditorPathByCommonLocations(version);
71
+ }
72
+ const editors = listInstalledEditors(hubPath);
73
+ if (editors.length === 0) {
74
+ return findEditorPathByCommonLocations(version);
75
+ }
76
+ if (version) {
77
+ const match = editors.find((e) => e.version === version);
78
+ if (match)
79
+ return getEditorBinary(match.path);
80
+ }
81
+ // Return the latest editor by version-aware sorting
82
+ const sorted = [...editors].sort((a, b) => compareUnityVersions(b.version, a.version));
83
+ return getEditorBinary(sorted[0].path);
84
+ }
85
+ /**
86
+ * Find editor by checking common installation directories.
87
+ */
88
+ function findEditorPathByCommonLocations(version) {
89
+ const os = platform();
90
+ const candidates = [];
91
+ switch (os) {
92
+ case 'win32': {
93
+ const programFiles = process.env['PROGRAMFILES'] ?? 'C:\\Program Files';
94
+ if (version) {
95
+ candidates.push(path.join(programFiles, 'Unity', 'Hub', 'Editor', version, 'Editor', 'Unity.exe'));
96
+ }
97
+ // Check for any editor
98
+ const hubEditorDir = path.join(programFiles, 'Unity', 'Hub', 'Editor');
99
+ if (fs.existsSync(hubEditorDir)) {
100
+ try {
101
+ const versions = fs.readdirSync(hubEditorDir).sort((a, b) => compareUnityVersions(b, a));
102
+ for (const v of versions) {
103
+ candidates.push(path.join(hubEditorDir, v, 'Editor', 'Unity.exe'));
104
+ }
105
+ }
106
+ catch { /* ignore */ }
107
+ }
108
+ break;
109
+ }
110
+ case 'darwin': {
111
+ if (version) {
112
+ candidates.push(`/Applications/Unity/Hub/Editor/${version}/Unity.app/Contents/MacOS/Unity`);
113
+ }
114
+ const hubEditorDir = '/Applications/Unity/Hub/Editor';
115
+ if (fs.existsSync(hubEditorDir)) {
116
+ try {
117
+ const versions = fs.readdirSync(hubEditorDir).sort((a, b) => compareUnityVersions(b, a));
118
+ for (const v of versions) {
119
+ candidates.push(path.join(hubEditorDir, v, 'Unity.app', 'Contents', 'MacOS', 'Unity'));
120
+ }
121
+ }
122
+ catch { /* ignore */ }
123
+ }
124
+ break;
125
+ }
126
+ case 'linux': {
127
+ if (version) {
128
+ candidates.push(`/opt/unity/hub/Editor/${version}/Editor/Unity`);
129
+ candidates.push(path.join(process.env['HOME'] ?? '', 'Unity', 'Hub', 'Editor', version, 'Editor', 'Unity'));
130
+ }
131
+ for (const baseDir of ['/opt/unity/hub/Editor', path.join(process.env['HOME'] ?? '', 'Unity', 'Hub', 'Editor')]) {
132
+ if (fs.existsSync(baseDir)) {
133
+ try {
134
+ const versions = fs.readdirSync(baseDir).sort((a, b) => compareUnityVersions(b, a));
135
+ for (const v of versions) {
136
+ candidates.push(path.join(baseDir, v, 'Editor', 'Unity'));
137
+ }
138
+ }
139
+ catch { /* ignore */ }
140
+ }
141
+ }
142
+ break;
143
+ }
144
+ }
145
+ for (const candidate of candidates) {
146
+ if (fs.existsSync(candidate)) {
147
+ return candidate;
148
+ }
149
+ }
150
+ return null;
151
+ }
152
+ /**
153
+ * Get the Unity binary path from an editor installation directory.
154
+ */
155
+ function getEditorBinary(editorDir) {
156
+ const os = platform();
157
+ switch (os) {
158
+ case 'win32':
159
+ return path.join(editorDir, 'Editor', 'Unity.exe');
160
+ case 'darwin':
161
+ return path.join(editorDir, 'Unity.app', 'Contents', 'MacOS', 'Unity');
162
+ default:
163
+ return path.join(editorDir, 'Editor', 'Unity');
164
+ }
165
+ }
166
+ /**
167
+ * Launch Unity Editor with the given project path.
168
+ * Spawns a detached process and returns immediately.
169
+ */
170
+ export function launchEditor(editorPath, projectPath, env) {
171
+ const args = ['-projectPath', path.resolve(projectPath)];
172
+ const child = spawn(editorPath, args, {
173
+ detached: true,
174
+ stdio: 'ignore',
175
+ env: { ...process.env, ...env },
176
+ });
177
+ child.unref();
178
+ console.log(`Launched Unity Editor (PID: ${child.pid})`);
179
+ }
180
+ //# sourceMappingURL=unity-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unity-editor.js","sourceRoot":"","sources":["../../src/utils/unity-editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Detect the Unity Hub installation path based on the current platform.
3
+ * Returns the path if found, or null.
4
+ */
5
+ export declare function findUnityHub(): string | null;
6
+ export interface InstalledEditor {
7
+ version: string;
8
+ path: string;
9
+ }
10
+ /**
11
+ * List installed Unity editors via Unity Hub CLI.
12
+ */
13
+ export declare function listInstalledEditors(hubPath: string): InstalledEditor[];
14
+ /**
15
+ * Install a Unity editor version via Unity Hub CLI.
16
+ */
17
+ export declare function installEditor(hubPath: string, version: string): void;
18
+ /**
19
+ * Create a new Unity project via Unity Hub CLI.
20
+ */
21
+ export declare function createProject(hubPath: string, projectPath: string, editorVersion?: string): void;
@@ -0,0 +1,90 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { execFileSync } from 'child_process';
4
+ import { platform } from 'os';
5
+ /**
6
+ * Detect the Unity Hub installation path based on the current platform.
7
+ * Returns the path if found, or null.
8
+ */
9
+ export function findUnityHub() {
10
+ const os = platform();
11
+ const candidates = [];
12
+ switch (os) {
13
+ case 'win32':
14
+ candidates.push(path.join(process.env['PROGRAMFILES'] ?? 'C:\\Program Files', 'Unity Hub', 'Unity Hub.exe'), path.join(process.env['LOCALAPPDATA'] ?? '', 'Programs', 'Unity Hub', 'Unity Hub.exe'));
15
+ break;
16
+ case 'darwin':
17
+ candidates.push('/Applications/Unity Hub.app/Contents/MacOS/Unity Hub');
18
+ break;
19
+ case 'linux':
20
+ candidates.push('/usr/bin/unity-hub', '/snap/bin/unity-hub', path.join(process.env['HOME'] ?? '', 'Applications', 'Unity Hub.AppImage'));
21
+ break;
22
+ }
23
+ for (const candidate of candidates) {
24
+ if (candidate && fs.existsSync(candidate)) {
25
+ return candidate;
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ /**
31
+ * List installed Unity editors via Unity Hub CLI.
32
+ */
33
+ export function listInstalledEditors(hubPath) {
34
+ try {
35
+ const output = execFileSync(hubPath, ['--', '--headless', 'editors', '--installed'], {
36
+ encoding: 'utf-8',
37
+ timeout: 30000,
38
+ });
39
+ const editors = [];
40
+ for (const line of output.split('\n')) {
41
+ const trimmed = line.trim();
42
+ if (!trimmed)
43
+ continue;
44
+ // Format: "2022.3.62f3 , installed at /path/to/editor"
45
+ const match = trimmed.match(/^([\d.]+\w*)\s*,?\s*installed at\s+(.+)$/i);
46
+ if (match) {
47
+ editors.push({ version: match[1], path: match[2].trim() });
48
+ }
49
+ }
50
+ return editors;
51
+ }
52
+ catch (err) {
53
+ console.error('Failed to list installed editors:', err.message);
54
+ return [];
55
+ }
56
+ }
57
+ /**
58
+ * Install a Unity editor version via Unity Hub CLI.
59
+ */
60
+ export function installEditor(hubPath, version) {
61
+ console.log(`Installing Unity Editor ${version} via Unity Hub...`);
62
+ try {
63
+ execFileSync(hubPath, ['--', '--headless', 'install', '--version', version], { encoding: 'utf-8', timeout: 600000, stdio: 'inherit' });
64
+ }
65
+ catch (err) {
66
+ throw new Error(`Failed to install Unity Editor ${version}: ${err.message}`);
67
+ }
68
+ }
69
+ /**
70
+ * Create a new Unity project via Unity Hub CLI.
71
+ */
72
+ export function createProject(hubPath, projectPath, editorVersion) {
73
+ const args = ['--', '--headless', 'create', '-projectPath', projectPath];
74
+ if (editorVersion) {
75
+ args.push('-version', editorVersion);
76
+ }
77
+ console.log(`Creating Unity project at: ${projectPath}`);
78
+ try {
79
+ execFileSync(hubPath, args, {
80
+ encoding: 'utf-8',
81
+ timeout: 120000,
82
+ stdio: 'inherit',
83
+ });
84
+ console.log('Project created successfully.');
85
+ }
86
+ catch (err) {
87
+ throw new Error(`Failed to create project: ${err.message}`);
88
+ }
89
+ }
90
+ //# sourceMappingURL=unity-hub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unity-hub.js","sourceRoot":"","sources":["../../src/utils/unity-hub.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAE9B;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,OAAO;YACV,UAAU,CAAC,IAAI,CACb,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,mBAAmB,EAAE,WAAW,EAAE,eAAe,CAAC,EAC3F,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,CAAC,CACvF,CAAC;YACF,MAAM;QACR,KAAK,QAAQ;YACX,UAAU,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;YACxE,MAAM;QACR,KAAK,OAAO;YACV,UAAU,CAAC,IAAI,CACb,oBAAoB,EACpB,qBAAqB,EACrB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,oBAAoB,CAAC,CAC3E,CAAC;YACF,MAAM;IACV,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,SAAS,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1C,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAOD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE;YACnF,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,uDAAuD;YACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;YACzE,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;QAC3E,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAe;IAC5D,OAAO,CAAC,GAAG,CAAC,2BAA2B,OAAO,mBAAmB,CAAC,CAAC;IACnE,IAAI,CAAC;QACH,YAAY,CACV,OAAO,EACP,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,EACrD,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CACzD,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,WAAmB,EAAE,aAAsB;IACxF,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IACzE,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE;YAC1B,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,6BAA8B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "unity-mcp-cli",
3
+ "version": "0.51.6",
4
+ "description": "Cross-platform CLI tool for Unity-MCP operations — create projects, install plugins, configure tools, and manage MCP connections",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "unity-mcp": "bin/unity-mcp.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "pretest": "npm run build",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "unity",
19
+ "mcp",
20
+ "model-context-protocol",
21
+ "ai",
22
+ "cli"
23
+ ],
24
+ "author": "Ivan Murzak",
25
+ "license": "Apache-2.0",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/IvanMurzak/Unity-MCP.git",
29
+ "directory": "cli"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "commander": "^13.1.0",
36
+ "semver": "^7.7.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.15.0",
40
+ "@types/semver": "^7.7.0",
41
+ "typescript": "^5.8.0",
42
+ "vitest": "^3.1.0"
43
+ }
44
+ }