Skip to content

aaronaalmendarez/roblox-mcp

Repository files navigation

🎮 Roblox Studio MCP

Give your AI full access to Roblox Studio

npm License Node TypeScript

Claude · Gemini · Codex · OpenCode · any MCP client

Quick Start · Features · Tools · Client Setup · Docs


An MCP server that connects AI assistants directly to a running Roblox Studio session. Read the instance tree, edit Luau scripts, set properties, manage attributes & tags, create objects, detect drift, and sync source files — all over a 100% local connection that never leaves your machine.

  Your AI                    MCP Server                Studio Plugin
 ┌──────────┐    stdio    ┌──────────────┐   HTTP    ┌──────────────┐
 │  Claude   │◄──────────►│   Node.js    │◄─────────►│    Luau      │
 │  Gemini   │            │  port 3002   │ localhost │  polls every │
 │  Codex    │            │              │           │    500ms     │
 └──────────┘            └──────┬───────┘           └──────────────┘
                                │
                         ┌──────┴───────┐
                         │ Blueprint V1 │
                         │  Rojo sync   │
                         └──────────────┘

🤖 Using an AI Agent? (Claude Code, Cursor, etc.)

Let your AI agent set everything up for you!

Option 1: Copy-Paste This Prompt

Just copy and paste this to your AI agent:

Go to https://raw.githubusercontent.com/aaronaalmendarez/roblox-mcp/main/AGENT.md
Read the entire file, then set up the Roblox Studio MCP on my machine. Follow all the installation steps in the "Complete Installation Guide" section.

Your agent will handle cloning, building, configuring MCP, and setting up Blueprint V1 automatically.

Option 2: Manual


🚀 Quick Start

1 → Install the Studio plugin (download .rbxmx) into your plugins folder

OS Path
Windows %LOCALAPPDATA%\Roblox\Plugins\
macOS ~/Documents/Roblox/Plugins/

2 → In Studio: Game Settings → Security → Allow HTTP Requests

3 → Start the server:

# From this repo
npm install && npm run build
node dist/index.js

4 → Configure your AI client (see Client Setup) — done!

Build plugin from source
npm run build:plugin
# Copy studio-plugin/MCPPlugin.rbxmx → plugins folder → restart Studio

✨ Features

37+ MCP Tools

Category What You Can Do
📂 Instance Hierarchy Browse game tree, search by name / class / content, list services
📝 Script Management Read, write, line-edit Luau scripts with range support
Batch Editing Atomic multi-op edits with SHA-256 hash checks + auto-rollback
🔩 Properties Get/set any property, mass ops, formula & relative calculations
🏗️ Object Lifecycle Create, delete, smart-duplicate with offset grids & variations
🏷️ Attributes & Tags Full CRUD for attributes + CollectionService tags
🩺 Diagnostics Drift detection, deprecated API lint, health endpoints, telemetry
💾 Snapshots In-memory script snapshots with instant rollback

IDE-First Sync

  • Blueprint V1Rojo-based multi-place source control
  • Bi-directional — push local files to Studio or pull Studio changes back
  • Conflict-safe — hash-based guards prevent accidental overwrites
  • Drift detection — know exactly when local and Studio have diverged

Built for Reliability

  • Optimistic concurrency via SHA-256 source hashes
  • Write idempotency — replay-safe with X-Idempotency-Key
  • Chunked script uploads for very large rewrites that exceed single MCP payload limits
  • Safe bridge fallback for script writes instead of set_property on Source
  • Full-source reads for large scripts automatically avoid truncated plugin responses
  • Smart plugin polling: hot → active → idle intervals
  • Drift checks ignore formatting-only differences by default and report both raw and normalized hashes
  • Atomic apply → verify → rollback pipeline

🆕 Recent Reliability Fixes

  • Large script reads are no longer silently truncated — full-source reads now return the complete script even when the plugin would otherwise cap the response to the first 1000 lines.
  • Formatting-only drift no longer shows up as content driftcheck_script_drift now normalizes line endings, BOM, trailing whitespace, and trailing final newlines by default.
  • Drift output is more explicit — diagnostics now include comparisonMode, formattingOnly, formattingDifferences, raw hashes/lengths, and normalized hashes/lengths.
  • Large script writes now have a safe transport — use the chunked upload tools or scripts/push-script-fast.mjs for large files; they commit through the plugin bridge and UpdateSourceAsync instead of set_property.
  • Source writes no longer go through property toolsset_property and mass_set_property now reject the Source property so escape sequences are not corrupted.
  • Server and plugin defaults are aligned around port 3002 — current builds start on 3002 first and keep 58741 only as a legacy fallback.

