Skip to content

Commit d49db61

Browse files
committed
feat: increase tool timeout
1 parent 72105ff commit d49db61

File tree

2 files changed

+60
-17
lines changed

2 files changed

+60
-17
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dependencies {
4242
implementation("io.ktor:ktor-server-core:$ktorVersion")
4343
implementation("io.ktor:ktor-server-netty:$ktorVersion")
4444
implementation("io.ktor:ktor-server-sse:$ktorVersion")
45+
implementation("io.ktor:ktor-server-cors:${ktorVersion}")
4546
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
4647
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
4748

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

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import io.ktor.http.*
44
import io.ktor.server.application.*
55
import io.ktor.server.cio.*
66
import io.ktor.server.engine.*
7+
import io.ktor.server.plugins.*
8+
import io.ktor.server.plugins.cors.routing.*
79
import io.ktor.server.response.*
810
import io.ktor.server.routing.*
911
import io.ktor.server.sse.*
@@ -14,10 +16,7 @@ import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
1416
import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
1517
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
1618
import 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.*
2120
import kotlinx.io.asSink
2221
import kotlinx.io.asSource
2322
import 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

Comments
 (0)