@@ -4,6 +4,8 @@ import io.ktor.http.*
44import io.ktor.server.application.*
55import io.ktor.server.cio.*
66import io.ktor.server.engine.*
7+ import io.ktor.server.plugins.*
8+ import io.ktor.server.plugins.cors.routing.*
79import io.ktor.server.response.*
810import io.ktor.server.routing.*
911import io.ktor.server.sse.*
@@ -14,10 +16,7 @@ import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
1416import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
1517import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
1618import io.modelcontextprotocol.kotlin.sdk.server.mcp
17- import kotlinx.coroutines.Job
18- import kotlinx.coroutines.awaitCancellation
19- import kotlinx.coroutines.runBlocking
20- import kotlinx.coroutines.withTimeout
19+ import kotlinx.coroutines.*
2120import kotlinx.io.asSink
2221import kotlinx.io.asSource
2322import kotlinx.io.buffered
@@ -38,14 +37,7 @@ class Mcp(
3837 private val implementation : Implementation =
3938 Implementation (name = "MCP GitHub Code Analysis Server ", version = "0.1.0"),
4039 private val serverOptions : ServerOptions =
41- ServerOptions (
42- capabilities =
43- ServerCapabilities (
44- prompts = ServerCapabilities .Prompts (listChanged = true),
45- resources = ServerCapabilities .Resources (subscribe = true, listChanged = true),
46- tools = ServerCapabilities .Tools (listChanged = true),
47- )
48- ),
40+ ServerOptions (capabilities = ServerCapabilities (tools = ServerCapabilities .Tools (listChanged = true))),
4941) {
5042
5143 /* * Starts an MCP server using standard input/output (stdio) for communication. */
@@ -78,24 +70,42 @@ class Mcp(
7870
7971 embeddedServer(CIO , host = " 0.0.0.0" , port = port) {
8072 install(SSE )
73+ install(CORS ) {
74+ anyHost()
75+ allowCredentials = true
76+ allowNonSimpleContentTypes = true
77+ allowMethod(HttpMethod .Options )
78+ allowMethod(HttpMethod .Post )
79+ allowMethod(HttpMethod .Get )
80+ allowHeader(HttpHeaders .ContentType )
81+ allowHeader(" Cache-Control" )
82+ }
8183
8284 routing {
85+ get(" /" ) { call.respondText(" MCP GitHub Code Analysis Server v0.1.0" , ContentType .Text .Plain ) }
86+
87+ get(" /health" ) { call.respondText(" MCP Server is running" , ContentType .Text .Plain ) }
88+
8389 sse(" /sse" ) {
90+ logger.info(" New SSE connection established from ${call.request.origin.remoteHost} " )
8491 val transport = SseServerTransport (" /message" , this )
8592 val server = configureServer()
8693 servers[transport.sessionId] = server
94+ logger.info(" Created server for session: ${transport.sessionId} " )
8795
8896 server.onClose {
8997 logger.info(" Server closed for session: ${transport.sessionId} " )
9098 servers.remove(transport.sessionId)
9199 }
92100
93101 try {
102+ logger.info(" Attempting to connect server for session: ${transport.sessionId} " )
94103 server.connect(transport)
95- logger.info(" Server connected for session: ${transport.sessionId} " )
104+ logger.info(" Server successfully connected for session: ${transport.sessionId} " )
96105 awaitCancellation()
97106 } catch (e: Exception ) {
98- logger.error(" Connection error: ${e.message} " , e)
107+ logger.error(" Connection error for session ${transport.sessionId} : ${e.message} " , e)
108+ throw e
99109 } finally {
100110 servers.remove(transport.sessionId)
101111 logger.info(" SSE connection closed for session: ${transport.sessionId} " )
@@ -108,6 +118,8 @@ class Mcp(
108118 call.request.queryParameters[" sessionId" ]
109119 ? : return @post call.respond(HttpStatusCode .BadRequest , " Missing sessionId parameter" )
110120
121+ logger.debug(" Handling message for session: $sessionId " )
122+
111123 val server = servers[sessionId]
112124 if (server == null ) {
113125 logger.warn(" Session not found: $sessionId " )
@@ -142,10 +154,16 @@ class Mcp(
142154 * @param port The port number on which the SSE MCP server will listen for client connections.
143155 */
144156 fun runSseUsingKtorPlugin (port : Int ): Unit = runBlocking {
145- logger.debug (" Starting SSE server on port $port " )
146- logger.debug (" Use inspector to connect to http://localhost:$port /sse" )
157+ logger.info (" Starting SSE server using Ktor plugin on port $port " )
158+ logger.info (" Use inspector to connect to http://localhost:$port /sse" )
147159
148160 embeddedServer(CIO , host = " 0.0.0.0" , port = port) {
161+ install(CORS ) {
162+ anyHost()
163+ allowCredentials = true
164+ allowNonSimpleContentTypes = true
165+ }
166+
149167 mcp {
150168 return @mcp configureServer()
151169 }
@@ -159,6 +177,7 @@ class Mcp(
159177 * @return The configured MCP server instance.
160178 */
161179 fun configureServer (): SdkServer {
180+ logger.info(" Configuring MCP server with implementation: ${implementation.name} v${implementation.version} " )
162181 val server = SdkServer (implementation, serverOptions)
163182
164183 server.addTool(
@@ -193,12 +212,35 @@ class Mcp(
193212 val repoUrl =
194213 arguments[" repoUrl" ]?.jsonPrimitive?.content ? : throw IllegalArgumentException (" Missing repoUrl parameter" )
195214 val branch = arguments[" branch" ]?.jsonPrimitive?.content ? : " main"
196- val result = repositoryAnalysisService.analyzeRepository(repoUrl, branch)
215+
216+ val startTime = System .currentTimeMillis()
217+ logger.info(" Starting repository analysis for: $repoUrl " )
218+ val result = withTimeout(3_600_000 ) { repositoryAnalysisService.analyzeRepository(repoUrl, branch) }
219+ val duration = System .currentTimeMillis() - startTime
220+ logger.info(" Analysis completed in ${duration} ms" )
221+
197222 CallToolResult (content = listOf (TextContent (result)))
223+ } catch (e: TimeoutCancellationException ) {
224+ CallToolResult (
225+ content =
226+ listOf (
227+ TextContent (
228+ buildString {
229+ append(" Repository analysis timed out after 2 minutes. " )
230+ append(" Large repositories may take longer to analyze. " )
231+ append(" Try with a smaller repository or specific branch." )
232+ }
233+ )
234+ ),
235+ isError = true ,
236+ )
198237 } catch (e: Exception ) {
238+ logger.error(" Analysis failed: ${e.message} " , e)
199239 CallToolResult (content = listOf (TextContent (" Error analyzing repository: ${e.message} " )), isError = true )
200240 }
201241 }
242+
243+ logger.info(" MCP server configured successfully with 1 tool" )
202244 return server
203245 }
204246}
0 commit comments