Example of the expected healthy case:

{
  "status": "in-sync",
  "comparisonMode": "canonical-text",
  "formattingOnly": true,
  "formattingDifferences": ["trailing-newline"],
  "rawLocalLength": 74884,
  "rawStudioLength": 74883,
  "normalizedLocalLength": 74883,
  "normalizedStudioLength": 74883
}

This means the raw bytes differ, but the actual script content is the same.

A real healthy verification case now looks like this:

  • Full source read: localLength: 74883, studioLength: 74883
  • Raw bytes can still differ by one trailing newline: rawLocalLength: 74884, rawStudioLength: 74883
  • Normalized hashes then match, so the result is correctly reported as in-sync
  • The result includes comparisonMode, formattingOnly, formattingDifferences, and raw vs normalized hashes/lengths

🔧 Tool Reference

📂 Instance Hierarchy — 9 tools
Tool Description
get_file_tree Instance hierarchy as a tree
search_files Search by name, class, or script content
get_services List Roblox services and children
search_objects Find by name, class, or property
get_project_structure Full game hierarchy (configurable depth)
get_instance_children Children + class types
get_class_info Properties/methods for any class
get_place_info Place ID, name, game settings
get_selection Currently selected objects
📝 Script Management — 15 tools
Tool Description
get_script_source Read source (optional line range, full reads safe for large scripts)
get_script_snapshot Source + SHA-256 hash with full-source recovery
set_script_source Full rewrite (editor-safe; use chunked upload for very large files)
begin_script_source_upload Start chunked upload session for large files
append_script_source_upload_chunk Append one chunk to an upload session
commit_script_source_upload Commit an uploaded script through the plugin bridge
cancel_script_source_upload Discard an upload session without writing
set_script_source_checked Write only if hash matches
set_script_source_fast Fast write with safe bridge fallback
set_script_source_fast_gzip Gzip-compressed fast write
edit_script_lines Replace line ranges
insert_script_lines Insert at position
delete_script_lines Delete line ranges
batch_script_edits Atomic multi-edit + rollback
apply_and_verify_script_source Apply → verify → rollback pipeline
💾 Snapshots & Safety — 4 tools
Tool Description
create_script_snapshot In-memory rollback point
list_script_snapshots List session snapshots
rollback_script_snapshot Restore from snapshot
cancel_pending_writes Cancel queued writes
🔩 Properties & Objects — 14 tools
Tool Description
get_instance_properties All properties of an instance
set_property Set any property except Source
mass_set_property Set on multiple instances except Source
mass_get_property Read from multiple instances
search_by_property Find by property value
set_calculated_property Formula-based property sets
set_relative_property Relative modifications
create_object Create instance
create_object_with_properties Create with initial props
mass_create_objects Batch create
mass_create_objects_with_properties Batch create with props
delete_object Delete instance
smart_duplicate Smart dup with offsets & variations
mass_duplicate Multiple smart dups at once
🏷️ Attributes & Tags — 7 tools
Tool Description
get_attribute / set_attribute Read/write single attribute
get_attributes All attributes on instance
delete_attribute Remove attribute
get_tags CollectionService tags
add_tag / remove_tag Add or remove tag
get_tagged All instances with a tag
🩺 Diagnostics — 4 tools
Tool Description
get_runtime_state Write queue + bridge telemetry
get_diagnostics Full diagnostic report
check_script_drift Local vs Studio drift check with formatting normalization and raw/normalized diagnostics
lint_deprecated_apis Deprecated API scanner

🔌 Client Setup

All configs point to the local build. Replace the path with your actual install location.

Claude Code
claude mcp add robloxstudio -- node /path/to/roblox-mcp/dist/index.js
Gemini CLI
gemini mcp add robloxstudio node --trust -- /path/to/roblox-mcp/dist/index.js
Claude Desktop / Generic JSON
{
  "mcpServers": {
    "robloxstudio-mcp": {
      "command": "node",
      "args": ["/path/to/roblox-mcp/dist/index.js"]
    }
  }
}
Codex CLI

~/.codex/config.toml:

[mcp_servers.robloxstudio]
command = "node"
args = ["/path/to/roblox-mcp/dist/index.js"]
OpenCode

~/.config/opencode/opencode.json:

