Skip to main content
Glama

Spline MCP Server

by aydinfer
version-history-tools.js7.66 kB
/** * Version History Tools for Spline.design * * Tools for managing version history and snapshots of Spline scenes. */ import { z } from "zod"; import { fetchFromSplineApi } from "../../utils/api-client.js"; /** * Register version history tools * @param {McpServer} server - The MCP server instance */ export function registerVersionHistoryTools(server) { server.tool( "createSnapshot", { sceneId: z.string().min(1).describe("Scene ID"), name: z.string().optional().describe("Snapshot name"), description: z.string().optional().describe("Snapshot description"), tags: z.array(z.string()).optional().describe("Snapshot tags"), }, async ({ sceneId, name, description, tags }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/snapshots`, { method: "POST", body: JSON.stringify({ name, description, tags, }), }); return { content: [{ type: "text", text: `Created snapshot "${name || 'Unnamed'}" (ID: ${result.snapshotId})` }] }; } catch (error) { return { content: [{ type: "text", text: `Error creating snapshot: ${error.message}` }], isError: true }; } } ); server.tool( "listSnapshots", { sceneId: z.string().min(1).describe("Scene ID"), page: z.number().int().min(1).default(1).describe("Page number"), pageSize: z.number().int().min(1).max(100).default(20).describe("Snapshots per page"), tags: z.array(z.string()).optional().describe("Filter by tags"), }, async ({ sceneId, page, pageSize, tags }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/snapshots`, { method: "GET", query: { page, pageSize, tags: tags?.join(','), }, }); return { content: [{ type: "text", text: `Found ${result.total} snapshots for scene ${sceneId}`, }, { type: "json", json: result.items, }] }; } catch (error) { return { content: [{ type: "text", text: `Error listing snapshots: ${error.message}` }], isError: true }; } } ); server.tool( "restoreSnapshot", { sceneId: z.string().min(1).describe("Scene ID"), snapshotId: z.string().min(1).describe("Snapshot ID"), createBackup: z.boolean().default(true).describe("Create backup of current state before restoring"), }, async ({ sceneId, snapshotId, createBackup }) => { try { await fetchFromSplineApi(`/scenes/${sceneId}/snapshots/${snapshotId}/restore`, { method: "POST", body: JSON.stringify({ createBackup, }), }); return { content: [{ type: "text", text: `Restored snapshot ${snapshotId}${createBackup ? ' with backup of current state' : ''}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error restoring snapshot: ${error.message}` }], isError: true }; } } ); server.tool( "compareSnapshots", { sceneId: z.string().min(1).describe("Scene ID"), snapshotAId: z.string().min(1).describe("First snapshot ID"), snapshotBId: z.string().min(1).describe("Second snapshot ID"), }, async ({ sceneId, snapshotAId, snapshotBId }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/snapshots/compare`, { method: "POST", body: JSON.stringify({ snapshotAId, snapshotBId, }), }); return { content: [{ type: "text", text: `Snapshot comparison results:` }, { type: "json", json: result.differences, }] }; } catch (error) { return { content: [{ type: "text", text: `Error comparing snapshots: ${error.message}` }], isError: true }; } } ); server.tool( "mergeSnapshot", { sceneId: z.string().min(1).describe("Scene ID"), snapshotId: z.string().min(1).describe("Snapshot ID to merge into current scene"), mergeStrategy: z.enum(["overwrite", "additive", "selective"]).default("selective") .describe("Merge strategy"), objectIdsToMerge: z.array(z.string()).optional() .describe("Object IDs to merge (for selective strategy)"), stateIdsToMerge: z.array(z.string()).optional() .describe("State IDs to merge (for selective strategy)"), eventIdsToMerge: z.array(z.string()).optional() .describe("Event IDs to merge (for selective strategy)"), createBackup: z.boolean().default(true).describe("Create backup of current state before merging"), }, async ({ sceneId, snapshotId, mergeStrategy, objectIdsToMerge, stateIdsToMerge, eventIdsToMerge, createBackup }) => { try { await fetchFromSplineApi(`/scenes/${sceneId}/snapshots/${snapshotId}/merge`, { method: "POST", body: JSON.stringify({ mergeStrategy, objectIdsToMerge, stateIdsToMerge, eventIdsToMerge, createBackup, }), }); return { content: [{ type: "text", text: `Merged snapshot ${snapshotId} using ${mergeStrategy} strategy` }] }; } catch (error) { return { content: [{ type: "text", text: `Error merging snapshot: ${error.message}` }], isError: true }; } } ); server.tool( "exportSnapshot", { sceneId: z.string().min(1).describe("Scene ID"), snapshotId: z.string().min(1).describe("Snapshot ID"), format: z.enum(["spline", "json"]).default("spline").describe("Export format"), }, async ({ sceneId, snapshotId, format }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/snapshots/${snapshotId}/export`, { method: "POST", body: JSON.stringify({ format, }), }); return { content: [{ type: "text", text: `Exported snapshot ${snapshotId} in ${format} format. Download URL: ${result.downloadUrl}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error exporting snapshot: ${error.message}` }], isError: true }; } } ); server.tool( "deleteSnapshot", { sceneId: z.string().min(1).describe("Scene ID"), snapshotId: z.string().min(1).describe("Snapshot ID"), }, async ({ sceneId, snapshotId }) => { try { await fetchFromSplineApi(`/scenes/${sceneId}/snapshots/${snapshotId}`, { method: "DELETE", }); return { content: [{ type: "text", text: `Deleted snapshot ${snapshotId}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error deleting snapshot: ${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