Code Explainer MCP
by BillDuke13
- src
/**
* Code Explainer MCP - A Cloudflare Worker that analyzes and explains code
*/
// Define the environment interface
interface Env {
SHARED_SECRET: string;
}
/**
* Analyzes and explains code with a comprehensive breakdown of structure and functionality.
*
* @param code {string} The source code to analyze
* @param programming_language {string} The programming language of the code
* @return {string} A detailed analysis of the code
*/
async function explainCode(code: string, programming_language: string): Promise<string> {
// Create a basic architecture diagram (ASCII)
const architectureDiagram = generateArchitectureDiagram(code, programming_language);
// Extract core functionality
const coreFunctionality = extractCoreFunctionality(code, programming_language);
// Extract main classes and functions
const { mainClasses, mainFunctions } = extractComponents(code, programming_language);
// Format the response according to the prompt template
const response = `
# Code Analysis for ${programming_language} Code
## Architecture Diagram
\`\`\`
${architectureDiagram}
\`\`\`
## Core Functionality
${coreFunctionality}
## Main Classes:
${mainClasses.map(c => `- ${c.name}: ${c.description}`).join('\n')}
## Main Functions:
${mainFunctions.map(f => `- ${f.name}: ${f.description}`).join('\n')}
Would you like me to explain all the functions and classes in detail? Or are you more interested in a specific part?
`;
return response;
}
/**
* Generates a comprehensive ASCII architecture diagram based on code analysis.
*
* @param code {string} The source code to analyze
* @param programming_language {string} The programming language of the code
* @return {string} An ASCII diagram representing the code architecture
*/
function generateArchitectureDiagram(code: string, programming_language: string): string {
// Detect language-specific patterns
let classRegex, functionRegex, methodRegex, importRegex;
switch(programming_language.toLowerCase()) {
case 'javascript':
case 'typescript':
case 'js':
case 'ts':
classRegex = /class\s+(\w+)(?:\s+extends\s+(\w+))?/g;
functionRegex = /function\s+(\w+)/g;
methodRegex = /(\w+)\s*\([^)]*\)\s*{/g;
importRegex = /import\s+(?:{[^}]*}|[^{;]*)(?:\s+from)?\s+['"]([^'"]+)['"]/g;
break;
case 'python':
classRegex = /class\s+(\w+)(?:\(([^)]+)\))?:/g;
functionRegex = /def\s+(\w+)/g;
methodRegex = /def\s+(\w+)\s*\(self,?[^)]*\):/g;
importRegex = /(?:from\s+(\w+(?:\.\w+)*)\s+import|import\s+(\w+(?:\.\w+)*))/g;
break;
case 'java':
case 'c#':
case 'csharp':
classRegex = /class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([^{]+))?/g;
functionRegex = /(?:public|private|protected|static)?\s+\w+\s+(\w+)\s*\([^)]*\)\s*{/g;
methodRegex = /(?:public|private|protected|static)?\s+\w+\s+(\w+)\s*\([^)]*\)\s*{/g;
importRegex = /import\s+([^;]+);/g;
break;
default:
// Generic patterns for other languages
classRegex = /class\s+(\w+)/g;
functionRegex = /function\s+(\w+)|def\s+(\w+)|(\w+)\s*\([^)]*\)\s*{/g;
methodRegex = /(\w+)\s*\([^)]*\)\s*{|def\s+(\w+)/g;
importRegex = /import|require|include|using/g;
}
// Extract components
let match;
// Reset regex lastIndex
classRegex.lastIndex = 0;
functionRegex.lastIndex = 0;
importRegex.lastIndex = 0;
// Extract classes with inheritance
interface ClassInfo {
name: string;
parent: string | null;
index: number;
}
const classes: ClassInfo[] = [];
while ((match = classRegex.exec(code)) !== null) {
classes.push({
name: match[1],
parent: match[2] || null,
index: match.index
});
}
// Extract functions
interface FunctionInfo {
name: string;
index: number;
}
const functions: FunctionInfo[] = [];
while ((match = functionRegex.exec(code)) !== null) {
// Skip if inside a class
let isInsideClass = false;
for (const cls of classes) {
const classCode = extractBlock(code, cls.index);
if (match.index > cls.index && match.index < cls.index + classCode.length) {
isInsideClass = true;
break;
}
}
if (!isInsideClass) {
functions.push({
name: match[1] || match[2] || match[3],
index: match.index
});
}
}
// Extract imports/dependencies
const imports: string[] = [];
while ((match = importRegex.exec(code)) !== null) {
imports.push(match[1] || match[2] || "external dependency");
}
// Analyze relationships between components
interface Relationship {
from: string;
to: string;
type: string;
}
const relationships: Relationship[] = [];
// Check for class inheritance
for (const cls of classes) {
if (cls.parent) {
relationships.push({
from: cls.name,
to: cls.parent,
type: 'inherits'
});
}
}
// Check for function calls
for (const func of functions) {
const functionCode = extractBlock(code, func.index);
// Check if this function calls other functions
for (const otherFunc of functions) {
if (func.name !== otherFunc.name &&
functionCode.includes(`${otherFunc.name}(`)) {
relationships.push({
from: func.name,
to: otherFunc.name,
type: 'calls'
});
}
}
}
// Generate the diagram
let diagram = '';
// Add header
diagram += '+----------------------+\n';
diagram += '| Code Structure |\n';
diagram += '+----------------------+\n';
// Add imports/dependencies if found
if (imports.length > 0) {
diagram += '\n Dependencies:\n';
for (let i = 0; i < Math.min(imports.length, 3); i++) {
diagram += ` [${imports[i]}]\n`;
}
if (imports.length > 3) {
diagram += ' [...more dependencies...]\n';
}
diagram += '\n |\n v\n';
}
// Add classes with inheritance
if (classes.length > 0) {
diagram += '\n Classes:\n';
// First add parent classes
const parentClasses = classes.filter(c => !c.parent);
for (const cls of parentClasses) {
diagram += ` +------------------+\n`;
diagram += ` | ${cls.name.padEnd(14)} |\n`;
diagram += ` +------------------+\n`;
// Add child classes
const childClasses = classes.filter(c => c.parent === cls.name);
if (childClasses.length > 0) {
for (let i = 0; i < childClasses.length; i++) {
const isLast = i === childClasses.length - 1;
diagram += ` ${isLast ? '└' : '├'}──extends──┐\n`;
diagram += ` +------------------+\n`;
diagram += ` | ${childClasses[i].name.padEnd(14)} |\n`;
diagram += ` +------------------+\n`;
}
}
diagram += '\n';
}
// Add standalone classes (no inheritance)
const standaloneClasses = classes.filter(c => !c.parent && !classes.some(other => other.parent === c.name));
if (standaloneClasses.length > 0) {
for (const cls of standaloneClasses) {
diagram += ` +------------------+\n`;
diagram += ` | ${cls.name.padEnd(14)} |\n`;
diagram += ` +------------------+\n`;
}
}
}
// Add functions and their relationships
if (functions.length > 0) {
diagram += '\n Functions:\n';
// Group functions by relationships
const processedFunctions = new Set();
// First process functions that call other functions
for (const rel of relationships.filter(r => r.type === 'calls')) {
if (!processedFunctions.has(rel.from)) {
diagram += ` [${rel.from}] ──calls──> [${rel.to}]\n`;
processedFunctions.add(rel.from);
processedFunctions.add(rel.to);
}
}
// Then add remaining functions
for (const func of functions) {
if (!processedFunctions.has(func.name)) {
diagram += ` [${func.name}]\n`;
processedFunctions.add(func.name);
}
}
}
// If no classes or functions found, show generic structure
if (classes.length === 0 && functions.length === 0) {
diagram += '\n +------------------+\n';
diagram += ' | Implementation |\n';
diagram += ' +------------------+\n';
}
return diagram;
}
/**
* Extracts and summarizes the core functionality of the code.
*
* @param code {string} The source code to analyze
* @param programming_language {string} The programming language of the code
* @return {string} A description of the core functionality
*/
function extractCoreFunctionality(code: string, programming_language: string): string {
// Define language-specific patterns
const patterns: Record<string, RegExp[]> = {
network: [
/fetch\s*\(/i,
/http/i,
/request/i,
/api/i,
/url/i,
/endpoint/i
],
ui: [
/render/i,
/component/i,
/view/i,
/display/i,
/ui/i,
/interface/i,
/dom/i
],
dataProcessing: [
/map\s*\(/i,
/filter\s*\(/i,
/reduce\s*\(/i,
/transform/i,
/convert/i,
/parse/i
],
authentication: [
/auth/i,
/login/i,
/password/i,
/credential/i,
/token/i,
/permission/i
],
database: [
/database/i,
/db\./i,
/query/i,
/sql/i,
/mongo/i,
/store/i,
/save/i,
/repository/i
],
testing: [
/test/i,
/assert/i,
/expect/i,
/mock/i,
/spec/i
],
algorithm: [
/algorithm/i,
/sort/i,
/search/i,
/calculate/i,
/compute/i
],
fileSystem: [
/file/i,
/read/i,
/write/i,
/path/i,
/directory/i,
/folder/i
]
};
// Add language-specific patterns
switch(programming_language.toLowerCase()) {
case 'javascript':
case 'typescript':
case 'js':
case 'ts':
patterns.ui.push(/react/i, /angular/i, /vue/i, /component/i, /jsx/i, /tsx/i);
patterns.network.push(/axios/i, /fetch/i, /xhr/i);
patterns.database.push(/mongoose/i, /sequelize/i, /typeorm/i);
break;
case 'python':
patterns.ui.push(/flask/i, /django/i, /template/i);
patterns.network.push(/requests/i, /urllib/i);
patterns.database.push(/sqlalchemy/i, /django\.db/i, /cursor/i);
break;
case 'java':
patterns.ui.push(/swing/i, /javafx/i, /awt/i);
patterns.network.push(/httpclient/i, /urlconnection/i);
patterns.database.push(/jdbc/i, /repository/i, /entity/i);
break;
case 'c#':
case 'csharp':
patterns.ui.push(/wpf/i, /xaml/i, /winforms/i);
patterns.network.push(/httpclient/i, /webclient/i);
patterns.database.push(/entity\s*framework/i, /dbcontext/i);
break;
}
// Check for patterns in the code
const matches: Record<string, boolean> = {
network: false,
ui: false,
dataProcessing: false,
authentication: false,
database: false,
testing: false,
algorithm: false,
fileSystem: false
};
// Count matches for each category
const matchCounts: Record<string, number> = {};
for (const category in patterns) {
matchCounts[category] = 0;
for (const pattern of patterns[category]) {
if (pattern.test(code)) {
matchCounts[category]++;
matches[category] = true;
}
}
}
// Determine primary and secondary purposes based on match counts
const sortedCategories = Object.entries(matchCounts)
.sort((a, b) => b[1] - a[1])
.filter(entry => entry[1] > 0)
.map(entry => entry[0]);
const primaryPurpose = sortedCategories[0];
const secondaryPurpose = sortedCategories[1];
// Generate description
let functionality = 'This code appears to ';
if (!primaryPurpose) {
functionality += 'provide general utility functions or core logic for the application.';
return functionality;
}
// Primary purpose description
switch(primaryPurpose) {
case 'ui':
functionality += 'implement a user interface ';
if (matches.network) {
functionality += 'that communicates with external services. ';
} else if (matches.database) {
functionality += 'that interacts with a database. ';
} else {
functionality += 'for displaying and interacting with data. ';
}
break;
case 'network':
functionality += 'handle network communication, ';
if (matches.api) {
functionality += 'likely serving as an API or service layer. ';
} else {
functionality += 'facilitating data exchange with external systems. ';
}
break;
case 'dataProcessing':
functionality += 'process and transform data, ';
if (matches.algorithm) {
functionality += 'implementing specific algorithms for data manipulation. ';
} else {
functionality += 'implementing business logic or data transformation. ';
}
break;
case 'database':
functionality += 'interact with a database, ';
if (matches.dataProcessing) {
functionality += 'performing data operations and transformations. ';
} else {
functionality += 'managing data persistence and retrieval. ';
}
break;
case 'authentication':
functionality += 'handle authentication and authorization, ';
if (matches.ui) {
functionality += 'providing secure user access to the interface. ';
} else if (matches.network) {
functionality += 'securing API endpoints or network resources. ';
} else {
functionality += 'managing user credentials and permissions. ';
}
break;
case 'testing':
functionality += 'implement tests for ';
if (matches.ui) {
functionality += 'user interface components. ';
} else if (matches.network) {
functionality += 'network communication. ';
} else if (matches.database) {
functionality += 'database operations. ';
} else {
functionality += 'application functionality. ';
}
break;
case 'algorithm':
functionality += 'implement specific algorithms ';
if (matches.dataProcessing) {
functionality += 'for data processing and transformation. ';
} else {
functionality += 'to solve computational problems. ';
}
break;
case 'fileSystem':
functionality += 'handle file system operations, ';
if (matches.dataProcessing) {
functionality += 'processing file data. ';
} else {
functionality += 'managing file reading, writing, or organization. ';
}
break;
default:
functionality += 'provide utility functions or core logic for the application. ';
}
// Add secondary purpose if available
if (secondaryPurpose && matchCounts[secondaryPurpose] > 1) {
functionality += 'It also includes functionality for ';
switch(secondaryPurpose) {
case 'ui':
functionality += 'user interface presentation';
break;
case 'network':
functionality += 'network communication';
break;
case 'dataProcessing':
functionality += 'data processing and transformation';
break;
case 'database':
functionality += 'database interaction';
break;
case 'authentication':
functionality += 'authentication and security';
break;
case 'testing':
functionality += 'testing and validation';
break;
case 'algorithm':
functionality += 'algorithmic computation';
break;
case 'fileSystem':
functionality += 'file system operations';
break;
}
functionality += '.';
}
return functionality;
}
/**
* Extracts main classes and functions from the code.
*
* @param code {string} The source code to analyze
* @param programming_language {string} The programming language of the code
* @return {Object} Object containing arrays of main classes and functions with descriptions
*/
function extractComponents(code: string, programming_language: string): {
mainClasses: Array<{name: string, description: string}>,
mainFunctions: Array<{name: string, description: string}>
} {
const mainClasses: Array<{name: string, description: string}> = [];
const mainFunctions: Array<{name: string, description: string}> = [];
// Simple regex to find class names
const classRegex = /class\s+(\w+)/g;
let classMatch;
while ((classMatch = classRegex.exec(code)) !== null) {
const className = classMatch[1];
const classCode = extractBlock(code, classMatch.index);
const description = generateComponentDescription(classCode, 'class');
mainClasses.push({ name: className, description });
}
// Simple regex to find function names
const functionRegex = /function\s+(\w+)/g;
let functionMatch;
while ((functionMatch = functionRegex.exec(code)) !== null) {
const functionName = functionMatch[1];
const functionCode = extractBlock(code, functionMatch.index);
const description = generateComponentDescription(functionCode, 'function');
mainFunctions.push({ name: functionName, description });
}
// For languages like JavaScript, also look for arrow functions assigned to variables
const arrowFunctionRegex = /const\s+(\w+)\s*=\s*(\([^)]*\)|[^=]*)\s*=>/g;
let arrowMatch;
while ((arrowMatch = arrowFunctionRegex.exec(code)) !== null) {
const functionName = arrowMatch[1];
const functionCode = extractBlock(code, arrowMatch.index);
const description = generateComponentDescription(functionCode, 'function');
mainFunctions.push({ name: functionName, description });
}
return { mainClasses, mainFunctions };
}
/**
* Extracts a code block starting from a given position.
*
* @param code {string} The full source code
* @param startIndex {number} The starting index of the block
* @return {string} The extracted code block
*/
function extractBlock(code: string, startIndex: number): string {
// Find the opening brace after the start index
const openingBraceIndex = code.indexOf('{', startIndex);
if (openingBraceIndex === -1) return '';
// Count braces to find the matching closing brace
let braceCount = 1;
let currentIndex = openingBraceIndex + 1;
while (braceCount > 0 && currentIndex < code.length) {
if (code[currentIndex] === '{') {
braceCount++;
} else if (code[currentIndex] === '}') {
braceCount--;
}
currentIndex++;
}
return code.substring(startIndex, currentIndex);
}
/**
* Generates a detailed description for a code component based on its content.
*
* @param componentCode {string} The code of the component
* @param type {string} The type of component ('class' or 'function')
* @return {string} A description of the component's purpose
*/
function generateComponentDescription(componentCode: string, type: string): string {
// First, look for JSDoc or other documentation comments
let commentRegex: RegExp | null = null;
// Different comment styles for different languages
if (componentCode.includes('"""') || componentCode.includes("'''")) {
// Python docstring
commentRegex = /(?:'''|""")([^]*?)(?:'''|""")/;
} else if (componentCode.includes('/**')) {
// JSDoc style comment
commentRegex = /\/\*\*([^]*?)\*\//;
} else if (componentCode.includes('//')) {
// Single line comments (try to find consecutive ones)
const lines = componentCode.split('\n');
const commentLines: string[] = [];
let inCommentBlock = false;
for (const line of lines) {
const trimmedLine = line.trim();
if (trimmedLine.startsWith('//')) {
commentLines.push(trimmedLine.substring(2).trim());
inCommentBlock = true;
} else if (inCommentBlock && trimmedLine.length === 0) {
// Allow empty lines in comment blocks
continue;
} else {
inCommentBlock = false;
if (commentLines.length > 0) {
break;
}
}
}
if (commentLines.length > 0) {
return commentLines.join(' ');
}
}
// Try to extract comment if regex was set
if (commentRegex) {
const commentMatch = componentCode.match(commentRegex);
if (commentMatch) {
// Clean up the comment
const comment = commentMatch[1]
.replace(/\s*\*\s*/g, ' ') // Remove asterisks from JSDoc
.replace(/\s+/g, ' ') // Normalize whitespace
.replace(/@\w+\s+[^\n]+/g, '') // Remove JSDoc tags
.trim();
if (comment.length > 0) {
return comment;
}
}
}
// If no comment is found, analyze the code to generate a description
// Extract the component name
let componentName = '';
if (type === 'class') {
const classNameMatch = componentCode.match(/class\s+(\w+)/);
if (classNameMatch) {
componentName = classNameMatch[1];
}
} else {
const functionNameMatch = componentCode.match(/function\s+(\w+)|def\s+(\w+)/);
if (functionNameMatch) {
componentName = functionNameMatch[1] || functionNameMatch[2];
}
}
// Convert camelCase or PascalCase to words
if (componentName) {
componentName = componentName
.replace(/([A-Z])/g, ' $1') // Add space before capital letters
.replace(/^./, str => str.toUpperCase()) // Capitalize first letter
.trim();
}
// Analyze code patterns
const patterns: Record<string, RegExp[]> = {
ui: [/render/i, /component/i, /view/i, /display/i, /dom/i, /element/i, /ui/i],
data: [/data/i, /state/i, /store/i, /model/i, /entity/i, /repository/i],
network: [/fetch/i, /http/i, /request/i, /api/i, /url/i, /endpoint/i],
utility: [/util/i, /helper/i, /format/i, /convert/i, /transform/i],
event: [/event/i, /listener/i, /handler/i, /callback/i, /click/i, /change/i],
auth: [/auth/i, /login/i, /permission/i, /role/i, /access/i, /token/i],
file: [/file/i, /read/i, /write/i, /save/i, /load/i, /path/i],
math: [/calc/i, /compute/i, /sum/i, /average/i, /math/i, /formula/i]
};
// Count matches for each category
const matchCounts: Record<string, number> = {};
for (const category in patterns) {
matchCounts[category] = 0;
for (const pattern of patterns[category]) {
if (pattern.test(componentCode)) {
matchCounts[category]++;
}
}
}
// Find the primary purpose based on the most matches
const primaryPurpose = Object.entries(matchCounts)
.sort((a, b) => b[1] - a[1])
.filter(entry => entry[1] > 0)[0]?.[0];
// Generate description based on component type and primary purpose
if (type === 'class') {
switch (primaryPurpose) {
case 'ui':
return `${componentName ? componentName + ' - ' : ''}A UI component that handles rendering and user interaction`;
case 'data':
return `${componentName ? componentName + ' - ' : ''}Manages data and state for the application`;
case 'network':
return `${componentName ? componentName + ' - ' : ''}Provides services or API interactions`;
case 'auth':
return `${componentName ? componentName + ' - ' : ''}Handles authentication and authorization`;
case 'file':
return `${componentName ? componentName + ' - ' : ''}Manages file operations and storage`;
default:
// Check if it's a base/parent class
if (componentCode.includes('extends') || componentCode.includes('implements')) {
return `${componentName ? componentName + ' - ' : ''}A base class that defines core functionality`;
}
return `${componentName ? componentName + ' - ' : ''}Encapsulates related functionality and data`;
}
} else { // function
// Check for parameters and return values
const hasParameters = /\([^)]+\)/.test(componentCode);
const hasReturn = /return/.test(componentCode);
switch (primaryPurpose) {
case 'ui':
return `${componentName ? componentName + ' - ' : ''}${hasReturn ? 'Generates' : 'Renders'} UI elements${hasParameters ? ' based on input parameters' : ''}`;
case 'data':
return `${componentName ? componentName + ' - ' : ''}${hasReturn ? 'Processes and transforms' : 'Manages'} data${hasParameters ? ' from input parameters' : ''}`;
case 'network':
return `${componentName ? componentName + ' - ' : ''}Handles network communication${hasParameters ? ' with specified endpoints' : ''}`;
case 'utility':
return `${componentName ? componentName + ' - ' : ''}Utility function that ${hasReturn ? 'processes input and returns a result' : 'performs operations'}`;
case 'event':
return `${componentName ? componentName + ' - ' : ''}Event handler that responds to user interactions`;
case 'auth':
return `${componentName ? componentName + ' - ' : ''}Manages authentication or authorization processes`;
case 'file':
return `${componentName ? componentName + ' - ' : ''}Handles file system operations`;
case 'math':
return `${componentName ? componentName + ' - ' : ''}Performs mathematical calculations${hasParameters ? ' on input values' : ''}`;
default:
if (hasReturn && hasParameters) {
return `${componentName ? componentName + ' - ' : ''}Processes input parameters and returns a result`;
} else if (hasReturn) {
return `${componentName ? componentName + ' - ' : ''}Computes and returns a value`;
} else if (hasParameters) {
return `${componentName ? componentName + ' - ' : ''}Performs operations based on input parameters`;
} else {
return `${componentName ? componentName + ' - ' : ''}Performs a specific operation or task`;
}
}
}
}
// Main worker handler
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Check if this is a POST request
if (request.method === 'POST') {
// Check for authentication
const authHeader = request.headers.get('Authorization');
const expectedAuth = `Bearer ${env.SHARED_SECRET}`;
if (!authHeader || authHeader !== expectedAuth) {
return new Response('Unauthorized', { status: 401 });
}
// Parse the request body
try {
const body = await request.json() as {
method: string;
params: string[];
};
// Check if this is an MCP request
if (body.method === 'explainCode' && Array.isArray(body.params) && body.params.length >= 2) {
const code = body.params[0];
const language = body.params[1];
// Call the explainCode function
const result = await explainCode(code, language);
// Return the result
return new Response(JSON.stringify({ result }), {
headers: { 'Content-Type': 'application/json' }
});
} else {
return new Response('Invalid method or parameters', { status: 400 });
}
} catch (error: any) {
const errorMessage = error?.message || 'Unknown error';
return new Response(`Error processing request: ${errorMessage}`, { status: 500 });
}
}
// Return a simple HTML page for GET requests
return new Response(`
<!DOCTYPE html>
<html>
<head>
<title>Code Explainer MCP</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
h1 { color: #333; }
pre { background: #f5f5f5; padding: 10px; border-radius: 5px; }
</style>
</head>
<body>
<h1>Code Explainer MCP</h1>
<p>This is a Cloudflare Worker that analyzes and explains code.</p>
<p>To use it, send a POST request with the following JSON body:</p>
<pre>
{
"method": "explainCode",
"params": ["your code here", "programming language"]
}
</pre>
<p>Make sure to include the Authorization header with your shared secret.</p>
</body>
</html>
`, {
headers: { 'Content-Type': 'text/html' }
});
}
};