{
  "mcp": {
    "robloxstudio": {
      "type": "local",
      "enabled": true,
      "command": ["node", "/path/to/roblox-mcp/dist/index.js"]
    }
  }
}
Published npm package

If using the published package instead of a local build:

npx -y @aaronalm19/roblox-mcp@latest

Full reference with Windows fallbacks: docs/CLIENTS.md


📘 Blueprint V1

IDE-first source control built on Rojo with multi-place support.

blueprint-v1/
├── places/
│   ├── registry.json           # Place ID → slug
│   ├── .active-place.json      # Active context
│   └── <slug>/
│       ├── default.project.json
│       ├── src/                 # Luau source
│       └── properties/
│           └── instances.json   # Non-script props
└── src/                         # Legacy fallback
npm run place:detect             # Auto-detect Studio place
npm run place:list               # List registered places
npm run blueprint:sync           # Property sync → Studio
npm run blueprint:watch          # Continuous sync
npm run blueprint:reverse-sync   # Pull Studio → local
npm run drift:check              # Detect file divergence
npm run luau:lint                # Static analysis (requires luau-lsp, see below)

Luau Lint Setup (luau-lsp)

npm run luau:lint uses luau-lsp which ships full Roblox type stubsPlayer, BasePart, Vector3, RemoteEvent, etc. all resolve correctly under --!strict.

One-time setup:

Option A — use the bundled binary (already in this repo, v1.63.0 Windows x64):

Expand-Archive tools\luau-lsp\luau-lsp-win64.zip -DestinationPath .tools\luau-lsp -Force

Option B — download the latest release for your platform:

Then generate the Rojo sourcemap:

rojo sourcemap blueprint-v1/places/<slug>/default.project.json --output sourcemap.json

Run:

npm run luau:lint          # findings=0 is the goal
npm run luau:lint:strict   # exits non-zero if any findings (use in CI)

Expected clean output:

[context] Place1 (125175608517936) [place1-2]
[luau-lint] files=4 analyzer=.tools/luau-lsp/luau-lsp.exe
[luau-lint] sourcemap=sourcemap.json
[luau-lint] findings=0

Deep dive: docs/BLUEPRINT_V1.md


📋 Blueprint Operator Playbook

Everything below is the strict operational guide for working with Blueprint V1. Follow these steps exactly.

1. Canonical Windows Flow (copy-paste)

Open a terminal in the repo root and run each step in order:

# Step 1 — Detect the place open in Studio and register it
npm run place:detect

# Step 2 — Confirm resolved paths
npm run place:status

# Step 3 — Start Rojo against the resolved project
rojo serve blueprint-v1/places/<slug>/default.project.json

# Step 4 — Start continuous property sync (separate terminal)
npm run blueprint:watch

# Step 5 — Start reverse sync guard (separate terminal)
npm run blueprint:reverse-sync

Or use the one-command launcher that does steps 3-5 automatically:

npm run dev:studio -- --place <slug>

This resolves the existing place context, then spawns the MCP server, Rojo, property watcher, and reverse-sync in parallel. It does not run place:detect — you must register the place first. Press Ctrl+C to stop all.


2. Required Tooling Install Matrix

Tool Required Install (Windows)
Node.js ≥ 18 ✅ Yes winget install OpenJS.NodeJS.LTS or nodejs.org
Rojo ✅ Yes (for script sync) cargo install rojo — or download binary and add to PATH
Luau CLI Optional (for lint) npm run luau:install (auto-downloads from luau-lang releases)
No winget or cargo?
  • Node.js: Download the .msi installer from nodejs.org/en/download
  • Rojo: Download rojo.exe from GitHub releases, place in a folder on your PATH
  • Luau: npm run luau:install handles this — it downloads the correct binary for your OS into .tools/

3. Expected Success Output Per Step

npm run place:detect

✔ Detected place: Place2 (136131439760483)
✔ Registered slug: place2
✔ Set as active place

npm run place:status

Mode:       place
Place:      Place2 (136131439760483)
Slug:       place2
Project:    blueprint-v1/places/place2/default.project.json
Source:     blueprint-v1/places/place2/src
Properties: blueprint-v1/places/place2/properties/instances.json

rojo serve ...

Rojo server listening on port 34872

http://localhost:3002/health

{
  "pluginConnected": true,
  "mcpServerActive": true,
  "plugin": { "version": "1.10.0" }
}

npm run blueprint:reverse-sync

Reverse sync active. Tracked scripts: 3
Polling every 2000ms...

If any output differs from the above, stop and consult the Troubleshooting table.


