threenative-engine-mcp 0.2.3 → 0.2.5
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/dist/index.d.ts +11 -2
- package/dist/index.js +55 -21
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface ICapabilityEntry {
|
|
|
11
11
|
readonly constraints: readonly string[];
|
|
12
12
|
readonly overrides?: readonly string[];
|
|
13
13
|
readonly requires?: readonly string[];
|
|
14
|
+
/** Absent unless something on this entry is deprecated; each string names what, and what to use. */
|
|
15
|
+
readonly deprecated?: readonly string[];
|
|
14
16
|
}
|
|
15
17
|
interface INotOwnedCapability {
|
|
16
18
|
readonly id: string;
|
|
@@ -65,7 +67,14 @@ declare function defaultManifestPath(cwd?: string): string;
|
|
|
65
67
|
declare function loadCapabilityManifest(file?: string): ICapabilityManifest;
|
|
66
68
|
declare function capabilitySituationTokens(value: string): string[];
|
|
67
69
|
declare function searchCapabilities(situation: string, manifestFile?: string, scope?: "mechanic" | "request"): ICapabilitySearchResponse;
|
|
68
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Every manifest entry named `symbol` (optionally in one `importPath`); throws when there is none.
|
|
72
|
+
* Two packages can export one name (`createThreeObject` from raw-unreal and ueformat), so a lookup
|
|
73
|
+
* by name alone must return both — answering with the first hides the second from detail.
|
|
74
|
+
*/
|
|
75
|
+
declare function capabilityDetails(symbol: string, manifestFile?: string, importPath?: string): readonly ICapabilityDetail[];
|
|
76
|
+
/** One capability's detail; code callers must name `importPath` when the symbol is shared. */
|
|
77
|
+
declare function capabilityDetail(symbol: string, manifestFile?: string, importPath?: string): ICapabilityDetail;
|
|
69
78
|
declare function toolDefinitions(): readonly IEngineTool[];
|
|
70
79
|
/**
|
|
71
80
|
* Handles one raw stdin line and returns the JSON-RPC response to write, or `undefined` when the
|
|
@@ -75,4 +84,4 @@ declare function toolDefinitions(): readonly IEngineTool[];
|
|
|
75
84
|
declare function handleLine(line: string, manifestFile: string): string | undefined;
|
|
76
85
|
declare function runServer(manifestFile?: string): void;
|
|
77
86
|
|
|
78
|
-
export { ENGINE_MCP_TOOL_NAMES, type ICapabilityDetail, type ICapabilityEntry, type ICapabilityManifest, type ICapabilitySearchResponse, type ICapabilitySearchResult, type IEngineTool, type INotOwnedCapability, RELEVANCE_FLOOR, capabilityDetail, capabilitySituationTokens, defaultManifestPath, handleLine, loadCapabilityManifest, runServer, searchCapabilities, toolDefinitions };
|
|
87
|
+
export { ENGINE_MCP_TOOL_NAMES, type ICapabilityDetail, type ICapabilityEntry, type ICapabilityManifest, type ICapabilitySearchResponse, type ICapabilitySearchResult, type IEngineTool, type INotOwnedCapability, RELEVANCE_FLOOR, capabilityDetail, capabilityDetails, capabilitySituationTokens, defaultManifestPath, handleLine, loadCapabilityManifest, runServer, searchCapabilities, toolDefinitions };
|
package/dist/index.js
CHANGED
|
@@ -131,14 +131,13 @@ function defaultManifestPath(cwd = process.cwd()) {
|
|
|
131
131
|
const override = process.env.THREENATIVE_CAPABILITIES_MANIFEST;
|
|
132
132
|
if (override !== void 0 && override.trim().length > 0) return path.resolve(cwd, override);
|
|
133
133
|
for (let directory = path.resolve(cwd); ; directory = path.dirname(directory)) {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (existsSync(installed)) return installed;
|
|
134
|
+
const nodeModules = path.join(directory, "node_modules");
|
|
135
|
+
const installed = path.join(nodeModules, "@threenative", "core", "capabilities.json");
|
|
136
|
+
if (existsSync(installed)) {
|
|
137
|
+
const relative = path.relative(realpathSync(directory), realpathSync(nodeModules));
|
|
138
|
+
if (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
139
|
+
return installed;
|
|
140
|
+
}
|
|
142
141
|
const parent = path.dirname(directory);
|
|
143
142
|
if (parent === directory) break;
|
|
144
143
|
}
|
|
@@ -156,6 +155,9 @@ function manifestError(file, reason) {
|
|
|
156
155
|
function isRecord(value) {
|
|
157
156
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
158
157
|
}
|
|
158
|
+
function isStringArray(value) {
|
|
159
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
160
|
+
}
|
|
159
161
|
function validateManifest(value, file) {
|
|
160
162
|
if (!isRecord(value) || value.version !== 2 || !Array.isArray(value.entries) || !Array.isArray(value.notOwned)) {
|
|
161
163
|
throw manifestError(
|
|
@@ -164,7 +166,7 @@ function validateManifest(value, file) {
|
|
|
164
166
|
);
|
|
165
167
|
}
|
|
166
168
|
for (const [index, raw] of value.entries.entries()) {
|
|
167
|
-
if (!isRecord(raw) || typeof raw.symbol !== "string" || typeof raw.package !== "string" || typeof raw.importPath !== "string" || typeof raw.kind !== "string" || typeof raw.signature !== "string" || typeof raw.summary !== "string" || typeof raw.example !== "string" || !Array.isArray(raw.situations) || !Array.isArray(raw.aliases) || !Array.isArray(raw.constraints) || raw.requires !== void 0 && !
|
|
169
|
+
if (!isRecord(raw) || typeof raw.symbol !== "string" || typeof raw.package !== "string" || typeof raw.importPath !== "string" || typeof raw.kind !== "string" || typeof raw.signature !== "string" || typeof raw.summary !== "string" || typeof raw.example !== "string" || !Array.isArray(raw.situations) || !Array.isArray(raw.aliases) || !Array.isArray(raw.constraints) || raw.requires !== void 0 && !isStringArray(raw.requires) || raw.deprecated !== void 0 && !isStringArray(raw.deprecated) || !raw.situations.every((situation) => typeof situation === "string") || !raw.aliases.every((alias) => typeof alias === "string") || !raw.constraints.every((constraint) => typeof constraint === "string")) {
|
|
168
170
|
throw manifestError(file, `entry ${index} is malformed`);
|
|
169
171
|
}
|
|
170
172
|
}
|
|
@@ -375,13 +377,25 @@ function searchCapabilities(situation, manifestFile = defaultManifestPath(), sco
|
|
|
375
377
|
verdict: "none"
|
|
376
378
|
};
|
|
377
379
|
}
|
|
378
|
-
function
|
|
380
|
+
function capabilityDetails(symbol, manifestFile = defaultManifestPath(), importPath) {
|
|
379
381
|
if (typeof symbol !== "string" || symbol.trim().length === 0)
|
|
380
382
|
throw new Error("engine_capability_detail requires a non-empty symbol string.");
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
383
|
+
const matches = loadCapabilityManifest(manifestFile).entries.filter(
|
|
384
|
+
(candidate) => candidate.symbol === symbol && (importPath === void 0 || candidate.importPath === importPath)
|
|
385
|
+
);
|
|
386
|
+
if (matches.length === 0)
|
|
387
|
+
throw new Error(
|
|
388
|
+
`Unknown engine capability '${symbol}'${importPath === void 0 ? "" : ` in '${importPath}'`}.`
|
|
389
|
+
);
|
|
390
|
+
return matches;
|
|
391
|
+
}
|
|
392
|
+
function capabilityDetail(symbol, manifestFile = defaultManifestPath(), importPath) {
|
|
393
|
+
const matches = capabilityDetails(symbol, manifestFile, importPath);
|
|
394
|
+
if (matches.length > 1)
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Ambiguous engine capability '${symbol}': pass importPath, one of ${matches.map((match) => `'${match.importPath}'`).join(", ")}.`
|
|
397
|
+
);
|
|
398
|
+
return matches[0];
|
|
385
399
|
}
|
|
386
400
|
var TOOL_DEFINITIONS = [
|
|
387
401
|
{
|
|
@@ -405,10 +419,16 @@ var TOOL_DEFINITIONS = [
|
|
|
405
419
|
{
|
|
406
420
|
annotations: { destructiveHint: false, openWorldHint: false, readOnlyHint: true },
|
|
407
421
|
name: "engine_capability_detail",
|
|
408
|
-
description: "Inspect one engine capability's import, signature, example, constraints, and overrides.",
|
|
422
|
+
description: "Inspect one engine capability's import, signature, example, constraints, and overrides. When several packages export the symbol, every match is returned under `matches`.",
|
|
409
423
|
inputSchema: {
|
|
410
424
|
additionalProperties: false,
|
|
411
|
-
properties: {
|
|
425
|
+
properties: {
|
|
426
|
+
importPath: {
|
|
427
|
+
description: "The search result's importPath; required when two packages export the same symbol.",
|
|
428
|
+
type: "string"
|
|
429
|
+
},
|
|
430
|
+
symbol: { type: "string" }
|
|
431
|
+
},
|
|
412
432
|
required: ["symbol"],
|
|
413
433
|
type: "object"
|
|
414
434
|
}
|
|
@@ -452,7 +472,7 @@ function handleToolCall(params, manifestFile) {
|
|
|
452
472
|
if (name === "engine_search_capabilities") {
|
|
453
473
|
if (typeof argumentsValue.situation !== "string")
|
|
454
474
|
throw new Error("engine_search_capabilities requires a string 'situation' argument.");
|
|
455
|
-
const scope = argumentsValue.scope
|
|
475
|
+
const scope = argumentsValue.scope === void 0 ? "mechanic" : argumentsValue.scope;
|
|
456
476
|
if (scope !== "request" && scope !== "mechanic")
|
|
457
477
|
throw new Error("engine_search_capabilities scope must be 'request' or 'mechanic'.");
|
|
458
478
|
const response = searchCapabilities(argumentsValue.situation, manifestFile, scope);
|
|
@@ -468,8 +488,22 @@ function handleToolCall(params, manifestFile) {
|
|
|
468
488
|
if (name === "engine_capability_detail") {
|
|
469
489
|
if (typeof argumentsValue.symbol !== "string")
|
|
470
490
|
throw new Error("engine_capability_detail requires a string 'symbol' argument.");
|
|
471
|
-
|
|
472
|
-
|
|
491
|
+
if (argumentsValue.importPath !== void 0 && typeof argumentsValue.importPath !== "string")
|
|
492
|
+
throw new Error("engine_capability_detail 'importPath' must be a string when given.");
|
|
493
|
+
const matches = capabilityDetails(
|
|
494
|
+
argumentsValue.symbol,
|
|
495
|
+
manifestFile,
|
|
496
|
+
argumentsValue.importPath
|
|
497
|
+
);
|
|
498
|
+
const detail = matches.length === 1 ? matches[0] : {
|
|
499
|
+
guidance: `${matches.length} packages export '${argumentsValue.symbol}'. Import the match whose summary fits; pass importPath to get one.`,
|
|
500
|
+
matches
|
|
501
|
+
};
|
|
502
|
+
logToolCall({
|
|
503
|
+
importPath: argumentsValue.importPath,
|
|
504
|
+
symbol: argumentsValue.symbol,
|
|
505
|
+
tool: name
|
|
506
|
+
});
|
|
473
507
|
return toolText(detail);
|
|
474
508
|
}
|
|
475
509
|
throw new Error(`Unknown engine MCP tool '${String(name)}'.`);
|
|
@@ -490,7 +524,7 @@ function handleLine(line, manifestFile) {
|
|
|
490
524
|
capabilities: { tools: { listChanged: false } },
|
|
491
525
|
instructions: AUTHORING_INSTRUCTIONS,
|
|
492
526
|
protocolVersion: "2025-06-18",
|
|
493
|
-
serverInfo: { name: "threenative-engine-mcp", version: "0.2.
|
|
527
|
+
serverInfo: { name: "threenative-engine-mcp", version: "0.2.5" }
|
|
494
528
|
});
|
|
495
529
|
}
|
|
496
530
|
if (request.method === "tools/list") {
|
|
@@ -526,4 +560,4 @@ if (entryPath !== void 0 && realpathSync(path.resolve(entryPath)) === realpathSy
|
|
|
526
560
|
}
|
|
527
561
|
}
|
|
528
562
|
|
|
529
|
-
export { ENGINE_MCP_TOOL_NAMES, RELEVANCE_FLOOR, capabilityDetail, capabilitySituationTokens, defaultManifestPath, handleLine, loadCapabilityManifest, runServer, searchCapabilities, toolDefinitions };
|
|
563
|
+
export { ENGINE_MCP_TOOL_NAMES, RELEVANCE_FLOOR, capabilityDetail, capabilityDetails, capabilitySituationTokens, defaultManifestPath, handleLine, loadCapabilityManifest, runServer, searchCapabilities, toolDefinitions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threenative-engine-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Offline MCP capability discovery for ThreeNative authoring agents.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"publint": "0.3.22",
|
|
48
48
|
"tsup": "8.5.1",
|
|
49
|
-
"typescript": "
|
|
49
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
50
|
+
"@typescript/native": "npm:typescript@7.0.2"
|
|
50
51
|
},
|
|
51
52
|
"scripts": {
|
|
52
53
|
"build": "tsup --config tsup.config.ts && publint",
|