Skip to main content
Glama

Spline MCP Server

by aydinfer
action-tools.js13.6 kB
import { z } from 'zod'; import apiClient from '../utils/api-client.js'; /** * Action management tools for Spline.design * @param {object} server - MCP server instance */ export const registerActionTools = (server) => { // Create an action server.tool( 'createAction', { sceneId: z.string().min(1).describe('Scene ID'), eventId: z.string().min(1).describe('Event ID to attach this action to'), type: z.enum([ 'transition', 'sound', 'video', 'openLink', 'resetScene', 'switchCamera', 'createObject', 'destroyObject', 'sceneTransition', 'animation', 'particlesControl', 'variableControl', 'conditional', 'setVariable', 'clearLocalStorage', 'apiRequest' ]).describe('Action type'), name: z.string().min(1).describe('Action name'), target: z.string().optional().describe('Target ID (object, state, camera, etc.)'), parameters: z.record(z.any()).optional().describe('Action parameters'), }, async ({ sceneId, eventId, type, name, target, parameters }) => { try { const actionData = { type, name, ...(target && { target }), ...(parameters && { parameters }), }; const result = await apiClient.request('POST', `/scenes/${sceneId}/events/${eventId}/actions`, actionData); return { content: [ { type: 'text', text: `Action "${name}" created successfully with ID: ${result.id}` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error creating action: ${error.message}` } ], isError: true }; } } ); // Configure transition action server.tool( 'configureTransitionAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), targetState: z.string().min(1).describe('Target state ID'), duration: z.number().min(0).optional().describe('Transition duration (ms)'), easing: z.enum(['linear', 'easeIn', 'easeOut', 'easeInOut']).optional() .describe('Transition easing'), delay: z.number().min(0).optional().describe('Delay before starting transition (ms)'), }, async ({ sceneId, actionId, targetState, duration, easing, delay }) => { try { const parameters = { targetState, ...(duration !== undefined && { duration }), ...(easing && { easing }), ...(delay !== undefined && { delay }), }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'transition', parameters }); return { content: [ { type: 'text', text: `Transition action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring transition action: ${error.message}` } ], isError: true }; } } ); // Configure sound action server.tool( 'configureSoundAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), soundUrl: z.string().url().describe('URL to sound file'), volume: z.number().min(0).max(1).optional().default(1).describe('Volume (0-1)'), loop: z.boolean().optional().default(false).describe('Whether to loop the sound'), spatial: z.boolean().optional().default(false).describe('Whether sound is spatial (3D)'), objectId: z.string().optional().describe('Object ID for spatial sound source'), }, async ({ sceneId, actionId, soundUrl, volume, loop, spatial, objectId }) => { try { const parameters = { soundUrl, volume, loop, spatial, ...(spatial && objectId && { objectId }), }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'sound', parameters }); return { content: [ { type: 'text', text: `Sound action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring sound action: ${error.message}` } ], isError: true }; } } ); // Configure animation action server.tool( 'configureAnimationAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), objectId: z.string().min(1).describe('Object ID to animate'), animationType: z.enum(['rotate', 'move', 'scale', 'fade']).describe('Animation type'), duration: z.number().min(0).describe('Animation duration (ms)'), easing: z.enum(['linear', 'easeIn', 'easeOut', 'easeInOut']).optional() .describe('Animation easing'), parameters: z.record(z.any()).describe('Animation-specific parameters'), }, async ({ sceneId, actionId, objectId, animationType, duration, easing, parameters }) => { try { const actionParameters = { objectId, animationType, duration, ...(easing && { easing }), ...parameters, }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'animation', parameters: actionParameters }); return { content: [ { type: 'text', text: `Animation action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring animation action: ${error.message}` } ], isError: true }; } } ); // Configure variable control action server.tool( 'configureVariableAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), variableName: z.string().min(1).describe('Variable name'), operation: z.enum(['set', 'increment', 'decrement', 'multiply', 'divide', 'toggle']) .describe('Operation to perform'), value: z.any().describe('Value to use in the operation'), }, async ({ sceneId, actionId, variableName, operation, value }) => { try { const parameters = { variableName, operation, value, }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'variableControl', parameters }); return { content: [ { type: 'text', text: `Variable control action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring variable control action: ${error.message}` } ], isError: true }; } } ); // Configure conditional action server.tool( 'configureConditionalAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), variableName: z.string().min(1).describe('Variable name to check'), condition: z.enum(['equals', 'notEquals', 'greaterThan', 'lessThan', 'contains']) .describe('Condition to check'), value: z.any().describe('Value to compare against'), trueActionIds: z.array(z.string()).describe('Actions to trigger if condition is true'), falseActionIds: z.array(z.string()).optional().describe('Actions to trigger if condition is false'), }, async ({ sceneId, actionId, variableName, condition, value, trueActionIds, falseActionIds }) => { try { const parameters = { variableName, condition, value, trueActions: trueActionIds, ...(falseActionIds && { falseActions: falseActionIds }), }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'conditional', parameters }); return { content: [ { type: 'text', text: `Conditional action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring conditional action: ${error.message}` } ], isError: true }; } } ); // Configure API request action server.tool( 'configureApiRequestAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), apiId: z.string().min(1).describe('API configuration ID'), mappings: z.array(z.object({ responseField: z.string().describe('Field from API response'), variableName: z.string().describe('Spline variable name'), variableType: z.enum(['string', 'number', 'boolean']).describe('Variable type'), })).optional().describe('Response mappings'), }, async ({ sceneId, actionId, apiId, mappings }) => { try { const parameters = { apiId, ...(mappings && { mappings }), }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'apiRequest', parameters }); return { content: [ { type: 'text', text: `API request action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring API request action: ${error.message}` } ], isError: true }; } } ); // Configure camera action server.tool( 'configureCameraAction', { sceneId: z.string().min(1).describe('Scene ID'), actionId: z.string().min(1).describe('Action ID'), cameraId: z.string().min(1).describe('Camera ID to switch to'), duration: z.number().min(0).optional().describe('Transition duration (ms)'), easing: z.enum(['linear', 'easeIn', 'easeOut', 'easeInOut']).optional() .describe('Transition easing'), }, async ({ sceneId, actionId, cameraId, duration, easing }) => { try { const parameters = { cameraId, ...(duration !== undefined && { duration }), ...(easing && { easing }), }; await apiClient.request('PUT', `/scenes/${sceneId}/actions/${actionId}`, { type: 'switchCamera', parameters }); return { content: [ { type: 'text', text: `Camera action ${actionId} configured successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error configuring camera action: ${error.message}` } ], isError: true }; } } ); // List actions for an event server.tool( 'listActions', { sceneId: z.string().min(1).describe('Scene ID'), eventId: z.string().min(1).describe('Event ID'), }, async ({ sceneId, eventId }) => { try { const actions = await apiClient.request('GET', `/scenes/${sceneId}/events/${eventId}/actions`); return { content: [ { type: 'text', text: JSON.stringify(actions, null, 2) } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error listing actions: ${error.message}` } ], isError: true }; } } ); // Delete an action server.tool( 'deleteAction', { sceneId: z.string().min(1).describe('Scene ID'), eventId: z.string().min(1).describe('Event ID'), actionId: z.string().min(1).describe('Action ID'), }, async ({ sceneId, eventId, actionId }) => { try { await apiClient.request('DELETE', `/scenes/${sceneId}/events/${eventId}/actions/${actionId}`); return { content: [ { type: 'text', text: `Action ${actionId} deleted successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error deleting action: ${error.message}` } ], isError: true }; } } ); };

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/aydinfer/spline-mcp-server'

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