Skip to main content
Glama
EL4CTEO

Roblox Studio MCP

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
studio_statusA

One-call snapshot of the connected Roblox Studio: place name and id, whether it is in edit / run / play mode, the current selection, which scripts are open in the editor, and how big the data model is.

Call this FIRST in any Studio session, and again whenever a tool reports NO_STUDIO or TIMEOUT — it is the cheapest way to tell a disconnected plugin apart from a genuinely failing request. Also call it before and after playtest, because most tools behave differently in run mode.

openScripts is what the user is actually working on: for each open tab it gives the script's path, the cursor line, any selected text, and which lines are on screen. Use it whenever a request is deictic — 'this function', 'the script I'm in', 'fix this' — instead of searching the place or asking which file they mean. Studio exposes no focused-tab API, so with several open, prefer the one holding a selection and otherwise ask.

Returns JSON. Selection is capped at 50 entries and selected text at 400 characters; use find or script_read for more.

list_studiosA

Lists every Roblox Studio window currently connected to this server, with its studioId, place name, transport (sse or poll), when it connected, and which one is active.

Call this whenever a tool reports AMBIGUOUS_STUDIO, and whenever the user refers to 'the other place' or 'my other window'. With a single Studio open every other tool targets it automatically, so you can skip it then.

Nothing is targeted by default when several are connected: pick one with set_active_studio, or pass studioId to a single tool call to act on one place without changing the default.

Each Studio is queried live, so placeName is the published name the user would recognise. A place never saved to Roblox has no published name and falls back to its data model name ('Place1').

context matters more than it looks. Pressing Play adds a second entry for the playtest's server — same place, same name, same id as the editor session. Instances created or changed in a 'playtest' context are thrown away the moment the user stops, so building there looks like it worked and then vanishes. Target 'edit' unless the user specifically wants to inspect or affect the running game.

set_active_studioA

Chooses which connected Studio window every other tool targets by default. Use it after list_studios when several places are open, and again whenever the user says to switch to another place.

The choice persists until it is changed or that Studio disconnects. While several Studios are connected and none has been chosen, tools refuse with AMBIGUOUS_STUDIO rather than guessing.

The choice belongs to this MCP connection alone. Several agents can share one Studio, and each keeps its own target, so calling this never moves another client's — two editors, or two sessions, can work on two places at once.

SUBAGENTS SHARE THEIR PARENT'S CONNECTION, and therefore its target. A subagent calling this retargets its parent and every sibling, and the damage is silent: later calls that name no studioId still succeed, just against the wrong place — and if that place is a playtest, everything written there is discarded when it stops. Inside a subagent, pass studioId on each call instead of calling this.

treeA

Lists the instance hierarchy under a path, breadth-first to a given depth. Returns a flat array of paths — flat is both cheaper and easier to act on than nested JSON, since every entry is directly usable as a path.

Use this to orient yourself in an unfamiliar place. Use find instead when you already know what you are looking for; a deep tree over a whole place wastes context on instances you will never touch.

With path omitted it lists only the containers a place is authored in — Workspace, ReplicatedStorage, ServerScriptService and friends. Roblox exposes ~120 services at the root, almost all engine internals; those are hidden and the response says how many. Pass an explicit path to look inside one of them anyway.

inspectA

Reads properties, attributes, tags and children of one or more instances. Pass every path you care about in a single call — batching costs one round trip instead of N.

Property selection comes from the live Roblox API dump for each instance's actual class, so it stays correct across engine updates: concise — class and child count only standard — the properties that characterise the class (Part gets Size, Position, CFrame, Anchored, Material...) full — every readable property; expensive, use on one or two instances at most

Bad paths do not fail the call: they come back under failures while the valid ones still return, so one typo does not cost you the whole batch.

findA

Searches the data model by name, class, property value and/or tag. Every filter you supply must match, so one call answers questions that would otherwise take several: "anchored BaseParts under Workspace.Map whose name contains door" is a single request.

This replaces separate name / class / property / tag search tools. Prefer it over tree whenever you know what you are looking for.

Tag searches are answered from CollectionService's index rather than by walking the tree, so they stay fast on large places. Narrow with path if a search reports TOO_BROAD.

script_readA

Reads Luau source from one or more scripts, with line numbers that script_edit accepts back verbatim.

Source comes from the Studio script editor's live buffer, so anything the user has typed but not yet saved is included. Reading the saved property instead would hand you stale code and you would 'fix' the change they just made.

Pass every script you need in one call. startLine/endLine apply to all of them, so use them when following one range across several files and read whole files otherwise.

script_editA

Edits Luau source through the Studio script editor. This is the tool to use for any change to existing code.

