Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions src/main/kotlin/mcp/code/analysis/config/AppConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,6 @@ data class AppConfig(
) {
companion object {

/**
* Creates an instance of [AppConfig] by retrieving values from environment variables. If an environment variable is
* not set, a default value is used.
*
* @return An instance of [AppConfig] with the retrieved or default values.
*/
fun fromEnv(): AppConfig =
AppConfig(
serverPort = System.getenv("SERVER_PORT")?.toIntOrNull() ?: 3001,
githubToken = System.getenv("GITHUB_TOKEN") ?: "",
cloneDirectory = System.getenv("CLONE_DIRECTORY") ?: "/tmp/mcp-github-code-analyzer/clones",
logDirectory = System.getenv("LOGS_DIRECTORY") ?: "/tmp/mcp-github-code-analyzer/logs",
modelApiUrl = System.getenv("MODEL_API_URL") ?: "http://localhost:11434/api",
modelApiKey = System.getenv("MODEL_API_KEY") ?: "",
modelName = System.getenv("MODEL_NAME") ?: "llama3.2",
)

/**
* Creates an instance of [AppConfig] by retrieving values from environment variables. If an environment variable is
* not set, a default value is used.
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/mcp/code/analysis/server/Server.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory
* Server for analyzing GitHub repositories using the Model Context Protocol (MCP). Provides functionalities for
* analyzing GitHub repositories and checking analysis status.
*/
data class Server(
open class Server(
private val repositoryAnalysisService: RepositoryAnalysisService = RepositoryAnalysisService(),
private val logger: Logger = LoggerFactory.getLogger(Server::class.java),
private val implementation: Implementation =
Expand Down Expand Up @@ -66,7 +66,7 @@ data class Server(
*
* @param port The port number on which the SSE MCP server will listen for client connections.
*/
fun runSseMcpServerWithPlainConfiguration(port: Int): Unit = runBlocking {
open fun runSseMcpServerWithPlainConfiguration(port: Int): Unit = runBlocking {
val servers = ConcurrentMap<String, SdkServer>()
logger.info("Starting SSE server on port $port.")
logger.info("Use inspector to connect to the http://localhost:$port/sse")
Expand Down Expand Up @@ -111,7 +111,7 @@ data class Server(
*
* @param port The port number on which the SSE MCP server will listen for client connections.
*/
fun runSseMcpServerUsingKtorPlugin(port: Int): Unit = runBlocking {
open fun runSseMcpServerUsingKtorPlugin(port: Int): Unit = runBlocking {
logger.info("Starting SSE server on port $port")
logger.info("Use inspector to connect to http://localhost:$port/sse")

Expand All @@ -123,7 +123,7 @@ data class Server(
*
* @return The configured MCP server instance.
*/
private fun configureServer(): SdkServer {
open fun configureServer(): SdkServer {
val server = SdkServer(implementation, serverOptions)

server.addTool(
Expand Down
18 changes: 9 additions & 9 deletions src/main/kotlin/mcp/code/analysis/service/CodeAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ data class CodeAnalyzer(
val relativePath = file.absolutePath.substring(repoDir.absolutePath.length + 1)
val lang = getLanguageFromExtension(file.extension)
val content = file.readLines().joinToString("\n")
"""---
|File: $relativePath
|~~~$lang
|$content
|~~~"""
.trimIndent()
"""|---
|File: $relativePath
|~~~$lang
|$content
|~~~"""
.trimMargin()
}
.toList()
.also { snippets ->
logger.info("Collected ${snippets.size} code snippets from ${repoDir.absolutePath}")
logger.debug(
"""Snippets Found:
|${snippets.joinToString("\n")}"""
.trimIndent()
"""|Snippets Found:
|${snippets.joinToString("\n")}"""
.trimMargin()
)
}

Expand Down
110 changes: 52 additions & 58 deletions src/main/kotlin/mcp/code/analysis/service/ModelContextService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ data class ModelContextService(
suspend fun generateResponse(prompt: String): String {
return try {
logger.info(
"""Sending request to Ollama with prompt:
|${prompt}..."""
.trimIndent()
"""|Sending request to Ollama with prompt:
|${prompt}..."""
.trimMargin()
)
val request = OllamaRequest(model = config.modelName, prompt = prompt)
val ollamaApiUrl = "${config.modelApiUrl}/generate"
Expand All @@ -61,9 +61,9 @@ data class ModelContextService(
} else {
val response = httpResponse.body<OllamaResponse>()
logger.info(
"""Received response from Ollama:
|${response.response}"""
.trimIndent()
"""|Received response from Ollama:
|${response.response}"""
.trimMargin()
)
response.response ?: "No response generated"
}
Expand All @@ -80,66 +80,60 @@ data class ModelContextService(
* @return A structured prompt for the model
*/
fun buildInsightsPrompt(readme: String) =
"""
|You are an expert codebase analyst with deep expertise in software architecture, secure and scalable system design, and programming languages including Java, Kotlin, Python, Go, Scala, JavaScript, TypeScript, C++, Rust, Ruby, and others.
|
|You will be provided with the README file of a repository. Based on the README **alone**, provide a comprehensive analysis covering the following aspects:
|
|1. **Overall architecture** — inferred from descriptions, diagrams, setup steps, or configuration details.
|2. **Primary programming languages** — identify the main languages used and describe how they interact if applicable.
|3. **Key components and dependencies** — identify modules, services, tools, or third-party integrations and their relationships.
|4. **Design patterns** — mention any explicitly referenced or implicitly suggested architectural or code patterns.
|5. **Code quality signals** — identify any potential issues or areas of improvement (e.g., based on structure, naming, tooling).
|6. **Security considerations** — highlight any security best practices followed or missing (e.g., credential handling, auth mechanisms).
|7. **Performance considerations** — discuss caching, concurrency, resource management, or deployment implications.
|8. **Language-specific practices** — note idiomatic usage or violations of best practices for the identified languages.
|
|If any of the above are not explicitly described, provide clearly labeled **inferences** based on available information.
|
|Format your response in markdown using clear sections. Include direct references to specific README content where relevant. If multiple languages are involved, explain any cross-language integration points.
|
|README Content:
|~~~markdown
|${readme.replace("```","~~~")}
|~~~"""
.trimIndent()
"""|You are an expert codebase analyst with deep expertise in software architecture, secure and scalable system design, and programming languages including Java, Kotlin, Python, Go, Scala, JavaScript, TypeScript, C++, Rust, Ruby, and others.
|
|You will be provided with the README file of a repository. Based on the README **alone**, provide a comprehensive analysis covering the following aspects:
|
|1. **Overall architecture** — inferred from descriptions, diagrams, setup steps, or configuration details.
|2. **Primary programming languages** — identify the main languages used and describe how they interact if applicable.
|3. **Key components and dependencies** — identify modules, services, tools, or third-party integrations and their relationships.
|4. **Design patterns** — mention any explicitly referenced or implicitly suggested architectural or code patterns.
|5. **Code quality signals** — identify any potential issues or areas of improvement (e.g., based on structure, naming, tooling).
|6. **Security considerations** — highlight any security best practices followed or missing (e.g., credential handling, auth mechanisms).
|7. **Performance considerations** — discuss caching, concurrency, resource management, or deployment implications.
|8. **Language-specific practices** — note idiomatic usage or violations of best practices for the identified languages.
|
|If any of the above are not explicitly described, provide clearly labeled **inferences** based on available information.
|
|Format your response in markdown using clear sections. Include direct references to specific README content where relevant. If multiple languages are involved, explain any cross-language integration points.
|
|README Content:
|~~~markdown
|${readme.replace("```","~~~")}
|~~~"""
.trimMargin()

/**
* Build a summary prompt for the model context based on the provided code structure and snippets.
*
* @param codeStructure Map representing the structure of the codebase
* @param codeSnippets List of code snippets from the repository
* @param insights List of insights generated from the README analysis
* @return A structured prompt for the model
*/
fun buildSummaryPrompt(codeStructure: Map<String, Any>, codeSnippets: List<String>, insights: String): String =
"""
|You are analyzing a software code repository. You are provided with the following information:
|
|**Code Structure:**
|${codeStructure.entries.joinToString("\n") { "${it.key}: ${it.value}" }}
|
|**Code Snippets:**
|${codeSnippets.joinToString("\n\n")}
|
|**Key Insights:**
|$insights
|
|Using this information, write a comprehensive and accessible summary of the codebase. Your goal is to help a technically proficient developer who is new to the project quickly understand its structure and purpose.
|
|Your summary must cover the following aspects:
|
|1. **Main purpose** of the project
|2. **Core architecture and components**
|3. **Technologies and programming languages** used
|4. **Key functionality and workflows**
|5. **Potential areas for improvement or refactoring**
|
|Where helpful, include **brief illustrative code snippets** from the examples provided to clarify key concepts, architectural decisions, or coding patterns.
|
|Format your response using markdown with clear section headings and concise, informative language. Avoid speculation beyond the provided inputs unless clearly stated as inference.
|"""
.trimIndent()
fun buildSummaryPrompt(codeStructure: Map<String, Any>, codeSnippets: List<String>): String =
"""|You are analyzing a software code repository. You are provided with the following information:
|
|**Code Structure:**
|${codeStructure.entries.joinToString("\n") { "${it.key}: ${it.value}" }}
|
|**Code Snippets:**
|${codeSnippets.joinToString("\n\n")}
|
|Using this information, write a comprehensive and accessible summary of the codebase. Your goal is to help a technically proficient developer who is new to the project quickly understand its structure and purpose.
|
|Your summary must cover the following aspects:
|
|1. **Main purpose** of the project
|2. **Core architecture and components**
|3. **Technologies and programming languages** used
|4. **Key functionality and workflows**
|5. **Potential areas for improvement or refactoring**
|
|Where helpful, include **brief illustrative code snippets** from the examples provided to clarify key concepts, architectural decisions, or coding patterns.
|
|Format your response using markdown with clear section headings and concise, informative language. Avoid speculation beyond the provided inputs unless clearly stated as inference.
|"""
.trimMargin()

private suspend fun sendRequest(url: String, request: OllamaRequest): HttpResponse {
return httpClient.post(url) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package mcp.code.analysis.service

import kotlinx.coroutines.*

/** Service for analyzing Git repositories. */
data class RepositoryAnalysisService(
private val gitService: GitService = GitService(),
Expand All @@ -13,7 +15,7 @@ data class RepositoryAnalysisService(
* @param branch The branch of the repository to analyze.
* @return A summary of the analysis results.
*/
suspend fun analyzeRepository(repoUrl: String, branch: String): String {
fun analyzeRepository(repoUrl: String, branch: String): String {
return try {
val repoDir = gitService.cloneRepository(repoUrl, branch)

Expand All @@ -22,10 +24,17 @@ data class RepositoryAnalysisService(
val codeSnippets = codeAnalyzer.collectAllCodeSnippets(repoDir)

val insightsPrompt = modelContextService.buildInsightsPrompt(readmeContent)
val insightsResponse = modelContextService.generateResponse(insightsPrompt)
val summaryPrompt = modelContextService.buildSummaryPrompt(codeStructure, codeSnippets)

val summaryPrompt = modelContextService.buildSummaryPrompt(codeStructure, codeSnippets, insightsResponse)
modelContextService.generateResponse(summaryPrompt)
runBlocking {
val insights = async { modelContextService.generateResponse(insightsPrompt) }
val summary = async { modelContextService.generateResponse(summaryPrompt) }
"""|${insights.await()}
|
|${summary.await()}
|"""
.trimMargin()
}
} catch (e: Exception) {
throw Exception("Error analyzing repository: ${e.message}", e)
}
Expand Down
Loading