diff --git a/.idea/libraries/io_modelcontextprotocol_kotlin_sdk.xml b/.idea/libraries/io_modelcontextprotocol_kotlin_sdk.xml
index 371aa6f53b37..f1e3398ce691 100644
--- a/.idea/libraries/io_modelcontextprotocol_kotlin_sdk.xml
+++ b/.idea/libraries/io_modelcontextprotocol_kotlin_sdk.xml
@@ -1,18 +1,45 @@
-
+
-
- b1d152f70209b9fd42165afc7b98beeae87cabe688f8e82429928958dc61c411
+
+ 095e5d11868ae359bd640c922c2d1ed7a20ba519496599ee697e81c468761339
+
+
+ 33d9417ab21ac60413d64f2b1d0075df42c6212ac1016a4817d67f8ee41c7c43
+
+
+ 9e46aa3b51db4f8f6df635ba52318a8a28dec3c9ab226912267e8aaf7acdfbc7
+
+
+ d4fcb967ca13cae00c6f76b41a974fb76d864e1806d6721d2dfc666480f66f22
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
+
+
+
+
\ No newline at end of file
diff --git a/lib/BUILD.bazel b/lib/BUILD.bazel
index 4d440354a364..d1ff90c4408b 100644
--- a/lib/BUILD.bazel
+++ b/lib/BUILD.bazel
@@ -2794,13 +2794,41 @@ jvm_import(
source_jar = "@io_mockk-mockk-core-jvm-1_14_5-sources_http//file"
)
-jvm_import(
+java_library(
name = "io-modelcontextprotocol-kotlin-sdk",
- jar = "@io_modelcontextprotocol-kotlin-sdk-jvm-0_6_1_http//file",
- source_jar = "@io_modelcontextprotocol-kotlin-sdk-jvm-0_6_1-sources_http//file",
+ exports = [
+ ":io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7_http_import",
+ ":io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7_http_import",
+ ":io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7_http_import",
+ ":io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7_http_import",
+ ],
visibility = ["//visibility:public"]
)
+jvm_import(
+ name = "io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7_http_import",
+ jar = "@io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7_http//file",
+ source_jar = "@io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7-sources_http//file"
+)
+
+jvm_import(
+ name = "io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7_http_import",
+ jar = "@io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7_http//file",
+ source_jar = "@io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7-sources_http//file"
+)
+
+jvm_import(
+ name = "io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7_http_import",
+ jar = "@io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7_http//file",
+ source_jar = "@io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7-sources_http//file"
+)
+
+jvm_import(
+ name = "io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7_http_import",
+ jar = "@io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7_http//file",
+ source_jar = "@io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7-sources_http//file"
+)
+
jvm_import(
name = "io-opentelemetry-sdk-extension-autoconfigure-spi",
jar = "@io_opentelemetry-opentelemetry-sdk-extension-autoconfigure-spi-1_45_0_http//file",
diff --git a/lib/MODULE.bazel b/lib/MODULE.bazel
index e46b3230919e..ba54ea98f202 100644
--- a/lib/MODULE.bazel
+++ b/lib/MODULE.bazel
@@ -4312,17 +4312,59 @@ http_file(
)
http_file(
- name = "io_modelcontextprotocol-kotlin-sdk-jvm-0_6_1_http",
- url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-jvm/0.6.1/kotlin-sdk-jvm-0.6.1.jar",
- sha256 = "b1d152f70209b9fd42165afc7b98beeae87cabe688f8e82429928958dc61c411",
- downloaded_file_path = "kotlin-sdk-jvm-0.6.1.jar"
+ name = "io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-jvm/0.7.7/kotlin-sdk-jvm-0.7.7.jar",
+ sha256 = "095e5d11868ae359bd640c922c2d1ed7a20ba519496599ee697e81c468761339",
+ downloaded_file_path = "kotlin-sdk-jvm-0.7.7.jar"
)
http_file(
- name = "io_modelcontextprotocol-kotlin-sdk-jvm-0_6_1-sources_http",
- url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-jvm/0.6.1/kotlin-sdk-jvm-0.6.1-sources.jar",
- sha256 = "8a681b8948a231946d47deaa38100351ad154cea8f15cbfc0361e10d5fa95eed",
- downloaded_file_path = "kotlin-sdk-jvm-0.6.1-sources.jar"
+ name = "io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-core-jvm/0.7.7/kotlin-sdk-core-jvm-0.7.7.jar",
+ sha256 = "33d9417ab21ac60413d64f2b1d0075df42c6212ac1016a4817d67f8ee41c7c43",
+ downloaded_file_path = "kotlin-sdk-core-jvm-0.7.7.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-client-jvm/0.7.7/kotlin-sdk-client-jvm-0.7.7.jar",
+ sha256 = "9e46aa3b51db4f8f6df635ba52318a8a28dec3c9ab226912267e8aaf7acdfbc7",
+ downloaded_file_path = "kotlin-sdk-client-jvm-0.7.7.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-server-jvm/0.7.7/kotlin-sdk-server-jvm-0.7.7.jar",
+ sha256 = "d4fcb967ca13cae00c6f76b41a974fb76d864e1806d6721d2dfc666480f66f22",
+ downloaded_file_path = "kotlin-sdk-server-jvm-0.7.7.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-jvm-0_7_7-sources_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-jvm/0.7.7/kotlin-sdk-jvm-0.7.7-sources.jar",
+ sha256 = "dd2f46d3cdc1f5d6c4b1fa990fccf78b3f93cb2cb1ad7dadf693b184aadc837e",
+ downloaded_file_path = "kotlin-sdk-jvm-0.7.7-sources.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-core-jvm-0_7_7-sources_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-core-jvm/0.7.7/kotlin-sdk-core-jvm-0.7.7-sources.jar",
+ sha256 = "9a9dc9bfd6b099c6fd2cbc12a401e2f44dd4fc3cbbce19f13cc46cb6e3a6e424",
+ downloaded_file_path = "kotlin-sdk-core-jvm-0.7.7-sources.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-client-jvm-0_7_7-sources_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-client-jvm/0.7.7/kotlin-sdk-client-jvm-0.7.7-sources.jar",
+ sha256 = "37f7715675946f59a96a94252bf07ca1bf9ccc7e9b65045ebe8bb840f7c241d4",
+ downloaded_file_path = "kotlin-sdk-client-jvm-0.7.7-sources.jar"
+)
+
+http_file(
+ name = "io_modelcontextprotocol-kotlin-sdk-server-jvm-0_7_7-sources_http",
+ url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/modelcontextprotocol/kotlin-sdk-server-jvm/0.7.7/kotlin-sdk-server-jvm-0.7.7-sources.jar",
+ sha256 = "3636f760f382a1f6fd424c431cd98d1d1cac5892601068839780cc32ef004b89",
+ downloaded_file_path = "kotlin-sdk-server-jvm-0.7.7-sources.jar"
)
http_file(
diff --git a/plugins/mcp-server/plugin-content.yaml b/plugins/mcp-server/plugin-content.yaml
index 790a00fa58ec..ebc31827f78a 100644
--- a/plugins/mcp-server/plugin-content.yaml
+++ b/plugins/mcp-server/plugin-content.yaml
@@ -29,6 +29,9 @@
- name: io.modelcontextprotocol.kotlin.sdk
files:
- name: $MAVEN_REPOSITORY$/io/modelcontextprotocol/kotlin-sdk-jvm/0/kotlin-sdk-jvm-0.jar
+ - name: $MAVEN_REPOSITORY$/io/modelcontextprotocol/kotlin-sdk-core-jvm/0/kotlin-sdk-core-jvm-0.jar
+ - name: $MAVEN_REPOSITORY$/io/modelcontextprotocol/kotlin-sdk-client-jvm/0/kotlin-sdk-client-jvm-0.jar
+ - name: $MAVEN_REPOSITORY$/io/modelcontextprotocol/kotlin-sdk-server-jvm/0/kotlin-sdk-server-jvm-0.jar
reason: <- intellij.mcpserver.stdio
- name: ktor-server-sse-jvm
files:
diff --git a/plugins/mcp-server/src/com/intellij/mcpserver/impl/McpServerService.kt b/plugins/mcp-server/src/com/intellij/mcpserver/impl/McpServerService.kt
index 85776045954e..5e2dcebe548f 100644
--- a/plugins/mcp-server/src/com/intellij/mcpserver/impl/McpServerService.kt
+++ b/plugins/mcp-server/src/com/intellij/mcpserver/impl/McpServerService.kt
@@ -3,17 +3,12 @@ package com.intellij.mcpserver.impl
import com.intellij.concurrency.currentThreadContext
import com.intellij.mcpserver.*
import com.intellij.mcpserver.impl.util.network.*
-import com.intellij.mcpserver.impl.util.network.McpServerConnectionAddressProvider
import com.intellij.mcpserver.impl.util.projectPathParameterName
import com.intellij.mcpserver.settings.McpServerSettings
import com.intellij.mcpserver.statistics.McpServerCounterUsagesCollector
import com.intellij.mcpserver.stdio.IJ_MCP_SERVER_PROJECT_PATH
import com.intellij.mcpserver.util.findMostRelevantProject
-import com.intellij.openapi.application.ApplicationInfo
-import com.intellij.openapi.application.ApplicationNamesInfo
-import com.intellij.openapi.application.EDT
-import com.intellij.openapi.application.readAction
-import com.intellij.openapi.application.writeIntentReadAction
+import com.intellij.openapi.application.*
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
@@ -48,6 +43,7 @@ import io.modelcontextprotocol.kotlin.sdk.*
import io.modelcontextprotocol.kotlin.sdk.server.RegisteredTool
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
+import io.modelcontextprotocol.kotlin.sdk.server.ServerSession
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
@@ -158,7 +154,8 @@ class McpServerService(val cs: CoroutineScope) {
private fun isKnownToken(token: String): Boolean = activeAuthorizedSessions.containsKey(token)
private fun getSessionOptions(token: String?): McpSessionOptions {
- return token?.let { activeAuthorizedSessions[it] } ?: McpSessionOptions(commandExecutionMode = AskCommandExecutionMode.RESPECT_GLOBAL_SETTINGS)
+ return token?.let { activeAuthorizedSessions[it] }
+ ?: McpSessionOptions(commandExecutionMode = AskCommandExecutionMode.RESPECT_GLOBAL_SETTINGS)
}
val port: Int
@@ -237,7 +234,7 @@ class McpServerService(val cs: CoroutineScope) {
finish()
}
}
- }) { applicationCall ->
+ }) { applicationCall, transport ->
// this is added because now a Kotlin MCP client doesn't support header adjusting for each request, only for initial one, see McpStdioRunner
val projectPath = applicationCall.request.headers[IJ_MCP_SERVER_PROJECT_PATH]
val mcpServer = Server(
@@ -250,24 +247,30 @@ class McpServerService(val cs: CoroutineScope) {
//prompts = ServerCapabilities.Prompts(listChanged = true),
//resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
tools = ServerCapabilities.Tools(listChanged = true),
+ logging = null,
+ experimental = null,
+ sampling = null,
+ prompts = null,
+ resources = null,
)
)
)
- mcpServer.setRequestHandler(Method.Defined.LoggingSetLevel) { _, _ ->
- // Workaround inspector failure
- return@setRequestHandler EmptyRequestResult()
- }
+ val session = mcpServer.createSession(transport)
+ //session.setRequestHandler(Method.Defined.LoggingSetLevel) { _, _ ->
+ // // Workaround inspector failure
+ // return@setRequestHandler EmptyRequestResult()
+ //}
launch {
var previousTools: List? = null
mcpTools.collectLatest { updatedTools ->
previousTools?.forEach { previousTool ->
mcpServer.removeTool(previousTool.descriptor.name)
}
- mcpServer.addTools(updatedTools.map { it.mcpToolToRegisteredTool(mcpServer, projectPath) })
+ mcpServer.addTools(updatedTools.map { it.mcpToolToRegisteredTool(mcpServer, session, projectPath) })
previousTools = updatedTools
}
}
- return@mcpPatched mcpServer
+ return@mcpPatched session
}
}.start(wait = false)
}
@@ -282,7 +285,7 @@ class McpServerService(val cs: CoroutineScope) {
}
}
- private fun McpTool.mcpToolToRegisteredTool(server: Server, projectPathFromInitialRequest: String?): RegisteredTool {
+ private fun McpTool.mcpToolToRegisteredTool(server: Server, session: ServerSession, projectPathFromInitialRequest: String?): RegisteredTool {
val tool = toSdkTool()
return RegisteredTool(tool) { request ->
val httpRequest = currentCoroutineContext().httpRequestOrNull
@@ -318,7 +321,7 @@ class McpServerService(val cs: CoroutineScope) {
val vfsEvent = CopyOnWriteArrayList()
val initialDocumentContents = ConcurrentHashMap()
- val clientVersion = server.clientVersion ?: Implementation("Unknown MCP client", "Unknown version")
+ val clientVersion = session.clientVersion ?: Implementation("Unknown MCP client", "Unknown version")
val additionalData = McpCallInfo(
callId = callId.getAndAdd(1),
@@ -491,6 +494,7 @@ private fun McpTool.toSdkTool(): Tool {
}
else null
val tool = Tool(name = descriptor.name,
+ title = null,
description = descriptor.description,
inputSchema = Tool.Input(
properties = descriptor.inputSchema.propertiesSchema,
diff --git a/plugins/mcp-server/src/com/intellij/mcpserver/impl/util/network/mcp.sdk.util.kt b/plugins/mcp-server/src/com/intellij/mcpserver/impl/util/network/mcp.sdk.util.kt
index ca3e0f2c2595..2c7bfe98bd71 100644
--- a/plugins/mcp-server/src/com/intellij/mcpserver/impl/util/network/mcp.sdk.util.kt
+++ b/plugins/mcp-server/src/com/intellij/mcpserver/impl/util/network/mcp.sdk.util.kt
@@ -4,11 +4,7 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.trace
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
-import io.ktor.server.application.Application
-import io.ktor.server.application.ApplicationCall
-import io.ktor.server.application.ApplicationCallPipeline
-import io.ktor.server.application.PipelineCall
-import io.ktor.server.application.install
+import io.ktor.server.application.*
import io.ktor.server.request.ApplicationRequest
import io.ktor.server.request.receiveText
import io.ktor.server.response.respond
@@ -28,17 +24,14 @@ import io.ktor.utils.io.KtorDsl
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
import io.modelcontextprotocol.kotlin.sdk.JSONRPCRequest
import io.modelcontextprotocol.kotlin.sdk.Method
-import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
-import io.modelcontextprotocol.kotlin.sdk.server.Server
+import io.modelcontextprotocol.kotlin.sdk.server.ServerSession
import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
+import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
+import io.modelcontextprotocol.kotlin.sdk.shared.Transport
import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.withContext
-import kotlinx.serialization.json.JsonArray
-import kotlinx.serialization.json.JsonElement
-import kotlinx.serialization.json.JsonNull
-import kotlinx.serialization.json.JsonPrimitive
-import kotlinx.serialization.json.buildJsonObject
-import kotlinx.serialization.json.decodeFromJsonElement
+import kotlinx.serialization.json.*
import kotlin.coroutines.CoroutineContext
private val logger = logger()
@@ -46,7 +39,7 @@ private val logger = logger()
@KtorDsl
fun Application.mcpPatched(
prePhase: suspend PipelineContext<*, PipelineCall>.() -> Unit,
- block: suspend (ApplicationCall) -> Server,
+ block: suspend (ApplicationCall, Transport) -> ServerSession,
) {
val transports = ConcurrentMap()
val streamableSessions = ConcurrentMap()
@@ -83,19 +76,19 @@ fun Application.mcpPatched(
private suspend fun ServerSSESession.mcpSseEndpoint(
postEndpoint: String,
transports: ConcurrentMap,
- block: suspend (ApplicationCall) -> Server,
+ block: suspend (ApplicationCall, Transport) -> ServerSession,
) {
val transport = mcpSseTransport(postEndpoint, transports)
- val server = block(call)
+ val serverSession = block(call, transport)
- server.onClose {
+ serverSession.onClose {
logger.trace { "Server connection closed for sessionId: ${transport.sessionId}" }
transports.remove(transport.sessionId)
}
- server.connect(transport)
logger.trace { "Server connected to transport for sessionId: ${transport.sessionId}" }
+ awaitCancellation()
}
internal fun ServerSSESession.mcpSseTransport(
@@ -137,7 +130,7 @@ internal suspend fun RoutingContext.mcpPostEndpoint(
private suspend fun RoutingContext.handleStreamablePost(
sessions: ConcurrentMap,
- block: suspend (ApplicationCall) -> Server,
+ block: suspend (ApplicationCall, Transport) -> ServerSession,
) {
val rawBody = try {
call.receiveText()
@@ -225,10 +218,10 @@ private suspend fun RoutingContext.findStreamableSession(
private suspend fun createStreamableSession(
applicationCall: ApplicationCall,
sessions: ConcurrentMap,
- block: suspend (ApplicationCall) -> Server,
+ block: suspend (ApplicationCall, Transport) -> ServerSession,
): StreamableSession {
val transport = StreamableHttpServerTransport()
- val server = block(applicationCall)
+ val serverSession = block(applicationCall, transport)
transport.onError {
logger.error("Error in Streamable HTTP transport", it)
@@ -237,14 +230,14 @@ private suspend fun createStreamableSession(
logger.trace { "Streamable HTTP transport closed for session ${transport.sessionId}" }
sessions.remove(transport.sessionId)
}
- server.onClose {
+ serverSession.onClose {
logger.trace { "Server closed for Streamable HTTP session ${transport.sessionId}" }
sessions.remove(transport.sessionId)
}
- server.connect(transport)
+ serverSession.connect(transport)
- val session = StreamableSession(transport, server)
+ val session = StreamableSession(transport, serverSession)
sessions[transport.sessionId] = session
logger.trace { "Streamable HTTP session started with id ${transport.sessionId}" }
return session
@@ -280,7 +273,7 @@ private suspend fun RoutingContext.respondJsonError(status: HttpStatusCode, code
}
private data class ParsedMessages(val messages: List, val isBatch: Boolean)
-private data class StreamableSession(val transport: StreamableHttpServerTransport, val server: Server)
+private data class StreamableSession(val transport: StreamableHttpServerTransport, val server: ServerSession)
//–– your custom context element
class HttpRequestElement(val request: ApplicationRequest) : CoroutineContext.Element {