Every edit in one call is all-or-nothing: the whole batch is resolved against current source before anything is written, so if one edit cannot be applied nothing is. Batch related changes together, even across different scripts.

Each edit picks exactly one mode: find/replace — literal text, not a pattern. Preferred: it survives line numbers shifting. Fails if the text is not unique, unless you set replaceAll, so include enough surrounding lines to pin it down. startLine/endLine + replacement — for line ranges from script_read. Numbers refer to the file as you read it; several line edits to one script are applied bottom-up so they do not shift each other. source — replaces the whole script. Only for small files or a rewrite; it discards anything the user changed since you read it.

Writes go through ScriptEditorService:UpdateSourceAsync, so an open editor tab updates in place and unsaved work is preserved. Undo for source changes is the script editor's own, per script — Ctrl+Z in a script tab reverts that script, not the whole batch.

script_grepA

Searches inside Luau source across the place and returns matching lines with their paths and line numbers.

Use this to find where something is defined or used before editing it — it is far cheaper than reading whole scripts to look for one call.

Patterns are Lua patterns, which are not regular expressions: % escapes instead of backslash, there is no alternation, and - means a lazy quantifier. Set literal to search for text exactly as written, which is usually what you want for identifiers.

Matches come from the script editor's live buffer, so unsaved edits are searched too.

script_createA

Creates Script, LocalScript or ModuleScript instances with their source.

Batch related scripts into one call: they are created inside one ChangeHistoryService recording, so the user can drop a whole generated system in a single undo. The response says whether that recording was actually opened — Studio refuses while another one is in progress.

Prefer Script with runContext: "Client" over LocalScript in new work — a Script with an explicit RunContext runs wherever you parent it, while LocalScript only runs under a player's character, backpack or PlayerGui. Use script_edit to change a script that already exists.

createA

Creates instances with their properties, attributes and tags set at creation, as one undoable step.

Nest with children to build a whole model in a single call. That is both faster and safer than creating a parent and then addressing it: a new instance's path is not knowable until it exists, and same-named siblings make guessing it unreliable.

Property names are checked against the live Roblox API dump before anything is sent to Studio, so a typo comes back with the closest real names rather than an engine error.

Use script_create for Script, LocalScript and ModuleScript — it takes source directly.

modifyA

Sets properties, attributes and tags on existing instances, as one undoable step.

Each entry takes a list of paths, so one entry can apply the same change to many instances — anchoring 200 parts is one entry, not 200. Combine with find to build the path list.

The batch is all-or-nothing: if any value is rejected the recording is cancelled and every instance reverts, rather than leaving the place half-changed.

Values use the same notation the Properties panel shows — see the properties field. To change a script's code use script_edit.

deleteA

Destroys instances and everything inside them, as one undoable step.

Deleting a container deletes its whole subtree, so the response reports how many descendants went with each one — check it before telling the user what happened.

Services cannot be deleted and are refused. Paths shift when same-named siblings are removed, so read fresh paths from find or tree before a second delete rather than reusing indexes from an earlier call.

moveA

Reparents instances, or clones them into a new parent, as one undoable step.

Set mode: "clone" to copy instead of move — that is how to duplicate something, optionally renaming it in the same call.

Moving an instance into itself or its own descendant is refused: it silently detaches the branch from the data model and undo does not bring it back.

consoleA

Reads the Studio Output window — prints, warnings and runtime errors, newest last.

This is how to find out what actually happened after a playtest or an execute_luau call. An error here usually names the script and line, which script_read can then open directly.

Filter with level to see only errors, or pattern to follow one subsystem's logging. Up to 2000 lines are held, so prefer a filter over a large limit.

Each connected session keeps its own log, recorded from the moment its plugin loaded — the editor session and a running playtest server do not share one. To read what a playtest printed, target the playtest's studioId (see list_studios); the editor's log will not have it. Nothing printed before the plugin loaded is recoverable, and output from the playtest client is not reachable at all, because Studio forbids client sessions from making HTTP requests.

performanceA

Reads the engine's own counters, and can run the script profiler.

snapshot returns what the Developer Console shows: frame, physics and render times in milliseconds, instance and part counts, draw calls, network rates, and memory broken down by category. Use it to answer 'why is this place heavy' with numbers instead of guesses.

profile runs Studio's script profiler — the Script Performance window — for seconds and reports which scripts consumed CPU. It blocks for that long, so keep it short. It only sees code that actually runs, so start a playtest first; profiling an idle edit session returns nothing.

