1- package shared
1+ package io.modelcontextprotocol.sample.server
22
33import io.ktor.http.HttpStatusCode
44import io.ktor.server.application.install
@@ -25,7 +25,13 @@ import io.modelcontextprotocol.kotlin.sdk.server.Server
2525import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
2626import io.modelcontextprotocol.kotlin.sdk.server.ServerSession
2727import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
28+ import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
2829import io.modelcontextprotocol.kotlin.sdk.server.mcp
30+ import kotlinx.coroutines.Job
31+ import kotlinx.coroutines.runBlocking
32+ import kotlinx.io.asSink
33+ import kotlinx.io.asSource
34+ import kotlinx.io.buffered
2935
3036fun configureServer (): Server {
3137 val server = Server (
@@ -71,7 +77,7 @@ fun configureServer(): Server {
7177 name = " kotlin-sdk-tool" ,
7278 description = " A test tool" ,
7379 inputSchema = Tool .Input (),
74- ) { request ->
80+ ) { _ ->
7581 CallToolResult (
7682 content = listOf (TextContent (" Hello, world!" )),
7783 )
@@ -96,8 +102,8 @@ fun configureServer(): Server {
96102
97103suspend fun runSseMcpServerWithPlainConfiguration (port : Int ) {
98104 val serverSessions = ConcurrentMap <String , ServerSession >()
99- println (" Starting sse server on port $port . " )
100- println (" Use inspector to connect to the http://localhost:$port /sse" )
105+ println (" Starting SSE server on port $port " )
106+ println (" Use inspector to connect to http://localhost:$port /sse" )
101107
102108 val server = configureServer()
103109
@@ -106,21 +112,21 @@ suspend fun runSseMcpServerWithPlainConfiguration(port: Int) {
106112 routing {
107113 sse(" /sse" ) {
108114 val transport = SseServerTransport (" /message" , this )
109-
110- // For SSE, you can also add prompts/tools/resources if needed:
111- // server.addTool(...), server.addPrompt(...), server.addResource(...)
112-
113115 val serverSession = server.connect(transport)
114- serverSessions[transport.sessionId] = server.connect(transport)
116+ serverSessions[transport.sessionId] = serverSession
115117
116118 serverSession.onClose {
117- println (" Server closed" )
119+ println (" Server session closed for: ${transport.sessionId} " )
118120 serverSessions.remove(transport.sessionId)
119121 }
120122 }
121123 post(" /message" ) {
122- println (" Received Message" )
123- val sessionId: String = call.request.queryParameters[" sessionId" ]!!
124+ val sessionId: String? = call.request.queryParameters[" sessionId" ]
125+ if (sessionId == null ) {
126+ call.respond(HttpStatusCode .BadRequest , " Missing sessionId parameter" )
127+ return @post
128+ }
129+
124130 val transport = serverSessions[sessionId]?.transport as ? SseServerTransport
125131 if (transport == null ) {
126132 call.respond(HttpStatusCode .NotFound , " Session not found" )
@@ -134,20 +140,43 @@ suspend fun runSseMcpServerWithPlainConfiguration(port: Int) {
134140}
135141
136142/* *
137- * Starts an SSE (Server Sent Events) MCP server using the Ktor framework and the specified port .
143+ * Starts an SSE (Server- Sent Events) MCP server using the Ktor plugin .
138144 *
139- * The url can be accessed in the MCP inspector at [http://localhost:$port]
145+ * This is the recommended approach for SSE servers as it simplifies configuration.
146+ * The URL can be accessed in the MCP inspector at http://localhost:[port]/sse
140147 *
141148 * @param port The port number on which the SSE MCP server will listen for client connections.
142- * @return Unit This method does not return a value.
143149 */
144150suspend fun runSseMcpServerUsingKtorPlugin (port : Int ) {
145- println (" Starting sse server on port $port " )
146- println (" Use inspector to connect to the http://localhost:$port /sse" )
151+ println (" Starting SSE server on port $port " )
152+ println (" Use inspector to connect to http://localhost:$port /sse" )
147153
148154 embeddedServer(CIO , host = " 127.0.0.1" , port = port) {
149155 mcp {
150156 return @mcp configureServer()
151157 }
152158 }.startSuspend(wait = true )
153159}
160+
161+ /* *
162+ * Starts an MCP server using Standard I/O transport.
163+ *
164+ * This mode is useful for process-based communication where the server
165+ * communicates via stdin/stdout with a parent process or client.
166+ */
167+ fun runMcpServerUsingStdio () {
168+ val server = configureServer()
169+ val transport = StdioServerTransport (
170+ inputStream = System .`in `.asSource().buffered(),
171+ outputStream = System .out .asSink().buffered()
172+ )
173+
174+ runBlocking {
175+ server.connect(transport)
176+ val done = Job ()
177+ server.onClose {
178+ done.complete()
179+ }
180+ done.join()
181+ }
182+ }
0 commit comments