@el4cteo/rbx-studio-mcp 0.1.4 → 0.1.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.js CHANGED
@@ -20,7 +20,7 @@ import { registerInputTools } from "./tools/input.js";
20
20
  import { registerDeviceTools } from "./tools/device.js";
21
21
  import { registerApiTools } from "./tools/api.js";
22
22
  import { registerResources } from "./resources.js";
23
- const VERSION = "0.1.4";
23
+ const VERSION = "0.1.5";
24
24
  function parsePort(argv) {
25
25
  const flag = argv.indexOf("--port");
26
26
  const raw = flag !== -1 ? argv[flag + 1] : process.env["ROBLOX_STUDIO_MCP_PORT"];
@@ -21,11 +21,6 @@ export function registerSessionTools(context) {
21
21
  "place or asking which file they mean. Studio exposes no focused-tab API, " +
22
22
  "so with several open, prefer the one holding a selection and otherwise " +
23
23
  "ask.\n\n" +
24
- "`debuggerBeta: \"off\"` appears only when the Debugger Luau API beta is " +
25
- "disabled, which is the default. `debug` cannot work until the user turns " +
26
- "it on in File > Beta Features and restarts Studio — tell them rather than " +
27
- "retrying, because nothing an agent can do will enable it. Everything else " +
28
- "works regardless.\n\n" +
29
24
  "Returns JSON. Selection is capped at 50 entries and selected text at 400 " +
30
25
  "characters; use `find` or `script_read` for more.",
31
26
  inputSchema: {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/tools/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/tools/session.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@el4cteo/rbx-studio-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Free, open-source MCP server for Roblox Studio. Push-based SSE transport, editor-safe script edits, token-lean tools.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,7 +9,7 @@
9
9
 
10
10
  local Config = {}
11
11
 
12
- Config.PLUGIN_VERSION = "0.1.4"
12
+ Config.PLUGIN_VERSION = "0.1.5"
13
13
 
14
14
  -- Fingerprint of plugin/src, stamped in by scripts/build-plugin.mjs. The server
15
15
  -- computes the same hash from its own copy of the sources and compares, so a
@@ -45,16 +45,17 @@
45
45
  --[[
46
46
  Fetched defensively, because this module is required at plugin start.
47
47
 
48
- `ScriptDebuggerService` exists only when the "Debugger Luau API" beta is on,
49
- and `GetService` throws for a service that is not registered. This file is
50
- required from init.server.luau alongside every other handler, so an
51
- unguarded throw here would take down the whole plugin -- every tool, not
52
- just these three -- for the majority of users, who have the beta off. The
53
- failure would also be silent from the outside: no plugin, no connection, and
54
- nothing to read.
55
-
56
- Missing is therefore a value, not an error, and `requireService` turns it
57
- into a message naming the beta.
48
+ Measured with the beta off and Studio restarted: `GetService` does NOT throw
49
+ here, it hands back a working service object. So this guard is not fixing an
50
+ observed crash -- it is insurance on the one call in this file that runs
51
+ before any tool is invoked. init.server.luau requires this module alongside
52
+ every other handler, so a throw at this line would take down all 29 tools
53
+ rather than the three that need a debugger, and it would do it silently: a
54
+ plugin that never loads never connects, leaving nothing to read anywhere.
55
+
56
+ The beta is NOT detected here, because nothing detects it cheaply. See the
57
+ note on the wholesale-refusal branch in `Debug.set` for the two probes that
58
+ were tried and why neither works.
58
59
  ]]
59
60
  local ScriptDebuggerService: any = nil
60
61
  do
@@ -322,6 +323,35 @@ function Debug.set(params: { [string]: any }): { [string]: any }
322
323
  end
323
324
  end
324
325
 
326
+ --[[
327
+ A wholesale refusal names the likely cause without asserting it.
328
+
329
+ `AddBreakpoint` is where the "Debugger Luau API" beta actually bites, and
330
+ its own message -- "Failed to execute AddBreakpoint request" -- names
331
+ nothing anyone can act on. The beta cannot be detected from here to say
332
+ so with certainty, and two attempts to are worth recording so they are
333
+ not tried a third time: with the beta OFF, `GetService`, `FindService`,
334
+ assigning `OnStopped` and `Enum.DebuggerResumeType` all still succeed;
335
+ with the beta ON, `ReflectionService` still does not list the class. The
336
+ first is always available and the second never is, so neither varies with
337
+ the thing being measured.
338
+
339
+ The only reliable test is this call, which cannot be run speculatively on
340
+ a user's script just to answer a status question. So the hint says what
341
+ to check first and what else it could be, and does not claim to know.
342
+ ]]
343
+ if #added == 0 and #failed > 0 then
344
+ Dispatch.fail(
345
+ "NO_BREAKPOINTS_SET",
346
+ string.format("No breakpoint could be set; all %d were refused.", #failed),
347
+ "Check that \"Debugger Luau API\" is on in File > Beta Features and that "
348
+ .. "Studio has been restarted since -- that is the usual cause, it is "
349
+ .. "off by default, and only the user can change it. Otherwise the "
350
+ .. "line may not be one that runs: a `return`, an `end` or a bare "
351
+ .. "declaration is often refused, so try the statement above it."
352
+ )
353
+ end
354
+
325
355
  return { added = added, failed = failed, installed = installed }
326
356
  end
327
357
 
@@ -1,185 +1,169 @@
1
- --!strict
2
- --[[
3
- Session and connectivity handlers. `studio.status` is the cheapest call in the
4
- system and doubles as the liveness probe, so it must never touch anything
5
- expensive -- notably it counts descendants lazily and caps the selection.
6
- ]]
7
-
8
- local MarketplaceService = game:GetService("MarketplaceService")
9
- local RunService = game:GetService("RunService")
10
- local Selection = game:GetService("Selection")
11
-
12
- local Dispatch = require(script.Parent.Parent.Dispatch)
13
- local Context = require(script.Parent.Parent.Context)
14
- local Editor = require(script.Parent.Parent.Editor)
15
- local Emulation = require(script.Parent.Parent.Emulation)
16
- local Paths = require(script.Parent.Parent.Paths)
17
-
18
- -- `version()` is marked deprecated but remains the only way to read the Studio
19
- -- build, and the agent needs it to know which engine APIs actually exist in this
20
- -- session. Bound indirectly so the deprecation lint stays enabled file-wide.
21
- local studioVersion: () -> string = (version :: any)
22
-
23
- --[[
24
- Whether the Debugger Luau API beta is on.
25
-
26
- `ScriptDebuggerService` is registered only when it is, so asking for the
27
- service is the test. Guarded because `GetService` throws on a service that
28
- does not exist, and status must answer for every Studio rather than only the
29
- ones where `debug` would have worked anyway.
30
- ]]
31
- local function debuggerAvailable(): boolean
32
- return (pcall(game.GetService, game, "ScriptDebuggerService"))
33
- end
34
-
35
- -- Selection can be tens of thousands of instances after a rubber-band drag.
36
- -- Anything past this is noise for an agent and would blow the response budget.
37
- local MAX_SELECTION = 50
38
-
39
- -- Counting descendants of a large place is O(n) over the whole DataModel, so it
40
- -- is cached briefly; status is polled often enough for this to matter.
41
- local COUNT_CACHE_SECONDS = 5
42
-
43
- local cachedCounts: { descendants: number, scripts: number }? = nil
44
- local cachedAt = 0
45
-
46
- --[[
47
- Which device Studio is pretending to be, or nil for none.
48
-
49
- Reported here because nothing else says it. Device emulation resizes the
50
- viewport and stays on until it is switched off, so every screenshot after it
51
- comes back the wrong shape with no indication why -- and a caller who did not
52
- set it, or who set it twenty calls ago, has no way to find out. `status` is
53
- the call agents are told to make first, which makes it the right place for a
54
- piece of session state that silently changes what everything else returns.
55
- ]]
56
- local function counts(): { descendants: number, scripts: number }
57
- local now = os.clock()
58
- local cache = cachedCounts
59
- if cache and now - cachedAt < COUNT_CACHE_SECONDS then
60
- return cache
61
- end
62
-
63
- local descendants = 0
64
- local scripts = 0
65
- for _, instance in game:GetDescendants() do
66
- descendants += 1
67
- if instance:IsA("LuaSourceContainer") then
68
- scripts += 1
69
- end
70
- end
71
-
72
- local fresh = { descendants = descendants, scripts = scripts }
73
- cachedCounts = fresh
74
- cachedAt = now
75
- return fresh
76
- end
77
-
78
- --[[
79
- The name the user would recognise.
80
-
81
- `game.Name` is the data model's name -- "Place1", "Place5" -- and has nothing
82
- to do with what the place is called on the Studio tab or the Creator
83
- Dashboard. Nothing local holds the real name: it lives on Roblox's servers, so
84
- it takes a lookup. Without it, a user saying "the other place, the published
85
- one" cannot be matched to any window, which is the whole point of being able
86
- to drive several Studios at once.
87
-
88
- Cached, including the failure, because an unpublished place would otherwise
89
- make a doomed web request on every status call.
90
- ]]
91
- local NAME_RETRY_SECONDS = 60
92
-
93
- local resolvedName: string? = nil
94
- local resolvedFor = -1
95
- local resolvedAt = 0
96
-
97
- local function publishedPlaceName(): string?
98
- local placeId = game.PlaceId
99
- -- A place that has never been saved to Roblox has no id and no remote name.
100
- if placeId == 0 then
101
- return nil
102
- end
103
-
104
- local fresh = resolvedFor == placeId
105
- and (resolvedName ~= nil or os.clock() - resolvedAt < NAME_RETRY_SECONDS)
106
- if fresh then
107
- return resolvedName
108
- end
109
-
110
- resolvedFor = placeId
111
- resolvedAt = os.clock()
112
-
113
- local ok, info = pcall(function()
114
- return MarketplaceService:GetProductInfo(placeId, Enum.InfoType.Asset)
115
- end)
116
- local name = if ok and typeof(info) == "table" then (info :: any).Name else nil
117
- resolvedName = if typeof(name) == "string" and name ~= "" then name else nil
118
- return resolvedName
119
- end
120
-
121
- local Session = {}
122
-
123
- function Session.status(): { [string]: any }
124
- local selected: { { path: string, className: string } } = {}
125
- for index, instance in Selection:Get() do
126
- if index > MAX_SELECTION then
127
- break
128
- end
129
- table.insert(selected, { path = Paths.of(instance), className = instance.ClassName })
130
- end
131
-
132
- local totals = counts()
133
- -- Open tabs ride along with status rather than getting their own tool: this
134
- -- is the call agents are told to make first, and "which script is the user
135
- -- looking at" is orientation, not a separate question.
136
- local openScripts = Editor.documents()
137
-
138
- local published = publishedPlaceName()
139
-
140
- return {
141
- openScripts = if #openScripts > 0 then openScripts else nil,
142
- placeName = published or (if game.Name ~= "" then game.Name else "Untitled place"),
143
- -- Kept separate when the two differ, so a path rooted at the data model
144
- -- name stays explicable next to a place called something else entirely.
145
- dataModelName = if published and published ~= game.Name then game.Name else nil,
146
- placeId = game.PlaceId,
147
- context = Context.of(),
148
- -- RunService:IsRunning() is true for both Play and Run; IsEdit()
149
- -- distinguishes the authoring session from a live one.
150
- isRunning = RunService:IsRunning(),
151
- isEdit = RunService:IsEdit(),
152
- isRunMode = RunService:IsRunning() and not RunService:IsClient(),
153
- isServerView = RunService:IsServer(),
154
- selection = selected,
155
- selectionCount = #Selection:Get(),
156
- descendantCount = totals.descendants,
157
- scriptCount = totals.scripts,
158
- studioVersion = studioVersion(),
159
- emulatedDevice = Emulation.summary(),
160
- -- Present only when it is off, so the usual answer costs nothing. Said
161
- -- here rather than left for `debug` to discover, because the fix needs
162
- -- the user: it is a Studio setting behind a restart, not something an
163
- -- agent can turn on mid-task.
164
- debuggerBeta = if debuggerAvailable() then nil else "off",
165
- }
166
- end
167
-
168
- --[[
169
- Round-trip probe used by the smoke test and by `studio_status` when the agent
170
- only needs to know the channel is alive.
171
- ]]
172
- function Session.ping(params: { [string]: any }): { [string]: any }
173
- return { pong = true, echo = params.echo }
174
- end
175
-
176
- function Session.register()
177
- Dispatch.registerAll("studio", {
178
- status = function()
179
- return Session.status()
180
- end,
181
- ping = Session.ping,
182
- })
183
- end
184
-
185
- return Session
1
+ --!strict
2
+ --[[
3
+ Session and connectivity handlers. `studio.status` is the cheapest call in the
4
+ system and doubles as the liveness probe, so it must never touch anything
5
+ expensive -- notably it counts descendants lazily and caps the selection.
6
+ ]]
7
+
8
+ local MarketplaceService = game:GetService("MarketplaceService")
9
+ local RunService = game:GetService("RunService")
10
+ local Selection = game:GetService("Selection")
11
+
12
+ local Dispatch = require(script.Parent.Parent.Dispatch)
13
+ local Context = require(script.Parent.Parent.Context)
14
+ local Editor = require(script.Parent.Parent.Editor)
15
+ local Emulation = require(script.Parent.Parent.Emulation)
16
+ local Paths = require(script.Parent.Parent.Paths)
17
+
18
+ -- `version()` is marked deprecated but remains the only way to read the Studio
19
+ -- build, and the agent needs it to know which engine APIs actually exist in this
20
+ -- session. Bound indirectly so the deprecation lint stays enabled file-wide.
21
+ local studioVersion: () -> string = (version :: any)
22
+
23
+
24
+ -- Selection can be tens of thousands of instances after a rubber-band drag.
25
+ -- Anything past this is noise for an agent and would blow the response budget.
26
+ local MAX_SELECTION = 50
27
+
28
+ -- Counting descendants of a large place is O(n) over the whole DataModel, so it
29
+ -- is cached briefly; status is polled often enough for this to matter.
30
+ local COUNT_CACHE_SECONDS = 5
31
+
32
+ local cachedCounts: { descendants: number, scripts: number }? = nil
33
+ local cachedAt = 0
34
+
35
+ --[[
36
+ Which device Studio is pretending to be, or nil for none.
37
+
38
+ Reported here because nothing else says it. Device emulation resizes the
39
+ viewport and stays on until it is switched off, so every screenshot after it
40
+ comes back the wrong shape with no indication why -- and a caller who did not
41
+ set it, or who set it twenty calls ago, has no way to find out. `status` is
42
+ the call agents are told to make first, which makes it the right place for a
43
+ piece of session state that silently changes what everything else returns.
44
+ ]]
45
+ local function counts(): { descendants: number, scripts: number }
46
+ local now = os.clock()
47
+ local cache = cachedCounts
48
+ if cache and now - cachedAt < COUNT_CACHE_SECONDS then
49
+ return cache
50
+ end
51
+
52
+ local descendants = 0
53
+ local scripts = 0
54
+ for _, instance in game:GetDescendants() do
55
+ descendants += 1
56
+ if instance:IsA("LuaSourceContainer") then
57
+ scripts += 1
58
+ end
59
+ end
60
+
61
+ local fresh = { descendants = descendants, scripts = scripts }
62
+ cachedCounts = fresh
63
+ cachedAt = now
64
+ return fresh
65
+ end
66
+
67
+ --[[
68
+ The name the user would recognise.
69
+
70
+ `game.Name` is the data model's name -- "Place1", "Place5" -- and has nothing
71
+ to do with what the place is called on the Studio tab or the Creator
72
+ Dashboard. Nothing local holds the real name: it lives on Roblox's servers, so
73
+ it takes a lookup. Without it, a user saying "the other place, the published
74
+ one" cannot be matched to any window, which is the whole point of being able
75
+ to drive several Studios at once.
76
+
77
+ Cached, including the failure, because an unpublished place would otherwise
78
+ make a doomed web request on every status call.
79
+ ]]
80
+ local NAME_RETRY_SECONDS = 60
81
+
82
+ local resolvedName: string? = nil
83
+ local resolvedFor = -1
84
+ local resolvedAt = 0
85
+
86
+ local function publishedPlaceName(): string?
87
+ local placeId = game.PlaceId
88
+ -- A place that has never been saved to Roblox has no id and no remote name.
89
+ if placeId == 0 then
90
+ return nil
91
+ end
92
+
93
+ local fresh = resolvedFor == placeId
94
+ and (resolvedName ~= nil or os.clock() - resolvedAt < NAME_RETRY_SECONDS)
95
+ if fresh then
96
+ return resolvedName
97
+ end
98
+
99
+ resolvedFor = placeId
100
+ resolvedAt = os.clock()
101
+
102
+ local ok, info = pcall(function()
103
+ return MarketplaceService:GetProductInfo(placeId, Enum.InfoType.Asset)
104
+ end)
105
+ local name = if ok and typeof(info) == "table" then (info :: any).Name else nil
106
+ resolvedName = if typeof(name) == "string" and name ~= "" then name else nil
107
+ return resolvedName
108
+ end
109
+
110
+ local Session = {}
111
+
112
+ function Session.status(): { [string]: any }
113
+ local selected: { { path: string, className: string } } = {}
114
+ for index, instance in Selection:Get() do
115
+ if index > MAX_SELECTION then
116
+ break
117
+ end
118
+ table.insert(selected, { path = Paths.of(instance), className = instance.ClassName })
119
+ end
120
+
121
+ local totals = counts()
122
+ -- Open tabs ride along with status rather than getting their own tool: this
123
+ -- is the call agents are told to make first, and "which script is the user
124
+ -- looking at" is orientation, not a separate question.
125
+ local openScripts = Editor.documents()
126
+
127
+ local published = publishedPlaceName()
128
+
129
+ return {
130
+ openScripts = if #openScripts > 0 then openScripts else nil,
131
+ placeName = published or (if game.Name ~= "" then game.Name else "Untitled place"),
132
+ -- Kept separate when the two differ, so a path rooted at the data model
133
+ -- name stays explicable next to a place called something else entirely.
134
+ dataModelName = if published and published ~= game.Name then game.Name else nil,
135
+ placeId = game.PlaceId,
136
+ context = Context.of(),
137
+ -- RunService:IsRunning() is true for both Play and Run; IsEdit()
138
+ -- distinguishes the authoring session from a live one.
139
+ isRunning = RunService:IsRunning(),
140
+ isEdit = RunService:IsEdit(),
141
+ isRunMode = RunService:IsRunning() and not RunService:IsClient(),
142
+ isServerView = RunService:IsServer(),
143
+ selection = selected,
144
+ selectionCount = #Selection:Get(),
145
+ descendantCount = totals.descendants,
146
+ scriptCount = totals.scripts,
147
+ studioVersion = studioVersion(),
148
+ emulatedDevice = Emulation.summary(),
149
+ }
150
+ end
151
+
152
+ --[[
153
+ Round-trip probe used by the smoke test and by `studio_status` when the agent
154
+ only needs to know the channel is alive.
155
+ ]]
156
+ function Session.ping(params: { [string]: any }): { [string]: any }
157
+ return { pong = true, echo = params.echo }
158
+ end
159
+
160
+ function Session.register()
161
+ Dispatch.registerAll("studio", {
162
+ status = function()
163
+ return Session.status()
164
+ end,
165
+ ping = Session.ping,
166
+ })
167
+ end
168
+
169
+ return Session