coverage reports which lines of which scripts actually executed — dead code, untested branches, whether a fix was even reached. Pass enable first, then play, then read the coverage back FROM THE PLAYTEST session, not the editor: instrumenting is per data model, and the playtest is a different one. enable is remembered for the place and re-applied by each new session as it loads. Pass an empty enable array to stop.

What it can and cannot see: instrumentation is fixed when a script is first compiled, so it measures modules required after that point — where most game logic lives — but never a script that starts with the place, which the data model compiles before any plugin exists. Those report 0 lines and are named as unmeasurable rather than counted as dead code.

scene breaks the place down by what it is actually made of: instances by category, triangles and draw calls, and the assets holding script, animation and audio memory — each named, so "2.4GB of memory" becomes "this animation is 138KB and these are the Animators using it". It also reports UNPARENTED INSTANCES, which is the closest thing here to a leak detector: objects still alive with nothing holding them in the tree, invisible to find and to tree because they are in neither.

Frame and network figures are only meaningful while something is running. Instance counts and memory are useful in edit mode too.

playtestA

Starts and stops playtests, so scripts can be made to run and then observed without asking the user to press anything.

play is the Play button: a character spawns and Players.PlayerAdded fires. run is Run mode, which executes scripts with no player at all. multiplayer starts a test with several players for testing replication. state reports without changing anything.

Pressing play adds a SECOND connected session for the playtest's server, and that is where the running game lives — console, performance and execute_luau must target its studioId, not the editor's. Call list_studios after starting and look for the entry whose context is a playtest.

A test does not block this call: it starts and the reply reports the state reached. Studio only ends it when something inside calls StudioTestService:EndTest(value) or when stop is used here; whatever EndTest passed comes back as lastResult on a later state. That makes a scripted check possible end to end: args is readable inside the test via StudioTestService:GetTestArgs(), so a test can be told what to do and report back what happened.

Stopping discards everything the playtest changed, exactly as pressing Stop does. Build in edit mode, then play — not the other way round.

The reply says whether the mode actually moved, not merely that Studio accepted the request.

execute_luauA

Runs Luau in Studio's plugin context and returns whatever it printed, returned, or threw.

This is the escape hatch. Reach for it only when no dedicated tool fits — create, modify, delete, move, script_edit and find validate their input, type values from the live API dump, and wrap writes in an undo recording. Code run here does none of that, so a typo becomes a runtime error instead of a suggestion, and changes it makes may not be undoable as one step.

Good uses: reading something no tool exposes, a one-off calculation over many instances, or calling an engine API the tools do not cover.

Output printed while it runs is captured and returned, so print is a reasonable way to get values out. return works too, including returning a table — it comes back as a structure, not a summary. There is no timeout: an infinite loop will hang Studio until it is force-quit.

Against a running playtest server, Studio disables loadstring, so the code is compiled through a ModuleScript instead and runs at script identity — plugin-only APIs are unavailable there. When that happens it is stated in the result rather than left to be inferred from a failure.

viewportA

Works with the 3D view and the Studio selection.

select sets, extends or shrinks what is highlighted in Studio. Select what you just built or changed — it shows the user the result, and puts the instance under Studio's own move and scale handles. studio_status reports the current selection; this sets it.

focus aims the Studio camera at an instance and frames it so the whole thing is on screen. This is what makes screenshot worth having: a picture of wherever the camera happened to be answers nothing, while a picture of the thing you just built answers 'does it look right', which no amount of reading properties can. Build, focus, screenshot.

The distance is computed from the subject's size and the camera's field of view, so a doorway and a whole map both arrive filling a similar share of the frame. from changes the angle you view it from, and padding how tightly it is framed.

camera sets or reads the camera directly, for shots framing cannot express — standing inside a room, or looking along a corridor.

raycast fires a ray through the world and reports the first thing it hits, with position, surface normal, distance and material. This answers 'what occupies this space', which the data model alone cannot: use it to find the ground under a spawn point, or check whether a gap is clear before placing something.

debugA

Sets breakpoints that record the stack and variables when they are hit, then reads back what they caught.

These are tracepoints, not a step debugger. A breakpoint fires, captures the call stack and the variables in scope, and lets execution continue; op: "snapshots" returns what was captured. Studio's debugger has to decide whether to resume the instant it stops, and cannot wait for a tool call to come back with an answer, so stepping through code line by line is not possible this way — but 'what was this value when it got here' is, which is usually the actual question.

condition is a Luau expression evaluated where the breakpoint sits, so a breakpoint can fire only on the case that matters — health < 0, player.Name == "someone".