4. Source of Truth Rules

Situation Who Wins Action
You edited a .luau file locally Local wins Rojo pushes to Studio automatically
You edited a script inside Studio Studio wins Run npm run blueprint:reverse-sync to pull changes back
Both sides changed the same script Neither — conflict A conflict snapshot folder is written; you manually merge
Non-script property changed in Studio Studio wins No automated pull — manually update instances.json to match
Non-script property changed in instances.json Local wins Run npm run blueprint:sync to push to Studio
You aren't sure what changed Check first Run npm run drift:check to compare hashes

Golden rule: Edit scripts in your IDE (Rojo syncs them). Edit non-script properties via instances.json. Only reverse-sync when you intentionally made Studio-side script changes.


5. File Naming & Path Mapping

Rojo uses file suffixes to determine the script type and instance name:

File Suffix Script Type Instance Name
.server.luau Script (runs on server) Filename without suffix
.client.luau LocalScript (runs on client) Filename without suffix
.module.luau ModuleScript (shared) Filename without suffix
.luau (no suffix) ModuleScript Full filename

Path resolution example:

File:     blueprint-v1/places/place2/src/ServerScriptService/HorrorMain.server.luau
Instance: game.ServerScriptService.HorrorMain       (Script)

File:     blueprint-v1/places/place2/src/StarterPlayer/StarterPlayerScripts/HorrorClient.client.luau
Instance: game.StarterPlayer.StarterPlayerScripts.HorrorClient   (LocalScript)

File:     blueprint-v1/places/place2/src/ReplicatedStorage/HorrorConfig.module.luau
Instance: game.ReplicatedStorage.HorrorConfig        (ModuleScript)

The directory path under src/ maps directly to the Roblox service hierarchy. The default.project.json defines which directories map to which services.


6. Conflict Handling

When reverse-sync detects both local and Studio changed the same script, it writes a conflict snapshot folder instead of overwriting:

blueprint-v1/places/<slug>/.reverse-sync-conflicts/
└── ServerScriptService/
    └── HorrorMain.server.luau/
        ├── local.luau       # Your local version at time of conflict
        ├── studio.luau      # The Studio version that diverged
        └── meta.json        # Timestamps, hashes, instance path

