--[[ Roblox MCP Server Script This script runs inside Roblox Studio and acts as an HTTP polling server to communicate with the MCP bridge application. INSTRUCTIONS: 1. Start this script by pressing Play in Roblox Studio 2. The script will start an HTTP server on the configured port 3. The MCP bridge will send commands to this server 4. Commands are executed and results are returned Alternative: Copy this to ServerScriptService for auto-start --]] local HttpService = game:GetService("HttpService") local RunService = game:GetService("RunService") -- Configuration local CONFIG = { -- HTTP server configuration PORT = 37425, -- How often to check for new commands (seconds) POLL_INTERVAL = 0.1, -- Enable debug logging DEBUG = true, } -- State local isRunning = false local commandQueue = {} local responseStore = {} -- Logging local function log(message, level) level = level or "info" if CONFIG.DEBUG then print(string.format("[RobloxMCP:%s] %s", level:upper(), message)) end end -- Get object by path local function getObjectFromPath(path) if not path or path == "" then return nil end -- Handle special paths if path == "game" or path == "Game" then return game end -- Handle Workspace specially if path == "Workspace" or path == "workspace" then return workspace end -- Split path by dot and traverse local parts = {} for part in string.gmatch(path, "[^%.]+") do table.insert(parts, part) end if #parts == 0 then return nil end local obj = game for _, part in ipairs(parts) do if part == "Workspace" or part == "workspace" then obj = workspace elseif typeof(obj) == "Instance" and obj:FindFirstChild(part) then obj = obj[part] else log("Could not find: " .. part .. " in " .. path, "error") return nil end end return obj end -- Create object at path local function createObjectAt(path, className, properties) local parentPath, objectName -- Extract parent path and object name local lastDot = string.find(path, "%.[^%.]+$") if lastDot then parentPath = string.sub(path, 1, lastDot - 1) objectName = string.sub(path, lastDot + 1) else parentPath = "game" objectName = path end local parent = getObjectFromPath(parentPath) if not parent then return nil, "Parent not found: " .. tostring(parentPath) end -- Create the object local obj = Instance.new(className) obj.Name = objectName -- Set properties if properties then for propName, propValue in pairs(properties) do local ok = pcall(function() obj[propName] = propValue end) if not ok then log("Failed to set property " .. propName, "warn") end end end obj.Parent = parent return obj end -- Command handlers local handlers = {} handlers.createScript = function(params) local obj = createObjectAt(params.path .. "." .. params.scriptName, params.scriptType or "Script", { Name = params.scriptName, }) if obj then obj.Source = params.source return { success = true, objectPath = params.path .. "." .. params.scriptName, } end return { success = false, error = "Failed to create script" } end handlers.createPart = function(params) local properties = { Name = params.partName, Anchored = params.anchored ~= false, } -- Set shape local shapeMap = { Ball = Enum.PartType.Ball, Block = Enum.PartType.Block, Cylinder = Enum.PartType.Cylinder, Wedge = Enum.PartType.Wedge, CornerWedge = Enum.PartType.CornerWedge, } properties.Shape = shapeMap[params.partType] or Enum.PartType.Block -- Set position if params.position then properties.Position = Vector3.new( params.position.x or 0, params.position.y or 0, params.position.z or 0 ) end -- Set size if params.size then properties.Size = Vector3.new( params.size.x or 4, params.size.y or 1, params.size.z or 2 ) end -- Set color if params.color then local ok = pcall(function() properties.BrickColor = BrickColor.new(params.color) end) if not ok and type(params.color) == "table" then properties.Color3 = Color3.new( params.color.r or 1, params.color.g or 1, params.color.b or 1 ) end end local part = createObjectAt( (paramss.parentPath or "Workspace") .. "." .. params.partName, "Part", properties ) return { success = part ~= nil, objectPath = (params.parentPath or "Workspace") .. "." .. params.partName, } end handlers.createModel = function(params) local model = createObjectAt( (params.parentPath or "Workspace") .. "." .. params.modelName, "Model", { Name = params.modelName } ) return { success = model ~= nil, objectPath = (params.parentPath or "Workspace") .. "." .. params.modelName, } end handlers.createFolder = function(params) local folder = createObjectAt( (params.parentPath or "Workspace") .. "." .. params.folderName, "Folder", { Name = params.folderName } ) return { success = folder ~= nil, objectPath = (params.parentPath or "Workspace") .. "." .. params.folderName, } end handlers.createGUI = function(params) local properties = params.properties or {} properties.Name = params.name if params.guiType == "ScreenGui" then properties.ResetOnSpawn = false elseif params.guiType == "Frame" or params.guiType == "TextLabel" or params.guiType == "TextButton" then properties.Size = properties.Size or UDim2.new(0, 200, 0, 50) properties.Position = properties.Position or UDim2.new(0, 0, 0, 0) end if params.guiType == "TextLabel" or params.guiType == "TextButton" then properties.Text = properties.Text or params.name properties.TextScaled = properties.TextScaled ~= false end local gui = createObjectAt( (params.parentPath or "StarterGui") .. "." .. params.name, params.guiType, properties ) return { success = gui ~= nil, objectPath = (params.parentPath or "StarterGui") .. "." .. params.name, } end handlers.setProperty = function(params) local obj = getObjectFromPath(params.path) if not obj then return { success = false, error = "Object not found: " .. params.path } end local value = params.value -- Convert to proper types if params.property == "Position" or params.property == "Size" then value = Vector3.new(value.x, value.y, value.z) elseif params.property == "Color3" then value = Color3.new(value.r, value.g, value.b) elseif params.property == "BrickColor" then value = BrickColor.new(value) elseif params.property == "CFrame" and value.components then value = CFrame.new(unpack(value.components)) end local ok = pcall(function() obj[params.property] = value end) return { success = ok, property = params.property, value = tostring(value), } end handlers.getHierarchy = function(params) local obj = getObjectFromPath(params.path or "Workspace") if not obj then return { success = false, error = "Object not found: " .. (params.path or "Workspace"), } end local function buildHierarchy(object, depth, currentDepth) if currentDepth > depth then return nil end local children = {} for _, child in ipairs(object:GetChildren()) do local childData = { name = child.Name, className = child.ClassName, } if currentDepth < depth then childData.children = buildHierarchy(child, depth, currentDepth + 1) end table.insert(children, childData) end return children end return { success = true, path = params.path or "Workspace", children = buildHierarchy(obj, params.depth or 2, 0), } end handlers.deleteObject = function(params) local obj = getObjectFromPath(params.path) if not obj then return { success = false, error = "Object not found: " .. params.path } end obj:Destroy() return { success = true, deletedPath = params.path } end handlers.executeCode = function(params) local fn, err = loadstring(params.code) if not fn then return { success = false, error = err } end local ok, result = pcall(fn) return { success = ok, result = tostring(result), context = params.context or "Plugin" } end -- Process a command local function processCommand(id, command, params) log("Processing command: " .. command, "info") local handler = handlers[command] if not handler then return { id = id, success = false, error = "Unknown command: " .. tostring(command), } end local ok, result = pcall(function() return handler(params) end) if not ok then return { id = id, success = false, error = tostring(result), } end result.id = id return result end -- HTTP polling endpoint (simulated via HttpService) -- Note: This requires HTTP requests to be enabled in Game Settings local function checkForCommands() -- In a real implementation, this would poll the MCP bridge server -- For now, commands can be queued via a shared object or ModuleScript for i, cmd in ipairs(commandQueue) do local response = processCommand(cmd.id, cmd.command, cmd.params) responseStore[cmd.id] = response table.remove(commandQueue, i) end end -- Main loop local function start() if isRunning then log("Already running", "warn") return end isRunning = true log("Starting Roblox MCP Server on port " .. CONFIG.PORT, "info") -- Create a debug GUI to show status local screenGui = Instance.new("ScreenGui") screenGui.Name = "RobloxMCPServer" screenGui.Parent = game:GetService("CoreGui") local frame = Instance.new("Frame") frame.Name = "Status" frame.Size = UDim2.new(0, 250, 0, 100) frame.Position = UDim2.new(1, -260, 0, 10) frame.BackgroundColor3 = Color3.new(0.1, 0.1, 0.1) frame.Parent = screenGui local statusLabel = Instance.new("TextLabel") statusLabel.Name = "StatusText" statusLabel.Size = UDim2.new(1, -10, 1, -10) statusLabel.Position = UDim2.new(0, 5, 0, 5) statusLabel.BackgroundTransparency = 1 statusLabel.Text = "Roblox MCP Server\nRunning on port " .. CONFIG.PORT .. "\n\nWaiting for commands..." statusLabel.TextColor3 = Color3.new(0, 1, 0) statusLabel.TextScaled = true statusLabel.Font = Enum.Font.Gotham statusLabel.Parent = frame -- Main update loop RunService.Heartbeat:Connect(function() if isRunning then checkForCommands() end end) log("Server started. Use the MCP bridge to send commands.", "success") end local function stop() isRunning = false log("Server stopped", "info") end -- Auto-start start() -- Export for external access _G.RobloxMCPServer = { start = start, stop = stop, isRunning = function() return isRunning end, queueCommand = function(id, command, params) table.insert(commandQueue, { id = id, command = command, params = params }) end, getResponse = function(id) return responseStore[id] end, } log("Roblox MCP Server Module loaded. Type _G.RobloxMCPServer for access.", "info")