logMessage is ALSO a Luau expression, not a template string: its value is printed when the breakpoint is hit, so write "index=" .. index rather than index={index}. Prose is a syntax error and the breakpoint is skipped. The engine prints it without stopping the thread at all, which makes it the cheapest way to watch a value change on a hot path or inside a tight loop — read the lines back with console.

So the two kinds cost different things: a logMessage breakpoint never stops and gives you one line you composed in advance, while one without it stops briefly and gives you the whole frame — every local and its type, without having to guess beforehand which value would matter. Reach for the log when you know what to watch, the capture when you do not.

Only one breakpoint exists per line, so the same line cannot both log and capture.

Put the breakpoint on a line that does something. A return, an end or a bare declaration can verify and then never fire — measured, not guessed: the same breakpoint moved from return squared, tag to the assignment above it went from silent to firing on every pass. If one verifies but catches nothing, suspect the line before suspecting the condition.

Breakpoints belong to the session that holds them. Set them in the editor session BEFORE starting a playtest, since code that already ran cannot be caught retroactively.

Nothing here leaves a thread stopped waiting for you. A capture breakpoint stops for as long as it takes to read the frame and then resumes itself, so a script with one mid-loop still runs to its last line, and the user is never left with a frozen Studio to rescue.

screenshotA

Takes a picture of the Studio viewport and returns it as an image you can actually look at.

Every other tool here reads the data model — names, properties, numbers — which answers 'is it there' but never 'does it look right'. A part can be at the correct position, anchored, correctly sized, and still be buried inside a wall, facing backwards, or hidden behind a GUI. Take a screenshot after building something visual, and before reporting that it worked.

It captures the viewport as the user currently sees it, so it shows their camera angle, not a framing of your choosing. Frame the subject with viewport op="focus" first — that is what makes this tool worth calling.

Works during a playtest too — address it at the playtest's studioId and you get the player's own view, which is the only way to check what a GUI actually looks like in front of the game. That one is taken on the client and read back through the editor session, so it is a little slower and needs the editor window still connected; the caption says playtest client when it came from there.

inputA

Sends real keyboard and mouse input to a running playtest — the same events a person pressing the keys would produce.

This is how to test what character cannot reach. character drives the Humanoid directly, which answers 'can it get to the door'; this answers 'does pressing E open it', 'does the sprint key work', 'does the menu close on Escape' — anything bound to input rather than to movement. Use character for going places and this for controls.

Steps run in order, so a sequence is one call: tap E, wait, click at a point, type a name. hold is how long a key or button stays down, after is how long to wait before the next step — a jump held for a second is a different test from a tapped one.

REQUIRES A RUNNING PLAYTEST, and must be addressed to the playtest's studioId from list_studios, not the editor's.

A pointer is drawn on screen and travels to each target before the click, so the user can see what you are aiming at. Turn it off with cursor: false.

How it works, because it explains the one thing that will surprise you: input belongs to the data model that creates it, and the character is driven by the CLIENT. Sending from the playtest's server succeeds and moves nothing. So this parents a short script into the player's PlayerGui, which runs on their client, and that reports back when the input has actually been delivered. Nothing is reported as sent until the client confirms it. If confirmation never arrives you get an error, not a success — check where things really are with character op="state".

Mouse coordinates are viewport pixels from the top-left, so pair this with screenshot to see what is where before clicking it.

deviceA

Resizes the Studio viewport to a real device, so you can see what a player on that device sees.

Most Roblox players are on a phone and most UI is built on a desktop monitor, which is where interfaces break: a button under the notch, a menu off the bottom of a 393-pixel-tall screen, text sized for a display three times larger. None of that is visible in the data model — every one of those instances has perfectly correct properties — so this is the only way to find it short of owning the hardware.

The workflow is: set a device, screenshot, look. Pair it with playtest to check a running game's HUD rather than the editor.

list gives the ids, each with its real name, form factor and resolution — ids look like "iphone_16", "ipad_a16", "samsung_galaxy_s25_ultra", "xbox", "meta_quest_3".

stop returns Studio to the normal editor viewport. Do that when you are finished: a left-over emulated device makes every later screenshot the wrong shape, and nothing on screen obviously says why.

apiA

Lists the properties, methods and events of any Roblox class, read from the engine that is running.

Use it before writing Luau against a class you are not certain of. Guessing a method name costs a runtime error and a round trip; this costs one call and is never out of date, because the answer comes from the running binary rather than from a published dump or from training data. That matters most for exactly the classes worth checking — new ones, and ones that changed recently.

Members come back as signatures rather than bare names — AddAccessory(accessory: Instance), HoldDuration: number — because a name tells you something exists and a signature tells you how to call it, which is the actual question.

