-- Roblox MCP Server - HTTP Polling Version -- This version polls the MCP server for commands via HTTP local HttpService = game:GetService("HttpService") local RunService = game:GetService("RunService") -- Configuration local MCP_SERVER_URL = "http://127.0.0.1:37423" local POLL_INTERVAL = 0.5 -- seconds local DEBUG = true -- State local isRunning = true local lastCommandId = 0 -- Logging local function log(msg) if DEBUG then print("[RobloxMCP] " .. msg) end end -- Get object by path local function getObjectFromPath(path) if not path or path == "" then return nil end if path == "game" or path == "Game" then return game end if path == "Workspace" or path == "workspace" then return workspace end local parts = {} for part in string.gmatch(path, "[^%.]+") do table.insert(parts, part) 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 return nil end end return obj end -- Create object at path local function createObjectAt(path, className, properties) local lastDot = string.find(path, "%.[^%.]+$") local parentPath = lastDot and string.sub(path, 1, lastDot - 1) or "game" local objectName = lastDot and string.sub(path, lastDot + 1) or path local parent = getObjectFromPath(parentPath) if not parent then return nil, "Parent not found" end local obj = Instance.new(className) obj.Name = objectName if properties then for prop, value in pairs(properties) do pcall(function() obj[prop] = value end) end end obj.Parent = parent return obj end -- Command handlers local handlers = {} handlers.createPart = function(params) local props = { Name = params.partName, Anchored = params.anchored ~= false, Shape = Enum.PartType.Block, } if params.position then props.Position = Vector3.new(params.position.x or 0, params.position.y or 0, params.position.z or 0) end if params.size then props.Size = Vector3.new(params.size.x or 4, params.size.y or 1, params.size.z or 2) end if params.color then pcall(function() props.BrickColor = BrickColor.new(params.color) end) end local part = createObjectAt((params.parentPath or "Workspace") .. "." .. params.partName, "Part", props) return {success = part ~= nil} end 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} end return {success = false} end handlers.setProperty = function(params) local obj = getObjectFromPath(params.path) if not obj then return {success = false, error = "Not found"} end local value = params.value 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) end pcall(function() obj[params.property] = value end) return {success = true} end handlers.executeCode = function(params) local fn, err = loadstring(params.code) if not fn then return {success = false, error = err} end local ok = pcall(fn) return {success = ok} end handlers.getHierarchy = function(params) local obj = getObjectFromPath(params.path or "Workspace") if not obj then return {success = false, error = "Not found"} end local function build(obj, depth) if depth <= 0 then return nil end local children = {} for _, child in ipairs(obj:GetChildren()) do table.insert(children, { name = child.Name, className = child.ClassName, }) end return children end return {success = true, children = build(obj, params.depth or 2)} end handlers.importGLB = function(params) -- Import GLB model into Roblox Studio -- GLB files need to be imported via the Editor API for assets -- For now, we'll create a placeholder model with instructions local parent = getObjectFromPath(params.parentPath or "Workspace") if not parent then return {success = false, error = "Parent path not found"} end -- Create a model to hold the imported GLB local model = Instance.new("Model") model.Name = params.modelName or "ImportedGLB" model.Parent = parent -- Create a placeholder part with info local placeholder = Instance.new("Part") placeholder.Name = "GLB_Placeholder" placeholder.Size = Vector3.new(4, 4, 4) placeholder.Position = Vector3.new(0, 5, 0) placeholder.Anchored = true placeholder.BrickColor = BrickColor.new("Bright blue") placeholder.Transparency = 0.5 placeholder.Parent = model -- Add a note local info = Instance.new("StringValue") info.Name = "ImportInfo" info.Value = "GLB Import: Use the 3D Importer (File > Import 3D) or Editor Service to import GLB files. This is a placeholder." info.Parent = model return { success = true, modelPath = (params.parentPath or "Workspace") .. "." .. params.modelName, note = "GLB files require manual import via Roblox Studio's 3D Importer or Editor Service API" } end -- Poll for commands local function pollForCommands() local success, response = pcall(function() return HttpService:RequestAsync({ Url = MCP_SERVER_URL .. "/poll?last=" .. lastCommandId, Method = "GET", }) end) if success and response.Success then local data = HttpService:JSONDecode(response.Body) if data.commands then for _, cmd in ipairs(data.commands) do log("Got command: " .. cmd.command) lastCommandId = cmd.id local handler = handlers[cmd.command] local result = {success = false, error = "Unknown command"} if handler then local ok, ret = pcall(handler, cmd.params) if ok then result = ret else result = {success = false, error = tostring(ret)} end end -- Send result back pcall(function() HttpService:RequestAsync({ Url = MCP_SERVER_URL .. "/result", Method = "POST", Headers = {["Content-Type"] = "application/json"}, Body = HttpService:JSONEncode({ id = cmd.id, result = result }) }) end) end end end end -- Main loop log("Starting Roblox MCP Server (HTTP Polling)") log("MCP Server: " .. MCP_SERVER_URL) RunService.Heartbeat:Connect(function() if isRunning then pcall(pollForCommands) end end) log("Roblox MCP Server is running!")