Skip to main content
Glama

socio-technical-analysis

Analyze repository collaboration patterns, contributor dynamics, and team interactions over time. Generate insights in JSON, Mermaid, or DOT formats to optimize development workflows.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
includeContributorPatternsNo
includeTeamDynamicsNo
repositoryUrlYes
timeRangeNo
visualizationFormatNojson

Implementation Reference

  • Core handler function implementing the socio-technical analysis logic: repository cloning, contributor analysis, code ownership, team dynamics, knowledge graph integration, visualization generation, and insights.
    export async function analyzeSocioTechnicalPatterns( repositoryUrl: string, includeContributorPatterns: boolean = true, includeTeamDynamics: boolean = true, timeRange?: { start?: string, end?: string }, visualizationFormat: "json" | "mermaid" | "dot" = "json" ): Promise<any> { console.log(`Analyzing socio-technical patterns for ${repositoryUrl}`); // Step 1: Clone/update the repository const repoPath = await getRepository(repositoryUrl); // Step 2: Analyze git history and contributors const contributorData = await analyzeContributors(repoPath, timeRange); // Step 3: Analyze code ownership and ownership patterns const ownershipData = includeContributorPatterns ? await analyzeCodeOwnership(repoPath, contributorData) : null; // Step 4: Analyze team dynamics and collaboration patterns const teamDynamicsData = includeTeamDynamics ? await analyzeTeamDynamics(repoPath, contributorData) : null; // Step 5: Build knowledge graph for technical dependencies console.log(`Building knowledge graph for technical dependencies...`); await buildKnowledgeGraph(repositoryUrl, 2, false); // Step 5b: Query knowledge graph to get actual nodes and relationships const graphData = await queryKnowledgeGraph({ query: "", repositoryUrl, contextDepth: 2 }); // Step 6: Create socio-technical graph const socioTechnicalGraph = combineDataIntoGraph( contributorData, ownershipData, teamDynamicsData, graphData.nodes, graphData.relationships ); // Step 7: Generate visualization let visualization = ""; if (visualizationFormat === "mermaid") { visualization = generateMermaidDiagram(socioTechnicalGraph); } else if (visualizationFormat === "dot") { visualization = generateDotGraph(socioTechnicalGraph); } // Step 8: Generate insights const insights = generateInsights( contributorData, ownershipData, teamDynamicsData, graphData.nodes, graphData.relationships ); // Return the analysis results return { repository: { url: repositoryUrl, path: repoPath }, analysis: { contributors: summarizeContributors(contributorData), codeOwnership: ownershipData ? summarizeOwnership(ownershipData) : null, teamDynamics: teamDynamicsData ? summarizeTeamDynamics(teamDynamicsData) : null, insights }, visualization, visualizationFormat }; }
  • MCP tool registration for 'socio-technical-analysis', including input schema validation and response formatting handler that calls the core analyzer.
    server.tool( "socio-technical-analysis", { repositoryUrl: z.string(), includeContributorPatterns: z.boolean().default(true), includeTeamDynamics: z.boolean().default(true), timeRange: z.object({ start: z.string().optional(), end: z.string().optional() }).optional(), visualizationFormat: z.enum(["json", "mermaid", "dot"]).default("json") }, async ({ repositoryUrl, includeContributorPatterns, includeTeamDynamics, timeRange, visualizationFormat }) => { try { const results = await analyzeSocioTechnicalPatterns( repositoryUrl, includeContributorPatterns, includeTeamDynamics, timeRange, visualizationFormat ); // Return appropriate content type based on visualization format if (visualizationFormat === "mermaid") { return { content: [{ type: "text", text: results.visualization, _metadata: { format: "mermaid" } }, { type: "text", text: JSON.stringify(results.analysis, null, 2) }] }; } else if (visualizationFormat === "dot") { return { content: [{ type: "text", text: results.visualization, _metadata: { format: "dot" } }, { type: "text", text: JSON.stringify(results.analysis, null, 2) }] }; } else { return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; } } catch (error) { return { content: [{ type: "text", text: `Error in socio-technical analysis: ${(error as Error).message}` }], isError: true }; } } );
  • Zod input schema defining parameters for the socio-technical-analysis tool: repository URL, analysis options, time range, and visualization format.
    { repositoryUrl: z.string(), includeContributorPatterns: z.boolean().default(true), includeTeamDynamics: z.boolean().default(true), timeRange: z.object({ start: z.string().optional(), end: z.string().optional() }).optional(), visualizationFormat: z.enum(["json", "mermaid", "dot"]).default("json") },
  • Helper function to analyze git contributors, commit history, and file changes per contributor.
    async function analyzeContributors( repoPath: string, timeRange?: { start?: string, end?: string } ): Promise<any> { console.log(`Analyzing contributors in ${repoPath}`); try { // Build the git log command with appropriate filters let gitLogCommand = 'git log --pretty=format:"%an|%ae|%ad|%H" --date=iso'; if (timeRange?.start) { gitLogCommand += ` --since="${timeRange.start}"`; } if (timeRange?.end) { gitLogCommand += ` --until="${timeRange.end}"`; } // Execute the git log command const gitLogOutput = execSync(gitLogCommand, { cwd: repoPath }).toString(); const commits = gitLogOutput.split('\n').filter(line => line.trim() !== ''); // Process the commits to get contributor information const contributorMap: Record<string, any> = {}; for (const commit of commits) { const [name, email, dateStr, hash] = commit.split('|'); if (!contributorMap[email]) { contributorMap[email] = { name, email, firstCommit: dateStr, lastCommit: dateStr, commitCount: 0, commits: [] }; } const contributor = contributorMap[email]; contributor.commitCount++; contributor.lastCommit = dateStr; contributor.commits.push({ hash, date: dateStr }); } // Get file changes per contributor for (const email of Object.keys(contributorMap)) { const contributor = contributorMap[email]; contributor.fileChangeCount = 0; contributor.fileChanges = {}; // Get last 100 commits for this contributor to analyze file changes // This is a simplification to avoid performance issues const sampleCommits = contributor.commits.slice(0, 100); for (const commit of sampleCommits) { try { // Get files changed in this commit const diffCommand = `git show --name-only --pretty="" ${commit.hash}`; const changedFiles = execSync(diffCommand, { cwd: repoPath }).toString().split('\n').filter(Boolean); for (const file of changedFiles) { if (!contributor.fileChanges[file]) { contributor.fileChanges[file] = 0; } contributor.fileChanges[file]++; contributor.fileChangeCount++; } } catch (error) { console.warn(`Error analyzing commit ${commit.hash}: ${(error as Error).message}`); } } } // Convert to array and sort by commit count const contributors = Object.values(contributorMap).sort((a: any, b: any) => b.commitCount - a.commitCount); return { totalContributors: contributors.length, totalCommits: commits.length, contributors }; } catch (error) { console.error(`Error analyzing contributors: ${(error as Error).message}`); return { totalContributors: 0, totalCommits: 0, contributors: [], error: (error as Error).message }; } }
  • Helper function to analyze team dynamics including team detection, collaboration graphs, and work patterns.
    async function analyzeTeamDynamics(repoPath: string, contributorData: any): Promise<any> { console.log(`Analyzing team dynamics in ${repoPath}`); try { // Step 1: Detect teams based on collaboration patterns const teams = detectTeams(contributorData); // Step 2: Analyze collaboration between contributors const collaborationGraph = analyzeCollaboration(repoPath, contributorData); // Step 3: Analyze work patterns const workPatterns = analyzeWorkPatterns(contributorData); return { teams, collaborationGraph, workPatterns }; } catch (error) { console.error(`Error analyzing team dynamics: ${(error as Error).message}`); return { error: (error as Error).message }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xjcf/MCP_CodeAnalysis'

If you have feedback or need assistance with the MCP directory API, please join our Discord server