describe takes a class name and gives the members it declares itself, counting the inherited ones separately. classes searches class names, which is how to find one whose exact spelling you do not have.

Deprecated members are never listed, only counted — Instance has eight, including clone, remove and getChildren. They still run, so picking one from a list gives you working code and a deprecation warning in the user's output.

This is not the same as inspect. inspect reads the values on an instance that exists; this reads the shape of a class whether or not anything in the place is one — which is what you need when deciding what to create in the first place.

geometryA

Cuts, joins and shatters parts with real constructive solid geometry.

This is how to build a shape that is not a box without importing a mesh: subtract a door out of a wall, union several parts into one solid, intersect to keep only the overlap, fragment to shatter something into debris.

subtract and intersect need the parts to actually overlap, and they fail differently when they do not. intersect returns nothing, which comes back as an error rather than a silent no-op. subtract returns the subject UNCHANGED — a full-size copy of it, reported as a created part — because cutting nothing out of something legitimately leaves it whole. So a subtract that succeeds is not proof that anything was cut: check the positions overlap with inspect first, or compare the result's size against the original.

Results keep the original's material, colour and anchoring. Roblox returns bare grey MeshParts, so a brick wall with a hole cut in it would otherwise come back as a grey slab — correct geometry that looks like a mistake.

The originals are consumed unless keepOriginals is set. The whole operation is one undo step.

assetsA

Searches Roblox's Creator Store and inserts models into the place.

search looks through the same public index Studio's own asset browser uses and returns ids with names, creators, vote ratios and — the part that matters — whether the model contains scripts. insert puts one into the place by id.

ALWAYS check hasScripts before inserting. Free models carrying scripts are the oldest hazard on the platform, and a model dropped into someone's game can run whatever it likes. The insert reports the script count again, and names them, so it can still be undone.

Only public assets can be inserted. A private or deleted id fails with a message saying so rather than inserting nothing quietly.

undoA

Steps Studio's undo history backwards or forwards.

Every write this server makes is already wrapped in an undo recording, so this reverses your own work as cleanly as the user pressing Ctrl+Z — one tool call is one step. Use it when the user says an edit was wrong, instead of trying to reconstruct the previous state by hand, which is guesswork and usually incomplete.

It reports how many steps actually applied, which is not always what was asked: the stack runs out, and an undo that did nothing otherwise looks exactly like one that worked.

Studio's history covers the whole session, including the user's own edits — undoing more steps than you made will start reverting THEIR work. Undo only what you just did, and only when asked.

collisionA

Controls which parts physically collide with which.

This is the right answer to 'these should pass through each other'. The alternative — turning CanCollide off — disables collision against everything, so a ghost that should pass through walls also falls through the floor.

The order is: create a group, assign parts to it, then set what it is collidable with. A group with nothing assigned does nothing.

Assigning a Model assigns every part inside it, which is almost always what is meant.

Groups are not undoable and not scoped to a session: remove when one was created to try something and is no longer wanted, rather than leaving it registered in the place indefinitely. The built-in "Default" group cannot be removed.

characterA

Moves and acts as the player character in a running playtest, so gameplay can be tested without asking the user to play it.

moveTo walks to a position or to an instance, following a path computed around walls and gaps rather than a straight line into them. It reports whether it ACTUALLY ARRIVED and how far short it stopped — a route blocked by something you did not know about otherwise looks identical to a successful walk.

act does the one-shot things worth testing: jump, sit, stand, respawn, kill (to exercise the death and respawn path), teleport, and equip/activate to use a Tool — which is how combat gets tested, since Activate is exactly what a mouse click triggers. Note that teleport skips everything in between, so triggers and collisions along the route do not fire — walk if you are testing those.

state reports position, health, walk speed and what the humanoid is doing. Call it before and after anything else here.

This drives the Humanoid directly rather than simulating keystrokes, which is the right tool for going places: pathfinding around a wall is one call here and a sequence of guessed key presses otherwise. For anything bound to a control rather than to movement — does E open the door, does the sprint key work, does Escape close the menu — use input, which sends real key and mouse events.

REQUIRES A RUNNING PLAYTEST, and the character lives in the playtest's data model — address these to the playtest's studioId from list_studios, not the editor's. Run mode has no character at all; use playtest op=play.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription
studio-statusWhich place is open, whether it is playing, what is selected, and which scripts the user has on screen. The cheapest orientation there is.
studio-treeThe authored containers and what is directly inside them, two levels deep. A map of the place, without the ~120 engine services that would bury it.
studio-consoleThe last 100 lines Studio printed, warnings and errors included. Reading this after a playtest is usually the first useful thing to do.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/EL4CTEO/rbx-studio-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server