The Model Context Protocol (MCP) lets AI assistants like Claude Code talk directly to Roblox Studio — reading your scene, writing scripts, inserting objects, and running code in real time. Instead of copy-pasting snippets back and forth, you get a live two-way bridge between the AI and your game.
This article walks you from zero to advanced: setting up the connection, then building increasingly complex things with Claude Code as your co-developer.
How the MCP Bridge Works
Claude Code ──stdio──► MCP Server (local binary) ──HTTP poll──► Roblox Studio Plugin
│
└── reads/writes your Place
The MCP server runs on your machine. A Studio plugin long-polls it for commands. When Claude calls a tool (e.g. run_code), the plugin executes it inside Studio and returns the result. Nothing leaves your machine except the prompts you send to Claude.
Setup
1. Install the MCP Server
Roblox now ships an MCP server built into Studio (as of February 2026). It is the recommended option — no Rust toolchain required.
Open Roblox Studio → File → Studio Settings → Beta Features → enable MCP Server.
Studio will start listening on localhost:3004 by default.
For the standalone open-source server (legacy), see the studio-rust-mcp-server repo. It is no longer actively updated but works as a reference.
2. Register it with Claude Code
claude mcp add roblox-studio --transport http http://localhost:3004/mcp
Or, if you are using the standalone binary on macOS:
claude mcp add --transport stdio roblox_studio \
-- '/Applications/RobloxStudioMCP.app/Contents/MacOS/rbx-studio-mcp' --stdio
Verify the tools are available:
claude mcp list
# roblox-studio ✓ tools: run_code, insert_model, get_console_output, ...
3. Open a Place in Studio
MCP commands operate on the currently open place. Open any baseplate and keep Studio visible — you will see changes happen live as Claude works.
Beginner: Spawning Objects and Running Scripts
Spawn a colored part
Tell Claude:
“In Roblox Studio, create a bright red brick part at position (0, 5, 0) with size (4, 4, 4).”
Claude calls run_code with:
local part = Instance.new("Part")
part.Size = Vector3.new(4, 4, 4)
part.Position = Vector3.new(0, 5, 0)
part.BrickColor = BrickColor.new("Bright red")
part.Anchored = true
part.Parent = workspace
The part appears in Studio instantly.
Print workspace contents
“List every object currently in Workspace.”
for _, obj in ipairs(workspace:GetChildren()) do
print(obj.Name, obj.ClassName)
end
Claude calls get_console_output afterwards to read the result and shows you the list directly in the chat.
Insert a free model
“Insert a SpawnLocation from the Creator Store.”
Claude calls insert_model with the asset ID. The model drops into your scene — no manual searching in the toolbox required.
Intermediate: Building Game Systems
Basic coin pickup system
“Create a coin pickup system. Coins should be yellow spheres scattered at random positions. When a player touches one it disappears and prints a message.”
Claude writes and inserts two scripts:
ServerScript (inside ServerScriptService):
local function createCoin(position)
local coin = Instance.new("Part")
coin.Name = "Coin"
coin.Shape = Enum.PartType.Ball
coin.Size = Vector3.new(1, 1, 1)
coin.BrickColor = BrickColor.new("Bright yellow")
coin.Material = Enum.Material.Neon
coin.Position = position
coin.Anchored = true
coin.Parent = workspace
coin.Touched:Connect(function(hit)
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
print(player.Name .. " collected a coin!")
coin:Destroy()
end
end)
end
-- Spawn 10 coins at random positions
for i = 1, 10 do
local x = math.random(-20, 20)
local z = math.random(-20, 20)
createCoin(Vector3.new(x, 2, z))
end
Then you ask Claude to test it:
“Start play mode and tell me if the coins spawned correctly.”
Claude calls start_stop_play, waits, then reads get_console_output to report back.
Leaderboard with points
“Add a leaderboard that tracks each player’s coin count. Increment it when they pick up a coin.”
Claude updates the script to use leaderstats:
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = leaderstats
end)
And modifies the touch handler:
local player = game.Players:GetPlayerFromCharacter(character)
if player then
player.leaderstats.Coins.Value += 1
coin:Destroy()
end
Advanced: Agentic Workflows
At this level you stop giving Claude individual instructions and start giving it goals. Claude plans, executes multiple tool calls, reads results, and iterates — just like a junior developer would.
Generate a complete obstacle course
“Design a 10-stage obstacle course that goes from easy to hard. Each stage should have a different mechanic: moving platforms, lava floors, shrinking paths. Add checkpoints between stages.”
Claude breaks this into steps automatically:
- Calls
run_codeto clear the workspace baseline - Generates each stage in a loop — different part configurations per stage
- Inserts
SpawnPartcheckpoints withTeleportServicehooks - Starts play mode via
start_stop_playto verify pathability - Reads
get_console_outputfor any errors - Patches broken stages and re-tests
No single prompt handles all of this — Claude chains tool calls until it is satisfied with the result.
Find and fix deprecated APIs
“Scan every Script and LocalScript in the game. List any that use deprecated Roblox APIs and rewrite them to use the modern equivalents.”
-- Claude uses run_code to enumerate scripts:
local function scanScripts(parent, results)
for _, obj in ipairs(parent:GetDescendants()) do
if obj:IsA("Script") or obj:IsA("LocalScript") then
table.insert(results, {name = obj:GetFullName(), source = obj.Source})
end
end
end
local results = {}
scanScripts(game, results)
for _, s in ipairs(results) do
print("===", s.name)
print(s.source)
end
Claude reads the console output, identifies usages like game.Players.LocalPlayer.Character.Humanoid.Health (deprecated pattern), and rewrites each script in place with a follow-up run_code call.
AI-driven NPC behavior
“Create an NPC that patrols between 3 waypoints. If a player gets within 10 studs, the NPC chases them. If the player escapes to 30 studs, the NPC returns to patrol.”
Claude generates a full state-machine script:
local NPC = workspace.NPC -- Claude inserts the NPC model first
local humanoid = NPC:FindFirstChild("Humanoid")
local rootPart = NPC:FindFirstChild("HumanoidRootPart")
local waypoints = {
Vector3.new(0, 0, 0),
Vector3.new(20, 0, 0),
Vector3.new(20, 0, 20),
}
local currentWaypoint = 1
local state = "patrol" -- "patrol" | "chase"
local CHASE_RANGE = 10
local ESCAPE_RANGE = 30
local function getNearestPlayer()
local nearest, dist = nil, math.huge
for _, p in ipairs(game.Players:GetPlayers()) do
local char = p.Character
if char and char:FindFirstChild("HumanoidRootPart") then
local d = (char.HumanoidRootPart.Position - rootPart.Position).Magnitude
if d < dist then nearest, dist = p, d end
end
end
return nearest, dist
end
game:GetService("RunService").Heartbeat:Connect(function()
local player, dist = getNearestPlayer()
if state == "patrol" then
if dist <= CHASE_RANGE then
state = "chase"
else
humanoid:MoveTo(waypoints[currentWaypoint])
if (rootPart.Position - waypoints[currentWaypoint]).Magnitude < 3 then
currentWaypoint = (currentWaypoint % #waypoints) + 1
end
end
elseif state == "chase" then
if dist > ESCAPE_RANGE then
state = "patrol"
elseif player.Character then
humanoid:MoveTo(player.Character.HumanoidRootPart.Position)
end
end
end)
After inserting the script Claude starts play mode, reads the console, and reports whether the NPC is moving correctly.
Useful Prompts Reference
| Goal | Prompt |
|---|---|
| Inspect scene | ”List every object in Workspace with its class and position.” |
| Quick prototype | ”Create a working door that opens when a player touches a button.” |
| Debug errors | ”Run the game, collect any errors from the console, and fix them.” |
| Bulk changes | ”Rename every Part named ‘Block’ to ‘Platform’ across the whole game.” |
| Performance audit | ”Find scripts using loops without task.wait() and add appropriate yields.” |
| Asset insertion | ”Insert a tree model from the Creator Store and place 20 copies randomly.” |
Security Considerations
- The MCP server runs locally — no game data leaves your machine to Roblox.
- Your prompts do go to Anthropic’s servers (Claude’s API). Avoid sending passwords, API keys, or private user data in prompts.
- Only connect trusted MCP clients (official Claude builds, Cursor). The server grants programmatic write access to your open place.
- Roblox’s built-in MCP server respects Studio’s undo history — you can Ctrl+Z changes Claude makes.
Sources
- Introducing the Open Source Studio MCP Server — Roblox Developer Forum
- Studio MCP Server Updates and External LLM Support — Roblox Developer Forum
- Assistant Updates: Studio Built-in MCP Server and Playtest Automation — Roblox Developer Forum
- Roblox/studio-rust-mcp-server — GitHub
- ZubeidHendricks/roblox-studio-mcp-claude-code — GitHub
- boshyxd/robloxstudio-mcp — GitHub
- Official Roblox Studio MCP Server — PulseMCP
- Roblox Studio MCP v2.5.0 — Community Resources