cold-mcp-super-design
Version:
MCP server for SuperDesign integration with Cursor/Windsurf/Claude Code - Generate UI designs, components, and wireframes
390 lines (385 loc) ⢠16.8 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
import fs from 'fs-extra';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
class SuperDesignMCPServer {
server;
designsPath;
constructor() {
this.server = new Server({
name: 'cold-mcp-super-design',
version: '1.0.0',
}, {
capabilities: {
tools: {},
},
});
// Find the workspace root (where the user is working)
const workspaceRoot = process.env.PWD || process.cwd();
this.designsPath = path.join(workspaceRoot, '.superdesign', 'design_iterations');
this.setupToolHandlers();
}
async ensureDesignsDirectory() {
await fs.ensureDir(this.designsPath);
}
setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'create_design',
description: 'Create a new UI design with HTML and CSS',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Name of the design (e.g., "login-form", "calculator")',
},
description: {
type: 'string',
description: 'Description of the design',
},
prompt: {
type: 'string',
description: 'The design prompt/requirements',
},
html: {
type: 'string',
description: 'HTML content for the design',
},
css: {
type: 'string',
description: 'CSS styles for the design',
},
},
required: ['name', 'description', 'prompt', 'html', 'css'],
},
},
{
name: 'create_design_revision',
description: 'Create a new revision of an existing design',
inputSchema: {
type: 'object',
properties: {
originalName: {
type: 'string',
description: 'Name of the original design to revise',
},
revisionDescription: {
type: 'string',
description: 'Description of what changed in this revision',
},
prompt: {
type: 'string',
description: 'The updated design prompt/requirements',
},
html: {
type: 'string',
description: 'Updated HTML content',
},
css: {
type: 'string',
description: 'Updated CSS styles',
},
},
required: ['originalName', 'revisionDescription', 'prompt', 'html', 'css'],
},
},
{
name: 'list_designs',
description: 'List all created designs and their revisions',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'get_design',
description: 'Get details of a specific design',
inputSchema: {
type: 'object',
properties: {
designId: {
type: 'string',
description: 'ID of the design to retrieve',
},
},
required: ['designId'],
},
},
{
name: 'generate_superdesign_prompt',
description: 'Generate a prompt for SuperDesign canvas integration',
inputSchema: {
type: 'object',
properties: {
designType: {
type: 'string',
description: 'Type of design (login, calculator, dashboard, etc.)',
},
colorScheme: {
type: 'string',
description: 'Color scheme (e.g., "gold, black, and white")',
},
style: {
type: 'string',
description: 'Design style (modern, minimal, elegant, etc.)',
},
additionalRequirements: {
type: 'string',
description: 'Any additional design requirements',
},
},
required: ['designType'],
},
},
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'create_design':
return await this.createDesign(args);
case 'create_design_revision':
return await this.createDesignRevision(args);
case 'list_designs':
return await this.listDesigns();
case 'get_design':
return await this.getDesign(args);
case 'generate_superdesign_prompt':
return await this.generateSuperDesignPrompt(args);
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`);
}
});
}
async createDesign(args) {
await this.ensureDesignsDirectory();
const design = {
id: uuidv4(),
name: args.name,
description: args.description,
prompt: args.prompt,
html: args.html,
css: args.css,
timestamp: new Date().toISOString(),
version: 1,
};
const fileName = `${args.name}.json`;
const filePath = path.join(this.designsPath, fileName);
await fs.writeJson(filePath, design, { spaces: 2 });
// Also create an HTML preview file
const htmlPreview = this.generateHTMLPreview(design);
const htmlFileName = `${args.name}.html`;
const htmlFilePath = path.join(this.designsPath, htmlFileName);
await fs.writeFile(htmlFilePath, htmlPreview);
return {
content: [
{
type: 'text',
text: `ā
Design "${args.name}" created successfully!\n\n` +
`š Saved to: ${filePath}\n` +
`š Preview: ${htmlFilePath}\n` +
`š Design ID: ${design.id}\n\n` +
`To preview in SuperDesign canvas:\n` +
`1. Press Cmd+Shift+P (or Ctrl+Shift+P)\n` +
`2. Type "Superdesign: Open canvas view"\n` +
`3. Open the HTML file: ${htmlFileName}`,
},
],
};
}
async createDesignRevision(args) {
await this.ensureDesignsDirectory();
// Find the original design to get the next version number
const originalPath = path.join(this.designsPath, `${args.originalName}.json`);
let version = 1;
if (await fs.pathExists(originalPath)) {
const originalDesign = await fs.readJson(originalPath);
version = originalDesign.version + 1;
}
const revision = {
id: uuidv4(),
name: `${args.originalName}-rev${version}`,
description: args.revisionDescription,
prompt: args.prompt,
html: args.html,
css: args.css,
timestamp: new Date().toISOString(),
version: version,
};
const fileName = `${revision.name}.json`;
const filePath = path.join(this.designsPath, fileName);
await fs.writeJson(filePath, revision, { spaces: 2 });
// Create HTML preview
const htmlPreview = this.generateHTMLPreview(revision);
const htmlFileName = `${revision.name}.html`;
const htmlFilePath = path.join(this.designsPath, htmlFileName);
await fs.writeFile(htmlFilePath, htmlPreview);
return {
content: [
{
type: 'text',
text: `ā
Design revision "${revision.name}" created successfully!\n\n` +
`š Saved to: ${filePath}\n` +
`š Preview: ${htmlFilePath}\n` +
`š Design ID: ${revision.id}\n` +
`š Version: ${version}\n\n` +
`To preview in SuperDesign canvas:\n` +
`1. Press Cmd+Shift+P (or Ctrl+Shift+P)\n` +
`2. Type "Superdesign: Open canvas view"\n` +
`3. Open the HTML file: ${htmlFileName}`,
},
],
};
}
generateHTMLPreview(design) {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${design.name} - SuperDesign Preview</title>
<style>
${design.css}
</style>
</head>
<body>
<!-- Design: ${design.name} -->
<!-- Description: ${design.description} -->
<!-- Generated: ${design.timestamp} -->
<!-- Version: ${design.version} -->
${design.html}
</body>
</html>`;
}
async listDesigns() {
await this.ensureDesignsDirectory();
const files = await fs.readdir(this.designsPath);
const jsonFiles = files.filter(file => file.endsWith('.json'));
if (jsonFiles.length === 0) {
return {
content: [
{
type: 'text',
text: 'š No designs found. Create your first design using the create_design tool!',
},
],
};
}
const designs = [];
for (const file of jsonFiles) {
try {
const design = await fs.readJson(path.join(this.designsPath, file));
designs.push(design);
}
catch (error) {
console.error(`Error reading design file ${file}:`, error);
}
}
designs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
const designList = designs.map(design => `šØ ${design.name} (v${design.version})\n` +
` š ${design.description}\n` +
` š ${design.id}\n` +
` š
${new Date(design.timestamp).toLocaleString()}\n`).join('\n');
return {
content: [
{
type: 'text',
text: `š Found ${designs.length} design(s):\n\n${designList}`,
},
],
};
}
async getDesign(args) {
await this.ensureDesignsDirectory();
const files = await fs.readdir(this.designsPath);
const jsonFiles = files.filter(file => file.endsWith('.json'));
for (const file of jsonFiles) {
try {
const design = await fs.readJson(path.join(this.designsPath, file));
if (design.id === args.designId) {
return {
content: [
{
type: 'text',
text: `šØ Design Details:\n\n` +
`š Name: ${design.name}\n` +
`š Description: ${design.description}\n` +
`š ID: ${design.id}\n` +
`š Version: ${design.version}\n` +
`š
Created: ${new Date(design.timestamp).toLocaleString()}\n\n` +
`š Prompt:\n${design.prompt}\n\n` +
`š HTML:\n\`\`\`html\n${design.html}\n\`\`\`\n\n` +
`šØ CSS:\n\`\`\`css\n${design.css}\n\`\`\``,
},
],
};
}
}
catch (error) {
console.error(`Error reading design file ${file}:`, error);
}
}
return {
content: [
{
type: 'text',
text: `ā Design with ID "${args.designId}" not found.`,
},
],
};
}
async generateSuperDesignPrompt(args) {
const colorScheme = args.colorScheme || 'modern blue and white';
const style = args.style || 'modern and clean';
const additional = args.additionalRequirements || '';
const prompt = `Help me design a ${args.designType} UI with the following specifications:
šØ **Design Type**: ${args.designType}
š **Color Scheme**: ${colorScheme}
⨠**Style**: ${style}
${additional ? `š **Additional Requirements**: ${additional}` : ''}
Please create a ${style} ${args.designType} interface using ${colorScheme} colors. The design should be:
- Responsive and mobile-friendly
- Accessible with proper contrast ratios
- Modern with clean typography
- User-friendly with intuitive interactions
${additional ? `- ${additional}` : ''}
Generate the HTML and CSS code, then use the create_design tool to save it to the SuperDesign canvas.
To preview the design:
1. Press Cmd+Shift+P (or Ctrl+Shift+P)
2. Type "Superdesign: Open canvas view"
3. Open the generated HTML file`;
return {
content: [
{
type: 'text',
text: `š **SuperDesign Prompt Generated:**\n\n${prompt}\n\n` +
`š” **Next Steps:**\n` +
`1. Copy this prompt to your AI assistant (Cursor/Windsurf/Claude Code)\n` +
`2. Let the AI generate the HTML/CSS\n` +
`3. Use the create_design tool to save the result\n` +
`4. Preview in SuperDesign canvas with Cmd+Shift+P ā "Superdesign: Open canvas view"`,
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Cold MCP SuperDesign server running on stdio');
}
}
const server = new SuperDesignMCPServer();
server.run().catch(console.error);
//# sourceMappingURL=index.js.map