robloxstudio-mcp 2.2.7 → 2.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robloxstudio-mcp",
3
- "version": "2.2.7",
3
+ "version": "2.2.8",
4
4
  "description": "MCP Server for Roblox Studio Integration - Access Studio data, scripts, and objects through AI tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -3027,11 +3027,47 @@ return {
3027
3027
  local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
3028
3028
  local LogService = TS.import(script, script.Parent.Parent.Parent, "node_modules", "@rbxts", "services").LogService
3029
3029
  local StudioTestService = game:GetService("StudioTestService")
3030
+ local ServerScriptService = game:GetService("ServerScriptService")
3031
+ local ScriptEditorService = game:GetService("ScriptEditorService")
3032
+ local STOP_SIGNAL = "__MCP_STOP__"
3030
3033
  local testRunning = false
3031
3034
  local outputBuffer = {}
3032
3035
  local logConnection
3033
3036
  local testResult
3034
3037
  local testError
3038
+ local stopListenerScript
3039
+ local function buildStopListenerSource()
3040
+ return `local LogService = game:GetService("LogService")\
3041
+ local StudioTestService = game:GetService("StudioTestService")\
3042
+ LogService.MessageOut:Connect(function(message)\
3043
+ if message == "{STOP_SIGNAL}" then\
3044
+ pcall(function() StudioTestService:EndTest("stopped_by_mcp") end)\
3045
+ end\
3046
+ end)`
3047
+ end
3048
+ local function injectStopListener()
3049
+ local listener = Instance.new("Script")
3050
+ listener.Name = "__MCP_StopListener"
3051
+ listener.Parent = ServerScriptService
3052
+ local source = buildStopListenerSource()
3053
+ local seOk = pcall(function()
3054
+ ScriptEditorService:UpdateSourceAsync(listener, function()
3055
+ return source
3056
+ end)
3057
+ end)
3058
+ if not seOk then
3059
+ listener.Source = source
3060
+ end
3061
+ stopListenerScript = listener
3062
+ end
3063
+ local function cleanupStopListener()
3064
+ if stopListenerScript then
3065
+ pcall(function()
3066
+ return stopListenerScript:Destroy()
3067
+ end)
3068
+ stopListenerScript = nil
3069
+ end
3070
+ end
3035
3071
  local function startPlaytest(requestData)
3036
3072
  local mode = requestData.mode
3037
3073
  if mode ~= "play" and mode ~= "run" then
@@ -3048,7 +3084,11 @@ local function startPlaytest(requestData)
3048
3084
  outputBuffer = {}
3049
3085
  testResult = nil
3050
3086
  testError = nil
3087
+ cleanupStopListener()
3051
3088
  logConnection = LogService.MessageOut:Connect(function(message, messageType)
3089
+ if message == STOP_SIGNAL then
3090
+ return nil
3091
+ end
3052
3092
  local _outputBuffer = outputBuffer
3053
3093
  local _arg0 = {
3054
3094
  message = message,
@@ -3057,6 +3097,12 @@ local function startPlaytest(requestData)
3057
3097
  }
3058
3098
  table.insert(_outputBuffer, _arg0)
3059
3099
  end)
