Skip to content

Commit 7cd82ed

Browse files
authored
feat: functional refactor (#7)
1 parent a794c20 commit 7cd82ed

7 files changed

Lines changed: 247 additions & 272 deletions

File tree

src/main/kotlin/Main.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ import org.slf4j.LoggerFactory
1212
*/
1313
fun main(args: Array<String>) {
1414
val logger = LoggerFactory.getLogger("Main")
15-
val config = AppConfig()
15+
val config = AppConfig.fromEnv()
1616
val server = Server()
1717

18-
val command = args.firstOrNull() ?: "--sse-server-ktor"
19-
val port = args.getOrNull(1)?.toIntOrNull() ?: config.serverPort
18+
val (command, port) = parseArgs(args, config.serverPort)
2019

2120
when (command) {
2221
"--stdio" -> server.runMcpServerUsingStdio()
2322
"--sse-server-ktor" -> server.runSseMcpServerUsingKtorPlugin(port)
2423
"--sse-server" -> server.runSseMcpServerWithPlainConfiguration(port)
25-
else -> {
26-
logger.error("Unknown command: $command")
27-
}
24+
else -> logger.error("Unknown command: $command")
2825
}
2926
}
27+
28+
private fun parseArgs(args: Array<String>, defaultPort: Int): Pair<String, Int> {
29+
val command = args.firstOrNull() ?: "--sse-server-ktor"
30+
val port = args.getOrNull(1)?.toIntOrNull() ?: defaultPort
31+
return command to port
32+
}
Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
package mcp.code.analysis.config
22

3-
/** Configuration settings for the application. Retrieves values from environment variables or uses default values. */
4-
class AppConfig {
5-
val serverPort: Int = System.getenv("SERVER_PORT")?.toIntOrNull() ?: 3001
6-
val githubToken: String = System.getenv("GITHUB_TOKEN") ?: ""
7-
val workingDirectory: String =
8-
System.getenv("WORKING_DIRECTORY") ?: System.getProperty("java.io.tmpdir").plus("/mcp-code-analysis")
3+
/**
4+
* Immutable configuration settings for the application. Retrieves values from environment variables or uses default
5+
* values.
6+
*/
7+
data class AppConfig(
8+
val serverPort: Int,
9+
val githubToken: String,
10+
val workingDirectory: String,
11+
val modelApiUrl: String,
12+
val modelApiKey: String,
13+
val modelName: String,
14+
) {
15+
companion object {
916

10-
// Default to local Ollama instance
11-
val modelApiUrl: String = System.getenv("MODEL_API_URL") ?: "http://localhost:11434/api"
12-
13-
// Not needed for Ollama local deployments
14-
val modelApiKey: String = System.getenv("MODEL_API_KEY") ?: ""
15-
16-
val modelName: String = System.getenv("MODEL_NAME") ?: "llama3.3"
17+
/**
18+
* Creates an instance of [AppConfig] by retrieving values from environment variables. If an environment variable is
19+
* not set, a default value is used.
20+
*
21+
* @return An instance of [AppConfig] with the retrieved or default values.
22+
*/
23+
fun fromEnv(): AppConfig =
24+
AppConfig(
25+
serverPort = System.getenv("SERVER_PORT")?.toIntOrNull() ?: 3001,
26+
githubToken = System.getenv("GITHUB_TOKEN") ?: "",
27+
workingDirectory =
28+
System.getenv("WORKING_DIRECTORY") ?: System.getProperty("java.io.tmpdir").plus("/mcp-code-analysis"),
29+
modelApiUrl = System.getenv("MODEL_API_URL") ?: "http://localhost:11434/api",
30+
modelApiKey = System.getenv("MODEL_API_KEY") ?: "",
31+
modelName = System.getenv("MODEL_NAME") ?: "llama3.2",
32+
)
33+
}
1734
}

src/main/kotlin/mcp/code/analysis/server/Server.kt

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,31 @@ import kotlinx.serialization.json.JsonObject
2020
import kotlinx.serialization.json.JsonPrimitive
2121
import kotlinx.serialization.json.jsonPrimitive
2222
import mcp.code.analysis.service.RepositoryAnalysisService
23+
import org.slf4j.Logger
2324
import org.slf4j.LoggerFactory
2425

2526
/**
2627
* Server for analyzing GitHub repositories using the Model Context Protocol (MCP). Provides functionalities for
2728
* analyzing GitHub repositories and checking analysis status.
2829
*/
29-
class Server {
30-
31-
private val logger = LoggerFactory.getLogger(this::class.java)
32-
private val analysisService = RepositoryAnalysisService()
33-
34-
/**
35-
* Starts an MCP server using standard input/output (stdio) for communication.
36-
*
37-
* This method configures the server and connects it to the standard input and output streams. It will handle listing
38-
* prompts, tools, and resources automatically.
39-
*/
30+
data class Server(
31+
private val repositoryAnalysisService: RepositoryAnalysisService = RepositoryAnalysisService(),
32+
private val logger: Logger = LoggerFactory.getLogger(Server::class.java),
33+
private val implementation: Implementation =
34+
Implementation(name = "MCP GitHub Code Analysis Server", version = "0.1.0"),
35+
private val serverOptions: ServerOptions =
36+
ServerOptions(
37+
capabilities =
38+
ServerCapabilities(
39+
prompts = ServerCapabilities.Prompts(listChanged = true),
40+
resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
41+
tools = ServerCapabilities.Tools(listChanged = true),
42+
)
43+
),
44+
) {
45+
46+
/** Starts an MCP server using standard input/output (stdio) for communication. */
4047
fun runMcpServerUsingStdio() {
41-
// Note: The server will handle listing prompts, tools, and resources automatically.
42-
// The handleListResourceTemplates will return empty as defined in the Server code.
4348
val server = configureServer()
4449
val transport =
4550
StdioServerTransport(
@@ -63,7 +68,7 @@ class Server {
6368
*/
6469
fun runSseMcpServerWithPlainConfiguration(port: Int): Unit = runBlocking {
6570
val servers = ConcurrentMap<String, SdkServer>()
66-
logger.info("Starting sse server on port $port. ")
71+
logger.info("Starting SSE server on port $port.")
6772
logger.info("Use inspector to connect to the http://localhost:$port/sse")
6873

6974
embeddedServer(CIO, host = "0.0.0.0", port = port) {
@@ -73,10 +78,10 @@ class Server {
7378
val transport = SseServerTransport("/message", this)
7479
val server: SdkServer = configureServer()
7580

76-
// For SSE, you can also add prompts/tools/resources if needed:
77-
// server.addTool(...), server.addPrompt(...), server.addResource(...)
81+
// For SSE, you can also add prompts/tools/resources if needed:
82+
// server.addTool(...), server.addPrompt(...), server.addResource(...)
7883

79-
servers[transport.sessionId] = server
84+
servers[transport.sessionId] = server
8085

8186
server.onClose {
8287
logger.info("Server closed")
@@ -107,15 +112,10 @@ class Server {
107112
* @param port The port number on which the SSE MCP server will listen for client connections.
108113
*/
109114
fun runSseMcpServerUsingKtorPlugin(port: Int): Unit = runBlocking {
110-
logger.info("Starting sse server on port $port")
111-
logger.info("Use inspector to connect to the http://localhost:$port/sse")
115+
logger.info("Starting SSE server on port $port")
116+
logger.info("Use inspector to connect to http://localhost:$port/sse")
112117

113-
embeddedServer(CIO, host = "0.0.0.0", port = port) {
114-
mcp {
115-
return@mcp configureServer()
116-
}
117-
}
118-
.start(wait = true)
118+
embeddedServer(CIO, host = "0.0.0.0", port = port) { mcp { configureServer() } }.start(wait = true)
119119
}
120120

121121
/**
@@ -124,18 +124,7 @@ class Server {
124124
* @return The configured MCP server instance.
125125
*/
126126
private fun configureServer(): SdkServer {
127-
val server =
128-
SdkServer(
129-
Implementation(name = "MCP GitHub Code Analysis Server", version = "0.1.0"),
130-
ServerOptions(
131-
capabilities =
132-
ServerCapabilities(
133-
prompts = ServerCapabilities.Prompts(listChanged = true),
134-
resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
135-
tools = ServerCapabilities.Tools(listChanged = true),
136-
)
137-
),
138-
)
127+
val server = SdkServer(implementation, serverOptions)
139128

140129
server.addTool(
141130
name = "github-code-analyzer-start",
@@ -156,7 +145,7 @@ class Server {
156145
JsonObject(
157146
mapOf(
158147
"type" to JsonPrimitive("string"),
159-
"description" to JsonPrimitive("Branch to analyze (default: mcp.code.analysis.server.main)"),
148+
"description" to JsonPrimitive("Branch to analyze (default: main)"),
160149
)
161150
),
162151
)
@@ -169,14 +158,12 @@ class Server {
169158
val repoUrl =
170159
arguments["repoUrl"]?.jsonPrimitive?.content ?: throw IllegalArgumentException("Missing repoUrl parameter")
171160
val branch = arguments["branch"]?.jsonPrimitive?.content ?: "main"
172-
val result = analysisService.analyzeRepository(repoUrl, branch)
173-
161+
val result = repositoryAnalysisService.analyzeRepository(repoUrl, branch)
174162
CallToolResult(content = listOf(TextContent(result)))
175163
} catch (e: Exception) {
176164
CallToolResult(content = listOf(TextContent("Error analyzing repository: ${e.message}")), isError = true)
177165
}
178166
}
179-
180167
return server
181168
}
182169
}

0 commit comments

Comments
 (0)