# Roblox Studio MCP
> **Experimental.** This is an active work-in-progress. APIs will change, features may break, and the rendered screenshots are blocky approximations — not pixel-accurate previews. Use at your own risk. Contributions and bug reports welcome.
An MCP (Model Context Protocol) server for controlling Roblox Studio from AI coding tools like [OpenCode](https://opencode.ai). Provides workspace exploration, instance manipulation, script management, toolbox integration, playtest controls, and viewport rendering.
## Architecture
```
OpenCode / Claude ──stdio/MCP──> MCP Server (Node.js) ──HTTP──> Studio Plugin (Lua)
:28821 bridge polls for commands
```
The MCP server runs a small HTTP server on `127.0.0.1:28821`. The Roblox Studio plugin polls this server every 250ms for pending commands, executes them inside Studio, and posts results back.
## Setup
### 1. Install dependencies and build
```bash
npm install
npm run build
```
### 2. Install the Studio plugin
**Automatic:**
```bash
npm run install-plugin
```
**Manual:**
Copy `plugin/RobloxStudioMCP.server.lua` to your Roblox Studio plugins folder:
| Platform | Path |
| -------- | -------------------------------- |
| macOS | `~/Documents/Roblox/Plugins/` |
| Windows | `%LOCALAPPDATA%\Roblox\Plugins\` |
### 3. Activate the plugin
In Studio, click the **MCP Bridge** button in the toolbar. A status widget will appear showing connection state.
> **Note:** Plugin HTTP requests are not gated by the "Allow HTTP Requests" game setting. That setting only applies to game scripts — plugins can make HTTP calls freely.
### 4. Configure OpenCode
The included `opencode.json` works when you run OpenCode from the project root:
```json
{
"mcp": {
"roblox-studio": {
"type": "local",
"command": ["node", "dist/index.js"],
"environment": {
"ROBLOX_MCP_PORT": "28821"
}
}
},
"default_agent": "studio"
}
```
If you want to use this from a different project, use the absolute path to `dist/index.js` in the command array.
## Tools (6 consolidated)
All tools use an `action` parameter to select the specific operation.
### `roblox_get` — Read-only queries
| Action | Description |
| --- | --- |
| `ping` | Check plugin connection status and get place info |
| `tree` | ASCII tree view of the instance hierarchy |
| `search` | Search by name substring and/or class name |
| `instance` | Get detailed info about a specific instance |
| `properties` | Read all common properties of an instance |
| `descendants_summary` | Class breakdown with counts for descendants |
| `selection` | Get currently selected instances |
| `output_log` | Read recent Output window entries |
| `texture_info` | Get texture/decal asset IDs for an instance and descendants |
### `roblox_manage` — Instance mutations
| Action | Description |
| --- | --- |
| `create` | Create Part, Model, Folder, etc. with properties |
| `create_multiple` | Batch create multiple instances at once |
| `update` | Update properties (Position, Size, Color, etc.) |
| `reset_pivot` | Reset a Model's WorldPivot to bounding box center |
| `delete` | Destroy an instance (undoable) |
| `clone` | Clone with optional rename/reparent |
| `reparent` | Move an instance to a new parent |
| `set_selection` | Select specific instances |
| `undo` | Undo last action |
| `redo` | Redo last undone action |
### `roblox_script` — Script CRUD & execution
| Action | Description |
| --- | --- |
| `create` | Create Script/LocalScript/ModuleScript |
| `read` | Read script source and metadata |
| `update` | Update source code (works with open editors) |
| `execute` | Execute a Lua snippet in Studio context |
### `roblox_scene` — Camera & screenshots
| Action | Description |
| --- | --- |
| `screenshot` | Render a PNG of the current viewport (geometry + color + materials, no textures) |
| `move_camera` | Position camera explicitly or auto-frame on an instance |
### `roblox_toolbox` — Creator Store
| Action | Description |
| --- | --- |
| `search` | Search for free models/decals/audio |
| `insert` | Insert a toolbox asset by ID |
| `strip_scripts` | Remove all scripts from an inserted model |
### `roblox_playtest` — Test sessions
| Action | Description |
| --- | --- |
| `start` | Begin a playtest session |
| `stop` | Stop the current playtest |
| `status` | Get current state (Edit/Run/Play) |
| `move_camera` | Move camera during playtest |
| `fire_click` | Fire a ClickDetector |
| `fire_proximity` | Trigger a ProximityPrompt |
| `get_state` | Read game state (players, leaderstats) |
| `execute` | Run Lua in the live game context |
## Instance Paths
Instances are referenced by dot-separated paths from `game`:
```
Workspace -- game.Workspace
Workspace.SpawnLocation -- a SpawnLocation in Workspace
ServerScriptService.GameScript -- a script in ServerScriptService
ReplicatedStorage.Modules.Utils -- nested path
```
## Agent
An OpenCode agent definition is included at `.opencode/agents/studio.md`. It configures the AI with Roblox Studio domain knowledge and tool usage patterns. The `opencode.json` sets it as the default agent.
## Environment Variables
| Variable | Default | Description |
| ----------------- | ------- | ---------------- |
| `ROBLOX_MCP_PORT` | `28821` | HTTP bridge port |
## Known Limitations
- **Screenshots** are software-rendered from geometry data — no textures, lighting, or post-processing. They show shapes, colors, and spatial relationships, not what Studio's viewport actually looks like.
- **Playtest control** uses `RunService:Run()`/`:Stop()` which works for server-side testing but doesn't fully replicate Play Solo (no local player character).
- **Toolbox search** hits the public Roblox API and may be rate-limited.
- **Script execution** runs via `require()` on a temporary ModuleScript. Some APIs may not be available in this context.
- **Instance paths** use dot-separated names, so instances with `.` in their name will not resolve correctly.
## License
MIT