@chrrxs/robloxstudio-mcp-inspector 2.16.4 → 2.17.1
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.js +234 -151
- package/package.json +1 -1
- package/studio-plugin/MCPInspectorPlugin.rbxmx +1456 -416
- package/studio-plugin/MCPPlugin.rbxmx +1456 -416
- package/studio-plugin/src/modules/ClientBroker.ts +10 -0
- package/studio-plugin/src/modules/Communication.ts +11 -7
- package/studio-plugin/src/modules/RuntimeLogBuffer.ts +36 -10
- package/studio-plugin/src/modules/ServerUrlSettings.ts +62 -9
- package/studio-plugin/src/modules/UI.ts +11 -4
- package/studio-plugin/src/modules/Utils.ts +147 -13
- package/studio-plugin/src/modules/handlers/BreakpointHandlers.ts +460 -0
- package/studio-plugin/src/modules/handlers/QueryHandlers.ts +0 -33
- package/studio-plugin/src/modules/handlers/ScriptHandlers.ts +3 -0
- package/studio-plugin/src/modules/handlers/ScriptProfilerHandlers.ts +386 -0
- package/studio-plugin/src/modules/handlers/TestHandlers.ts +3 -209
- package/studio-plugin/src/server/index.server.ts +20 -5
package/dist/index.js
CHANGED
|
@@ -891,13 +891,23 @@ var init_http_server = __esm({
|
|
|
891
891
|
capture_device_matrix: (tools, body) => tools.captureDeviceMatrix(body.entries, body.target, body.format, body.quality, body.settleSeconds, body.restoreAfter, body.instance_id),
|
|
892
892
|
start_playtest: (tools, body) => tools.startPlaytest(body.mode, body.numPlayers, body.instance_id),
|
|
893
893
|
stop_playtest: (tools, body) => tools.stopPlaytest(body.instance_id),
|
|
894
|
-
get_playtest_output: (tools, body) => tools.getPlaytestOutput(body.target, body.instance_id),
|
|
895
894
|
multiplayer_test_start: (tools, body) => tools.multiplayerTestStart(body.numPlayers, body.testArgs, body.timeout, body.instance_id),
|
|
896
895
|
multiplayer_test_state: (tools, body) => tools.multiplayerTestState(body.instance_id),
|
|
897
896
|
multiplayer_test_add_players: (tools, body) => tools.multiplayerTestAddPlayers(body.numPlayers, body.timeout, body.instance_id),
|
|
898
897
|
multiplayer_test_leave_client: (tools, body) => tools.multiplayerTestLeaveClient(body.target, body.timeout, body.instance_id),
|
|
899
898
|
multiplayer_test_end: (tools, body) => tools.multiplayerTestEnd(body.value, body.timeout, body.instance_id),
|
|
900
899
|
get_runtime_logs: (tools, body) => tools.getRuntimeLogs(body.target, body.since, body.tail, body.filter, body.instance_id),
|
|
900
|
+
capture_script_profiler: (tools, body) => tools.captureScriptProfiler(body.target, {
|
|
901
|
+
duration_ms: body.duration_ms,
|
|
902
|
+
frequency: body.frequency,
|
|
903
|
+
max_functions: body.max_functions,
|
|
904
|
+
min_total_us: body.min_total_us,
|
|
905
|
+
filter: body.filter,
|
|
906
|
+
include_native: body.include_native,
|
|
907
|
+
include_plugin: body.include_plugin,
|
|
908
|
+
output_path: body.output_path
|
|
909
|
+
}, body.instance_id),
|
|
910
|
+
breakpoints: (tools, body) => tools.breakpoints(body.action, body, body.target, body.instance_id),
|
|
901
911
|
get_connected_instances: (tools) => tools.getConnectedInstances(),
|
|
902
912
|
export_build: (tools, body) => tools.exportBuild(body.instancePath, body.outputId, body.style, body.instance_id),
|
|
903
913
|
create_build: (tools, body) => tools.createBuild(body.id, body.style, body.palette, body.parts, body.bounds),
|
|
@@ -918,12 +928,10 @@ var init_http_server = __esm({
|
|
|
918
928
|
clone_object: (tools, body) => tools.cloneObject(body.instancePath, body.targetParentPath, body.instance_id),
|
|
919
929
|
get_descendants: (tools, body) => tools.getDescendants(body.instancePath, body.maxDepth, body.classFilter, body.instance_id),
|
|
920
930
|
compare_instances: (tools, body) => tools.compareInstances(body.instancePathA, body.instancePathB, body.instance_id),
|
|
921
|
-
get_output_log: (tools, body) => tools.getOutputLog(body.maxEntries, body.messageType, body.instance_id),
|
|
922
931
|
bulk_set_attributes: (tools, body) => tools.bulkSetAttributes(body.instancePath, body.attributes, body.instance_id),
|
|
923
932
|
capture_screenshot: (tools, body) => tools.captureScreenshot(body.instance_id, body.format, body.quality),
|
|
924
933
|
simulate_mouse_input: (tools, body) => tools.simulateMouseInput(body.action, body.x, body.y, body.button, body.scrollDirection, body.target, body.instance_id),
|
|
925
934
|
simulate_keyboard_input: (tools, body) => tools.simulateKeyboardInput(body.keyCode, body.action, body.duration, body.text, body.target, body.instance_id),
|
|
926
|
-
character_navigation: (tools, body) => tools.characterNavigation(body.position, body.instancePath, body.waitForCompletion, body.timeout, body.target, body.instance_id),
|
|
927
935
|
get_memory_breakdown: (tools, body) => tools.getMemoryBreakdown(body.target, body.tags, body.instance_id),
|
|
928
936
|
get_scene_analysis: (tools, body) => tools.getSceneAnalysis(body.mode, body.target, body.topN, body.raw, body.instance_id),
|
|
929
937
|
export_rbxm: (tools, body) => tools.exportRbxm(body.instance_paths, body.output_path, body.target, body.instance_id),
|
|
@@ -4458,6 +4466,76 @@ ${code}`
|
|
|
4458
4466
|
content: [{ type: "text", text: JSON.stringify(body) }]
|
|
4459
4467
|
};
|
|
4460
4468
|
}
|
|
4469
|
+
async captureScriptProfiler(target, request = {}, instance_id) {
|
|
4470
|
+
const targetRole = target ?? "server";
|
|
4471
|
+
const data = { ...request };
|
|
4472
|
+
const outputPath = data.output_path;
|
|
4473
|
+
delete data.output_path;
|
|
4474
|
+
if (outputPath !== void 0 && typeof outputPath !== "string") {
|
|
4475
|
+
throw new Error("output_path must be a string when provided");
|
|
4476
|
+
}
|
|
4477
|
+
if (outputPath) {
|
|
4478
|
+
data.__mcp_include_raw_json = true;
|
|
4479
|
+
}
|
|
4480
|
+
const resolved = this.bridge.resolveTarget({ instance_id, target: targetRole });
|
|
4481
|
+
if (!resolved.ok)
|
|
4482
|
+
throw new RoutingFailure(resolved.error);
|
|
4483
|
+
if (resolved.mode !== "single") {
|
|
4484
|
+
throw new RoutingFailure({
|
|
4485
|
+
code: "target_role_not_present_on_instance",
|
|
4486
|
+
message: 'capture_script_profiler profiles one runtime peer at a time. Pick target="server" or a specific "client-N".',
|
|
4487
|
+
data: {
|
|
4488
|
+
instances: this.bridge.getPublicInstances(),
|
|
4489
|
+
count: this.bridge.getInstances().length
|
|
4490
|
+
}
|
|
4491
|
+
});
|
|
4492
|
+
}
|
|
4493
|
+
data.__mcp_instance_id = resolved.targetInstanceId;
|
|
4494
|
+
data.__mcp_target_role = resolved.targetRole;
|
|
4495
|
+
const response = await this.client.request("/api/capture-script-profiler", data, resolved.targetInstanceId, resolved.targetRole);
|
|
4496
|
+
const body = response !== null && typeof response === "object" && !Array.isArray(response) ? { ...response, target: resolved.targetRole } : response;
|
|
4497
|
+
if (body !== null && typeof body === "object" && !Array.isArray(body)) {
|
|
4498
|
+
const mutable = body;
|
|
4499
|
+
const rawJson = mutable.raw_json;
|
|
4500
|
+
if (typeof rawJson === "string") {
|
|
4501
|
+
if (typeof outputPath === "string" && outputPath !== "") {
|
|
4502
|
+
const resolvedOutputPath = path.resolve(outputPath);
|
|
4503
|
+
fs.mkdirSync(path.dirname(resolvedOutputPath), { recursive: true });
|
|
4504
|
+
fs.writeFileSync(resolvedOutputPath, rawJson, "utf8");
|
|
4505
|
+
mutable.output_path = resolvedOutputPath;
|
|
4506
|
+
}
|
|
4507
|
+
delete mutable.raw_json;
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
return { content: [{ type: "text", text: JSON.stringify(body) }] };
|
|
4511
|
+
}
|
|
4512
|
+
async breakpoints(action, request = {}, target, instance_id) {
|
|
4513
|
+
if (!action || typeof action !== "string") {
|
|
4514
|
+
throw new Error("breakpoints requires action=set|remove|clear|list");
|
|
4515
|
+
}
|
|
4516
|
+
const targetRole = target ?? "edit";
|
|
4517
|
+
const data = { ...request, action };
|
|
4518
|
+
delete data.target;
|
|
4519
|
+
delete data.instance_id;
|
|
4520
|
+
const resolved = this.bridge.resolveTarget({ instance_id, target: targetRole });
|
|
4521
|
+
if (!resolved.ok)
|
|
4522
|
+
throw new RoutingFailure(resolved.error);
|
|
4523
|
+
if (resolved.mode !== "single") {
|
|
4524
|
+
throw new RoutingFailure({
|
|
4525
|
+
code: "target_role_not_present_on_instance",
|
|
4526
|
+
message: "This tool does not support target=all. Pick a specific role or omit target.",
|
|
4527
|
+
data: {
|
|
4528
|
+
instances: this.bridge.getPublicInstances(),
|
|
4529
|
+
count: this.bridge.getInstances().length
|
|
4530
|
+
}
|
|
4531
|
+
});
|
|
4532
|
+
}
|
|
4533
|
+
data.__mcp_instance_id = resolved.targetInstanceId;
|
|
4534
|
+
data.__mcp_target_role = resolved.targetRole;
|
|
4535
|
+
const response = await this.client.request("/api/breakpoints", data, resolved.targetInstanceId, resolved.targetRole);
|
|
4536
|
+
const body = response !== null && typeof response === "object" && !Array.isArray(response) ? { ...response, target: resolved.targetRole } : response;
|
|
4537
|
+
return { content: [{ type: "text", text: JSON.stringify(body) }] };
|
|
4538
|
+
}
|
|
4461
4539
|
async startPlaytest(mode, numPlayers, instance_id) {
|
|
4462
4540
|
if (mode !== "play" && mode !== "run") {
|
|
4463
4541
|
throw new Error('mode must be "play" or "run"');
|
|
@@ -4569,17 +4647,6 @@ ${code}`
|
|
|
4569
4647
|
content: [{ type: "text", text: JSON.stringify(body) }]
|
|
4570
4648
|
};
|
|
4571
4649
|
}
|
|
4572
|
-
async getPlaytestOutput(target, instance_id) {
|
|
4573
|
-
const response = await this._callSingle("/api/get-playtest-output", {}, target || "edit", instance_id);
|
|
4574
|
-
return {
|
|
4575
|
-
content: [
|
|
4576
|
-
{
|
|
4577
|
-
type: "text",
|
|
4578
|
-
text: JSON.stringify(response)
|
|
4579
|
-
}
|
|
4580
|
-
]
|
|
4581
|
-
};
|
|
4582
|
-
}
|
|
4583
4650
|
async _buildMultiplayerState(instanceId) {
|
|
4584
4651
|
const peers = this.bridge.getPublicInstances().filter((i) => i.instanceId === instanceId).sort((a, b) => a.role.localeCompare(b.role));
|
|
4585
4652
|
const body = {
|
|
@@ -5530,23 +5597,6 @@ ${code}`
|
|
|
5530
5597
|
}]
|
|
5531
5598
|
};
|
|
5532
5599
|
}
|
|
5533
|
-
async characterNavigation(position, instancePath, waitForCompletion, timeout, target, instance_id) {
|
|
5534
|
-
if (!position && !instancePath) {
|
|
5535
|
-
throw new Error("Either position or instancePath is required for character_navigation");
|
|
5536
|
-
}
|
|
5537
|
-
const response = await this._callSingle("/api/character-navigation", {
|
|
5538
|
-
position,
|
|
5539
|
-
instancePath,
|
|
5540
|
-
waitForCompletion,
|
|
5541
|
-
timeout
|
|
5542
|
-
}, target || "edit", instance_id);
|
|
5543
|
-
return {
|
|
5544
|
-
content: [{
|
|
5545
|
-
type: "text",
|
|
5546
|
-
text: JSON.stringify(response)
|
|
5547
|
-
}]
|
|
5548
|
-
};
|
|
5549
|
-
}
|
|
5550
5600
|
async cloneObject(instancePath, targetParentPath, instance_id) {
|
|
5551
5601
|
if (!instancePath || !targetParentPath) {
|
|
5552
5602
|
throw new Error("instancePath and targetParentPath are required for clone_object");
|
|
@@ -5568,10 +5618,6 @@ ${code}`
|
|
|
5568
5618
|
const response = await this._callSingle("/api/compare-instances", { instancePathA, instancePathB }, void 0, instance_id);
|
|
5569
5619
|
return { content: [{ type: "text", text: JSON.stringify(response) }] };
|
|
5570
5620
|
}
|
|
5571
|
-
async getOutputLog(maxEntries, messageType, instance_id) {
|
|
5572
|
-
const response = await this._callSingle("/api/get-output-log", { maxEntries, messageType }, void 0, instance_id);
|
|
5573
|
-
return { content: [{ type: "text", text: JSON.stringify(response) }] };
|
|
5574
|
-
}
|
|
5575
5621
|
async bulkSetAttributes(instancePath, attributes, instance_id) {
|
|
5576
5622
|
if (!instancePath || !attributes) {
|
|
5577
5623
|
throw new Error("instancePath and attributes are required for bulk_set_attributes");
|
|
@@ -6145,7 +6191,7 @@ var init_definitions = __esm({
|
|
|
6145
6191
|
properties: {
|
|
6146
6192
|
path: {
|
|
6147
6193
|
type: "string",
|
|
6148
|
-
description:
|
|
6194
|
+
description: 'Canonical DataModel path (default: game root), such as game.Workspace or game.ServerScriptService[".dir"]'
|
|
6149
6195
|
},
|
|
6150
6196
|
instance_id: {
|
|
6151
6197
|
type: "string",
|
|
@@ -6249,7 +6295,7 @@ var init_definitions = __esm({
|
|
|
6249
6295
|
properties: {
|
|
6250
6296
|
instancePath: {
|
|
6251
6297
|
type: "string",
|
|
6252
|
-
description:
|
|
6298
|
+
description: 'Canonical DataModel path, such as game.Workspace.Part or game.ServerScriptService[".dir"].Main'
|
|
6253
6299
|
},
|
|
6254
6300
|
excludeSource: {
|
|
6255
6301
|
type: "boolean",
|
|
@@ -6272,7 +6318,7 @@ var init_definitions = __esm({
|
|
|
6272
6318
|
properties: {
|
|
6273
6319
|
instancePath: {
|
|
6274
6320
|
type: "string",
|
|
6275
|
-
description:
|
|
6321
|
+
description: 'Canonical DataModel path, such as game.Workspace.Part or game.ServerScriptService[".dir"].Main'
|
|
6276
6322
|
},
|
|
6277
6323
|
instance_id: {
|
|
6278
6324
|
type: "string",
|
|
@@ -6334,7 +6380,7 @@ var init_definitions = __esm({
|
|
|
6334
6380
|
properties: {
|
|
6335
6381
|
path: {
|
|
6336
6382
|
type: "string",
|
|
6337
|
-
description: "
|
|
6383
|
+
description: "Canonical DataModel path (default: workspace root)"
|
|
6338
6384
|
},
|
|
6339
6385
|
maxDepth: {
|
|
6340
6386
|
type: "number",
|
|
@@ -6361,7 +6407,7 @@ var init_definitions = __esm({
|
|
|
6361
6407
|
properties: {
|
|
6362
6408
|
instancePath: {
|
|
6363
6409
|
type: "string",
|
|
6364
|
-
description: "
|
|
6410
|
+
description: "Canonical DataModel path"
|
|
6365
6411
|
},
|
|
6366
6412
|
propertyName: {
|
|
6367
6413
|
type: "string",
|
|
@@ -6388,7 +6434,7 @@ var init_definitions = __esm({
|
|
|
6388
6434
|
paths: {
|
|
6389
6435
|
type: "array",
|
|
6390
6436
|
items: { type: "string" },
|
|
6391
|
-
description: "
|
|
6437
|
+
description: "Canonical DataModel paths"
|
|
6392
6438
|
},
|
|
6393
6439
|
propertyName: {
|
|
6394
6440
|
type: "string",
|
|
@@ -6415,7 +6461,7 @@ var init_definitions = __esm({
|
|
|
6415
6461
|
paths: {
|
|
6416
6462
|
type: "array",
|
|
6417
6463
|
items: { type: "string" },
|
|
6418
|
-
description: "
|
|
6464
|
+
description: "Canonical DataModel paths"
|
|
6419
6465
|
},
|
|
6420
6466
|
propertyName: {
|
|
6421
6467
|
type: "string",
|
|
@@ -6438,7 +6484,7 @@ var init_definitions = __esm({
|
|
|
6438
6484
|
properties: {
|
|
6439
6485
|
instancePath: {
|
|
6440
6486
|
type: "string",
|
|
6441
|
-
description: "
|
|
6487
|
+
description: "Canonical DataModel path"
|
|
6442
6488
|
},
|
|
6443
6489
|
properties: {
|
|
6444
6490
|
type: "object",
|
|
@@ -6466,7 +6512,7 @@ var init_definitions = __esm({
|
|
|
6466
6512
|
},
|
|
6467
6513
|
parent: {
|
|
6468
6514
|
type: "string",
|
|
6469
|
-
description: "
|
|
6515
|
+
description: "Canonical parent DataModel path"
|
|
6470
6516
|
},
|
|
6471
6517
|
name: {
|
|
6472
6518
|
type: "string",
|
|
@@ -6502,7 +6548,7 @@ var init_definitions = __esm({
|
|
|
6502
6548
|
},
|
|
6503
6549
|
parent: {
|
|
6504
6550
|
type: "string",
|
|
6505
|
-
description: "
|
|
6551
|
+
description: "Canonical parent DataModel path"
|
|
6506
6552
|
},
|
|
6507
6553
|
name: {
|
|
6508
6554
|
type: "string",
|
|
@@ -6534,7 +6580,7 @@ var init_definitions = __esm({
|
|
|
6534
6580
|
properties: {
|
|
6535
6581
|
instancePath: {
|
|
6536
6582
|
type: "string",
|
|
6537
|
-
description: "
|
|
6583
|
+
description: "Canonical DataModel path"
|
|
6538
6584
|
},
|
|
6539
6585
|
instance_id: {
|
|
6540
6586
|
type: "string",
|
|
@@ -6554,7 +6600,7 @@ var init_definitions = __esm({
|
|
|
6554
6600
|
properties: {
|
|
6555
6601
|
instancePath: {
|
|
6556
6602
|
type: "string",
|
|
6557
|
-
description: "
|
|
6603
|
+
description: "Canonical DataModel path"
|
|
6558
6604
|
},
|
|
6559
6605
|
count: {
|
|
6560
6606
|
type: "number",
|
|
@@ -6615,7 +6661,7 @@ var init_definitions = __esm({
|
|
|
6615
6661
|
properties: {
|
|
6616
6662
|
instancePath: {
|
|
6617
6663
|
type: "string",
|
|
6618
|
-
description: "
|
|
6664
|
+
description: "Canonical DataModel path"
|
|
6619
6665
|
},
|
|
6620
6666
|
count: {
|
|
6621
6667
|
type: "number",
|
|
@@ -6678,7 +6724,7 @@ var init_definitions = __esm({
|
|
|
6678
6724
|
properties: {
|
|
6679
6725
|
instancePath: {
|
|
6680
6726
|
type: "string",
|
|
6681
|
-
description: "
|
|
6727
|
+
description: "Canonical path to a LuaSourceContainer"
|
|
6682
6728
|
},
|
|
6683
6729
|
startLine: {
|
|
6684
6730
|
type: "number",
|
|
@@ -6705,7 +6751,7 @@ var init_definitions = __esm({
|
|
|
6705
6751
|
properties: {
|
|
6706
6752
|
instancePath: {
|
|
6707
6753
|
type: "string",
|
|
6708
|
-
description: "
|
|
6754
|
+
description: "Canonical path to a LuaSourceContainer"
|
|
6709
6755
|
},
|
|
6710
6756
|
source: {
|
|
6711
6757
|
type: "string",
|
|
@@ -6728,7 +6774,7 @@ var init_definitions = __esm({
|
|
|
6728
6774
|
properties: {
|
|
6729
6775
|
instancePath: {
|
|
6730
6776
|
type: "string",
|
|
6731
|
-
description: "
|
|
6777
|
+
description: "Canonical path to a LuaSourceContainer"
|
|
6732
6778
|
},
|
|
6733
6779
|
old_string: {
|
|
6734
6780
|
type: "string",
|
|
@@ -6759,7 +6805,7 @@ var init_definitions = __esm({
|
|
|
6759
6805
|
properties: {
|
|
6760
6806
|
instancePath: {
|
|
6761
6807
|
type: "string",
|
|
6762
|
-
description: "
|
|
6808
|
+
description: "Canonical path to a LuaSourceContainer"
|
|
6763
6809
|
},
|
|
6764
6810
|
afterLine: {
|
|
6765
6811
|
type: "number",
|
|
@@ -6786,7 +6832,7 @@ var init_definitions = __esm({
|
|
|
6786
6832
|
properties: {
|
|
6787
6833
|
instancePath: {
|
|
6788
6834
|
type: "string",
|
|
6789
|
-
description: "
|
|
6835
|
+
description: "Canonical path to a LuaSourceContainer"
|
|
6790
6836
|
},
|
|
6791
6837
|
startLine: {
|
|
6792
6838
|
type: "number",
|
|
@@ -6814,7 +6860,7 @@ var init_definitions = __esm({
|
|
|
6814
6860
|
properties: {
|
|
6815
6861
|
instancePath: {
|
|
6816
6862
|
type: "string",
|
|
6817
|
-
description: "
|
|
6863
|
+
description: "Canonical DataModel path"
|
|
6818
6864
|
},
|
|
6819
6865
|
attributeName: {
|
|
6820
6866
|
type: "string",
|
|
@@ -6844,7 +6890,7 @@ var init_definitions = __esm({
|
|
|
6844
6890
|
properties: {
|
|
6845
6891
|
instancePath: {
|
|
6846
6892
|
type: "string",
|
|
6847
|
-
description: "
|
|
6893
|
+
description: "Canonical DataModel path"
|
|
6848
6894
|
},
|
|
6849
6895
|
instance_id: {
|
|
6850
6896
|
type: "string",
|
|
@@ -6863,7 +6909,7 @@ var init_definitions = __esm({
|
|
|
6863
6909
|
properties: {
|
|
6864
6910
|
instancePath: {
|
|
6865
6911
|
type: "string",
|
|
6866
|
-
description: "
|
|
6912
|
+
description: "Canonical DataModel path"
|
|
6867
6913
|
},
|
|
6868
6914
|
attributeName: {
|
|
6869
6915
|
type: "string",
|
|
@@ -6887,7 +6933,7 @@ var init_definitions = __esm({
|
|
|
6887
6933
|
properties: {
|
|
6888
6934
|
instancePath: {
|
|
6889
6935
|
type: "string",
|
|
6890
|
-
description: "
|
|
6936
|
+
description: "Canonical DataModel path"
|
|
6891
6937
|
},
|
|
6892
6938
|
instance_id: {
|
|
6893
6939
|
type: "string",
|
|
@@ -6906,7 +6952,7 @@ var init_definitions = __esm({
|
|
|
6906
6952
|
properties: {
|
|
6907
6953
|
instancePath: {
|
|
6908
6954
|
type: "string",
|
|
6909
|
-
description: "
|
|
6955
|
+
description: "Canonical DataModel path"
|
|
6910
6956
|
},
|
|
6911
6957
|
tagName: {
|
|
6912
6958
|
type: "string",
|
|
@@ -6929,7 +6975,7 @@ var init_definitions = __esm({
|
|
|
6929
6975
|
properties: {
|
|
6930
6976
|
instancePath: {
|
|
6931
6977
|
type: "string",
|
|
6932
|
-
description: "
|
|
6978
|
+
description: "Canonical DataModel path"
|
|
6933
6979
|
},
|
|
6934
6980
|
tagName: {
|
|
6935
6981
|
type: "string",
|
|
@@ -7100,7 +7146,7 @@ var init_definitions = __esm({
|
|
|
7100
7146
|
{
|
|
7101
7147
|
name: "start_playtest",
|
|
7102
7148
|
category: "write",
|
|
7103
|
-
description: "Start a simple single-player Studio playtest in play or run mode, waiting until a runtime peer registers with MCP.
|
|
7149
|
+
description: "Start a simple single-player Studio playtest in play or run mode, waiting until a runtime peer registers with MCP. Read print/warn/error output with get_runtime_logs, then end with stop_playtest. For multi-client testing use multiplayer_test_start instead.",
|
|
7104
7150
|
inputSchema: {
|
|
7105
7151
|
type: "object",
|
|
7106
7152
|
properties: {
|
|
@@ -7124,7 +7170,7 @@ var init_definitions = __esm({
|
|
|
7124
7170
|
{
|
|
7125
7171
|
name: "stop_playtest",
|
|
7126
7172
|
category: "write",
|
|
7127
|
-
description: "Stop playtest and
|
|
7173
|
+
description: "Stop playtest and wait for runtime peers to disconnect.",
|
|
7128
7174
|
inputSchema: {
|
|
7129
7175
|
type: "object",
|
|
7130
7176
|
properties: {
|
|
@@ -7135,24 +7181,6 @@ var init_definitions = __esm({
|
|
|
7135
7181
|
}
|
|
7136
7182
|
}
|
|
7137
7183
|
},
|
|
7138
|
-
{
|
|
7139
|
-
name: "get_playtest_output",
|
|
7140
|
-
category: "read",
|
|
7141
|
-
description: "Poll output buffer without stopping. Returns isRunning and captured messages.",
|
|
7142
|
-
inputSchema: {
|
|
7143
|
-
type: "object",
|
|
7144
|
-
properties: {
|
|
7145
|
-
target: {
|
|
7146
|
-
type: "string",
|
|
7147
|
-
description: 'Instance target: "edit" (default), "server", "client-1", "client-2", etc.'
|
|
7148
|
-
},
|
|
7149
|
-
instance_id: {
|
|
7150
|
-
type: "string",
|
|
7151
|
-
description: "Which connected Studio place to target. Required when multiple places are connected; omit when one. Use get_connected_instances to list available IDs."
|
|
7152
|
-
}
|
|
7153
|
-
}
|
|
7154
|
-
}
|
|
7155
|
-
},
|
|
7156
7184
|
{
|
|
7157
7185
|
name: "set_network_profile",
|
|
7158
7186
|
category: "write",
|
|
@@ -7536,7 +7564,7 @@ var init_definitions = __esm({
|
|
|
7536
7564
|
{
|
|
7537
7565
|
name: "get_runtime_logs",
|
|
7538
7566
|
category: "read",
|
|
7539
|
-
description: "Read the in-memory log buffers captured by Studio plugin peers. Each buffer captures ~64 KB of recent LogService.MessageOut entries
|
|
7567
|
+
description: "Read the in-memory log buffers captured by Studio plugin peers. Each buffer captures ~64 KB of recent LogService output; runtime peers seed from LogService:GetLogHistory() at plugin load so early startup logs emitted before the plugin finishes loading can still be returned, then continue capturing LogService.MessageOut entries. Oldest entries drop when over budget. Entries include capturedBy for the plugin buffer that observed the log. In ordinary Studio play/run sessions, LogService reflects logs across edit/server/client, so script-origin peer is not reliable and entries omit peer. In StudioTestService multiplayer sessions only, peer attribution is reliable and entries also include peer. target=all (default) merges buffers and dedups same-message-and-level entries captured within 2s across different buffers.",
|
|
7540
7568
|
inputSchema: {
|
|
7541
7569
|
type: "object",
|
|
7542
7570
|
properties: {
|
|
@@ -7563,6 +7591,120 @@ var init_definitions = __esm({
|
|
|
7563
7591
|
}
|
|
7564
7592
|
}
|
|
7565
7593
|
},
|
|
7594
|
+
{
|
|
7595
|
+
name: "capture_script_profiler",
|
|
7596
|
+
category: "read",
|
|
7597
|
+
description: `Capture one short ScriptProfilerService sample on a running server or client peer and return a compact CPU summary. Use this for Luau/script optimization, not render, physics, networking, or engine microprofiler lanes. Minimal flow: start or reproduce the workload, call capture_script_profiler with target="server" or a specific "client-N", inspect top_functions, patch the suspected hot path, then capture again with the same target/workload/duration_ms/frequency/filter/min_total_us to compare. top_functions is sorted by descending total_us after native/plugin/min/filter exclusions; each row includes rank plus function_index, the 1-based index into the raw Roblox Functions array. Function and node TotalDuration values follow Roblox's exported Script Profiler JSON format and are reported in microseconds as total_us. total_us is cumulative profiler TotalDuration during the capture; nested labels/functions can overlap, so do not sum rows as total CPU time. source is the runtime script path reported by Roblox and may need mapping back to editable source with search tools. If function names are too broad, add debug.profilebegin("Area:SpecificStep") / debug.profileend() around suspected code and pass filter="Area:" or another label prefix; matching custom labels appear in debug_labels and top_functions with their script source and no line number. The result echoes effective options in applied and omitted.filtered_out counts rows removed by filter. Keep captures short while actively triggering the behavior; duration_ms defaults to 1000 and is clamped to 100-15000. Pass output_path when you need the raw Roblox Script Profiler JSON for offline comparison or deeper analysis. This tool owns the start/stop/request profiler lifecycle for one capture and does not expose long-lived profiler sessions.`,
|
|
7598
|
+
inputSchema: {
|
|
7599
|
+
type: "object",
|
|
7600
|
+
properties: {
|
|
7601
|
+
target: {
|
|
7602
|
+
type: "string",
|
|
7603
|
+
pattern: "^(server|client-[0-9]+)$",
|
|
7604
|
+
description: 'Runtime peer to profile: "server" (default) or "client-N". Use get_connected_instances to discover available runtime roles. target="edit" is invalid because ScriptProfiler captures running code.'
|
|
7605
|
+
},
|
|
7606
|
+
duration_ms: {
|
|
7607
|
+
type: "number",
|
|
7608
|
+
default: 1e3,
|
|
7609
|
+
minimum: 100,
|
|
7610
|
+
maximum: 15e3,
|
|
7611
|
+
description: "Sample duration in milliseconds. Defaults to 1000; clamped to 100-15000 so the Studio bridge does not hang on long captures."
|
|
7612
|
+
},
|
|
7613
|
+
frequency: {
|
|
7614
|
+
type: "number",
|
|
7615
|
+
default: 1e3,
|
|
7616
|
+
minimum: 1,
|
|
7617
|
+
maximum: 1e4,
|
|
7618
|
+
description: "ScriptProfiler sampling frequency in samples per second (Hz). Defaults to 1000."
|
|
7619
|
+
},
|
|
7620
|
+
max_functions: {
|
|
7621
|
+
type: "number",
|
|
7622
|
+
default: 20,
|
|
7623
|
+
minimum: 1,
|
|
7624
|
+
maximum: 100,
|
|
7625
|
+
description: "Maximum number of top_functions and debug_labels to return. Defaults to 20; clamped to 1-100."
|
|
7626
|
+
},
|
|
7627
|
+
min_total_us: {
|
|
7628
|
+
type: "number",
|
|
7629
|
+
default: 0,
|
|
7630
|
+
minimum: 0,
|
|
7631
|
+
description: "Omit functions below this TotalDuration in microseconds after capture. Defaults to 0."
|
|
7632
|
+
},
|
|
7633
|
+
filter: {
|
|
7634
|
+
type: "string",
|
|
7635
|
+
description: "Optional case-insensitive substring matched against function name and source before top_functions are returned. Useful for focusing on one module or debug.profilebegin label prefix."
|
|
7636
|
+
},
|
|
7637
|
+
include_native: {
|
|
7638
|
+
type: "boolean",
|
|
7639
|
+
description: "Include native Roblox frames in top_functions. Defaults to false to keep optimization output focused on game Luau and debug labels."
|
|
7640
|
+
},
|
|
7641
|
+
include_plugin: {
|
|
7642
|
+
type: "boolean",
|
|
7643
|
+
description: "Include plugin frames in top_functions. Defaults to false because the MCP capture implementation can otherwise add noise."
|
|
7644
|
+
},
|
|
7645
|
+
output_path: {
|
|
7646
|
+
type: "string",
|
|
7647
|
+
description: "Optional local path where the MCP server writes the raw Script Profiler JSON. The tool result then includes output_path instead of inlining the raw JSON."
|
|
7648
|
+
},
|
|
7649
|
+
instance_id: {
|
|
7650
|
+
type: "string",
|
|
7651
|
+
description: "Which connected Studio place to target. Required when multiple places are connected; omit when one. Use get_connected_instances to list available IDs."
|
|
7652
|
+
}
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
},
|
|
7656
|
+
{
|
|
7657
|
+
name: "breakpoints",
|
|
7658
|
+
category: "write",
|
|
7659
|
+
description: 'Manage Studio debugger breakpoints through ScriptDebuggerService. Use this when the user asks to debug with Studio breakpoints. Prefer log breakpoints for agent debugging: pass log_message and let continue_execution default to true, reproduce the issue, then read get_runtime_logs filtered by "Breakpoint". Minimal flow: set a log breakpoint, run or trigger the behavior, call get_runtime_logs with filter="Breakpoint", then call action="clear" to remove MCP-managed breakpoints. Generated breakpoint logs are prefixed with "Breakpoint" plus script_path:line; Studio breakpoint errors also start with "Breakpoint", so this filter captures both successful breakpoint logs and breakpoint-related failures. Set breakpoints on target="edit" before starting a playtest when possible; for an already-running playtest target the runtime DataModel directly, such as "server" or "client-1". Do not set continue_execution=false unless the target DataModel already has a ScriptDebuggerService.OnStopped handler that returns Enum.DebuggerResumeType.Resume for breakpoint/non-exception stops; otherwise the playtest can get stuck and MCP can lose the server/client peers. Minimal OnStopped reference: local sds=game:GetService("ScriptDebuggerService"); sds.OnStopped=function(info) if info.Reason ~= Enum.ScriptStoppedReason.Exception then return Enum.DebuggerResumeType.Resume end print("EXCEPTION:", info.ExceptionText); return Enum.DebuggerResumeType.Resume end. MCP-managed breakpoints persist minimal script_path/line recovery data per place and target so action="list" and action="clear" can find tool-created edit/server/client breakpoints after MCP/plugin reloads. action="clear" removes only breakpoints created through this MCP tool by default; pass clear_all=true only when you intentionally want to clear every Studio breakpoint in the targeted DataModel, including user-created breakpoints. This tool only manages breakpoint lifecycle; it does not pause, resume, step, inspect variables, or install OnStopped callbacks. Requires Studio Debugger Luau API beta enabled.',
|
|
7660
|
+
inputSchema: {
|
|
7661
|
+
type: "object",
|
|
7662
|
+
properties: {
|
|
7663
|
+
action: {
|
|
7664
|
+
type: "string",
|
|
7665
|
+
enum: ["set", "remove", "clear", "list"],
|
|
7666
|
+
description: "Breakpoint action to run. set/remove require script_path and line. clear removes MCP-managed breakpoints by default. list returns breakpoints created through this MCP tool in the targeted DataModel."
|
|
7667
|
+
},
|
|
7668
|
+
clear_all: {
|
|
7669
|
+
type: "boolean",
|
|
7670
|
+
description: 'Only applies to action="clear". Omit or set false to remove only MCP-managed breakpoints tracked by this tool. Set true to call ScriptDebuggerService:ClearBreakpoints() and clear every Studio breakpoint in the targeted DataModel, including user-created breakpoints.'
|
|
7671
|
+
},
|
|
7672
|
+
script_path: {
|
|
7673
|
+
type: "string",
|
|
7674
|
+
description: 'Canonical path to a LuaSourceContainer, for example game.ServerScriptService.Main or game.ServerScriptService[".dir"].ReproScript. Required for set/remove.'
|
|
7675
|
+
},
|
|
7676
|
+
line: {
|
|
7677
|
+
type: "number",
|
|
7678
|
+
description: "1-based line number for set/remove."
|
|
7679
|
+
},
|
|
7680
|
+
enabled: {
|
|
7681
|
+
type: "boolean",
|
|
7682
|
+
description: "Whether the breakpoint is enabled when set. Defaults to true."
|
|
7683
|
+
},
|
|
7684
|
+
condition: {
|
|
7685
|
+
type: "string",
|
|
7686
|
+
description: "Optional Luau condition expression for set."
|
|
7687
|
+
},
|
|
7688
|
+
log_message: {
|
|
7689
|
+
type: "string",
|
|
7690
|
+
description: `Optional Studio breakpoint log expression list for set, such as "'health', health". Literal text must be quoted as a Luau string. The tool prefixes this with "Breakpoint" and script_path:line. After reproducing, read get_runtime_logs with filter="Breakpoint" so breakpoint logs and Studio breakpoint errors are both visible.`
|
|
7691
|
+
},
|
|
7692
|
+
continue_execution: {
|
|
7693
|
+
type: "boolean",
|
|
7694
|
+
description: "Whether the breakpoint should log and continue without pausing. Defaults to true when log_message is provided; otherwise false. Only set false when you have first installed a ScriptDebuggerService.OnStopped handler on the same target that resumes breakpoint/non-exception stops with Enum.DebuggerResumeType.Resume; without that handler the playtest can get stuck and MCP can lose server/client peers."
|
|
7695
|
+
},
|
|
7696
|
+
target: {
|
|
7697
|
+
type: "string",
|
|
7698
|
+
description: 'Peer to target: "edit" (default), "server", or "client-N". Set edit breakpoints before playtests; target server/client-N for running play DataModels.'
|
|
7699
|
+
},
|
|
7700
|
+
instance_id: {
|
|
7701
|
+
type: "string",
|
|
7702
|
+
description: "Which connected Studio place to target. Required when multiple places are connected; omit when one. Use get_connected_instances to list available IDs."
|
|
7703
|
+
}
|
|
7704
|
+
},
|
|
7705
|
+
required: ["action"]
|
|
7706
|
+
}
|
|
7707
|
+
},
|
|
7566
7708
|
// === Multi-Instance ===
|
|
7567
7709
|
{
|
|
7568
7710
|
name: "get_connected_instances",
|
|
@@ -7612,7 +7754,7 @@ var init_definitions = __esm({
|
|
|
7612
7754
|
properties: {
|
|
7613
7755
|
instancePath: {
|
|
7614
7756
|
type: "string",
|
|
7615
|
-
description: "
|
|
7757
|
+
description: "Canonical path to the Model or Folder to export"
|
|
7616
7758
|
},
|
|
7617
7759
|
outputId: {
|
|
7618
7760
|
type: "string",
|
|
@@ -7769,7 +7911,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
7769
7911
|
},
|
|
7770
7912
|
targetPath: {
|
|
7771
7913
|
type: "string",
|
|
7772
|
-
description: "
|
|
7914
|
+
description: "Canonical parent DataModel path where the model will be created"
|
|
7773
7915
|
},
|
|
7774
7916
|
position: {
|
|
7775
7917
|
type: "array",
|
|
@@ -7900,7 +8042,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
7900
8042
|
},
|
|
7901
8043
|
targetPath: {
|
|
7902
8044
|
type: "string",
|
|
7903
|
-
description: "
|
|
8045
|
+
description: "Canonical parent DataModel path for the scene (default: game.Workspace)"
|
|
7904
8046
|
},
|
|
7905
8047
|
instance_id: {
|
|
7906
8048
|
type: "string",
|
|
@@ -7992,7 +8134,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
7992
8134
|
},
|
|
7993
8135
|
parentPath: {
|
|
7994
8136
|
type: "string",
|
|
7995
|
-
description: "
|
|
8137
|
+
description: "Canonical parent DataModel path (default: game.Workspace)"
|
|
7996
8138
|
},
|
|
7997
8139
|
position: {
|
|
7998
8140
|
type: "object",
|
|
@@ -8170,42 +8312,6 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8170
8312
|
}
|
|
8171
8313
|
}
|
|
8172
8314
|
},
|
|
8173
|
-
// === Character Navigation ===
|
|
8174
|
-
{
|
|
8175
|
-
name: "character_navigation",
|
|
8176
|
-
category: "write",
|
|
8177
|
-
description: 'Move the player character to a target position or instance during playtest. Uses PathfindingService for automatic navigation around obstacles, falling back to direct movement. Requires an active playtest in "play" mode. Does NOT simulate player input - moves the character directly.',
|
|
8178
|
-
inputSchema: {
|
|
8179
|
-
type: "object",
|
|
8180
|
-
properties: {
|
|
8181
|
-
position: {
|
|
8182
|
-
type: "array",
|
|
8183
|
-
items: { type: "number" },
|
|
8184
|
-
description: "Target world position [x, y, z]. Either this or instancePath is required."
|
|
8185
|
-
},
|
|
8186
|
-
instancePath: {
|
|
8187
|
-
type: "string",
|
|
8188
|
-
description: "Instance to navigate to (dot notation). The character walks to its Position. Either this or position is required."
|
|
8189
|
-
},
|
|
8190
|
-
waitForCompletion: {
|
|
8191
|
-
type: "boolean",
|
|
8192
|
-
description: "Wait for the character to arrive before returning (default: true)"
|
|
8193
|
-
},
|
|
8194
|
-
timeout: {
|
|
8195
|
-
type: "number",
|
|
8196
|
-
description: "Max seconds to wait for navigation to complete (default: 25)"
|
|
8197
|
-
},
|
|
8198
|
-
target: {
|
|
8199
|
-
type: "string",
|
|
8200
|
-
description: 'Instance target: "edit" (default), "server", "client-1", "client-2", etc.'
|
|
8201
|
-
},
|
|
8202
|
-
instance_id: {
|
|
8203
|
-
type: "string",
|
|
8204
|
-
description: "Which connected Studio place to target. Required when multiple places are connected; omit when one. Use get_connected_instances to list available IDs."
|
|
8205
|
-
}
|
|
8206
|
-
}
|
|
8207
|
-
}
|
|
8208
|
-
},
|
|
8209
8315
|
// === Instance Operations ===
|
|
8210
8316
|
{
|
|
8211
8317
|
name: "clone_object",
|
|
@@ -8216,11 +8322,11 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8216
8322
|
properties: {
|
|
8217
8323
|
instancePath: {
|
|
8218
8324
|
type: "string",
|
|
8219
|
-
description: "
|
|
8325
|
+
description: "Canonical path of the instance to clone"
|
|
8220
8326
|
},
|
|
8221
8327
|
targetParentPath: {
|
|
8222
8328
|
type: "string",
|
|
8223
|
-
description: "
|
|
8329
|
+
description: "Canonical path of the parent to place the clone under"
|
|
8224
8330
|
},
|
|
8225
8331
|
instance_id: {
|
|
8226
8332
|
type: "string",
|
|
@@ -8240,7 +8346,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8240
8346
|
properties: {
|
|
8241
8347
|
instancePath: {
|
|
8242
8348
|
type: "string",
|
|
8243
|
-
description: "
|
|
8349
|
+
description: "Canonical root DataModel path"
|
|
8244
8350
|
},
|
|
8245
8351
|
maxDepth: {
|
|
8246
8352
|
type: "number",
|
|
@@ -8267,11 +8373,11 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8267
8373
|
properties: {
|
|
8268
8374
|
instancePathA: {
|
|
8269
8375
|
type: "string",
|
|
8270
|
-
description: "First
|
|
8376
|
+
description: "First canonical DataModel path"
|
|
8271
8377
|
},
|
|
8272
8378
|
instancePathB: {
|
|
8273
8379
|
type: "string",
|
|
8274
|
-
description: "Second
|
|
8380
|
+
description: "Second canonical DataModel path"
|
|
8275
8381
|
},
|
|
8276
8382
|
instance_id: {
|
|
8277
8383
|
type: "string",
|
|
@@ -8281,29 +8387,6 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8281
8387
|
required: ["instancePathA", "instancePathB"]
|
|
8282
8388
|
}
|
|
8283
8389
|
},
|
|
8284
|
-
// === Output & Diagnostics ===
|
|
8285
|
-
{
|
|
8286
|
-
name: "get_output_log",
|
|
8287
|
-
category: "read",
|
|
8288
|
-
description: "Get the Studio output log history. Works in both edit and play mode.",
|
|
8289
|
-
inputSchema: {
|
|
8290
|
-
type: "object",
|
|
8291
|
-
properties: {
|
|
8292
|
-
maxEntries: {
|
|
8293
|
-
type: "number",
|
|
8294
|
-
description: "Maximum number of log entries to return (default: 100)"
|
|
8295
|
-
},
|
|
8296
|
-
messageType: {
|
|
8297
|
-
type: "string",
|
|
8298
|
-
description: 'Filter by message type (e.g. "Enum.MessageType.MessageOutput", "Enum.MessageType.MessageWarning", "Enum.MessageType.MessageError")'
|
|
8299
|
-
},
|
|
8300
|
-
instance_id: {
|
|
8301
|
-
type: "string",
|
|
8302
|
-
description: "Which connected Studio place to target. Required when multiple places are connected; omit when one. Use get_connected_instances to list available IDs."
|
|
8303
|
-
}
|
|
8304
|
-
}
|
|
8305
|
-
}
|
|
8306
|
-
},
|
|
8307
8390
|
// === Bulk Attributes ===
|
|
8308
8391
|
{
|
|
8309
8392
|
name: "bulk_set_attributes",
|
|
@@ -8314,7 +8397,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8314
8397
|
properties: {
|
|
8315
8398
|
instancePath: {
|
|
8316
8399
|
type: "string",
|
|
8317
|
-
description: "
|
|
8400
|
+
description: "Canonical DataModel path"
|
|
8318
8401
|
},
|
|
8319
8402
|
attributes: {
|
|
8320
8403
|
type: "object",
|
|
@@ -8396,7 +8479,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8396
8479
|
instance_paths: {
|
|
8397
8480
|
type: "array",
|
|
8398
8481
|
items: { type: "string" },
|
|
8399
|
-
description: 'DataModel paths to serialize (e.g. ["Workspace.TestRig", "ServerStorage.Templates.NPC"])'
|
|
8482
|
+
description: 'Canonical DataModel paths to serialize (e.g. ["game.Workspace.TestRig", "game.ServerStorage.Templates.NPC"])'
|
|
8400
8483
|
},
|
|
8401
8484
|
output_path: {
|
|
8402
8485
|
type: "string",
|
|
@@ -8438,7 +8521,7 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
8438
8521
|
},
|
|
8439
8522
|
parent_path: {
|
|
8440
8523
|
type: "string",
|
|
8441
|
-
description: 'DataModel path of the Instance to parent imported instances under (e.g. "ServerStorage.Imported")'
|
|
8524
|
+
description: 'Canonical DataModel path of the Instance to parent imported instances under (e.g. "game.ServerStorage.Imported")'
|
|
8442
8525
|
},
|
|
8443
8526
|
target: {
|
|
8444
8527
|
type: "string",
|