robloxstudio-mcp 2.6.0 → 2.7.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +117 -5
- package/package.json +48 -48
package/dist/index.js
CHANGED
|
@@ -1046,14 +1046,29 @@ var OpenCloudClient = class {
|
|
|
1046
1046
|
getMimeType(fileName) {
|
|
1047
1047
|
const ext = fileName.split(".").pop()?.toLowerCase();
|
|
1048
1048
|
const mimeTypes = {
|
|
1049
|
+
// Image (Decal)
|
|
1049
1050
|
png: "image/png",
|
|
1050
1051
|
jpg: "image/jpeg",
|
|
1051
1052
|
jpeg: "image/jpeg",
|
|
1052
1053
|
bmp: "image/bmp",
|
|
1053
|
-
tga: "image/
|
|
1054
|
+
tga: "image/tga",
|
|
1055
|
+
// Audio
|
|
1056
|
+
mp3: "audio/mpeg",
|
|
1057
|
+
ogg: "audio/ogg",
|
|
1058
|
+
wav: "audio/wav",
|
|
1059
|
+
flac: "audio/flac",
|
|
1060
|
+
// Model
|
|
1061
|
+
fbx: "model/fbx",
|
|
1062
|
+
gltf: "model/gltf+json",
|
|
1063
|
+
glb: "model/gltf-binary",
|
|
1064
|
+
rbxm: "model/x-rbxm",
|
|
1065
|
+
rbxmx: "model/x-rbxm",
|
|
1066
|
+
// Video
|
|
1067
|
+
mp4: "video/mp4",
|
|
1068
|
+
mov: "video/mov"
|
|
1054
1069
|
};
|
|
1055
1070
|
if (!ext || !mimeTypes[ext]) {
|
|
1056
|
-
throw new Error(`Unsupported
|
|
1071
|
+
throw new Error(`Unsupported file format: .${ext ?? "(none)"}. Supported: Image: png/jpg/bmp/tga, Audio: mp3/ogg/wav/flac, Model: fbx/gltf/glb/rbxm/rbxmx, Video: mp4/mov`);
|
|
1057
1072
|
}
|
|
1058
1073
|
return mimeTypes[ext];
|
|
1059
1074
|
}
|
|
@@ -1148,12 +1163,18 @@ var RobloxCookieClient = class {
|
|
|
1148
1163
|
return response;
|
|
1149
1164
|
}
|
|
1150
1165
|
async uploadDecal(fileContent, name, description) {
|
|
1166
|
+
return this.uploadAssetByTypeId(fileContent, name, description, 13, "Decal");
|
|
1167
|
+
}
|
|
1168
|
+
async uploadAudio(fileContent, name, description) {
|
|
1169
|
+
return this.uploadAssetByTypeId(fileContent, name, description, 3, "Audio");
|
|
1170
|
+
}
|
|
1171
|
+
async uploadAssetByTypeId(fileContent, name, description, assetTypeId, assetLabel) {
|
|
1151
1172
|
if (!this.cookie) {
|
|
1152
1173
|
throw new Error("ROBLOSECURITY cookie is not set.");
|
|
1153
1174
|
}
|
|
1154
1175
|
const encodedName = encodeURIComponent(name);
|
|
1155
1176
|
const encodedDesc = encodeURIComponent(description);
|
|
1156
|
-
const url = `https://data.roblox.com/data/upload/json?assetTypeId
|
|
1177
|
+
const url = `https://data.roblox.com/data/upload/json?assetTypeId=${assetTypeId}&name=${encodedName}&description=${encodedDesc}`;
|
|
1157
1178
|
const response = await this.fetchWithCsrf(url, {
|
|
1158
1179
|
method: "POST",
|
|
1159
1180
|
headers: {
|
|
@@ -1165,11 +1186,11 @@ var RobloxCookieClient = class {
|
|
|
1165
1186
|
});
|
|
1166
1187
|
if (!response.ok) {
|
|
1167
1188
|
const body = await response.text();
|
|
1168
|
-
throw new Error(
|
|
1189
|
+
throw new Error(`${assetLabel} upload failed (${response.status}): ${body}`);
|
|
1169
1190
|
}
|
|
1170
1191
|
const result = await response.json();
|
|
1171
1192
|
if (!result.Success || !result.AssetId) {
|
|
1172
|
-
throw new Error(
|
|
1193
|
+
throw new Error(`${assetLabel} upload failed: ${result.Message || "Unknown error"}`);
|
|
1173
1194
|
}
|
|
1174
1195
|
return {
|
|
1175
1196
|
assetId: result.AssetId,
|
|
@@ -2531,6 +2552,59 @@ ${code}`
|
|
|
2531
2552
|
}]
|
|
2532
2553
|
};
|
|
2533
2554
|
}
|
|
2555
|
+
async uploadAsset(filePath, assetType, displayName, description, userId, groupId) {
|
|
2556
|
+
if (!fs.existsSync(filePath)) {
|
|
2557
|
+
throw new Error(`File not found: ${filePath}`);
|
|
2558
|
+
}
|
|
2559
|
+
const fileContent = fs.readFileSync(filePath);
|
|
2560
|
+
const fileName = path.basename(filePath);
|
|
2561
|
+
const cookieSupported = assetType === "Decal" || assetType === "Audio";
|
|
2562
|
+
if (cookieSupported && this.cookieClient.hasCookie()) {
|
|
2563
|
+
const upload = assetType === "Decal" ? this.cookieClient.uploadDecal(fileContent, displayName, description || "") : this.cookieClient.uploadAudio(fileContent, displayName, description || "");
|
|
2564
|
+
const result2 = await upload;
|
|
2565
|
+
return {
|
|
2566
|
+
content: [{
|
|
2567
|
+
type: "text",
|
|
2568
|
+
text: JSON.stringify({
|
|
2569
|
+
done: true,
|
|
2570
|
+
response: {
|
|
2571
|
+
assetId: String(result2.assetId),
|
|
2572
|
+
displayName,
|
|
2573
|
+
assetType,
|
|
2574
|
+
backingAssetId: String(result2.backingAssetId)
|
|
2575
|
+
}
|
|
2576
|
+
})
|
|
2577
|
+
}]
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
if (!this.openCloudClient.hasApiKey()) {
|
|
2581
|
+
const cookieHint = cookieSupported ? " Alternatively, set ROBLOSECURITY to use cookie auth." : "";
|
|
2582
|
+
throw new Error(`No auth configured for ${assetType} upload. Set ROBLOX_OPEN_CLOUD_API_KEY (needs asset:write scope).${cookieHint}`);
|
|
2583
|
+
}
|
|
2584
|
+
const resolvedGroupId = groupId || process.env.ROBLOX_CREATOR_GROUP_ID;
|
|
2585
|
+
const resolvedUserId = userId || process.env.ROBLOX_CREATOR_USER_ID;
|
|
2586
|
+
if (!resolvedUserId && !resolvedGroupId) {
|
|
2587
|
+
throw new Error("Creator identity required for Open Cloud upload. Set ROBLOX_CREATOR_USER_ID or ROBLOX_CREATOR_GROUP_ID, or pass userId/groupId as parameters.");
|
|
2588
|
+
}
|
|
2589
|
+
const creator = {};
|
|
2590
|
+
if (resolvedGroupId) {
|
|
2591
|
+
creator.groupId = resolvedGroupId;
|
|
2592
|
+
} else {
|
|
2593
|
+
creator.userId = resolvedUserId;
|
|
2594
|
+
}
|
|
2595
|
+
const result = await this.openCloudClient.createAsset({
|
|
2596
|
+
assetType,
|
|
2597
|
+
displayName,
|
|
2598
|
+
description: description || "",
|
|
2599
|
+
creationContext: { creator }
|
|
2600
|
+
}, fileContent, fileName);
|
|
2601
|
+
return {
|
|
2602
|
+
content: [{
|
|
2603
|
+
type: "text",
|
|
2604
|
+
text: JSON.stringify(result)
|
|
2605
|
+
}]
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2534
2608
|
async simulateMouseInput(action, x, y, button, scrollDirection, target) {
|
|
2535
2609
|
if (!action) {
|
|
2536
2610
|
throw new Error("action is required for simulate_mouse_input");
|
|
@@ -3015,6 +3089,8 @@ var RobloxStudioMCPServer = class {
|
|
|
3015
3089
|
return await this.tools.previewAsset(args?.assetId, args?.includeProperties, args?.maxDepth);
|
|
3016
3090
|
case "upload_decal":
|
|
3017
3091
|
return await this.tools.uploadDecal(args?.filePath, args?.displayName, args?.description, args?.userId, args?.groupId);
|
|
3092
|
+
case "upload_asset":
|
|
3093
|
+
return await this.tools.uploadAsset(args?.filePath, args?.assetType, args?.displayName, args?.description, args?.userId, args?.groupId);
|
|
3018
3094
|
case "clone_object":
|
|
3019
3095
|
return await this.tools.cloneObject(args?.instancePath, args?.targetParentPath);
|
|
3020
3096
|
case "move_object":
|
|
@@ -4511,6 +4587,42 @@ part(0,2,0,2,1,1,"b")`,
|
|
|
4511
4587
|
required: ["filePath", "displayName"]
|
|
4512
4588
|
}
|
|
4513
4589
|
},
|
|
4590
|
+
{
|
|
4591
|
+
name: "upload_asset",
|
|
4592
|
+
category: "write",
|
|
4593
|
+
description: "Upload any supported asset type to Roblox: Audio (mp3/ogg/wav/flac), Decal (png/jpg/bmp/tga), Model (fbx/gltf/glb/rbxm/rbxmx), Animation (rbxm/rbxmx), or Video (mp4/mov). For Audio and Decal, supports ROBLOSECURITY cookie auth (recommended) or ROBLOX_OPEN_CLOUD_API_KEY. Other types require Open Cloud API key. Audio: max 7 min, 100 uploads/month (ID-verified). Video: max 5 min, requires 13+ ID-verified.",
|
|
4594
|
+
inputSchema: {
|
|
4595
|
+
type: "object",
|
|
4596
|
+
properties: {
|
|
4597
|
+
filePath: {
|
|
4598
|
+
type: "string",
|
|
4599
|
+
description: "Absolute path to the file on disk"
|
|
4600
|
+
},
|
|
4601
|
+
assetType: {
|
|
4602
|
+
type: "string",
|
|
4603
|
+
enum: ["Audio", "Decal", "Model", "Animation", "Video"],
|
|
4604
|
+
description: "Type of asset to upload. Must match the file format."
|
|
4605
|
+
},
|
|
4606
|
+
displayName: {
|
|
4607
|
+
type: "string",
|
|
4608
|
+
description: "Display name for the asset (max 50 characters)"
|
|
4609
|
+
},
|
|
4610
|
+
description: {
|
|
4611
|
+
type: "string",
|
|
4612
|
+
description: "Description for the asset (default: empty string)"
|
|
4613
|
+
},
|
|
4614
|
+
userId: {
|
|
4615
|
+
type: "string",
|
|
4616
|
+
description: "Roblox user ID for the asset creator. Overrides ROBLOX_CREATOR_USER_ID env var."
|
|
4617
|
+
},
|
|
4618
|
+
groupId: {
|
|
4619
|
+
type: "string",
|
|
4620
|
+
description: "Roblox group ID for the asset creator. Overrides ROBLOX_CREATOR_GROUP_ID env var. Takes precedence over userId if both provided."
|
|
4621
|
+
}
|
|
4622
|
+
},
|
|
4623
|
+
required: ["filePath", "assetType", "displayName"]
|
|
4624
|
+
}
|
|
4625
|
+
},
|
|
4514
4626
|
{
|
|
4515
4627
|
name: "capture_screenshot",
|
|
4516
4628
|
category: "read",
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "robloxstudio-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "MCP Server for Roblox Studio Integration - Access Studio data, scripts, and objects through AI tools",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"robloxstudio-mcp": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist/**/*",
|
|
12
|
-
"studio-plugin/**/*"
|
|
13
|
-
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsup",
|
|
16
|
-
"prepack": "node ../../scripts/prepack.mjs",
|
|
17
|
-
"postpack": "node ../../scripts/postpack.mjs"
|
|
18
|
-
},
|
|
19
|
-
"keywords": [
|
|
20
|
-
"mcp",
|
|
21
|
-
"roblox",
|
|
22
|
-
"studio",
|
|
23
|
-
"ai",
|
|
24
|
-
"model-context-protocol",
|
|
25
|
-
"game-development"
|
|
26
|
-
],
|
|
27
|
-
"author": "",
|
|
28
|
-
"license": "MIT",
|
|
29
|
-
"repository": {
|
|
30
|
-
"type": "git",
|
|
31
|
-
"url": "https://github.com/boshyxd/robloxstudio-mcp.git"
|
|
32
|
-
},
|
|
33
|
-
"homepage": "https://github.com/boshyxd/robloxstudio-mcp#readme",
|
|
34
|
-
"bugs": {
|
|
35
|
-
"url": "https://github.com/boshyxd/robloxstudio-mcp/issues"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
39
|
-
"cors": "^2.8.5",
|
|
40
|
-
"express": "^4.18.2",
|
|
41
|
-
"node-fetch": "^3.3.2",
|
|
42
|
-
"uuid": "^9.0.1",
|
|
43
|
-
"ws": "^8.14.2"
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@robloxstudio-mcp/core": "*"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "robloxstudio-mcp",
|
|
3
|
+
"version": "2.7.0-next.0",
|
|
4
|
+
"description": "MCP Server for Roblox Studio Integration - Access Studio data, scripts, and objects through AI tools",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"robloxstudio-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/**/*",
|
|
12
|
+
"studio-plugin/**/*"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"prepack": "node ../../scripts/prepack.mjs",
|
|
17
|
+
"postpack": "node ../../scripts/postpack.mjs"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"roblox",
|
|
22
|
+
"studio",
|
|
23
|
+
"ai",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"game-development"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/boshyxd/robloxstudio-mcp.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/boshyxd/robloxstudio-mcp#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/boshyxd/robloxstudio-mcp/issues"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
39
|
+
"cors": "^2.8.5",
|
|
40
|
+
"express": "^4.18.2",
|
|
41
|
+
"node-fetch": "^3.3.2",
|
|
42
|
+
"uuid": "^9.0.1",
|
|
43
|
+
"ws": "^8.14.2"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@robloxstudio-mcp/core": "*"
|
|
47
|
+
}
|
|
48
|
+
}
|