3100
+ local injected, injErr = pcall(function()
3101
+ return injectStopListener()
3102
+ end)
3103
+ if not injected then
3104
+ warn(`[MCP] Failed to inject stop listener: {injErr}`)
3105
+ end
3060
3106
  task.spawn(function()
3061
3107
  local ok, result = pcall(function()
3062
3108
  if mode == "play" then
@@ -3074,6 +3120,7 @@ local function startPlaytest(requestData)
3074
3120
  logConnection = nil
3075
3121
  end
3076
3122
  testRunning = false
3123
+ cleanupStopListener()
3077
3124
  end)
3078
3125
  return {
3079
3126
  success = true,
@@ -3086,14 +3133,7 @@ local function stopPlaytest(_requestData)
3086
3133
  error = "No test is currently running",
3087
3134
  }
3088
3135
  end
3089
- local ok, err = pcall(function()
3090
- StudioTestService:EndTest("stopped_by_mcp")
3091
- end)
3092
- if not ok then
3093
- return {
3094
- error = `EndTest failed: {err}`,
3095
- }
3096
- end
3136
+ warn(STOP_SIGNAL)
3097
3137
  local _object = {
3098
3138
  success = true,
3099
3139
  }
@@ -3103,7 +3143,7 @@ local function stopPlaytest(_requestData)
3103
3143
  table.move(outputBuffer, 1, #outputBuffer, _length + 1, _array)
3104
3144
  _object[_left] = _array
3105
3145
  _object.outputCount = #outputBuffer
3106
- _object.message = "Playtest stopped."
3146
+ _object.message = "Playtest stop signal sent."
3107
3147
  return _object
3108
3148
  end
3109
3149
  local function getPlaytestOutput(_requestData)
@@ -3133,7 +3173,7 @@ return {
3133
3173
  <Properties>
3134
3174
  <string name="Name">State</string>
3135
3175
  <string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
3136
- local CURRENT_VERSION = "2.2.7"
3176
+ local CURRENT_VERSION = "2.2.8"
3137
3177
  local MAX_CONNECTIONS = 5
3138
3178
  local BASE_PORT = 58741
3139
3179
  local activeTabIndex = 0
@@ -1,6 +1,10 @@
1
1
  import { LogService } from "@rbxts/services";
2
2
 
3
3
  const StudioTestService = game.GetService("StudioTestService");
4
+ const ServerScriptService = game.GetService("ServerScriptService");
5
+ const ScriptEditorService = game.GetService("ScriptEditorService");
6
+
7
+ const STOP_SIGNAL = "__MCP_STOP__";
4
8
 
5
9
  interface OutputEntry {
6
10
  message: string;
@@ -13,6 +17,40 @@ let outputBuffer: OutputEntry[] = [];
13
17
  let logConnection: RBXScriptConnection | undefined;
14
18
  let testResult: unknown;
15
19
  let testError: string | undefined;
20
+ let stopListenerScript: Script | undefined;
21
+
22
+ function buildStopListenerSource(): string {
23
+ return `local LogService = game:GetService("LogService")
24
+ local StudioTestService = game:GetService("StudioTestService")
25
+ LogService.MessageOut:Connect(function(message)
26
+ if message == "${STOP_SIGNAL}" then
27
+ pcall(function() StudioTestService:EndTest("stopped_by_mcp") end)
28
+ end
29
+ end)`;
30
+ }
31
+
32
+ function injectStopListener() {
33
+ const listener = new Instance("Script");
34
+ listener.Name = "__MCP_StopListener";
35
+ listener.Parent = ServerScriptService;
36
+
37
+ const source = buildStopListenerSource();
38
+ const [seOk] = pcall(() => {
39
+ ScriptEditorService.UpdateSourceAsync(listener, () => source);
40
+ });
41
+ if (!seOk) {
42
+ (listener as unknown as { Source: string }).Source = source;
43
+ }
44
+
45
+ stopListenerScript = listener;
46
+ }
47
+
48
+ function cleanupStopListener() {
49
+ if (stopListenerScript) {
50
+ pcall(() => stopListenerScript!.Destroy());
51
+ stopListenerScript = undefined;
52
+ }
53
+ }
16
54
 
17
55
  function startPlaytest(requestData: Record<string, unknown>) {
18
56
  const mode = requestData.mode as string | undefined;
@@ -30,7 +68,10 @@ function startPlaytest(requestData: Record<string, unknown>) {
30
68
  testResult = undefined;
31
69
  testError = undefined;
32
70
 
71
+ cleanupStopListener();
72
+
33
73
  logConnection = LogService.MessageOut.Connect((message, messageType) => {
74
+ if (message === STOP_SIGNAL) return;
34
75
  outputBuffer.push({
35
76
  message,
36
77
  messageType: messageType.Name,
@@ -38,6 +79,11 @@ function startPlaytest(requestData: Record<string, unknown>) {
38
79
  });
39
80
  });
40
81
 
82
+ const [injected, injErr] = pcall(() => injectStopListener());
83
+ if (!injected) {
84
+ warn(`[MCP] Failed to inject stop listener: ${injErr}`);
85
+ }
86
+
41
87
  task.spawn(() => {
42
88
  const [ok, result] = pcall(() => {
43
89
  if (mode === "play") {
@@ -57,6 +103,8 @@ function startPlaytest(requestData: Record<string, unknown>) {
57
103
  logConnection = undefined;
58
104
  }
59
105
  testRunning = false;
106
+
107
+ cleanupStopListener();
60
108
  });
61
109
 
62
110
  return { success: true, message: `Playtest started in ${mode} mode` };
@@ -67,19 +115,13 @@ function stopPlaytest(_requestData: Record<string, unknown>) {
67
115
  return { error: "No test is currently running" };
68
116
  }
69
117
 
70
- const [ok, err] = pcall(() => {
71
- (StudioTestService as unknown as { EndTest(reason: string): void }).EndTest("stopped_by_mcp");
72
- });
73
-
74
- if (!ok) {
75
- return { error: `EndTest failed: ${err}` };
76
- }
118
+ warn(STOP_SIGNAL);
77
119
 
78
120
  return {
79
121
  success: true,
80
122
  output: [...outputBuffer],
81
123
  outputCount: outputBuffer.size(),
82
- message: "Playtest stopped.",
124
+ message: "Playtest stop signal sent.",
83
125
  };
84
126
  }
85
127