draw-it-mcp
Version:
šØ A beautiful drawing app with Cursor & Claude Code MCP integration. Draw, save, and let AI analyze your artwork!
282 lines (247 loc) ⢠9.8 kB
JavaScript
import { spawn } from 'child_process';
import { createServer } from 'http';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, '..');
// Read version from package.json
const packageJsonPath = path.join(projectRoot, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const version = packageJson.version;
// ASCII Art Banner
const banner = `
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®
ā Draw-it-MCP - MCP-Powered Drawing Assistant for AI Coding ā
ā v${version.padEnd(6)} ā
ā Features: ā
ā ⢠Beautiful canvas drawing interface ā
ā ⢠Save & load your artwork ā
ā ⢠Cursor & Claude Code MCP integration ā
ā ⢠Dark/Light theme support ā
ā ā
ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ
`;
console.log('\x1b[36m%s\x1b[0m', banner);
// Find available port
async function findAvailablePort(startPort = 3001) {
return new Promise((resolve) => {
const server = createServer();
server.listen(startPort, () => {
const port = server.address().port;
server.close(() => {
resolve(port);
});
});
server.on('error', () => {
resolve(findAvailablePort(startPort + 1));
});
});
}
// Check if this is first run
function isFirstRun() {
const flagFile = path.join(projectRoot, '.first-run');
if (!fs.existsSync(flagFile)) {
fs.writeFileSync(flagFile, Date.now().toString());
return true;
}
return false;
}
// Handle update command
if (process.argv.includes('update')) {
console.log('š Updating Draw-it-MCP...\n');
const updateProcess = spawn('npm', ['update', '-g', 'draw-it-mcp'], {
stdio: 'inherit',
shell: true
});
updateProcess.on('close', (code) => {
if (code === 0) {
console.log('\nā
Update completed successfully!');
console.log('š Draw-it-MCP is now up to date.');
} else {
console.log('\nā Update failed. Trying alternative method...');
console.log('š Running: npm install -g draw-it-mcp@latest\n');
const installProcess = spawn('npm', ['install', '-g', 'draw-it-mcp@latest'], {
stdio: 'inherit',
shell: true
});
installProcess.on('close', (installCode) => {
if (installCode === 0) {
console.log('\nā
Installation completed successfully!');
console.log('š Draw-it-MCP has been updated to the latest version.');
} else {
console.log('\nā Automatic update failed. Please run manually:');
console.log(' npm install -g draw-it-mcp@latest');
}
process.exit(installCode);
});
}
});
process.exit(0); // Don't proceed to main()
}
// Handle MCP server execution
if (process.argv.includes('mcp:server')) {
// When called as "draw-it-mcp mcp:server", run the MCP server directly
const mcpPath = path.resolve(__dirname, '..', 'src', 'mcp', 'drawing-mcp-server.js');
spawn('node', [mcpPath], { stdio: 'inherit' });
process.exit(0);
}
// Show MCP configuration for Cursor & Claude Code
function showMCPConfiguration() {
console.log('\nš MCP Configuration for Cursor & Claude Code');
console.log('='.repeat(50));
console.log('Copy and paste one of these configurations:\n');
// Get installation paths
const globalNodeModulesPath = path.dirname(path.dirname(__dirname));
const mcpServerPath = path.join(projectRoot, 'src', 'mcp', 'drawing-mcp-server.js');
console.log('š§ Option 1: Using NPX (Recommended)');
console.log('```json');
console.log(JSON.stringify({
mcpServers: {
"draw-it-mcp": {
command: "npx",
args: ["-y", "draw-it-mcp", "mcp:server"]
}
}
}, null, 2));
console.log('```\n');
console.log('š§ Option 2: Using absolute path');
console.log('```json');
console.log(JSON.stringify({
mcpServers: {
"draw-it-mcp": {
command: "node",
args: [mcpServerPath]
}
}
}, null, 2));
console.log('```\n');
console.log('š” Setup Instructions:');
console.log('1. Copy one of the JSON configurations above');
console.log('2. In Cursor: Open Settings ā Extensions ā MCP Settings');
console.log('3. In Claude Code: Use command palette ā "Claude Code: Edit MCP Settings"');
console.log('4. Paste the configuration into your MCP settings');
console.log('5. Restart Cursor/Claude Code');
console.log('6. Start drawing and use MCP tools to analyze your artwork!\n');
}
// Main function
async function main() {
try {
console.log('š Starting Draw-it-MCP...\n');
// Check if we're in development or installed via npm
const isDev = fs.existsSync(path.join(projectRoot, 'package-lock.json'));
const nodeModulesExists = fs.existsSync(path.join(projectRoot, 'node_modules'));
if (!nodeModulesExists) {
console.log('š¦ Installing dependencies... This may take a moment.');
const npmInstall = spawn('npm', ['install'], {
cwd: projectRoot,
stdio: 'inherit',
shell: true
});
await new Promise((resolve, reject) => {
npmInstall.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`npm install failed with code ${code}`));
}
});
});
}
// Find available port
const port = await findAvailablePort(3001);
console.log(`š Found available port: ${port}`);
// Always build on first run or if build doesn't exist
const buildDir = path.join(projectRoot, '.next');
if (!fs.existsSync(buildDir) || isFirstRun()) {
console.log('šļø Building application for the first time...');
const buildProcess = spawn('npx', ['next', 'build'], {
cwd: projectRoot,
stdio: 'inherit',
shell: true
});
await new Promise((resolve, reject) => {
buildProcess.on('close', (code) => {
if (code === 0) {
console.log('ā
Build completed successfully!');
resolve();
} else {
reject(new Error(`Build failed with code ${code}`));
}
});
});
}
// Start the application
console.log('šØ Launching Draw-it-MCP...\n');
const serverProcess = spawn('npx', ['next', 'start', '-p', port.toString()], {
cwd: projectRoot,
stdio: 'inherit',
shell: true,
env: { ...process.env, PORT: port.toString() }
});
// Show success message
setTimeout(() => {
console.log('\n' + '='.repeat(60));
console.log('š Draw-it-MCP is running!');
console.log(`š Open: \x1b[32mhttp://localhost:${port}\x1b[0m`);
console.log('');
console.log('š” Quick Tips:');
console.log(' ⢠Click colors to change brush color');
console.log(' ⢠Use different brush sizes for varied strokes');
console.log(' ⢠Save your drawings for later');
console.log(' ⢠Toggle dark/light theme');
console.log('');
console.log('š¤ Cursor & Claude Code Integration:');
console.log(' ⢠MCP server available for AI analysis');
console.log(' ⢠See MCP configuration below');
console.log('');
console.log('ā¹ļø Press Ctrl+C to stop');
console.log('='.repeat(60) + '\n');
// Show MCP configuration for Cursor & Claude Code
showMCPConfiguration();
// Open browser if first run
if (isFirstRun()) {
setTimeout(async () => {
try {
const open = await import('open');
await open.default(`http://localhost:${port}`);
console.log('š Browser opened automatically!');
} catch (error) {
console.log('š” Please open your browser and navigate to the URL above');
}
}, 2000);
}
}, 2000);
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('\nš Shutting down Draw-it-MCP...');
serverProcess.kill('SIGINT');
setTimeout(() => {
console.log('š Thanks for using Draw-it-MCP!');
process.exit(0);
}, 1000);
});
// Handle server process exit
serverProcess.on('close', (code) => {
if (code !== 0) {
console.error(`\nā Server process exited with code ${code}`);
console.log('š” Try running again or check for port conflicts');
}
process.exit(code);
});
} catch (error) {
console.error('\nā Error starting Draw-it-MCP:');
console.error(error.message);
console.log('\nš” Troubleshooting:');
console.log(' ⢠Make sure Node.js 18+ is installed');
console.log(' ⢠Check if port 3001 is available');
console.log(' ⢠Try running: npm install');
console.log(' ⢠If build fails, try: npx create-next-app@latest --typescript');
console.log(' ⢠For MCP setup: https://github.com/Pandoll-AI/draw-it-mcp#ai-powered-art-analysis-optional');
process.exit(1);
}
}
// Run the application
main().catch(console.error);