From 8af2116c787691631cab94978160d3b3c40a5912 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 29 Jul 2025 05:57:02 +0000 Subject: [PATCH 1/4] Initial plan From 52b545ddfefd6ad4a6176e6f60640bdda99a2257 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 29 Jul 2025 06:16:22 +0000 Subject: [PATCH 2/4] Implement MCP tools for Mixcore CMS template operations Co-authored-by: Smilefounder <3785721+Smilefounder@users.noreply.github.com> --- .../Extensions/StartupExtensions.cs | 1 + .../mix.mcp.lib/Tools/MixTemplateTools.cs | 436 ++++++++++++++++++ 2 files changed, 437 insertions(+) create mode 100644 src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs diff --git a/src/services/mix.mcp/mix.mcp.lib/Extensions/StartupExtensions.cs b/src/services/mix.mcp/mix.mcp.lib/Extensions/StartupExtensions.cs index 95b334218..0b97f0f6c 100644 --- a/src/services/mix.mcp/mix.mcp.lib/Extensions/StartupExtensions.cs +++ b/src/services/mix.mcp/mix.mcp.lib/Extensions/StartupExtensions.cs @@ -63,6 +63,7 @@ public static IHostApplicationBuilder AddMCPServices(this IHostApplicationBuilde .WithHttpTransport() .WithStdioServerTransport() .WithTools() + .WithTools() .WithPrompts() .WithPrompts() .WithPrompts() diff --git a/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs new file mode 100644 index 000000000..9ec37de59 --- /dev/null +++ b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs @@ -0,0 +1,436 @@ +using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using Mix.Database.Entities.Cms; +using Mix.Heart.UnitOfWork; +using Mix.Lib.ViewModels; +using Mix.Lib.Dtos; +using Mix.Constant.Enums; +using ModelContextProtocol.Server; +using Newtonsoft.Json; +using System.ComponentModel; + +namespace Mix.MCP.Lib.Tools +{ + /// + /// MCP tool for interacting with Mixcore CMS templates + /// + [McpServerToolType] + public class MixTemplateTools : BaseMcpTool + { + /// + /// Initializes a new instance of the MixTemplateTools class + /// + public MixTemplateTools( + UnitOfWorkInfo cmsUow, + ILogger logger) + : base(cmsUow, logger) + { + } + + /// + /// Get all templates with optional filtering + /// + [McpServerTool, Description("Get all Mixcore CMS templates with optional filtering")] + public async Task GetTemplates( + [Description("Optional theme ID to filter by")] int? themeId = null, + [Description("Optional folder type (0=Layouts, 1=Pages, 2=Modules, 3=Forms, 4=Edms, 5=Posts, 6=Widgets, 7=Masters)")] int? folderType = null, + [Description("Optional keyword to search for")] string keyword = null, + [Description("Page index (0-based)")] int pageIndex = 0, + [Description("Page size")] int pageSize = 10) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var query = _cmsUow.Repository().GetModelListBy(m => true); + + if (themeId.HasValue) + { + query = query.Where(m => m.MixThemeId == themeId.Value); + } + + if (folderType.HasValue) + { + query = query.Where(m => m.FolderType == (MixTemplateFolderType)folderType.Value); + } + + if (!string.IsNullOrEmpty(keyword)) + { + query = query.Where(m => m.FileName.Contains(keyword) || m.Content.Contains(keyword)); + } + + var total = await query.CountAsync(cancellationToken); + var templates = await query + .Skip(pageIndex * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + var viewModels = new List(); + foreach (var template in templates) + { + var vm = new MixTemplateViewModel(template, _cmsUow); + await vm.ExpandView(cancellationToken); + viewModels.Add(new + { + Id = vm.Id, + FileName = vm.FileName, + Extension = vm.Extension, + FolderType = vm.FolderType.ToString(), + MixThemeName = vm.MixThemeName, + MixThemeId = vm.MixThemeId, + Content = vm.Content, + Scripts = vm.Scripts, + Styles = vm.Styles, + CreatedDateTime = vm.CreatedDateTime, + LastModified = vm.LastModified, + CreatedBy = vm.CreatedBy, + ModifiedBy = vm.ModifiedBy + }); + } + + return JsonConvert.SerializeObject(new + { + Items = viewModels, + TotalItems = total, + PageIndex = pageIndex, + PageSize = pageSize, + TotalPages = (int)Math.Ceiling((double)total / pageSize) + }); + }, "GetTemplates"); + } + + /// + /// Get a single template by ID + /// + [McpServerTool, Description("Get a single Mixcore CMS template by ID")] + public async Task GetTemplateById( + [Description("Template ID")] int id) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var template = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); + + if (template == null) + { + throw new Exception($"Template with ID {id} not found"); + } + + var viewModel = new MixTemplateViewModel(template, _cmsUow); + await viewModel.ExpandView(cancellationToken); + + return JsonConvert.SerializeObject(new + { + Id = viewModel.Id, + FileName = viewModel.FileName, + Extension = viewModel.Extension, + FileFolder = viewModel.FileFolder, + FolderType = viewModel.FolderType.ToString(), + MixThemeName = viewModel.MixThemeName, + MixThemeId = viewModel.MixThemeId, + Content = viewModel.Content, + Scripts = viewModel.Scripts, + Styles = viewModel.Styles, + CreatedDateTime = viewModel.CreatedDateTime, + LastModified = viewModel.LastModified, + CreatedBy = viewModel.CreatedBy, + ModifiedBy = viewModel.ModifiedBy + }); + }, "GetTemplateById"); + } + + /// + /// Create a new template + /// + [McpServerTool, Description("Create a new Mixcore CMS template")] + public async Task CreateTemplate( + [Description("Template filename")] string fileName, + [Description("File extension (e.g., 'cshtml')")] string extension, + [Description("Folder type (0=Layouts, 1=Pages, 2=Modules, 3=Forms, 4=Edms, 5=Posts, 6=Widgets, 7=Masters)")] int folderType, + [Description("Theme ID")] int themeId, + [Description("Template content")] string content = "", + [Description("JavaScript content")] string scripts = "", + [Description("CSS content")] string styles = "") + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var template = new MixTemplateViewModel(_cmsUow) + { + FileName = fileName, + Extension = extension, + FolderType = (MixTemplateFolderType)folderType, + MixThemeId = themeId, + Content = content, + Scripts = scripts, + Styles = styles + }; + + var result = await template.SaveAsync(cancellationToken); + + if (result <= 0) + { + throw new Exception("Failed to create template"); + } + + return JsonConvert.SerializeObject(new + { + Id = result, + Message = "Template created successfully" + }); + }, "CreateTemplate"); + } + + /// + /// Update an existing template + /// + [McpServerTool, Description("Update an existing Mixcore CMS template")] + public async Task UpdateTemplate( + [Description("Template ID")] int id, + [Description("Template filename")] string fileName = null, + [Description("File extension")] string extension = null, + [Description("Template content")] string content = null, + [Description("JavaScript content")] string scripts = null, + [Description("CSS content")] string styles = null) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); + + if (entity == null) + { + throw new Exception($"Template with ID {id} not found"); + } + + var template = new MixTemplateViewModel(entity, _cmsUow); + + // Update only provided fields + if (!string.IsNullOrEmpty(fileName)) + template.FileName = fileName; + if (!string.IsNullOrEmpty(extension)) + template.Extension = extension; + if (content != null) + template.Content = content; + if (scripts != null) + template.Scripts = scripts; + if (styles != null) + template.Styles = styles; + + await template.SaveAsync(cancellationToken); + + return JsonConvert.SerializeObject(new + { + Id = id, + Message = "Template updated successfully" + }); + }, "UpdateTemplate"); + } + + /// + /// Delete a template + /// + [McpServerTool, Description("Delete a Mixcore CMS template")] + public async Task DeleteTemplate( + [Description("Template ID")] int id) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); + + if (entity == null) + { + throw new Exception($"Template with ID {id} not found"); + } + + var template = new MixTemplateViewModel(entity, _cmsUow); + await template.DeleteAsync(cancellationToken); + + return JsonConvert.SerializeObject(new + { + Id = id, + Message = "Template deleted successfully" + }); + }, "DeleteTemplate"); + } + + /// + /// Copy an existing template + /// + [McpServerTool, Description("Copy an existing Mixcore CMS template")] + public async Task CopyTemplate( + [Description("Template ID to copy")] int id) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); + + if (entity == null) + { + throw new Exception($"Template with ID {id} not found"); + } + + var template = new MixTemplateViewModel(entity, _cmsUow); + var copyResult = await template.CopyAsync(cancellationToken); + + return JsonConvert.SerializeObject(new + { + OriginalId = id, + NewId = copyResult.Id, + NewFileName = copyResult.FileName, + Message = "Template copied successfully" + }); + }, "CopyTemplate"); + } + + /// + /// Get default template structure + /// + [McpServerTool, Description("Get default template structure for creating new templates")] + public async Task GetDefaultTemplate( + [Description("Theme ID for the default template")] int themeId, + [Description("Folder type (0=Layouts, 1=Pages, 2=Modules, 3=Forms, 4=Edms, 5=Posts, 6=Widgets, 7=Masters)")] int folderType) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var defaultTemplate = new MixTemplateViewModel(_cmsUow) + { + MixThemeId = themeId, + FolderType = (MixTemplateFolderType)folderType, + Extension = "cshtml", + Content = "", + Scripts = "", + Styles = "" + }; + + await defaultTemplate.ExpandView(cancellationToken); + + return JsonConvert.SerializeObject(new + { + MixThemeId = defaultTemplate.MixThemeId, + FolderType = defaultTemplate.FolderType.ToString(), + Extension = defaultTemplate.Extension, + Content = defaultTemplate.Content, + Scripts = defaultTemplate.Scripts, + Styles = defaultTemplate.Styles, + FileFolder = defaultTemplate.FileFolder + }); + }, "GetDefaultTemplate"); + } + + /// + /// Filter templates with advanced search + /// + [McpServerTool, Description("Filter Mixcore CMS templates with advanced search criteria")] + public async Task FilterTemplates( + [Description("Search criteria in JSON format. Example: {\"keyword\":\"layout\",\"themeId\":1,\"folderType\":0,\"pageIndex\":0,\"pageSize\":10}")] string searchCriteria) + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var criteria = JsonConvert.DeserializeObject(searchCriteria); + + if (criteria == null) + { + throw new Exception("Invalid search criteria format"); + } + + var query = _cmsUow.Repository().GetModelListBy(m => true); + + // Apply filters based on criteria + if (criteria.themeId != null) + { + query = query.Where(m => m.MixThemeId == (int)criteria.themeId); + } + + if (criteria.folderType != null) + { + query = query.Where(m => m.FolderType == (MixTemplateFolderType)(int)criteria.folderType); + } + + if (criteria.keyword != null && !string.IsNullOrEmpty((string)criteria.keyword)) + { + string keyword = (string)criteria.keyword; + query = query.Where(m => m.FileName.Contains(keyword) || m.Content.Contains(keyword)); + } + + int pageIndex = criteria.pageIndex ?? 0; + int pageSize = criteria.pageSize ?? 10; + + var total = await query.CountAsync(cancellationToken); + var templates = await query + .Skip(pageIndex * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + return JsonConvert.SerializeObject(new + { + Items = templates.Select(t => new + { + Id = t.Id, + FileName = t.FileName, + Extension = t.Extension, + FolderType = t.FolderType.ToString(), + MixThemeName = t.MixThemeName, + MixThemeId = t.MixThemeId, + CreatedDateTime = t.CreatedDateTime, + LastModified = t.LastModified + }), + TotalItems = total, + PageIndex = pageIndex, + PageSize = pageSize, + TotalPages = (int)Math.Ceiling((double)total / pageSize) + }); + }, "FilterTemplates"); + } + + /// + /// List all available themes for template creation + /// + [McpServerTool, Description("List all available themes for template creation")] + public async Task GetAvailableThemes() + { + return await ExecuteWithExceptionHandlingAsync(async cancellationToken => + { + var themes = await _cmsUow.Repository().GetModelListByAsync( + t => true, // Remove the status filter for now since we can't find MixContentStatus + cancellationToken: cancellationToken); + + return JsonConvert.SerializeObject(themes.Select(t => new + { + Id = t.Id, + SystemName = t.SystemName, + Title = t.Title, + CreatedDateTime = t.CreatedDateTime + })); + }, "GetAvailableThemes"); + } + + /// + /// Get template folder types information + /// + [McpServerTool, Description("Get information about template folder types")] + public string GetTemplateFolderTypes() + { + var folderTypes = Enum.GetValues() + .Select(ft => new + { + Value = (int)ft, + Name = ft.ToString(), + Description = GetFolderTypeDescription(ft) + }); + + return JsonConvert.SerializeObject(folderTypes); + } + + private static string GetFolderTypeDescription(MixTemplateFolderType folderType) + { + return folderType switch + { + MixTemplateFolderType.Layouts => "Layout templates that define the overall structure of pages", + MixTemplateFolderType.Pages => "Page templates for specific pages", + MixTemplateFolderType.Modules => "Module templates for specific functionality", + MixTemplateFolderType.Forms => "Form templates for user input", + MixTemplateFolderType.Edms => "Electronic Document Management System templates", + MixTemplateFolderType.Posts => "Post templates for blog/news content", + MixTemplateFolderType.Widgets => "Widget templates for reusable components", + MixTemplateFolderType.Masters => "Master templates for hierarchical structures", + _ => "Unknown folder type" + }; + } + } +} \ No newline at end of file From 57d19938f90c06ccf4160ffe0b1920c13611b23f Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 06:17:13 +0000 Subject: [PATCH 3/4] style: format code with dotnet-format This commit fixes the style issues introduced in 52b545d according to the output from dotnet-format. Details: https://github.com/mixcore/mix.core/pull/786 --- .../mix.mcp.lib/Tools/MixTemplateTools.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs index 9ec37de59..4daf01556 100644 --- a/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs +++ b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.cs @@ -41,17 +41,17 @@ public async Task GetTemplates( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var query = _cmsUow.Repository().GetModelListBy(m => true); - + if (themeId.HasValue) { query = query.Where(m => m.MixThemeId == themeId.Value); } - + if (folderType.HasValue) { query = query.Where(m => m.FolderType == (MixTemplateFolderType)folderType.Value); } - + if (!string.IsNullOrEmpty(keyword)) { query = query.Where(m => m.FileName.Contains(keyword) || m.Content.Contains(keyword)); @@ -107,7 +107,7 @@ public async Task GetTemplateById( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var template = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); - + if (template == null) { throw new Exception($"Template with ID {id} not found"); @@ -163,7 +163,7 @@ public async Task CreateTemplate( }; var result = await template.SaveAsync(cancellationToken); - + if (result <= 0) { throw new Exception("Failed to create template"); @@ -192,7 +192,7 @@ public async Task UpdateTemplate( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); - + if (entity == null) { throw new Exception($"Template with ID {id} not found"); @@ -232,7 +232,7 @@ public async Task DeleteTemplate( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); - + if (entity == null) { throw new Exception($"Template with ID {id} not found"); @@ -259,7 +259,7 @@ public async Task CopyTemplate( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var entity = await _cmsUow.Repository().GetSingleAsync(m => m.Id == id, cancellationToken); - + if (entity == null) { throw new Exception($"Template with ID {id} not found"); @@ -323,25 +323,25 @@ public async Task FilterTemplates( return await ExecuteWithExceptionHandlingAsync(async cancellationToken => { var criteria = JsonConvert.DeserializeObject(searchCriteria); - + if (criteria == null) { throw new Exception("Invalid search criteria format"); } var query = _cmsUow.Repository().GetModelListBy(m => true); - + // Apply filters based on criteria if (criteria.themeId != null) { query = query.Where(m => m.MixThemeId == (int)criteria.themeId); } - + if (criteria.folderType != null) { query = query.Where(m => m.FolderType == (MixTemplateFolderType)(int)criteria.folderType); } - + if (criteria.keyword != null && !string.IsNullOrEmpty((string)criteria.keyword)) { string keyword = (string)criteria.keyword; From 83ece7f6b0a569e8bc27649c9b2bfb29d34dbe06 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 29 Jul 2025 06:20:04 +0000 Subject: [PATCH 4/4] Add documentation and validation for MCP template tools Co-authored-by: Smilefounder <3785721+Smilefounder@users.noreply.github.com> --- .../mix.mcp.lib/Tools/MixTemplateTools.md | 128 ++++++++++++++ .../Tools/MixTemplateTools_Examples.md | 159 ++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.md create mode 100644 src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools_Examples.md diff --git a/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.md b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.md new file mode 100644 index 000000000..6beea6b32 --- /dev/null +++ b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools.md @@ -0,0 +1,128 @@ +# Mixcore CMS Template MCP Tools + +This implementation provides MCP (Model Context Protocol) tools for interacting with Mixcore CMS templates, allowing LLMs like Claude to create and manage theme templates. + +## Available Tools + +### Core Template Operations + +1. **GetTemplates** - List all templates with filtering + - Optional theme ID filter + - Optional folder type filter (0-7) + - Keyword search in filename and content + - Pagination support + +2. **GetTemplateById** - Get a single template by ID + - Returns complete template data including content, scripts, styles + - Expands view with file system content + +3. **CreateTemplate** - Create a new template + - Requires filename, extension, folder type, theme ID + - Optional content, scripts, styles + - Validates uniqueness and theme existence + +4. **UpdateTemplate** - Update existing template + - Partial updates supported + - Can update filename, extension, content, scripts, styles + +5. **DeleteTemplate** - Delete a template by ID + - Safe deletion with existence validation + +6. **CopyTemplate** - Copy existing template + - Creates duplicate with "Copy_" prefix + - Returns new template ID and filename + +### Helper Operations + +7. **GetDefaultTemplate** - Get default template structure + - Provides template skeleton for different folder types + - Includes default scripts and styles blocks + +8. **FilterTemplates** - Advanced filtering with JSON criteria + - Flexible search with multiple criteria + - Supports complex filtering scenarios + +9. **GetAvailableThemes** - List all themes + - Shows available themes for template creation + - Includes theme metadata + +10. **GetTemplateFolderTypes** - Get folder type information + - Lists all available folder types with descriptions + - Helps understand template organization + +## Folder Types + +The following folder types are supported: + +- **0 - Layouts**: Layout templates that define the overall structure of pages +- **1 - Pages**: Page templates for specific pages +- **2 - Modules**: Module templates for specific functionality +- **3 - Forms**: Form templates for user input +- **4 - Edms**: Electronic Document Management System templates +- **5 - Posts**: Post templates for blog/news content +- **6 - Widgets**: Widget templates for reusable components +- **7 - Masters**: Master templates for hierarchical structures + +## Usage Examples + +### Creating a New Layout Template + +```json +{ + "tool": "CreateTemplate", + "arguments": { + "fileName": "main-layout", + "extension": "cshtml", + "folderType": 0, + "themeId": 1, + "content": "\n\n\n @ViewBag.Title\n\n\n @RenderBody()\n\n", + "scripts": "", + "styles": "" + } +} +``` + +### Searching Templates + +```json +{ + "tool": "GetTemplates", + "arguments": { + "themeId": 1, + "folderType": 0, + "keyword": "layout", + "pageIndex": 0, + "pageSize": 10 + } +} +``` + +### Advanced Filtering + +```json +{ + "tool": "FilterTemplates", + "arguments": { + "searchCriteria": "{\"keyword\":\"blog\",\"themeId\":1,\"folderType\":5,\"pageIndex\":0,\"pageSize\":20}" + } +} +``` + +## Integration + +The tools are automatically registered in the MCP server startup and are available at the `/mcp` endpoint. They use the existing Mixcore CMS infrastructure and maintain consistency with the web API endpoints. + +## API Mapping + +These MCP tools map to the following Mixcore REST API endpoints: + +- `GetTemplates` → `GET /api/v2/rest/mix-portal/mix-template` +- `GetTemplateById` → `GET /api/v2/rest/mix-portal/mix-template/{id}` +- `CreateTemplate` → `POST /api/v2/rest/mix-portal/mix-template` +- `UpdateTemplate` → `PUT /api/v2/rest/mix-portal/mix-template/{id}` +- `DeleteTemplate` → `DELETE /api/v2/rest/mix-portal/mix-template/{id}` +- `CopyTemplate` → `GET /api/v2/rest/mix-portal/mix-template/copy/{id}` +- `GetDefaultTemplate` → `GET /api/v2/rest/mix-portal/mix-template/default` +- `FilterTemplates` → `POST /api/v2/rest/mix-portal/mix-template/filter` + +This ensures LLMs can perform all the same operations available through the web interface while maintaining data consistency and security. \ No newline at end of file diff --git a/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools_Examples.md b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools_Examples.md new file mode 100644 index 000000000..d5f4cd6d6 --- /dev/null +++ b/src/services/mix.mcp/mix.mcp.lib/Tools/MixTemplateTools_Examples.md @@ -0,0 +1,159 @@ +# Mixcore CMS Template MCP Tools - Usage Examples for LLMs + +This document shows how LLMs (like Claude) can use the MCP tools to create and manage Mixcore CMS templates. + +## Example Workflow: Creating a Blog Template Theme + +### 1. First, discover available themes and folder types + +```json +{ + "tool": "GetAvailableThemes", + "arguments": {} +} +``` + +Response: +```json +[ + { + "Id": 1, + "SystemName": "default-theme", + "Title": "Default Theme", + "CreatedDateTime": "2024-01-01T00:00:00Z" + } +] +``` + +```json +{ + "tool": "GetTemplateFolderTypes", + "arguments": {} +} +``` + +Response: +```json +[ + { + "Value": 0, + "Name": "Layouts", + "Description": "Layout templates that define the overall structure of pages" + }, + { + "Value": 5, + "Name": "Posts", + "Description": "Post templates for blog/news content" + } +] +``` + +### 2. Create a main layout template + +```json +{ + "tool": "CreateTemplate", + "arguments": { + "fileName": "blog-layout", + "extension": "cshtml", + "folderType": 0, + "themeId": 1, + "content": "\n\n\n \n @ViewBag.Title - My Blog\n \n @RenderSection(\"Styles\", false)\n\n\n
\n \n
\n
\n @RenderBody()\n
\n
\n
\n

© 2024 My Blog. All rights reserved.

\n
\n
\n @RenderSection(\"Scripts\", false)\n\n", + "styles": "", + "scripts": "" + } +} +``` + +### 3. Create a blog post template + +```json +{ + "tool": "CreateTemplate", + "arguments": { + "fileName": "blog-post", + "extension": "cshtml", + "folderType": 5, + "themeId": 1, + "content": "@{\n Layout = \"~/Views/Shared/blog-layout.cshtml\";\n ViewBag.Title = Model.Title;\n}\n\n
\n
\n

@Model.Title

\n
\n @Model.CreatedDateTime.ToString(\"MMMM dd, yyyy\")\n @if (!string.IsNullOrEmpty(Model.CreatedBy))\n {\n by @Model.CreatedBy\n }\n
\n
\n \n @if (!string.IsNullOrEmpty(Model.Image))\n {\n
\n \"@Model.Title\"\n
\n }\n \n
\n @Html.Raw(Model.Content)\n
\n \n \n
", + "styles": "" + } +} +``` + +### 4. Create a blog post list template + +```json +{ + "tool": "CreateTemplate", + "arguments": { + "fileName": "blog-list", + "extension": "cshtml", + "folderType": 5, + "themeId": 1, + "content": "@{\n Layout = \"~/Views/Shared/blog-layout.cshtml\";\n ViewBag.Title = \"Blog Posts\";\n}\n\n
\n
\n

Latest Blog Posts

\n

Discover our latest thoughts and insights

\n
\n \n
\n @foreach (var post in Model.Items)\n {\n
\n @if (!string.IsNullOrEmpty(post.Image))\n {\n
\n \"@post.Title\"\n
\n }\n \n
\n

\n @post.Title\n

\n \n
\n @post.CreatedDateTime.ToString(\"MMM dd, yyyy\")\n
\n \n
\n @Html.Raw(post.Excerpt ?? post.Content.Substring(0, Math.Min(150, post.Content.Length)) + \"...\")\n
\n \n Read More\n
\n
\n }\n
\n \n @if (Model.TotalPages > 1)\n {\n \n }\n
", + "styles": "" + } +} +``` + +### 5. List all created templates to verify + +```json +{ + "tool": "GetTemplates", + "arguments": { + "themeId": 1, + "pageSize": 20 + } +} +``` + +### 6. Make updates to a template + +```json +{ + "tool": "UpdateTemplate", + "arguments": { + "id": 1, + "content": "\n\n\n \n @ViewBag.Title - My Awesome Blog\n \n \n @RenderSection(\"Styles\", false)\n\n\n \n\n" + } +} +``` + +### 7. Create a copy for a different theme variation + +```json +{ + "tool": "CopyTemplate", + "arguments": { + "id": 1 + } +} +``` + +## Advanced Usage + +### Search templates by content + +```json +{ + "tool": "FilterTemplates", + "arguments": { + "searchCriteria": "{\"keyword\":\"blog\",\"pageSize\":50}" + } +} +``` + +### Get a specific template's full details + +```json +{ + "tool": "GetTemplateById", + "arguments": { + "id": 1 + } +} +``` + +This shows how LLMs can programmatically create complete theme templates for Mixcore CMS, making it easy to generate sophisticated website templates through natural language instructions. \ No newline at end of file