feat: Add save_theme MCP tool for persistent theme storage

- Add save_theme tool to save themes permanently to database
- Update set_theme_variable to track changes in store's previewTheme
- Enables full theme creation workflow via MCP tools

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 05:43:05 -06:00
parent acde6b37d6
commit 9d3aa6f2ff

View File

@@ -4,7 +4,8 @@ import { registerTool, unregisterTools } from '../webmcp'
export const THEME_TOOLS = [
'get_design_tokens',
'get_active_theme',
'set_theme_variable'
'set_theme_variable',
'save_theme'
]
export function registerThemeTools() {
@@ -97,7 +98,7 @@ export function registerThemeTools() {
// set_theme_variable
registerTool(
'set_theme_variable',
'Modifica una variable CSS del tema en tiempo real (cambio temporal, no se guarda)',
'Modifica una variable CSS del tema en tiempo real (cambio temporal hasta que uses save_theme)',
{
type: 'object',
properties: {
@@ -114,24 +115,96 @@ export function registerThemeTools() {
},
(args: { name: string; value: string }) => {
try {
const themeStore = useThemeStore()
const root = document.documentElement
const varName = args.name.startsWith('--') ? args.name : `--${args.name}`
const keyName = args.name.startsWith('--') ? args.name.slice(2) : args.name
// Get current value for feedback
const currentValue = getComputedStyle(root).getPropertyValue(varName).trim()
// Set new value
// Set new value in DOM
root.style.setProperty(varName, args.value)
// Update the store's previewTheme to track changes
if (themeStore.activeTheme) {
// Find which category this variable belongs to
const variables = themeStore.activeTheme.variables
for (const category of Object.keys(variables) as (keyof typeof variables)[]) {
if (keyName in variables[category]) {
themeStore.updateVariable(category, keyName, args.value)
break
}
}
}
return `Variable ${varName} cambiada:\n` +
` Anterior: ${currentValue || '(no definida)'}\n` +
` Nuevo: ${args.value}\n\n` +
`Nota: Este cambio es temporal. Para hacerlo permanente, usa el editor de temas en /themes`
`Usa save_theme para guardar los cambios permanentemente.`
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// save_theme
registerTool(
'save_theme',
'Guarda el tema actual con los cambios realizados permanentemente en la base de datos',
{
type: 'object',
properties: {
name: {
type: 'string',
description: 'Nombre para el nuevo tema'
},
description: {
type: 'string',
description: 'Descripción opcional del tema'
},
setAsDefault: {
type: 'boolean',
description: 'Si es true, establece este tema como el activo por defecto'
}
},
required: ['name']
},
async (args: { name: string; description?: string; setAsDefault?: boolean }) => {
try {
const themeStore = useThemeStore()
// Get variables to save (preview has the modified values, or use active)
const variablesToSave = themeStore.previewTheme || themeStore.activeTheme?.variables
if (!variablesToSave) {
return 'Error: No hay tema con variables para guardar'
}
// Save the theme
const result = await themeStore.saveTheme({
name: args.name,
description: args.description || `Tema creado el ${new Date().toLocaleString()}`,
variables: variablesToSave,
metadata: {
author: 'Claude',
version: '1.0',
base: themeStore.activeTheme?.id || null
}
})
// Set as default if requested
if (args.setAsDefault && result.id) {
await themeStore.setDefaultTheme(result.id)
return `Tema "${args.name}" guardado y establecido como default.\nID: ${result.id}`
}
return `Tema "${args.name}" guardado permanentemente en la base de datos.\nID: ${result.id}`
} catch (e: any) {
return `Error al guardar tema: ${e.message}`
}
}
)
}
export function unregisterThemeTools() {