Recovery workflow:

  1. Open the conflict folder (e.g. .reverse-sync-conflicts/ServerScriptService/HorrorMain.server.luau/)
  2. Compare local.luau (your version) vs studio.luau (Studio's version)
  3. Manually merge the changes into the original .luau file in src/
  4. Delete the conflict folder
  5. Run npm run blueprint:reverse-sync again — it will re-baseline from the merged file

State tracking: Each tracked script's hashes are stored in:

blueprint-v1/places/<slug>/.reverse-sync-state.json

This file contains lastLocalHash and lastStudioHash per script. If you need to force a full re-sync, delete this file and restart reverse-sync.


7. Common Failures & Fixes

Failure Cause Fix
Place resolves wrong slug .active-place.json points to old place npm run place:detect (re-detects from Studio)
rojo: command not found Rojo not installed or not on PATH Install via cargo install rojo or download binary
Module path mismatch File in wrong src/ subdirectory Match directory to Roblox service name exactly
HTTP 403 from plugin HTTP requests disabled in Studio Game Settings → Security → Allow HTTP Requests
Stale .active-place.json Switched Studio places without re-detecting npm run place:detect
ECONNREFUSED :3002 MCP server not running node dist/index.js or npm run dev:studio
Reverse-sync shows 0 tracked No scripts match Rojo mappings Verify files exist in resolved src/ path
Rojo sync not updating Studio Rojo serving wrong project file Check npm run place:status for correct project path
Lint says "luau-analyze not found" Luau CLI not installed npm run luau:install
blueprint:doctor fails Server or plugin not connected Start server, open Studio, enable plugin

8. One-Command Dev Launcher

The dev:studio script is the recommended daily driver:

npm run dev:studio -- --place place2

This starts all four services in parallel:

Service What It Does
MCP server node dist/index.js
Rojo rojo serve blueprint-v1/places/place2/default.project.json
Property watcher Continuous blueprint:watch for non-script sync
Reverse sync Guarded Studio → local pull

Output on success:

Starting studio dev orchestrator...
Context: Place2 (136131439760483) [place2]
Orchestrator active. Press Ctrl+C to stop all processes.

Flags: --with-rojo, --with-watch, --with-reverse are all enabled by the default dev:studio npm script. Use node scripts/dev-studio.mjs --place place2 --with-rojo to select individually.


9. Blueprint Scope Boundaries

Blueprint separates concerns cleanly between two systems:

What Managed By Files
Scripts (Luau code) Rojo .server.luau, .client.luau, .module.luau in src/
Non-script properties (Position, Size, Color, etc.) Sync scripts properties/instances.json
Attributes Sync scripts properties/instances.json (attributes field)
Tags Sync scripts properties/instances.json (tags field)
Instance creation / hierarchy Rojo (via default.project.json) default.project.json tree

Do NOT:

  • Edit .luau files through instances.json — Rojo handles scripts
  • Create new services by adding directories without updating default.project.json
  • Mix legacy blueprint-v1/src/ with place-specific blueprint-v1/places/<slug>/src/

10. Example: Horror Game (place2)

A complete real-world place from this repository:

blueprint-v1/places/place2/
├── default.project.json              # Rojo project mapping 12 services
├── .reverse-sync-state.json          # Tracks 3 scripts with SHA-256 hashes
├── .reverse-sync-conflicts/          # Empty (no conflicts currently)
├── src/
│   ├── ServerScriptService/
│   │   └── HorrorMain.server.luau    # → game.ServerScriptService.HorrorMain (Script)
│   ├── ReplicatedStorage/
│   │   └── HorrorConfig.module.luau  # → game.ReplicatedStorage.HorrorConfig (ModuleScript)
│   └── StarterPlayer/
│       └── StarterPlayerScripts/
│           └── HorrorClient.client.luau  # → game.StarterPlayer.StarterPlayerScripts.HorrorClient (LocalScript)
└── properties/
    ├── instances.json                # Non-script property manifest (empty for now)
    └── schema.json                   # Property schema definitions

Registry entry (blueprint-v1/places/registry.json):

{
  "136131439760483": {
    "placeId": 136131439760483,
    "gameId": 9708597637,
    "slug": "place2",
    "displayName": "Place2"
  }
}

Full workflow for this place:

# One-time: detect and register
npm run place:detect
# → ✔ Detected place: Place2 (136131439760483), slug: place2

# Daily: start everything
npm run dev:studio -- --place place2
# → MCP server, Rojo, property watcher, and reverse sync all running

# Or manually:
rojo serve blueprint-v1/places/place2/default.project.json
npm run blueprint:watch
npm run blueprint:reverse-sync

🛠️ Development

npm install                      # Dependencies
npm run build                    # TypeScript → dist/
npm run build:plugin             # Build .rbxmx plugin
npm run dev                      # Dev server (tsx hot reload)
npm run typecheck                # Type-check
npm test                         # Jest suite
npm run test:all                 # Jest + Luau E2E

Verify Connection

curl http://localhost:3002/health
curl http://localhost:3002/diagnostics

Project Layout

├── src/                         # TypeScript MCP server
│   ├── index.ts                 # Tool definitions + handler
│   ├── http-server.ts           # Express bridge (:3002)
│   ├── bridge-service.ts        # Plugin comms
│   └── tools/                   # Tool implementations
├── studio-plugin/               # Luau Studio plugin
├── blueprint-v1/                # Rojo projects + sync state
├── scripts/                     # 20+ CLI helpers
├── tests/                       # Jest + Luau E2E
└── docs/                        # Additional docs

🔒 Security

Local-only All traffic stays on localhost:3002
No telemetry Zero data collection — your projects are private
Explicit Tools only run when your AI invokes them
Separated Read and write operations are distinct

❓ Troubleshooting

Problem Fix
Plugin missing .rbxmx in plugins folder → restart Studio
HTTP 403 Game Settings → Security → Allow HTTP Requests
Disconnected Start the MCP server — red is normal until then
No tools Restart MCP client + Studio, check /health
Slow or large writes Use chunked upload tools or push-script-fast.mjs
Firewall Allow localhost:3002

📚 Docs

Client Configurations Setup for every MCP client
Blueprint V1 Guide Multi-place sync deep dive
Plugin Installation Detailed plugin setup

🤝 Contributing

git clone https://github.com/aaronaalmendarez/roblox-mcp.git
cd roblox-mcp
npm install
npm run dev

Issues and PRs welcome on GitHub.

🙏 Acknowledgements

Original project: boshyxd/robloxstudio-mcp This fork extends that foundation for multi-agent workflows, local blueprint-first development, and enhanced tooling.


MIT License © 2025

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors