feat: Add additional theme management MCP tools

- list_themes: List all available themes (system + custom)
- switch_theme: Change active theme by name or ID
- set_default_theme: Set a theme as the default startup theme
- delete_theme: Remove custom themes (protects system themes)
- reset_theme: Discard unsaved changes
- export_theme: Export theme as JSON for backup/sharing

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

View File

@@ -5,7 +5,13 @@ export const THEME_TOOLS = [
'get_design_tokens', 'get_design_tokens',
'get_active_theme', 'get_active_theme',
'set_theme_variable', 'set_theme_variable',
'save_theme' 'save_theme',
'list_themes',
'switch_theme',
'set_default_theme',
'delete_theme',
'reset_theme',
'export_theme'
] ]
export function registerThemeTools() { export function registerThemeTools() {
@@ -205,6 +211,232 @@ export function registerThemeTools() {
} }
} }
) )
// list_themes
registerTool(
'list_themes',
'Lista todos los temas disponibles (del sistema y personalizados)',
{
type: 'object',
properties: {}
},
async () => {
try {
const themeStore = useThemeStore()
await themeStore.fetchThemes()
const themes = themeStore.themes
if (themes.length === 0) {
return 'No hay temas disponibles'
}
const systemThemes = themes.filter(t => t.is_system)
const userThemes = themes.filter(t => !t.is_system)
let result = `Temas disponibles (${themes.length}):\n\n`
if (systemThemes.length > 0) {
result += `[SISTEMA]\n`
result += systemThemes.map(t =>
` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}`
).join('\n')
result += '\n\n'
}
if (userThemes.length > 0) {
result += `[PERSONALIZADOS]\n`
result += userThemes.map(t =>
` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}`
).join('\n')
}
return result
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// switch_theme
registerTool(
'switch_theme',
'Cambia al tema especificado por nombre o ID',
{
type: 'object',
properties: {
theme: {
type: 'string',
description: 'Nombre o ID del tema a activar'
}
},
required: ['theme']
},
async (args: { theme: string }) => {
try {
const themeStore = useThemeStore()
await themeStore.fetchThemes()
// Find theme by ID or name
const theme = themeStore.themes.find(t =>
t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase()
)
if (!theme) {
const available = themeStore.themes.map(t => t.name).join(', ')
return `Tema "${args.theme}" no encontrado.\nDisponibles: ${available}`
}
themeStore.selectTheme(theme)
return `Tema cambiado a "${theme.name}"\nID: ${theme.id}`
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// set_default_theme
registerTool(
'set_default_theme',
'Establece un tema como el default (se cargará automáticamente al iniciar)',
{
type: 'object',
properties: {
theme: {
type: 'string',
description: 'Nombre o ID del tema a establecer como default'
}
},
required: ['theme']
},
async (args: { theme: string }) => {
try {
const themeStore = useThemeStore()
await themeStore.fetchThemes()
const theme = themeStore.themes.find(t =>
t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase()
)
if (!theme) {
const available = themeStore.themes.map(t => t.name).join(', ')
return `Tema "${args.theme}" no encontrado.\nDisponibles: ${available}`
}
await themeStore.setDefaultTheme(theme.id)
return `Tema "${theme.name}" establecido como default.\nSe cargará automáticamente al iniciar la aplicación.`
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// delete_theme
registerTool(
'delete_theme',
'Elimina un tema personalizado (no se pueden eliminar temas del sistema)',
{
type: 'object',
properties: {
theme: {
type: 'string',
description: 'Nombre o ID del tema a eliminar'
}
},
required: ['theme']
},
async (args: { theme: string }) => {
try {
const themeStore = useThemeStore()
await themeStore.fetchThemes()
const theme = themeStore.themes.find(t =>
t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase()
)
if (!theme) {
return `Tema "${args.theme}" no encontrado`
}
if (theme.is_system) {
return `No se puede eliminar "${theme.name}" porque es un tema del sistema`
}
const success = await themeStore.deleteTheme(theme.id)
if (success) {
return `Tema "${theme.name}" eliminado correctamente`
} else {
return `Error al eliminar el tema "${theme.name}"`
}
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// reset_theme
registerTool(
'reset_theme',
'Descarta todos los cambios no guardados y restaura el tema activo original',
{
type: 'object',
properties: {}
},
() => {
try {
const themeStore = useThemeStore()
if (!themeStore.previewTheme) {
return 'No hay cambios pendientes para descartar'
}
const themeName = themeStore.activeTheme?.name || 'desconocido'
themeStore.resetPreview()
return `Cambios descartados. Tema "${themeName}" restaurado a su estado original.`
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
// export_theme
registerTool(
'export_theme',
'Exporta un tema como JSON para respaldo o compartir',
{
type: 'object',
properties: {
theme: {
type: 'string',
description: 'Nombre o ID del tema a exportar. Si no se especifica, exporta el tema activo.'
}
}
},
async (args: { theme?: string }) => {
try {
const themeStore = useThemeStore()
let theme = themeStore.activeTheme
if (args.theme) {
await themeStore.fetchThemes()
theme = themeStore.themes.find(t =>
t.id === args.theme || t.name.toLowerCase() === args.theme!.toLowerCase()
) || null
}
if (!theme) {
return args.theme
? `Tema "${args.theme}" no encontrado`
: 'No hay tema activo para exportar'
}
const exported = themeStore.exportTheme(theme)
return `Tema "${theme.name}" exportado:\n\n${exported}`
} catch (e: any) {
return `Error: ${e.message}`
}
}
)
} }
export function unregisterThemeTools() { export function unregisterThemeTools() {