wwise-waapi-mcp 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/LICENSE +19 -0
- package/README.md +221 -0
- package/README_ZH.md +221 -0
- package/config/domains.json +130 -0
- package/config/runtime.json +4 -0
- package/dist/src/core/server.js +80 -0
- package/dist/src/core/transport.js +92 -0
- package/dist/src/domains/audio/tools.js +193 -0
- package/dist/src/domains/catalog/tools.js +198 -0
- package/dist/src/domains/debug/tools.js +139 -0
- package/dist/src/domains/example/tools.js +56 -0
- package/dist/src/domains/log/tools.js +79 -0
- package/dist/src/domains/object/tools.js +499 -0
- package/dist/src/domains/plugin/tools.js +45 -0
- package/dist/src/domains/profiler/tools.js +266 -0
- package/dist/src/domains/project/tools.js +179 -0
- package/dist/src/domains/remote/tools.js +73 -0
- package/dist/src/domains/sound/tools.js +38 -0
- package/dist/src/domains/soundbank/tools.js +137 -0
- package/dist/src/domains/soundengine/tools.js +529 -0
- package/dist/src/domains/sourceControl/tools.js +191 -0
- package/dist/src/domains/switchContainer/tools.js +64 -0
- package/dist/src/domains/transport/tools.js +116 -0
- package/dist/src/domains/ui/tools.js +126 -0
- package/dist/src/domains/undo/tools.js +75 -0
- package/dist/src/index.js +95 -0
- package/dist/src/lib/errors.js +31 -0
- package/dist/src/lib/logger.js +43 -0
- package/dist/src/lib/referenceCatalog.js +167 -0
- package/dist/src/lib/response.js +88 -0
- package/dist/src/lib/runtimePaths.js +21 -0
- package/dist/src/lib/toolFactory.js +73 -0
- package/dist/src/lib/waapiClient.js +97 -0
- package/dist/src/lib/waapiSchemaResolver.js +120 -0
- package/dist/src/registry/toolRegistry.js +180 -0
- package/dist/src/registry/types.js +2 -0
- package/dist/tests/verify.js +119 -0
- package/package.json +56 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createStdioTransport = createStdioTransport;
|
|
7
|
+
exports.startHttpSseServer = startHttpSseServer;
|
|
8
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
11
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
12
|
+
/**
|
|
13
|
+
* 创建基于标准输入输出的 MCP 传输层。
|
|
14
|
+
* 运行时通过 stdin/stdout 与 MCP 客户端通信。
|
|
15
|
+
*/
|
|
16
|
+
function createStdioTransport() {
|
|
17
|
+
return new stdio_js_1.StdioServerTransport();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 启动基于 Streamable HTTP(支持 SSE 流)的 MCP HTTP 服务器。
|
|
21
|
+
* 每个新会话会创建独立的服务器实例和传输层实例。
|
|
22
|
+
*
|
|
23
|
+
* 端点:POST/GET/DELETE http://<host>:<port>/mcp
|
|
24
|
+
*
|
|
25
|
+
* @param serverFactory 每次新会话时调用,返回已配置的 McpServer。
|
|
26
|
+
* @param port 监听端口,默认 3000。
|
|
27
|
+
* @param host 监听地址,默认 127.0.0.1。
|
|
28
|
+
*/
|
|
29
|
+
async function startHttpSseServer(serverFactory, port = 3000, host = "127.0.0.1") {
|
|
30
|
+
// session ID → transport;每个已初始化的会话在此映射中保留。
|
|
31
|
+
const sessions = new Map();
|
|
32
|
+
const httpServer = node_http_1.default.createServer(async (req, res) => {
|
|
33
|
+
const url = req.url ?? "/";
|
|
34
|
+
if (!url.startsWith("/mcp")) {
|
|
35
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
36
|
+
res.end(JSON.stringify({ error: "Not found. Use /mcp endpoint." }));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
40
|
+
try {
|
|
41
|
+
if (req.method === "POST") {
|
|
42
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
43
|
+
// 已有会话 — 转发给对应传输层
|
|
44
|
+
await sessions.get(sessionId).handleRequest(req, res);
|
|
45
|
+
}
|
|
46
|
+
else if (!sessionId) {
|
|
47
|
+
// 新会话 — 初始化请求(无 session ID)
|
|
48
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
49
|
+
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
|
|
50
|
+
onsessioninitialized: (id) => {
|
|
51
|
+
sessions.set(id, transport);
|
|
52
|
+
},
|
|
53
|
+
onsessionclosed: (id) => {
|
|
54
|
+
sessions.delete(id);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const server = serverFactory();
|
|
58
|
+
await server.connect(transport);
|
|
59
|
+
await transport.handleRequest(req, res);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
63
|
+
res.end(JSON.stringify({ error: "Session not found." }));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (req.method === "GET" || req.method === "DELETE") {
|
|
67
|
+
if (!sessionId || !sessions.has(sessionId)) {
|
|
68
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
69
|
+
res.end(JSON.stringify({ error: "Valid mcp-session-id header required." }));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await sessions.get(sessionId).handleRequest(req, res);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
76
|
+
res.end(JSON.stringify({ error: "Method not allowed." }));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (!res.headersSent) {
|
|
81
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
82
|
+
res.end(JSON.stringify({ error: "Internal server error." }));
|
|
83
|
+
}
|
|
84
|
+
console.error("HTTP/SSE request error:", err);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
await new Promise((resolve, reject) => {
|
|
88
|
+
httpServer.once("error", reject);
|
|
89
|
+
httpServer.listen(port, host, resolve);
|
|
90
|
+
});
|
|
91
|
+
console.error(`Wwise MCP server is running on HTTP/SSE at http://${host}:${port}/mcp`);
|
|
92
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAudioTools = getAudioTools;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
const toolFactory_js_1 = require("../../lib/toolFactory.js");
|
|
6
|
+
/**
|
|
7
|
+
* 音频文件和采样展示工具(ak.wwise.core.audio.*)。
|
|
8
|
+
* 包括音频导入、映射模笓及静音控制,均需要 WAAPI 连接。
|
|
9
|
+
* 导入和静音操作为高风险,展示已导入音频的操作为中风险。
|
|
10
|
+
*/
|
|
11
|
+
function getAudioTools() {
|
|
12
|
+
return [
|
|
13
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
14
|
+
name: "ak.wwise.core.audio.import",
|
|
15
|
+
title: "Import Audio",
|
|
16
|
+
description: "Import one or more audio files into the Wwise project.",
|
|
17
|
+
domain: "audio",
|
|
18
|
+
risk: "high",
|
|
19
|
+
permissions: ["waapi:authoring:write"],
|
|
20
|
+
tags: ["waapi", "audio", "import", "stub"],
|
|
21
|
+
examples: [{ title: "Import one wav file", input: { imports: [{ audioFile: "C:/audio/footstep.wav", objectPath: "\\Actor-Mixer Hierarchy\\Default Work Unit\\Footsteps<Sound SFX>" }] } }],
|
|
22
|
+
inputSchema: {
|
|
23
|
+
imports: v4_1.z.array(v4_1.z.unknown()).min(1),
|
|
24
|
+
importOperation: v4_1.z.string().optional(),
|
|
25
|
+
default: v4_1.z.unknown().optional(),
|
|
26
|
+
autoAddToSourceControl: v4_1.z.boolean().optional(),
|
|
27
|
+
autoCheckOutToSourceControl: v4_1.z.boolean().optional(),
|
|
28
|
+
options: v4_1.z.unknown().optional()
|
|
29
|
+
},
|
|
30
|
+
inputSchemaJson: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
importOperation: { type: "string" },
|
|
34
|
+
imports: { type: "array", minItems: 1, items: {} },
|
|
35
|
+
default: {},
|
|
36
|
+
autoAddToSourceControl: { type: "boolean" },
|
|
37
|
+
autoCheckOutToSourceControl: { type: "boolean" },
|
|
38
|
+
options: {}
|
|
39
|
+
},
|
|
40
|
+
required: ["imports"],
|
|
41
|
+
additionalProperties: false
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
45
|
+
name: "ak.wwise.core.audio.mute",
|
|
46
|
+
title: "Mute Object",
|
|
47
|
+
description: "Mute one or more Wwise audio objects in the authoring tool.",
|
|
48
|
+
domain: "audio",
|
|
49
|
+
risk: "medium",
|
|
50
|
+
permissions: ["waapi:authoring:write"],
|
|
51
|
+
tags: ["waapi", "audio", "mute", "stub"],
|
|
52
|
+
examples: [{ title: "Mute selected objects", input: { objects: ["{GUID}"] } }],
|
|
53
|
+
inputSchema: {
|
|
54
|
+
objects: v4_1.z.array(v4_1.z.union([v4_1.z.string(), v4_1.z.number().int()])).min(1),
|
|
55
|
+
options: v4_1.z.unknown().optional()
|
|
56
|
+
},
|
|
57
|
+
inputSchemaJson: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
objects: { type: "array", minItems: 1, items: { oneOf: [{ type: "string" }, { type: "integer" }] } },
|
|
61
|
+
options: {}
|
|
62
|
+
},
|
|
63
|
+
required: ["objects"],
|
|
64
|
+
additionalProperties: false
|
|
65
|
+
}
|
|
66
|
+
}),
|
|
67
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
68
|
+
name: "ak.wwise.core.audioSourcePeaks.getMinMaxPeaksInRegion",
|
|
69
|
+
title: "Get Source Peaks",
|
|
70
|
+
description: "Fetch peak values for a source region.",
|
|
71
|
+
domain: "audio",
|
|
72
|
+
risk: "low",
|
|
73
|
+
permissions: ["waapi:authoring:read"],
|
|
74
|
+
tags: ["waapi", "audio", "analysis", "stub"],
|
|
75
|
+
examples: [{ title: "Inspect a source region", input: { audioSource: "{GUID}", start: 0, end: 1000 } }],
|
|
76
|
+
inputSchema: {
|
|
77
|
+
audioSource: v4_1.z.string().min(1),
|
|
78
|
+
start: v4_1.z.number().nonnegative(),
|
|
79
|
+
end: v4_1.z.number().positive(),
|
|
80
|
+
options: v4_1.z.unknown().optional()
|
|
81
|
+
},
|
|
82
|
+
inputSchemaJson: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
audioSource: { type: "string", minLength: 1 },
|
|
86
|
+
start: { type: "number", minimum: 0 },
|
|
87
|
+
end: { type: "number", exclusiveMinimum: 0 },
|
|
88
|
+
options: {}
|
|
89
|
+
},
|
|
90
|
+
required: ["audioSource", "start", "end"],
|
|
91
|
+
additionalProperties: false
|
|
92
|
+
}
|
|
93
|
+
}),
|
|
94
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
95
|
+
name: "ak.wwise.core.audio.resetMute",
|
|
96
|
+
title: "Reset Mute",
|
|
97
|
+
description: "Unmute all objects that were muted via WAAPI.",
|
|
98
|
+
domain: "audio",
|
|
99
|
+
risk: "medium",
|
|
100
|
+
permissions: ["waapi:authoring:write"],
|
|
101
|
+
tags: ["waapi", "audio", "mute"],
|
|
102
|
+
examples: [{ title: "Reset all mutes" }],
|
|
103
|
+
inputSchemaJson: { type: "object", properties: {}, additionalProperties: false }
|
|
104
|
+
}),
|
|
105
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
106
|
+
name: "ak.wwise.core.audio.resetSolo",
|
|
107
|
+
title: "Reset Solo",
|
|
108
|
+
description: "Unsolo all objects that were soloed via WAAPI.",
|
|
109
|
+
domain: "audio",
|
|
110
|
+
risk: "medium",
|
|
111
|
+
permissions: ["waapi:authoring:write"],
|
|
112
|
+
tags: ["waapi", "audio", "solo"],
|
|
113
|
+
examples: [{ title: "Reset all solos" }],
|
|
114
|
+
inputSchemaJson: { type: "object", properties: {}, additionalProperties: false }
|
|
115
|
+
}),
|
|
116
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
117
|
+
name: "ak.wwise.core.audio.solo",
|
|
118
|
+
title: "Solo Objects",
|
|
119
|
+
description: "Solo or unsolo one or more Wwise objects.",
|
|
120
|
+
domain: "audio",
|
|
121
|
+
risk: "medium",
|
|
122
|
+
permissions: ["waapi:authoring:write"],
|
|
123
|
+
tags: ["waapi", "audio", "solo"],
|
|
124
|
+
examples: [{ title: "Solo a sound", input: { objects: ["{GUID}"], value: true } }],
|
|
125
|
+
inputSchema: { objects: v4_1.z.array(v4_1.z.string().min(1)).min(1), value: v4_1.z.boolean() },
|
|
126
|
+
inputSchemaJson: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
objects: { type: "array", minItems: 1, items: { type: "string", minLength: 1 } },
|
|
130
|
+
value: { type: "boolean" }, options: {}
|
|
131
|
+
},
|
|
132
|
+
required: ["objects", "value"],
|
|
133
|
+
additionalProperties: false
|
|
134
|
+
}
|
|
135
|
+
}),
|
|
136
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
137
|
+
name: "ak.wwise.core.audio.importTabDelimited",
|
|
138
|
+
title: "Import Tab-Delimited",
|
|
139
|
+
description: "Import audio files using a tab-delimited import file.",
|
|
140
|
+
domain: "audio",
|
|
141
|
+
risk: "high",
|
|
142
|
+
permissions: ["waapi:authoring:write"],
|
|
143
|
+
tags: ["waapi", "audio", "import"],
|
|
144
|
+
examples: [{ title: "Import tab file", input: { importLanguage: "SFX", importOperation: "createNew", importFile: "C:/audio/batch.txt" } }],
|
|
145
|
+
inputSchema: {
|
|
146
|
+
importLanguage: v4_1.z.string().min(1),
|
|
147
|
+
importOperation: v4_1.z.enum(["createNew", "useExisting", "replaceExisting"]),
|
|
148
|
+
importFile: v4_1.z.string().min(1),
|
|
149
|
+
importLocation: v4_1.z.string().optional(),
|
|
150
|
+
autoAddToSourceControl: v4_1.z.boolean().optional(),
|
|
151
|
+
autoCheckOutToSourceControl: v4_1.z.boolean().optional()
|
|
152
|
+
},
|
|
153
|
+
inputSchemaJson: {
|
|
154
|
+
type: "object",
|
|
155
|
+
properties: {
|
|
156
|
+
importLanguage: { type: "string", minLength: 1 },
|
|
157
|
+
importOperation: { type: "string", enum: ["createNew", "useExisting", "replaceExisting"] },
|
|
158
|
+
importFile: { type: "string", minLength: 1 },
|
|
159
|
+
importLocation: { type: "string" },
|
|
160
|
+
autoAddToSourceControl: { type: "boolean" },
|
|
161
|
+
autoCheckOutToSourceControl: { type: "boolean" }, options: {}
|
|
162
|
+
},
|
|
163
|
+
required: ["importLanguage", "importOperation", "importFile"],
|
|
164
|
+
additionalProperties: false
|
|
165
|
+
}
|
|
166
|
+
}),
|
|
167
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
168
|
+
name: "ak.wwise.core.audioSourcePeaks.getMinMaxPeaksInTrimmedRegion",
|
|
169
|
+
title: "Get Min/Max Peaks in Trimmed Region",
|
|
170
|
+
description: "Get the min/max peak pairs within the trimmed active region of an audio source.",
|
|
171
|
+
domain: "audio",
|
|
172
|
+
risk: "low",
|
|
173
|
+
permissions: ["waapi:authoring:read"],
|
|
174
|
+
tags: ["waapi", "audio", "peaks", "waveform"],
|
|
175
|
+
examples: [{ title: "Sample 100 peaks in trim region", input: { object: "{GUID}", numPeaks: 100 } }],
|
|
176
|
+
inputSchema: {
|
|
177
|
+
object: v4_1.z.string().min(1),
|
|
178
|
+
numPeaks: v4_1.z.number().int().min(1),
|
|
179
|
+
getCrossChannelPeaks: v4_1.z.boolean().optional()
|
|
180
|
+
},
|
|
181
|
+
inputSchemaJson: {
|
|
182
|
+
type: "object",
|
|
183
|
+
properties: {
|
|
184
|
+
object: { type: "string", minLength: 1 },
|
|
185
|
+
numPeaks: { type: "integer", minimum: 1 },
|
|
186
|
+
getCrossChannelPeaks: { type: "boolean" }, options: {}
|
|
187
|
+
},
|
|
188
|
+
required: ["object", "numPeaks"],
|
|
189
|
+
additionalProperties: false
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
];
|
|
193
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCatalogTools = getCatalogTools;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
const response_js_1 = require("../../lib/response.js");
|
|
6
|
+
const referenceCatalog_js_1 = require("../../lib/referenceCatalog.js");
|
|
7
|
+
const errors_js_1 = require("../../lib/errors.js");
|
|
8
|
+
/**
|
|
9
|
+
* 返回进展式揭露工具列表。
|
|
10
|
+
* 这些工具不需要 WAAPI 连接,内部直接操作注册表和参考目录。
|
|
11
|
+
*
|
|
12
|
+
* 发现工具(暴露到 MCP):
|
|
13
|
+
* - catalog.listDomains: 提供领域摘要
|
|
14
|
+
* - catalog.listTools: 提供指定领域下的工具列表
|
|
15
|
+
* - catalog.getToolSchema: 按需加载并返回单个工具的完整 schema 详情
|
|
16
|
+
* - catalog.executeTool: 动态执行任何已注册的工具(实现渐进式执行)
|
|
17
|
+
*/
|
|
18
|
+
function getCatalogTools(registry) {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
name: "catalog.listDomains",
|
|
22
|
+
title: "List Domains",
|
|
23
|
+
description: "Return domain-level discovery summaries for progressive tool disclosure.",
|
|
24
|
+
domain: "catalog",
|
|
25
|
+
risk: "low",
|
|
26
|
+
permissions: [],
|
|
27
|
+
tags: ["catalog", "discovery"],
|
|
28
|
+
examples: [
|
|
29
|
+
{
|
|
30
|
+
title: "List all available domains"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
implementationStatus: "implemented",
|
|
34
|
+
callable: true,
|
|
35
|
+
isDiscoveryTool: true,
|
|
36
|
+
outputSchemaJson: response_js_1.standardResponseJsonSchema,
|
|
37
|
+
handler: async () => {
|
|
38
|
+
return (0, response_js_1.ok)({
|
|
39
|
+
domains: registry.listDomains()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "catalog.listTools",
|
|
45
|
+
title: "List Tools",
|
|
46
|
+
description: "Return implemented and reference-discovered tools for a specific domain.",
|
|
47
|
+
domain: "catalog",
|
|
48
|
+
risk: "low",
|
|
49
|
+
permissions: [],
|
|
50
|
+
tags: ["catalog", "discovery"],
|
|
51
|
+
examples: [
|
|
52
|
+
{
|
|
53
|
+
title: "List object-domain tools",
|
|
54
|
+
input: {
|
|
55
|
+
domain: "object",
|
|
56
|
+
includePlanned: true
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
implementationStatus: "implemented",
|
|
61
|
+
callable: true,
|
|
62
|
+
isDiscoveryTool: true,
|
|
63
|
+
inputSchema: {
|
|
64
|
+
domain: v4_1.z.string().min(1).describe("Domain name, for example object or soundengine."),
|
|
65
|
+
includePlanned: v4_1.z.boolean().optional().describe("Whether reference-only tools should be included.")
|
|
66
|
+
},
|
|
67
|
+
inputSchemaJson: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
domain: { type: "string", minLength: 1 },
|
|
71
|
+
includePlanned: { type: "boolean" }
|
|
72
|
+
},
|
|
73
|
+
required: ["domain"],
|
|
74
|
+
additionalProperties: false
|
|
75
|
+
},
|
|
76
|
+
outputSchemaJson: response_js_1.standardResponseJsonSchema,
|
|
77
|
+
handler: async (rawArgs) => {
|
|
78
|
+
const args = rawArgs;
|
|
79
|
+
const domain = registry.getDomain(args.domain);
|
|
80
|
+
if (!domain) {
|
|
81
|
+
return (0, response_js_1.fail)("domain_not_found", `Unknown domain: ${args.domain}`);
|
|
82
|
+
}
|
|
83
|
+
return (0, response_js_1.ok)({
|
|
84
|
+
domain,
|
|
85
|
+
tools: registry.listTools(args.domain, undefined, args.includePlanned ?? true)
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "catalog.getToolSchema",
|
|
91
|
+
title: "Get Tool Schema",
|
|
92
|
+
description: "Return schema and reference help for one implemented or planned tool.",
|
|
93
|
+
domain: "catalog",
|
|
94
|
+
risk: "low",
|
|
95
|
+
permissions: [],
|
|
96
|
+
tags: ["catalog", "discovery", "schema"],
|
|
97
|
+
examples: [
|
|
98
|
+
{
|
|
99
|
+
title: "Inspect a registered WAAPI scaffold",
|
|
100
|
+
input: {
|
|
101
|
+
toolName: "ak.soundengine.postEvent"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
implementationStatus: "implemented",
|
|
106
|
+
callable: true,
|
|
107
|
+
isDiscoveryTool: true,
|
|
108
|
+
inputSchema: {
|
|
109
|
+
toolName: v4_1.z.string().min(1).describe("Exact tool name.")
|
|
110
|
+
},
|
|
111
|
+
inputSchemaJson: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
toolName: { type: "string", minLength: 1 }
|
|
115
|
+
},
|
|
116
|
+
required: ["toolName"],
|
|
117
|
+
additionalProperties: false
|
|
118
|
+
},
|
|
119
|
+
outputSchemaJson: response_js_1.standardResponseJsonSchema,
|
|
120
|
+
handler: async (rawArgs) => {
|
|
121
|
+
const args = rawArgs;
|
|
122
|
+
const tool = registry.getCallableTool(args.toolName);
|
|
123
|
+
const discovery = registry.getToolDiscovery(args.toolName);
|
|
124
|
+
if (!discovery) {
|
|
125
|
+
return (0, response_js_1.fail)("tool_not_found", `Unknown tool: ${args.toolName}`);
|
|
126
|
+
}
|
|
127
|
+
const referenceDocument = (0, referenceCatalog_js_1.loadReferenceDocument)(args.toolName);
|
|
128
|
+
return (0, response_js_1.ok)({
|
|
129
|
+
tool: discovery,
|
|
130
|
+
schemas: {
|
|
131
|
+
input: tool?.inputSchemaJson,
|
|
132
|
+
output: tool?.outputSchemaJson,
|
|
133
|
+
reference: referenceDocument ? (0, referenceCatalog_js_1.extractReferenceSummary)(referenceDocument) : null
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "catalog.executeTool",
|
|
140
|
+
title: "Execute Tool",
|
|
141
|
+
description: "Dynamically execute any registered tool by name with the provided arguments. This is the unified execution interface for progressive tool disclosure.",
|
|
142
|
+
domain: "catalog",
|
|
143
|
+
risk: "medium",
|
|
144
|
+
permissions: [],
|
|
145
|
+
tags: ["catalog", "execution"],
|
|
146
|
+
examples: [
|
|
147
|
+
{
|
|
148
|
+
title: "Execute a tool discovered via catalog.listTools",
|
|
149
|
+
input: {
|
|
150
|
+
toolName: "ak.soundengine.postEvent",
|
|
151
|
+
arguments: {
|
|
152
|
+
gameObject: "Player",
|
|
153
|
+
eventName: "Play_Music"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
implementationStatus: "implemented",
|
|
159
|
+
callable: true,
|
|
160
|
+
isDiscoveryTool: true,
|
|
161
|
+
inputSchema: {
|
|
162
|
+
toolName: v4_1.z.string().min(1).describe("The exact name of the tool to execute."),
|
|
163
|
+
arguments: v4_1.z.record(v4_1.z.string(), v4_1.z.unknown()).optional().describe("Arguments to pass to the tool. Must match the tool's inputSchema.")
|
|
164
|
+
},
|
|
165
|
+
inputSchemaJson: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: {
|
|
168
|
+
toolName: { type: "string", minLength: 1 },
|
|
169
|
+
arguments: { type: "object", additionalProperties: true }
|
|
170
|
+
},
|
|
171
|
+
required: ["toolName"],
|
|
172
|
+
additionalProperties: false
|
|
173
|
+
},
|
|
174
|
+
outputSchemaJson: response_js_1.standardResponseJsonSchema,
|
|
175
|
+
handler: async (rawArgs) => {
|
|
176
|
+
const args = rawArgs;
|
|
177
|
+
const tool = registry.getCallableTool(args.toolName);
|
|
178
|
+
if (!tool) {
|
|
179
|
+
return (0, response_js_1.fail)("tool_not_found", `Tool not found: ${args.toolName}. Use catalog.listTools to discover available tools.`);
|
|
180
|
+
}
|
|
181
|
+
if (!tool.handler) {
|
|
182
|
+
return (0, response_js_1.fail)("tool_not_executable", `Tool ${args.toolName} is not executable. It may be in planned status.`);
|
|
183
|
+
}
|
|
184
|
+
if (!tool.callable) {
|
|
185
|
+
return (0, response_js_1.fail)("tool_not_callable", `Tool ${args.toolName} is not callable.`);
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const result = await tool.handler(args.arguments, undefined);
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
// Delegate to toFailureResponse which properly handles AppError with preserved codes
|
|
193
|
+
return (0, errors_js_1.toFailureResponse)(error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDebugTools = getDebugTools;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
const toolFactory_js_1 = require("../../lib/toolFactory.js");
|
|
6
|
+
/**
|
|
7
|
+
* Wwise 调试工具(ak.wwise.debug.*)。
|
|
8
|
+
* 支持读取 WAL 树结构和清除持久化内存,均需要 WAAPI 连接。
|
|
9
|
+
*/
|
|
10
|
+
function getDebugTools() {
|
|
11
|
+
return [
|
|
12
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
13
|
+
name: "ak.wwise.debug.getWalTree",
|
|
14
|
+
title: "Get WAL Tree",
|
|
15
|
+
description: "Read the debug WAL tree structure.",
|
|
16
|
+
domain: "debug",
|
|
17
|
+
risk: "medium",
|
|
18
|
+
permissions: ["waapi:debug"],
|
|
19
|
+
tags: ["waapi", "debug", "stub"],
|
|
20
|
+
examples: [{ title: "Read WAL tree" }],
|
|
21
|
+
inputSchemaJson: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {},
|
|
24
|
+
additionalProperties: false
|
|
25
|
+
}
|
|
26
|
+
}),
|
|
27
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
28
|
+
name: "ak.wwise.cli.generateSoundbank",
|
|
29
|
+
title: "CLI Generate SoundBank",
|
|
30
|
+
description: "Run the CLI SoundBank generation operation.",
|
|
31
|
+
domain: "debug",
|
|
32
|
+
risk: "high",
|
|
33
|
+
permissions: ["waapi:cli"],
|
|
34
|
+
tags: ["waapi", "cli", "soundbank", "stub"],
|
|
35
|
+
examples: [{ title: "Generate SoundBanks via CLI", input: { project: "C:/Projects/GameAudio/GameAudio.wproj" } }],
|
|
36
|
+
inputSchema: {
|
|
37
|
+
project: v4_1.z.string().min(1)
|
|
38
|
+
},
|
|
39
|
+
inputSchemaJson: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
project: { type: "string", minLength: 1 }
|
|
43
|
+
},
|
|
44
|
+
required: ["project"],
|
|
45
|
+
additionalProperties: false
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
49
|
+
name: "ak.wwise.core.executeLuaScript",
|
|
50
|
+
title: "Execute Lua Script",
|
|
51
|
+
description: "Execute a Lua script in the Wwise authoring environment.",
|
|
52
|
+
domain: "debug",
|
|
53
|
+
risk: "high",
|
|
54
|
+
permissions: ["waapi:authoring:write", "waapi:debug"],
|
|
55
|
+
tags: ["waapi", "lua", "debug", "stub"],
|
|
56
|
+
examples: [{ title: "Execute inline Lua", input: { script: 'print("hello")' } }],
|
|
57
|
+
inputSchema: {
|
|
58
|
+
script: v4_1.z.string().min(1)
|
|
59
|
+
},
|
|
60
|
+
inputSchemaJson: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
script: { type: "string", minLength: 1 }
|
|
64
|
+
},
|
|
65
|
+
required: ["script"],
|
|
66
|
+
additionalProperties: false
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
70
|
+
name: "ak.wwise.core.debug.enableAsserts",
|
|
71
|
+
title: "Enable Asserts",
|
|
72
|
+
description: "Enable or disable Wwise debug assertions.",
|
|
73
|
+
domain: "debug",
|
|
74
|
+
risk: "high",
|
|
75
|
+
permissions: ["waapi:authoring:write"],
|
|
76
|
+
tags: ["waapi", "debug"],
|
|
77
|
+
examples: [{ title: "Enable debug asserts", input: { enable: true } }],
|
|
78
|
+
inputSchema: { enable: v4_1.z.boolean() },
|
|
79
|
+
inputSchemaJson: { type: "object", properties: { enable: { type: "boolean" }, options: {} }, required: ["enable"], additionalProperties: false }
|
|
80
|
+
}),
|
|
81
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
82
|
+
name: "ak.wwise.core.debug.enableAutomationMode",
|
|
83
|
+
title: "Enable Automation Mode",
|
|
84
|
+
description: "Enable or disable automation mode in Wwise (suppresses UI dialogs).",
|
|
85
|
+
domain: "debug",
|
|
86
|
+
risk: "high",
|
|
87
|
+
permissions: ["waapi:authoring:write"],
|
|
88
|
+
tags: ["waapi", "debug", "automation"],
|
|
89
|
+
examples: [{ title: "Enable automation mode", input: { enable: true } }],
|
|
90
|
+
inputSchema: { enable: v4_1.z.boolean() },
|
|
91
|
+
inputSchemaJson: { type: "object", properties: { enable: { type: "boolean" }, options: {} }, required: ["enable"], additionalProperties: false }
|
|
92
|
+
}),
|
|
93
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
94
|
+
name: "ak.wwise.core.debug.generateToneWAV",
|
|
95
|
+
title: "Generate Tone WAV",
|
|
96
|
+
description: "Generate a WAV tone file for testing purposes.",
|
|
97
|
+
domain: "debug",
|
|
98
|
+
risk: "medium",
|
|
99
|
+
permissions: ["waapi:authoring:write"],
|
|
100
|
+
tags: ["waapi", "debug", "audio"],
|
|
101
|
+
examples: [{ title: "Generate a 440 Hz sine wave", input: { path: "C:/temp/tone.wav", frequency: 440 } }],
|
|
102
|
+
inputSchema: {
|
|
103
|
+
path: v4_1.z.string().min(1),
|
|
104
|
+
bitDepth: v4_1.z.number().int().optional(),
|
|
105
|
+
sampleRate: v4_1.z.number().int().optional(),
|
|
106
|
+
sustainTime: v4_1.z.number().optional(),
|
|
107
|
+
sustainLevel: v4_1.z.number().optional(),
|
|
108
|
+
attackTime: v4_1.z.number().optional(),
|
|
109
|
+
releaseTime: v4_1.z.number().optional(),
|
|
110
|
+
waveform: v4_1.z.enum(["sine", "square", "triangle", "sawtooth", "whiteNoise", "pinkNoise"]).optional(),
|
|
111
|
+
frequency: v4_1.z.number().optional()
|
|
112
|
+
},
|
|
113
|
+
inputSchemaJson: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {
|
|
116
|
+
path: { type: "string", minLength: 1 },
|
|
117
|
+
bitDepth: { type: "integer" }, sampleRate: { type: "integer" },
|
|
118
|
+
sustainTime: { type: "number" }, sustainLevel: { type: "number" },
|
|
119
|
+
attackTime: { type: "number" }, releaseTime: { type: "number" },
|
|
120
|
+
waveform: { type: "string", enum: ["sine", "square", "triangle", "sawtooth", "whiteNoise", "pinkNoise"] },
|
|
121
|
+
frequency: { type: "number" }, options: {}
|
|
122
|
+
},
|
|
123
|
+
required: ["path"],
|
|
124
|
+
additionalProperties: false
|
|
125
|
+
}
|
|
126
|
+
}),
|
|
127
|
+
(0, toolFactory_js_1.createWaapiStubTool)({
|
|
128
|
+
name: "ak.wwise.core.debug.restartWaapiServers",
|
|
129
|
+
title: "Restart WAAPI Servers",
|
|
130
|
+
description: "Restart the WAAPI server endpoint inside Wwise Authoring.",
|
|
131
|
+
domain: "debug",
|
|
132
|
+
risk: "high",
|
|
133
|
+
permissions: ["waapi:authoring:write"],
|
|
134
|
+
tags: ["waapi", "debug"],
|
|
135
|
+
examples: [{ title: "Restart WAAPI servers" }],
|
|
136
|
+
inputSchemaJson: { type: "object", properties: {}, additionalProperties: false }
|
|
137
|
+
})
|
|
138
|
+
];
|
|
139
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getExampleTools = getExampleTools;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
const response_js_1 = require("../../lib/response.js");
|
|
6
|
+
/**
|
|
7
|
+
* 示例领域工具,用于演示如何添加新工具。
|
|
8
|
+
* 这些工具不调用 WAAPI,可在离线状态下正常运行。
|
|
9
|
+
*/
|
|
10
|
+
function getExampleTools() {
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
name: "example.echo",
|
|
14
|
+
title: "Echo Message",
|
|
15
|
+
description: "Example business-domain tool used to demonstrate how to add a new domain.",
|
|
16
|
+
domain: "example",
|
|
17
|
+
risk: "low",
|
|
18
|
+
permissions: [],
|
|
19
|
+
tags: ["example", "sample"],
|
|
20
|
+
examples: [
|
|
21
|
+
{
|
|
22
|
+
title: "Echo and uppercase a value",
|
|
23
|
+
input: {
|
|
24
|
+
message: "hello wwise",
|
|
25
|
+
uppercase: true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
implementationStatus: "implemented",
|
|
30
|
+
callable: true,
|
|
31
|
+
inputSchema: {
|
|
32
|
+
message: v4_1.z.string().min(1).describe("Text to echo back."),
|
|
33
|
+
uppercase: v4_1.z.boolean().optional().describe("Whether to uppercase the echoed text.")
|
|
34
|
+
},
|
|
35
|
+
inputSchemaJson: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
message: { type: "string", minLength: 1 },
|
|
39
|
+
uppercase: { type: "boolean" }
|
|
40
|
+
},
|
|
41
|
+
required: ["message"],
|
|
42
|
+
additionalProperties: false
|
|
43
|
+
},
|
|
44
|
+
outputSchemaJson: response_js_1.standardResponseJsonSchema,
|
|
45
|
+
handler: async (rawArgs) => {
|
|
46
|
+
const args = rawArgs;
|
|
47
|
+
const echoed = args.uppercase ? args.message.toUpperCase() : args.message;
|
|
48
|
+
return (0, response_js_1.ok)({
|
|
49
|
+
message: echoed,
|
|
50
|
+
original: args.message,
|
|
51
|
+
domain: "example"
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
];
|
|
56
|
+
}
|