# 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
