Skip to main content
Glama
index.ts17 kB
import { StudioHttpClient } from './studio-client.js'; import { BridgeService } from '../bridge-service.js'; export class RobloxStudioTools { private client: StudioHttpClient; constructor(bridge: BridgeService) { this.client = new StudioHttpClient(bridge); } // File System Tools async getFileTree(path: string = '') { const response = await this.client.request('/api/file-tree', { path }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async searchFiles(query: string, searchType: string = 'name') { const response = await this.client.request('/api/search-files', { query, searchType }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Studio Context Tools async getPlaceInfo() { const response = await this.client.request('/api/place-info', {}); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async getServices(serviceName?: string) { const response = await this.client.request('/api/services', { serviceName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async searchObjects(query: string, searchType: string = 'name', propertyName?: string) { const response = await this.client.request('/api/search-objects', { query, searchType, propertyName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Property & Instance Tools async getInstanceProperties(instancePath: string) { if (!instancePath) { throw new Error('Instance path is required for get_instance_properties'); } const response = await this.client.request('/api/instance-properties', { instancePath }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async getInstanceChildren(instancePath: string) { if (!instancePath) { throw new Error('Instance path is required for get_instance_children'); } const response = await this.client.request('/api/instance-children', { instancePath }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async searchByProperty(propertyName: string, propertyValue: string) { if (!propertyName || !propertyValue) { throw new Error('Property name and value are required for search_by_property'); } const response = await this.client.request('/api/search-by-property', { propertyName, propertyValue }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async getClassInfo(className: string) { if (!className) { throw new Error('Class name is required for get_class_info'); } const response = await this.client.request('/api/class-info', { className }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Project Tools async getProjectStructure(path?: string, maxDepth?: number, scriptsOnly?: boolean) { const response = await this.client.request('/api/project-structure', { path, maxDepth, scriptsOnly }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Property Modification Tools async setProperty(instancePath: string, propertyName: string, propertyValue: any) { if (!instancePath || !propertyName) { throw new Error('Instance path and property name are required for set_property'); } const response = await this.client.request('/api/set-property', { instancePath, propertyName, propertyValue }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async massSetProperty(paths: string[], propertyName: string, propertyValue: any) { if (!paths || paths.length === 0 || !propertyName) { throw new Error('Paths array and property name are required for mass_set_property'); } const response = await this.client.request('/api/mass-set-property', { paths, propertyName, propertyValue }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async massGetProperty(paths: string[], propertyName: string) { if (!paths || paths.length === 0 || !propertyName) { throw new Error('Paths array and property name are required for mass_get_property'); } const response = await this.client.request('/api/mass-get-property', { paths, propertyName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Object Creation Tools async createObject(className: string, parent: string, name?: string) { if (!className || !parent) { throw new Error('Class name and parent are required for create_object'); } const response = await this.client.request('/api/create-object', { className, parent, name }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async createObjectWithProperties(className: string, parent: string, name?: string, properties?: Record<string, any>) { if (!className || !parent) { throw new Error('Class name and parent are required for create_object_with_properties'); } const response = await this.client.request('/api/create-object', { className, parent, name, properties }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async massCreateObjects(objects: Array<{className: string, parent: string, name?: string}>) { if (!objects || objects.length === 0) { throw new Error('Objects array is required for mass_create_objects'); } const response = await this.client.request('/api/mass-create-objects', { objects }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async massCreateObjectsWithProperties(objects: Array<{className: string, parent: string, name?: string, properties?: Record<string, any>}>) { if (!objects || objects.length === 0) { throw new Error('Objects array is required for mass_create_objects_with_properties'); } const response = await this.client.request('/api/mass-create-objects-with-properties', { objects }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async deleteObject(instancePath: string) { if (!instancePath) { throw new Error('Instance path is required for delete_object'); } const response = await this.client.request('/api/delete-object', { instancePath }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Smart Duplication Tools async smartDuplicate( instancePath: string, count: number, options?: { namePattern?: string; // e.g., "Button{n}" where {n} is replaced with index positionOffset?: [number, number, number]; // X, Y, Z offset per duplicate rotationOffset?: [number, number, number]; // X, Y, Z rotation offset per duplicate scaleOffset?: [number, number, number]; // X, Y, Z scale multiplier per duplicate propertyVariations?: Record<string, any[]>; // Property name to array of values targetParents?: string[]; // Different parent for each duplicate } ) { if (!instancePath || count < 1) { throw new Error('Instance path and count > 0 are required for smart_duplicate'); } const response = await this.client.request('/api/smart-duplicate', { instancePath, count, options }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async massDuplicate( duplications: Array<{ instancePath: string; count: number; options?: { namePattern?: string; positionOffset?: [number, number, number]; rotationOffset?: [number, number, number]; scaleOffset?: [number, number, number]; propertyVariations?: Record<string, any[]>; targetParents?: string[]; } }> ) { if (!duplications || duplications.length === 0) { throw new Error('Duplications array is required for mass_duplicate'); } const response = await this.client.request('/api/mass-duplicate', { duplications }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Calculated Property Tools async setCalculatedProperty( paths: string[], propertyName: string, formula: string, variables?: Record<string, any> ) { if (!paths || paths.length === 0 || !propertyName || !formula) { throw new Error('Paths, property name, and formula are required for set_calculated_property'); } const response = await this.client.request('/api/set-calculated-property', { paths, propertyName, formula, variables }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Relative Property Tools async setRelativeProperty( paths: string[], propertyName: string, operation: 'add' | 'multiply' | 'divide' | 'subtract' | 'power', value: any, component?: 'X' | 'Y' | 'Z' // For Vector3/UDim2 properties ) { if (!paths || paths.length === 0 || !propertyName || !operation || value === undefined) { throw new Error('Paths, property name, operation, and value are required for set_relative_property'); } const response = await this.client.request('/api/set-relative-property', { paths, propertyName, operation, value, component }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Script Management Tools async getScriptSource(instancePath: string, startLine?: number, endLine?: number) { if (!instancePath) { throw new Error('Instance path is required for get_script_source'); } const response = await this.client.request('/api/get-script-source', { instancePath, startLine, endLine }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async setScriptSource(instancePath: string, source: string) { if (!instancePath || typeof source !== 'string') { throw new Error('Instance path and source code string are required for set_script_source'); } const response = await this.client.request('/api/set-script-source', { instancePath, source }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Partial Script Editing Tools async editScriptLines(instancePath: string, startLine: number, endLine: number, newContent: string) { if (!instancePath || !startLine || !endLine || typeof newContent !== 'string') { throw new Error('Instance path, startLine, endLine, and newContent are required for edit_script_lines'); } const response = await this.client.request('/api/edit-script-lines', { instancePath, startLine, endLine, newContent }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async insertScriptLines(instancePath: string, afterLine: number, newContent: string) { if (!instancePath || typeof newContent !== 'string') { throw new Error('Instance path and newContent are required for insert_script_lines'); } const response = await this.client.request('/api/insert-script-lines', { instancePath, afterLine: afterLine || 0, newContent }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async deleteScriptLines(instancePath: string, startLine: number, endLine: number) { if (!instancePath || !startLine || !endLine) { throw new Error('Instance path, startLine, and endLine are required for delete_script_lines'); } const response = await this.client.request('/api/delete-script-lines', { instancePath, startLine, endLine }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Attribute Tools async getAttribute(instancePath: string, attributeName: string) { if (!instancePath || !attributeName) { throw new Error('Instance path and attribute name are required for get_attribute'); } const response = await this.client.request('/api/get-attribute', { instancePath, attributeName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async setAttribute(instancePath: string, attributeName: string, attributeValue: any, valueType?: string) { if (!instancePath || !attributeName) { throw new Error('Instance path and attribute name are required for set_attribute'); } const response = await this.client.request('/api/set-attribute', { instancePath, attributeName, attributeValue, valueType }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async getAttributes(instancePath: string) { if (!instancePath) { throw new Error('Instance path is required for get_attributes'); } const response = await this.client.request('/api/get-attributes', { instancePath }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async deleteAttribute(instancePath: string, attributeName: string) { if (!instancePath || !attributeName) { throw new Error('Instance path and attribute name are required for delete_attribute'); } const response = await this.client.request('/api/delete-attribute', { instancePath, attributeName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } // Tag Tools (CollectionService) async getTags(instancePath: string) { if (!instancePath) { throw new Error('Instance path is required for get_tags'); } const response = await this.client.request('/api/get-tags', { instancePath }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async addTag(instancePath: string, tagName: string) { if (!instancePath || !tagName) { throw new Error('Instance path and tag name are required for add_tag'); } const response = await this.client.request('/api/add-tag', { instancePath, tagName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async removeTag(instancePath: string, tagName: string) { if (!instancePath || !tagName) { throw new Error('Instance path and tag name are required for remove_tag'); } const response = await this.client.request('/api/remove-tag', { instancePath, tagName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } async getTagged(tagName: string) { if (!tagName) { throw new Error('Tag name is required for get_tagged'); } const response = await this.client.request('/api/get-tagged', { tagName }); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/boshyxd/robloxstudio-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server