@npgamedev/godot-mcp-server 0.0.1 → 1.0.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/ATTRIBUTIONS.md +141 -0
- package/LICENSE +28 -0
- package/README.md +386 -4
- package/dist/extensions/extensionChanges.js +131 -0
- package/dist/extensions/extensionCommand.js +25 -0
- package/dist/extensions/extensionDiscovery.js +141 -0
- package/dist/extensions/extensionRegistrar.js +82 -0
- package/dist/extensions/extensions.js +33 -0
- package/dist/groups/builtinGroups.js +60 -0
- package/dist/groups/defs/3dTools.js +17 -0
- package/dist/groups/defs/animationAuthoring.js +16 -0
- package/dist/groups/defs/assetOps.js +6 -0
- package/dist/groups/defs/audio.js +6 -0
- package/dist/groups/defs/classdb.js +6 -0
- package/dist/groups/defs/cleanup.js +6 -0
- package/dist/groups/defs/debugger.js +6 -0
- package/dist/groups/defs/editorAdvanced.js +16 -0
- package/dist/groups/defs/inputMap.js +6 -0
- package/dist/groups/defs/layerNaming.js +6 -0
- package/dist/groups/defs/lspCodeAnalysis.js +23 -0
- package/dist/groups/defs/lspCodeNavigation.js +15 -0
- package/dist/groups/defs/navigation.js +17 -0
- package/dist/groups/defs/particles.js +21 -0
- package/dist/groups/defs/pathEditing.js +22 -0
- package/dist/groups/defs/placeholders.js +28 -0
- package/dist/groups/defs/procedural.js +6 -0
- package/dist/groups/defs/resourceIo.js +6 -0
- package/dist/groups/defs/runtimeAdvanced.js +17 -0
- package/dist/groups/defs/sceneAdvanced.js +6 -0
- package/dist/groups/defs/sceneInheritance.js +6 -0
- package/dist/groups/defs/signals.js +6 -0
- package/dist/groups/defs/spriteframes.js +16 -0
- package/dist/groups/defs/theme.js +6 -0
- package/dist/groups/defs/tilemap.js +6 -0
- package/dist/groups/defs/tileset.js +22 -0
- package/dist/groups/defs/tilesetEdit.js +21 -0
- package/dist/groups/defs/userData.js +6 -0
- package/dist/groups/extensionGroups.js +182 -0
- package/dist/groups/groupActivation.js +210 -0
- package/dist/groups/groupCatalogue.js +52 -0
- package/dist/groups/groupMatch.js +182 -0
- package/dist/groups/groupResult.js +16 -0
- package/dist/groups/groupState.js +15 -0
- package/dist/groups/groupToolHandlers.js +103 -0
- package/dist/groups/groupTypes.js +10 -0
- package/dist/groups/groups.js +205 -0
- package/dist/index.js +144 -0
- package/dist/lsp/lspClient.js +509 -0
- package/dist/lsp/lspLabels.js +105 -0
- package/dist/lsp/lspProjectScan.js +156 -0
- package/dist/lsp/lspSession.js +139 -0
- package/dist/lsp/lspStatusReporter.js +76 -0
- package/dist/lsp/lspUri.js +68 -0
- package/dist/mcp/prompts.js +59 -0
- package/dist/mcp/resources.js +113 -0
- package/dist/mcp/roots.js +30 -0
- package/dist/registration/catalogue.js +123 -0
- package/dist/registration/extensionCollision.js +38 -0
- package/dist/registration/operations.js +67 -0
- package/dist/registration/screenshotResponse.js +71 -0
- package/dist/registration/toolDispatch.js +76 -0
- package/dist/registration/toolMeta.js +104 -0
- package/dist/registration/toolRefs.js +48 -0
- package/dist/registration/toolRegistry.js +211 -0
- package/dist/registry.js +291 -0
- package/dist/registryLiveness.js +113 -0
- package/dist/security/pathGuard.js +97 -0
- package/dist/security/profiles.js +104 -0
- package/dist/security/untrusted.js +23 -0
- package/dist/shared/errorContract.js +154 -0
- package/dist/shared/errors.js +21 -0
- package/dist/shared/pagination.js +135 -0
- package/dist/shared/schemaCoercion.js +173 -0
- package/dist/shared/stableJson.js +27 -0
- package/dist/shared/types.js +1 -0
- package/dist/shared/version.js +82 -0
- package/dist/startup/cliArgs.js +103 -0
- package/dist/startup/configReload.js +57 -0
- package/dist/startup/hooks.js +89 -0
- package/dist/startup/lifecycle.js +22 -0
- package/dist/startup/portConfig.js +127 -0
- package/dist/startup/reconcile.js +81 -0
- package/dist/startup/registrars.js +59 -0
- package/dist/startup/serverMode.js +19 -0
- package/dist/startup/startupEnv.js +142 -0
- package/dist/tools/animation.js +88 -0
- package/dist/tools/asset.js +58 -0
- package/dist/tools/assetWrite.js +16 -0
- package/dist/tools/audio.js +40 -0
- package/dist/tools/classdb.js +43 -0
- package/dist/tools/collision.js +23 -0
- package/dist/tools/debug.js +46 -0
- package/dist/tools/diff.js +18 -0
- package/dist/tools/editor.js +222 -0
- package/dist/tools/file.js +38 -0
- package/dist/tools/folder.js +27 -0
- package/dist/tools/inputMap.js +54 -0
- package/dist/tools/layerNames.js +29 -0
- package/dist/tools/lsp.js +524 -0
- package/dist/tools/navigation.js +24 -0
- package/dist/tools/node.js +145 -0
- package/dist/tools/nodeManagement.js +82 -0
- package/dist/tools/particles.js +83 -0
- package/dist/tools/path.js +30 -0
- package/dist/tools/playtest.js +99 -0
- package/dist/tools/procedural.js +101 -0
- package/dist/tools/resource.js +47 -0
- package/dist/tools/runtime.js +338 -0
- package/dist/tools/save.js +64 -0
- package/dist/tools/scene.js +102 -0
- package/dist/tools/sceneInheritance.js +19 -0
- package/dist/tools/sceneQuery.js +38 -0
- package/dist/tools/script.js +75 -0
- package/dist/tools/signals.js +53 -0
- package/dist/tools/sound.js +31 -0
- package/dist/tools/spatial.js +41 -0
- package/dist/tools/spriteframes.js +94 -0
- package/dist/tools/texture.js +35 -0
- package/dist/tools/theme.js +35 -0
- package/dist/tools/threeD.js +116 -0
- package/dist/tools/tilemap.js +51 -0
- package/dist/tools/tileset.js +226 -0
- package/dist/transport/authHandshake.js +43 -0
- package/dist/transport/bridge.js +225 -0
- package/dist/transport/channel.js +352 -0
- package/dist/transport/heartbeat.js +54 -0
- package/dist/transport/runtimeConnection.js +239 -0
- package/dist/transport/tokenPath.js +98 -0
- package/package.json +97 -4
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the per-instance session token the toolkit published into the registry.
|
|
3
|
+
*
|
|
4
|
+
* The toolkit is authoritative for the token's on-disk LOCATION. At its registry
|
|
5
|
+
* publish sites it globalizes the `user://` token path to an absolute path —
|
|
6
|
+
* honoring `application/config/use_custom_user_dir` live — and writes that into the
|
|
7
|
+
* project's registry entry. This module looks up `entry.token_path`, asserts the
|
|
8
|
+
* published path STRUCTURALLY (absolute, no traversal, the invariant
|
|
9
|
+
* `…/project_instance_<hash>/mcp_token` shape), confirms it is a regular file, and
|
|
10
|
+
* returns its contents. It does NOT re-derive the path: no project-name resolution,
|
|
11
|
+
* no per-OS user-dir reconstruction, no hash recompute.
|
|
12
|
+
*
|
|
13
|
+
* `GODOT_MCP_TOKEN_PATH` is an explicit operator override — a trusted absolute path
|
|
14
|
+
* to an existing file, read directly without the registry or the suffix shape check
|
|
15
|
+
* (it may point anywhere, e.g. a test-harness temp dir).
|
|
16
|
+
*
|
|
17
|
+
* Pure path/filesystem logic — no wire protocol, no channel/auth coupling.
|
|
18
|
+
* `assertPublishedTokenPath` is exported for direct unit testing; the transport
|
|
19
|
+
* imports only `readToken`.
|
|
20
|
+
*/
|
|
21
|
+
import { readFile, stat } from "node:fs/promises";
|
|
22
|
+
import { BridgeError } from "../shared/errors.js";
|
|
23
|
+
import { lookupProject } from "../registry.js";
|
|
24
|
+
/** Absolute path: POSIX `/…`, Windows `<drive>:/…`, or UNC `//…` (normalize `\`→`/` first). */
|
|
25
|
+
const ABSOLUTE_PATH = /^([A-Za-z]:\/|\/)/;
|
|
26
|
+
/**
|
|
27
|
+
* Validate a registry-published token path before opening it. The toolkit
|
|
28
|
+
* publishes an absolute, globalized path; this re-asserts the shape a moved or
|
|
29
|
+
* stale registry (or a hand-set value) could otherwise corrupt. Lexical only —
|
|
30
|
+
* symlink resolution is out of scope (single-user localhost threat model). Throws
|
|
31
|
+
* `AUTH_FAILED` on any violation.
|
|
32
|
+
*/
|
|
33
|
+
export function assertPublishedTokenPath(published) {
|
|
34
|
+
const norm = published.replace(/\\/g, "/");
|
|
35
|
+
// A regex (not path.isAbsolute) keeps the check platform-independent, so a
|
|
36
|
+
// Windows-shaped path validates the same on a POSIX CI runner.
|
|
37
|
+
if (!ABSOLUTE_PATH.test(norm)) {
|
|
38
|
+
throw new BridgeError("AUTH_FAILED", `published token path is not absolute: ${published}`);
|
|
39
|
+
}
|
|
40
|
+
if (norm.split("/").includes("..")) {
|
|
41
|
+
throw new BridgeError("AUTH_FAILED", `published token path contains '..': ${published}`);
|
|
42
|
+
}
|
|
43
|
+
// Invariant suffix — a FORMAT check on the 12-hex instance segment, never a
|
|
44
|
+
// recomputed hash (recomputing would re-add the cross-repo derivation this module
|
|
45
|
+
// exists to remove).
|
|
46
|
+
if (!/(?:^|\/)addons\/godot_mcp_toolkit\/project_instance_[0-9a-f]{12}\/mcp_token$/.test(norm)) {
|
|
47
|
+
throw new BridgeError("AUTH_FAILED", `published token path has an unexpected shape: ${published} — expected …/addons/godot_mcp_toolkit/project_instance_<hash>/mcp_token`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Read the session token from disk. Re-reads on every call (no caching) so a
|
|
52
|
+
* reconnect after a plugin restart picks up the rotated token.
|
|
53
|
+
*
|
|
54
|
+
* @param projectPath absolute project root, used as the registry key. Production
|
|
55
|
+
* always passes a concrete path; the cwd fallback is a test-only convenience.
|
|
56
|
+
* @returns the trimmed token contents.
|
|
57
|
+
* @throws BridgeError `AUTH_FAILED` — no registry entry, an empty or malformed
|
|
58
|
+
* published path, or a missing/unreadable token file (each with a distinct,
|
|
59
|
+
* actionable message).
|
|
60
|
+
*/
|
|
61
|
+
export async function readToken(projectPath) {
|
|
62
|
+
// Operator override: a trusted absolute path read directly, bypassing the
|
|
63
|
+
// registry and the suffix shape check (still required to be an existing file).
|
|
64
|
+
const envPath = process.env.GODOT_MCP_TOKEN_PATH;
|
|
65
|
+
if (envPath) {
|
|
66
|
+
if (!ABSOLUTE_PATH.test(envPath.replace(/\\/g, "/"))) {
|
|
67
|
+
throw new BridgeError("AUTH_FAILED", `GODOT_MCP_TOKEN_PATH must be an absolute path: ${envPath}`);
|
|
68
|
+
}
|
|
69
|
+
return readRegularFile(envPath, `GODOT_MCP_TOKEN_PATH points at no readable file: ${envPath}`);
|
|
70
|
+
}
|
|
71
|
+
const key = projectPath ?? process.cwd();
|
|
72
|
+
const entry = lookupProject(key);
|
|
73
|
+
if (!entry) {
|
|
74
|
+
throw new BridgeError("AUTH_FAILED", `no registry entry for ${key} — is the Godot editor running with the MCP toolkit plugin? Reconnect or relaunch.`);
|
|
75
|
+
}
|
|
76
|
+
const published = entry.token_path;
|
|
77
|
+
if (!published) {
|
|
78
|
+
throw new BridgeError("AUTH_FAILED", `registry entry for ${key} has no token path — the editor may not have published yet; relaunch the editor.`);
|
|
79
|
+
}
|
|
80
|
+
assertPublishedTokenPath(published);
|
|
81
|
+
return readRegularFile(published, `token file not found at published path ${published} — the project may have moved; reconnect or relaunch the editor.`);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read a regular file's trimmed contents, throwing `AUTH_FAILED` with `failMsg` if
|
|
85
|
+
* it is missing, not a regular file, or unreadable. Shared by the operator-override
|
|
86
|
+
* and registry-published read paths so both fail with one actionable message.
|
|
87
|
+
*/
|
|
88
|
+
async function readRegularFile(path, failMsg) {
|
|
89
|
+
try {
|
|
90
|
+
const info = await stat(path);
|
|
91
|
+
if (!info.isFile())
|
|
92
|
+
throw new Error("not a regular file");
|
|
93
|
+
return (await readFile(path, "utf-8")).trim();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new BridgeError("AUTH_FAILED", failMsg);
|
|
97
|
+
}
|
|
98
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,101 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npgamedev/godot-mcp-server",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server that connects AI coding assistants to the Godot 4.2+ editor (scenes, nodes, scripts, ClassDB, playtests) via the companion godot-mcp-toolkit plugin.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"godot-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"ATTRIBUTIONS.md"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22"
|
|
18
|
+
},
|
|
5
19
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/NPGameDev/godot-mcp-server.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/NPGameDev/godot-mcp-server/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/NPGameDev/godot-mcp-server#readme",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"clean": "node -e \"import('node:fs').then(fs => fs.rmSync('dist', { recursive: true, force: true }))\"",
|
|
33
|
+
"build": "npm run clean && tsc",
|
|
34
|
+
"postbuild": "node scripts/add-shebang.mjs",
|
|
35
|
+
"docs:api": "typedoc",
|
|
36
|
+
"docs:tools": "tsx scripts/generate-tool-reference.ts",
|
|
37
|
+
"docs:tools:check": "tsx scripts/generate-tool-reference.ts --check",
|
|
38
|
+
"measure:tokens": "tsx scripts/measure-tokens.ts",
|
|
39
|
+
"start": "node dist/index.js",
|
|
40
|
+
"smoke": "tsx test/run-smoke.ts",
|
|
41
|
+
"smoke:single": "tsx test/smoke.ts",
|
|
42
|
+
"smoke:ci": "tsx test/smoke.ts --ci",
|
|
43
|
+
"flows": "tsx test/run-flows.ts",
|
|
44
|
+
"flows:single": "tsx test/flows.ts",
|
|
45
|
+
"fixture:inject-addon": "node scripts/inject-fixture-addon.mjs",
|
|
46
|
+
"eval": "tsx test/eval/eval-runner.ts",
|
|
47
|
+
"test:unit": "tsx test/unit/run-all.ts",
|
|
48
|
+
"test:integration:dispatch": "tsx test/integration/dispatch/run.ts",
|
|
49
|
+
"test:integration:portpin": "tsx test/integration/port-pin-probe.ts",
|
|
50
|
+
"repro:lsp-conflict": "tsx test/integration/lsp-conflict-repro.ts",
|
|
51
|
+
"probe:screenshot": "tsx test/screenshot-window-probe.ts",
|
|
52
|
+
"stress:dispatch": "tsx test/integration/dispatch-safety-stress.ts",
|
|
53
|
+
"lint": "eslint src/ test/",
|
|
54
|
+
"lint:fix": "eslint src/ test/ --fix",
|
|
55
|
+
"lint:pkg": "publint",
|
|
56
|
+
"format": "prettier --check .",
|
|
57
|
+
"format:fix": "prettier --write .",
|
|
58
|
+
"check:arch": "bash scripts/check_arch_freshness.sh",
|
|
59
|
+
"audit": "npm audit --omit=dev",
|
|
60
|
+
"prepublishOnly": "npm run build"
|
|
61
|
+
},
|
|
62
|
+
"keywords": [
|
|
63
|
+
"mcp",
|
|
64
|
+
"godot",
|
|
65
|
+
"claude",
|
|
66
|
+
"model-context-protocol",
|
|
67
|
+
"ai",
|
|
68
|
+
"editor",
|
|
69
|
+
"plugin",
|
|
70
|
+
"gamedev"
|
|
71
|
+
],
|
|
72
|
+
"author": "NPGameDev <np@npgamedev.com> (https://npgamedev.com)",
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@eslint/js": "10.0.1",
|
|
75
|
+
"@sinonjs/fake-timers": "^15.4.0",
|
|
76
|
+
"@types/node": "25.6.0",
|
|
77
|
+
"@types/sinonjs__fake-timers": "^15.0.1",
|
|
78
|
+
"@types/ws": "8.18.1",
|
|
79
|
+
"eslint": "10.2.1",
|
|
80
|
+
"eslint-config-prettier": "10.1.8",
|
|
81
|
+
"prettier": "3.8.3",
|
|
82
|
+
"publint": "0.3.21",
|
|
83
|
+
"tsx": "4.23.0",
|
|
84
|
+
"typedoc": "0.28.19",
|
|
85
|
+
"typedoc-plugin-markdown": "4.12.0",
|
|
86
|
+
"typescript": "6.0.3",
|
|
87
|
+
"typescript-eslint": "8.59.0"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
91
|
+
"ws": "8.21.0",
|
|
92
|
+
"zod": "4.3.6"
|
|
93
|
+
},
|
|
94
|
+
"overrides": {
|
|
95
|
+
"fast-uri": "^3.1.4"
|
|
96
|
+
},
|
|
97
|
+
"allowScripts": {
|
|
98
|
+
"esbuild@0.28.1": true,
|
|
99
|
+
"fsevents@2.3.3": true
|
|
100
|
+
}
|
|
8
101
|
}
|