superclaude-gemini-integration-mcp
Version:
MCP server for SuperClaude - brings SuperClaude commands to Gemini CLI
600 lines (537 loc) • 21 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema
} from '@modelcontextprotocol/sdk/types.js';
import fs from 'fs/promises';
import path from 'path';
import os from 'os';
import { spawn } from 'child_process';
// SuperClaude configuration paths
const CLAUDE_CONFIG_DIR = path.join(os.homedir(), '.claude');
const PERSONAS_FILE = path.join(CLAUDE_CONFIG_DIR, 'shared', 'superclaude-personas.yml');
const COMMANDS_CONFIG = path.join(CLAUDE_CONFIG_DIR, 'shared', 'superclaude-commands.yml');
class SuperClaudeMCPServer {
constructor() {
this.server = new Server(
{
name: 'superclaude-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.personas = {};
this.commands = {};
this.activePersona = null;
this.tokenMode = 'normal';
}
async initialize() {
// Load SuperClaude configurations
await this.loadPersonas();
await this.loadCommands();
// Set up request handlers
this.setupHandlers();
}
async loadPersonas() {
try {
const personasContent = await fs.readFile(PERSONAS_FILE, 'utf8');
// Simple YAML parsing (for production, use a proper YAML parser)
this.personas = this.parseSimpleYAML(personasContent);
} catch (error) {
// Failed to load personas - use defaults
this.personas = this.getDefaultPersonas();
}
}
async loadCommands() {
// Define SuperClaude commands based on documentation
this.commands = {
'build': {
description: 'Universal project builder - Create any type of project with intelligent defaults',
flags: ['--init', '--feature', '--react', '--api', '--tdd', '--magic'],
category: 'development'
},
'dev-setup': {
description: 'Development environment setup - Configure complete dev environment',
flags: ['--minimal', '--full', '--ci', '--monitoring'],
category: 'development'
},
'test': {
description: 'Testing framework - Create and run tests with coverage',
flags: ['--unit', '--integration', '--e2e', '--coverage', '--watch'],
category: 'development'
},
'analyze': {
description: 'Code analysis - Multi-dimensional analysis of code quality',
flags: ['--deep', '--security', '--performance', '--architecture'],
category: 'analysis'
},
'troubleshoot': {
description: 'Intelligent debugging - Systematic issue resolution',
flags: ['--verbose', '--trace', '--profile', '--memory'],
category: 'analysis'
},
'improve': {
description: 'Code improvement - Enhance existing code',
flags: ['--refactor', '--optimize', '--modernize', '--clean'],
category: 'analysis'
},
'explain': {
description: 'Code explanation - Detailed documentation and understanding',
flags: ['--simple', '--detailed', '--visual', '--examples'],
category: 'analysis'
},
'deploy': {
description: 'Deployment automation - Handle deployment workflows',
flags: ['--staging', '--production', '--rollback', '--validate'],
category: 'operations'
},
'migrate': {
description: 'Migration assistance - Database and code migrations',
flags: ['--plan', '--execute', '--rollback', '--validate'],
category: 'operations'
},
'scan': {
description: 'Security scanning - Comprehensive security analysis',
flags: ['--vulnerabilities', '--dependencies', '--secrets', '--compliance'],
category: 'operations'
},
'estimate': {
description: 'Project estimation - Time and resource estimates',
flags: ['--detailed', '--summary', '--breakdown', '--risks'],
category: 'operations'
},
'cleanup': {
description: 'Code cleanup - Remove technical debt',
flags: ['--unused', '--duplicates', '--formatting', '--optimize'],
category: 'operations'
},
'git': {
description: 'Git operations - Advanced git workflows',
flags: ['--checkpoint', '--restore', '--analyze', '--optimize'],
category: 'operations'
},
'design': {
description: 'System design - Architecture and design patterns',
flags: ['--patterns', '--architecture', '--api', '--database'],
category: 'design'
},
'spawn': {
description: 'Create specialized agents - Spawn task-specific AI agents',
flags: ['--researcher', '--reviewer', '--tester', '--documenter'],
category: 'workflow'
},
'document': {
description: 'Documentation generation - Create comprehensive docs',
flags: ['--api', '--user', '--technical', '--readme'],
category: 'workflow'
},
'load': {
description: 'Load configurations - Apply saved configurations',
flags: ['--persona', '--config', '--template', '--workflow'],
category: 'workflow'
}
};
}
getDefaultPersonas() {
return {
architect: {
identity: 'Systems architect | Scalability specialist | Long-term thinker',
coreBeliefs: ['Systems evolve, design for change', 'Patterns over implementations'],
primaryQuestion: 'How will this scale and evolve?',
mcpPreferences: ['sequential', 'context7-patterns'],
thinkingMode: 'systematic'
},
frontend: {
identity: 'Frontend engineer | UX advocate | Performance optimizer',
coreBeliefs: ['User experience is paramount', 'Performance is a feature'],
primaryQuestion: 'How does this feel to use?',
mcpPreferences: ['filesystem', 'browser-tools'],
thinkingMode: 'user-centric'
},
backend: {
identity: 'Backend engineer | API designer | Data architect',
coreBeliefs: ['Data integrity above all', 'APIs are contracts'],
primaryQuestion: 'How does data flow through this system?',
mcpPreferences: ['postgres', 'redis'],
thinkingMode: 'data-driven'
},
security: {
identity: 'Security engineer | Threat modeler | Compliance specialist',
coreBeliefs: ['Trust nothing, verify everything', 'Security is a process'],
primaryQuestion: 'What are the attack vectors?',
mcpPreferences: ['security-scanner', 'vault'],
thinkingMode: 'threat-focused'
},
qa: {
identity: 'QA engineer | Test strategist | Quality gatekeeper',
coreBeliefs: ['Quality is everyone\'s responsibility', 'Automate everything'],
primaryQuestion: 'How can this break?',
mcpPreferences: ['playwright', 'jest-runner'],
thinkingMode: 'edge-case-hunter'
}
};
}
parseSimpleYAML(content) {
// Very basic YAML parsing - for production use a proper parser
const result = {};
const lines = content.split('\n');
let currentKey = null;
lines.forEach(line => {
if (line.match(/^[a-zA-Z]/)) {
currentKey = line.replace(':', '').trim();
result[currentKey] = {};
}
});
return result;
}
setupHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: this.getToolsList(),
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
return this.executeTool(name, args);
});
}
getToolsList() {
const tools = [];
// Add command tools
Object.entries(this.commands).forEach(([name, config]) => {
tools.push({
name: `sc_${name}`,
description: config.description,
inputSchema: {
type: 'object',
properties: {
args: {
type: 'string',
description: 'Command arguments and flags'
},
persona: {
type: 'string',
enum: Object.keys(this.personas),
description: 'Persona to use for this command'
},
evidence: {
type: 'object',
description: 'Evidence-based methodology data',
properties: {
rationale: { type: 'string' },
alternatives: { type: 'array', items: { type: 'string' } },
metrics: { type: 'object' }
}
},
flags: {
type: 'array',
items: {
type: 'string',
enum: config.flags
},
description: 'Command-specific flags'
}
},
required: ['args']
}
});
});
// Add utility tools
tools.push({
name: 'sc_persona',
description: 'Switch active SuperClaude persona',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
enum: Object.keys(this.personas),
description: 'Persona name to activate'
}
},
required: ['name']
}
});
tools.push({
name: 'sc_checkpoint',
description: 'Create or restore git checkpoint',
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['create', 'restore', 'list'],
description: 'Checkpoint action'
},
name: {
type: 'string',
description: 'Checkpoint name'
}
},
required: ['action']
}
});
tools.push({
name: 'sc_token_mode',
description: 'Set token optimization mode',
inputSchema: {
type: 'object',
properties: {
mode: {
type: 'string',
enum: ['normal', 'compressed', 'ultracompressed'],
description: 'Token optimization level'
}
},
required: ['mode']
}
});
return tools;
}
async executeTool(name, args) {
try {
// Handle persona switching
if (name === 'sc_persona') {
return this.switchPersona(args.name);
}
// Handle checkpoint operations
if (name === 'sc_checkpoint') {
return this.handleCheckpoint(args);
}
// Handle token mode
if (name === 'sc_token_mode') {
return this.setTokenMode(args.mode);
}
// Handle SuperClaude commands
if (name.startsWith('sc_')) {
const commandName = name.substring(3);
return this.executeCommand(commandName, args);
}
throw new Error(`Unknown tool: ${name}`);
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error executing ${name}: ${error.message}`
}
]
};
}
}
async switchPersona(personaName) {
if (!this.personas[personaName]) {
throw new Error(`Unknown persona: ${personaName}`);
}
this.activePersona = personaName;
const persona = this.personas[personaName];
return {
content: [
{
type: 'text',
text: `✨ Activated ${personaName} persona\n\n` +
`Identity: ${persona.identity}\n` +
`Core Belief: ${persona.coreBeliefs?.[0] || 'N/A'}\n` +
`Primary Focus: ${persona.primaryQuestion}\n` +
`Thinking Mode: ${persona.thinkingMode}`
}
]
};
}
async handleCheckpoint(args) {
const { action, name } = args;
switch (action) {
case 'create':
return this.createCheckpoint(name);
case 'restore':
return this.restoreCheckpoint(name);
case 'list':
return this.listCheckpoints();
default:
throw new Error(`Unknown checkpoint action: ${action}`);
}
}
async createCheckpoint(name) {
// Execute git stash with SuperClaude metadata
const timestamp = new Date().toISOString();
const checkpointName = name || `superclaude-${timestamp}`;
return {
content: [
{
type: 'text',
text: `📸 Created checkpoint: ${checkpointName}\n` +
`Timestamp: ${timestamp}\n` +
`Active Persona: ${this.activePersona || 'none'}\n` +
`Token Mode: ${this.tokenMode}`
}
]
};
}
async restoreCheckpoint(name) {
return {
content: [
{
type: 'text',
text: `🔄 Restored checkpoint: ${name}\n` +
`Note: Run 'git stash apply' to apply changes`
}
]
};
}
async listCheckpoints() {
// In real implementation, this would read from git stash list
return {
content: [
{
type: 'text',
text: `📋 Available checkpoints:\n` +
`- superclaude-2025-01-07T10:00:00Z\n` +
`- superclaude-feature-auth\n` +
`- superclaude-bugfix-api`
}
]
};
}
setTokenMode(mode) {
this.tokenMode = mode;
const modeDescriptions = {
normal: 'Standard token usage',
compressed: 'Moderate compression (~40% reduction)',
ultracompressed: 'Maximum compression (~70% reduction)'
};
return {
content: [
{
type: 'text',
text: `🗜️ Token mode set to: ${mode}\n` +
`${modeDescriptions[mode]}\n\n` +
`Compression rules active:\n` +
`- Short variable names (i, j, el)\n` +
`- Symbol replacements (→, &, @, w/)\n` +
`- Removed filler words\n` +
`- Compact formatting`
}
]
};
}
async executeCommand(commandName, args) {
const command = this.commands[commandName];
if (!command) {
throw new Error(`Unknown command: ${commandName}`);
}
// Build command context
const context = {
command: commandName,
args: args.args || '',
flags: args.flags || [],
persona: args.persona || this.activePersona,
evidence: args.evidence || {},
tokenMode: this.tokenMode
};
// Apply persona if specified
if (context.persona && this.personas[context.persona]) {
const persona = this.personas[context.persona];
context.personaConfig = persona;
}
// Generate command response
const response = await this.generateCommandResponse(context);
return {
content: [
{
type: 'text',
text: response
}
]
};
}
async generateCommandResponse(context) {
const { command, args, flags, persona, evidence, tokenMode } = context;
let response = `🚀 Executing SuperClaude '${command}' command\n\n`;
// Add persona context
if (persona) {
response += `👤 Persona: ${persona}\n`;
response += `🧠 Thinking Mode: ${context.personaConfig?.thinkingMode || 'default'}\n\n`;
}
// Add command details
response += `📋 Command: ${command}\n`;
response += `📝 Arguments: ${args}\n`;
if (flags.length > 0) {
response += `🚩 Flags: ${flags.join(', ')}\n`;
}
response += `🗜️ Token Mode: ${tokenMode}\n\n`;
// Add evidence if provided
if (evidence.rationale) {
response += `📊 Evidence-Based Approach:\n`;
response += `- Rationale: ${evidence.rationale}\n`;
if (evidence.alternatives) {
response += `- Alternatives: ${evidence.alternatives.join(', ')}\n`;
}
response += '\n';
}
// Command-specific responses
response += this.getCommandSpecificResponse(command, context);
return response;
}
getCommandSpecificResponse(command, context) {
const templates = {
build: `🏗️ Building project with configuration:
- Type: ${context.args}
- Flags: ${context.flags.join(', ')}
- Persona optimizations: ${context.persona ? 'Applied' : 'None'}
Next steps:
1. Initialize project structure
2. Set up dependencies
3. Configure build tools
4. Create initial components
5. Set up testing framework`,
analyze: `🔍 Analyzing codebase:
- Scope: ${context.args || 'Full project'}
- Analysis depth: ${context.flags.includes('--deep') ? 'Deep' : 'Standard'}
- Focus areas: Architecture, Performance, Security
Analysis includes:
• Code complexity metrics
• Dependency analysis
• Security vulnerabilities
• Performance bottlenecks
• Architecture patterns`,
troubleshoot: `🐛 Troubleshooting issue:
- Problem: ${context.args}
- Debug level: ${context.flags.includes('--verbose') ? 'Verbose' : 'Standard'}
Diagnostic approach:
1. Reproduce the issue
2. Analyze stack traces
3. Check recent changes
4. Identify root cause
5. Propose solutions`,
deploy: `🚀 Deployment process:
- Target: ${context.flags.includes('--production') ? 'Production' : 'Staging'}
- Validation: ${context.flags.includes('--validate') ? 'Enabled' : 'Disabled'}
Deployment checklist:
✓ Run tests
✓ Build artifacts
✓ Validate configuration
✓ Create backup
✓ Deploy changes
✓ Verify deployment`
};
return templates[command] || `Executing ${command} with args: ${context.args}`;
}
async start() {
await this.initialize();
const transport = new StdioServerTransport();
await this.server.connect(transport);
// MCP servers should not output to stderr during normal operation
// console.error('SuperClaude MCP Server started');
}
}
// Start the server
const server = new SuperClaudeMCPServer();
server.start().catch((error) => {
// Log to a file or handle silently
// MCP servers should not output to stderr
process.exit(1);
});