Skip to content

Commit 6721cd6

Browse files
authored
Upgraded kotlin mcp sdk to 0.7.3 and WebSocket transport support (#3483)
* support for websocket transport * latest kotlin-sdk 0.7.3
1 parent 55680b7 commit 6721cd6

31 files changed

+2258
-626
lines changed

gradle/libs.versions.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ kotlin = "2.1.21"
1818
kotlinBinaryCompatibilityPlugin = "0.18.1"
1919
ktor = "3.3.0"
2020
mavenPublish = "0.34.0"
21+
mcp = "0.7.3"
2122
micrometer = "1.12.13"
2223
netty = "4.2.6.Final"
2324
okHttp = "5.1.0"
@@ -184,9 +185,9 @@ lettuceCore = { module = "io.lettuce:lettuce-core", version = "6.8.1.RELEASE" }
184185
logbackClassic = { module = "ch.qos.logback:logback-classic", version = "1.5.6" }
185186
logbackCore = { module = "ch.qos.logback:logback-core", version = "1.5.6" }
186187
loggingApi = { module = "io.github.microutils:kotlin-logging", version = "3.0.5" }
187-
mcpKotlinSdkClient = { module = "io.modelcontextprotocol:kotlin-sdk-client", version = "0.7.2" }
188-
mcpKotlinSdkCore = { module = "io.modelcontextprotocol:kotlin-sdk-core", version = "0.7.2" }
189-
mcpKotlinSdkServer = { module = "io.modelcontextprotocol:kotlin-sdk-server", version = "0.7.2" }
188+
mcpKotlinSdkClient = { module = "io.modelcontextprotocol:kotlin-sdk-client", version.ref = "mcp" }
189+
mcpKotlinSdkCore = { module = "io.modelcontextprotocol:kotlin-sdk-core", version.ref = "mcp" }
190+
mcpKotlinSdkServer = { module = "io.modelcontextprotocol:kotlin-sdk-server", version.ref = "mcp" }
190191
micrometerCore = { module = "io.micrometer:micrometer-core", version.ref = "micrometer" }
191192
micrometerRegistryPrometheus = { module = "io.micrometer:micrometer-registry-prometheus", version.ref = "micrometer" }
192193
mockitoCore = { module = "org.mockito:mockito-core", version = "5.20.0" }

misk-mcp/README.md

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,44 @@ class MyAppModule : KAbstractModule() {
3434

3535
## Web Action Integration
3636

37-
To expose MCP functionality through HTTP endpoints, you need to create web actions using the MCP annotations and install the appropriate WebActionModule.
37+
To expose MCP functionality through HTTP endpoints, you need to create web actions using the MCP annotations and install the appropriate WebActionModule. The misk-mcp module supports two transport protocols:
3838

39-
### Required and Optional Endpoints
39+
### Transport Options
4040

41+
#### Server-Sent Events (SSE) Transport
42+
Uses HTTP POST requests with SSE responses for real-time communication:
4143
- **`@McpPost`** (Required): Handles incoming MCP requests from clients
42-
- **`@McpGet`** (Optional): Enables out-of-band server-to-client notifications, typically used when a stateful session is present
44+
- **`@McpGet`** (Optional): Enables out-of-band server-to-client notifications
4345
- **`@McpDelete`** (Optional): Allows clients to explicitly delete an existing stateful session
4446

47+
#### WebSocket Transport
48+
Uses persistent WebSocket connections for full bidirectional communication:
49+
- **`@McpWebSocket`** (Required): Handles all MCP communication over WebSocket
50+
51+
### SSE Transport Example
52+
4553
```kotlin
4654
@ExperimentalMiskApi
4755
@Singleton
48-
class MyMcpWebAction @Inject constructor(
56+
class MyMcpSseAction @Inject constructor(
4957
private val mcpStreamManager: McpStreamManager
5058
) : WebAction {
5159

5260
@McpPost
5361
suspend fun handleMcpRequest(
5462
@RequestBody message: JSONRPCMessage,
55-
@RequestHeaders headers: Headers,
5663
sendChannel: SendChannel<ServerSentEvent>
5764
) {
58-
val sessionId = headers[SESSION_ID_HEADER]
59-
mcpStreamManager.withResponseChannel(sendChannel) {
65+
mcpStreamManager.withSseChannel(sendChannel) {
6066
handleMessage(message)
6167
}
6268
}
6369

6470
@McpGet
6571
suspend fun streamServerEvents(
66-
@RequestHeaders headers: Headers,
6772
sendChannel: SendChannel<ServerSentEvent>
6873
) {
69-
val sessionId = headers[SESSION_ID_HEADER]
70-
mcpStreamManager.withResponseChannel(sendChannel) {
74+
mcpStreamManager.withSseChannel(sendChannel) {
7175
// Stream server-initiated events to client
7276
}
7377
}
@@ -83,6 +87,47 @@ class MyMcpWebAction @Inject constructor(
8387
}
8488
```
8589

90+
### WebSocket Transport Example
91+
92+
```kotlin
93+
@ExperimentalMiskApi
94+
@Singleton
95+
class MyMcpWebSocketAction @Inject constructor(
96+
private val mcpStreamManager: McpStreamManager
97+
) : WebAction {
98+
99+
@McpWebSocket
100+
fun handleWebSocket(webSocket: WebSocket): WebSocketListener {
101+
return mcpStreamManager.withWebSocket(webSocket)
102+
}
103+
}
104+
```
105+
106+
### Transport Comparison
107+
108+
| Feature | SSE Transport | WebSocket Transport |
109+
|---------|---------------|-------------------|
110+
| **Connection Type** | HTTP POST + SSE | Persistent WebSocket |
111+
| **Communication** | Client→Server (POST)<br/>Server→Client (SSE) | Full bidirectional |
112+
| **Complexity** | Multiple endpoints | Single endpoint |
113+
| **Session Management** | Optional via headers | Built-in connection state |
114+
| **Use Cases** | Traditional web apps<br/>Request-response patterns | Real-time applications<br/>Interactive AI tools |
115+
| **Client Support** | Universal HTTP support | WebSocket support required |
116+
117+
### Choosing a Transport
118+
119+
**Use SSE Transport when:**
120+
- Building traditional web applications
121+
- Need maximum client compatibility
122+
- Implementing request-response patterns
123+
- Want explicit control over session management
124+
125+
**Use WebSocket Transport when:**
126+
- Building real-time interactive applications
127+
- Need bidirectional communication
128+
- Want simplified connection management
129+
- Implementing conversational AI interfaces
130+
86131
**Important**: You must install a WebActionModule to register your MCP web actions:
87132

88133
```kotlin

misk-mcp/api/misk-mcp.api

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,6 @@ public final class misk/mcp/MiskMcpServer : io/modelcontextprotocol/kotlin/sdk/s
114114
public static final field Companion Lmisk/mcp/MiskMcpServer$Companion;
115115
public final fun getConfig ()Lmisk/mcp/config/McpServerConfig;
116116
public final fun getName ()Ljava/lang/String;
117-
public final fun handleMessage (Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
118-
public final fun handleMessage (Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
119-
public static synthetic fun handleMessage$default (Lmisk/mcp/MiskMcpServer;Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
120117
}
121118

122119
public final class misk/mcp/MiskMcpServer$Companion {
@@ -141,6 +138,21 @@ public final class misk/mcp/StructuredMcpTool$StructuredToolResult : misk/mcp/Mc
141138
public fun toString ()Ljava/lang/String;
142139
}
143140

141+
public final class misk/mcp/TypedCreateElicitationResult {
142+
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/CreateElicitationResult$Action;Ljava/lang/Object;Lkotlinx/serialization/json/JsonObject;)V
143+
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/CreateElicitationResult$Action;
144+
public final fun component2 ()Ljava/lang/Object;
145+
public final fun component3 ()Lkotlinx/serialization/json/JsonObject;
146+
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/CreateElicitationResult$Action;Ljava/lang/Object;Lkotlinx/serialization/json/JsonObject;)Lmisk/mcp/TypedCreateElicitationResult;
147+
public static synthetic fun copy$default (Lmisk/mcp/TypedCreateElicitationResult;Lio/modelcontextprotocol/kotlin/sdk/CreateElicitationResult$Action;Ljava/lang/Object;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lmisk/mcp/TypedCreateElicitationResult;
148+
public fun equals (Ljava/lang/Object;)Z
149+
public final fun getAction ()Lio/modelcontextprotocol/kotlin/sdk/CreateElicitationResult$Action;
150+
public final fun getContent ()Ljava/lang/Object;
151+
public final fun get_meta ()Lkotlinx/serialization/json/JsonObject;
152+
public fun hashCode ()I
153+
public fun toString ()Ljava/lang/String;
154+
}
155+
144156
public abstract interface annotation class misk/mcp/action/McpDelete : java/lang/annotation/Annotation {
145157
}
146158

@@ -150,6 +162,11 @@ public abstract interface annotation class misk/mcp/action/McpGet : java/lang/an
150162
public abstract interface annotation class misk/mcp/action/McpPost : java/lang/annotation/Annotation {
151163
}
152164

165+
public final class misk/mcp/action/McpServerSessionsKt {
166+
public static final fun currentServerSession (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
167+
public static final fun handleMessage (Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
168+
}
169+
153170
public final class misk/mcp/action/McpSessionId {
154171
public fun <init> (Lmisk/scope/ActionScoped;)V
155172
public final fun get ()Ljava/lang/String;
@@ -161,13 +178,17 @@ public final class misk/mcp/action/McpSessionIdKt {
161178

162179
public final class misk/mcp/action/McpStreamManager {
163180
public static final field Companion Lmisk/mcp/action/McpStreamManager$Companion;
164-
public fun <init> (Lmisk/scope/ActionScoped;Lcom/google/inject/Provider;)V
165181
public final fun withResponseChannel (Lkotlinx/coroutines/channels/SendChannel;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
182+
public final fun withSseChannel (Lkotlinx/coroutines/channels/SendChannel;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
183+
public final fun withWebSocket (Lmisk/web/actions/WebSocket;)Lmisk/web/actions/WebSocketListener;
166184
}
167185

168186
public final class misk/mcp/action/McpStreamManager$Companion {
169187
}
170188

189+
public abstract interface annotation class misk/mcp/action/McpWebSocket : java/lang/annotation/Annotation {
190+
}
191+
171192
public final class misk/mcp/config/McpConfig : java/util/LinkedHashMap, misk/config/Config {
172193
public fun <init> ()V
173194
public fun <init> (Ljava/util/Map;)V
@@ -231,14 +252,17 @@ public final class misk/mcp/config/McpServerConfig : misk/config/Config {
231252
public fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;)V
232253
public fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;)V
233254
public fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;)V
234-
public synthetic fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
255+
public fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;Z)V
256+
public synthetic fun <init> (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
235257
public final fun component1 ()Ljava/lang/String;
236258
public final fun component2 ()Lmisk/mcp/config/McpPromptConfig;
237259
public final fun component3 ()Lmisk/mcp/config/McpResourceConfig;
238260
public final fun component4 ()Lmisk/mcp/config/McpToolConfig;
239-
public final fun copy (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;)Lmisk/mcp/config/McpServerConfig;
240-
public static synthetic fun copy$default (Lmisk/mcp/config/McpServerConfig;Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;ILjava/lang/Object;)Lmisk/mcp/config/McpServerConfig;
261+
public final fun component5 ()Z
262+
public final fun copy (Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;Z)Lmisk/mcp/config/McpServerConfig;
263+
public static synthetic fun copy$default (Lmisk/mcp/config/McpServerConfig;Ljava/lang/String;Lmisk/mcp/config/McpPromptConfig;Lmisk/mcp/config/McpResourceConfig;Lmisk/mcp/config/McpToolConfig;ZILjava/lang/Object;)Lmisk/mcp/config/McpServerConfig;
241264
public fun equals (Ljava/lang/Object;)Z
265+
public final fun getEnforce_strict_capabilities ()Z
242266
public final fun getPrompts ()Lmisk/mcp/config/McpPromptConfig;
243267
public final fun getResources ()Lmisk/mcp/config/McpResourceConfig;
244268
public final fun getTools ()Lmisk/mcp/config/McpToolConfig;
@@ -260,16 +284,52 @@ public final class misk/mcp/config/McpToolConfig : misk/config/Config {
260284
public fun toString ()Ljava/lang/String;
261285
}
262286

287+
public final class misk/mcp/internal/JsonSchemaExtensionsKt {
288+
public static final fun generateJsonSchema (Lkotlin/reflect/KClass;ILjava/lang/String;)Lkotlinx/serialization/json/JsonObject;
289+
public static synthetic fun generateJsonSchema$default (Lkotlin/reflect/KClass;ILjava/lang/String;ILjava/lang/Object;)Lkotlinx/serialization/json/JsonObject;
290+
}
291+
263292
public final class misk/mcp/internal/McpJsonKt {
264293
public static final fun getMcpJson ()Lkotlinx/serialization/json/Json;
265294
}
266295

296+
public final class misk/mcp/internal/McpServerSession : kotlin/coroutines/AbstractCoroutineContextElement {
297+
public static final field Key Lmisk/mcp/internal/McpServerSession$Key;
298+
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;)V
299+
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;
300+
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;)Lmisk/mcp/internal/McpServerSession;
301+
public static synthetic fun copy$default (Lmisk/mcp/internal/McpServerSession;Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;ILjava/lang/Object;)Lmisk/mcp/internal/McpServerSession;
302+
public fun equals (Ljava/lang/Object;)Z
303+
public final fun getServerSession ()Lio/modelcontextprotocol/kotlin/sdk/server/ServerSession;
304+
public fun hashCode ()I
305+
public fun toString ()Ljava/lang/String;
306+
}
307+
308+
public final class misk/mcp/internal/McpServerSession$Key : kotlin/coroutines/CoroutineContext$Key {
309+
}
310+
311+
public abstract class misk/mcp/internal/MiskServerTransport : io/modelcontextprotocol/kotlin/sdk/shared/AbstractTransport {
312+
public fun <init> ()V
313+
public abstract fun getCall ()Lmisk/web/HttpCall;
314+
public abstract fun getStreamId ()Ljava/lang/String;
315+
public abstract fun handleMessage (Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
316+
}
317+
267318
public final class misk/mcp/testing/ClientExtensionsKt {
268-
public static final fun asKtorClient (Lokhttp3/OkHttpClient;)Lio/ktor/client/HttpClient;
269-
public static final fun asMcpClient (Lio/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
270-
public static final fun asMcpClient (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
271-
public static synthetic fun asMcpClient$default (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
319+
public static final fun asKtorClient (Lokhttp3/OkHttpClient;Z)Lio/ktor/client/HttpClient;
320+
public static synthetic fun asKtorClient$default (Lokhttp3/OkHttpClient;ZILjava/lang/Object;)Lio/ktor/client/HttpClient;
321+
public static final fun asMcpClient (Lio/modelcontextprotocol/kotlin/sdk/shared/AbstractTransport;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/client/ClientOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
322+
public static synthetic fun asMcpClient$default (Lio/modelcontextprotocol/kotlin/sdk/shared/AbstractTransport;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/client/ClientOptions;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
323+
public static final fun asMcpStreamableHttpClient (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
324+
public static synthetic fun asMcpStreamableHttpClient$default (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
272325
public static final fun asMcpStreamableHttpTransport (Lio/ktor/client/HttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport;
273326
public static synthetic fun asMcpStreamableHttpTransport$default (Lio/ktor/client/HttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport;
327+
public static final fun asMcpWebSocketClient (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
328+
public static synthetic fun asMcpWebSocketClient$default (Lokhttp3/OkHttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
329+
public static final fun asMcpWebSocketTransport (Lio/ktor/client/HttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/client/WebSocketClientTransport;
330+
public static synthetic fun asMcpWebSocketTransport$default (Lio/ktor/client/HttpClient;Lokhttp3/HttpUrl;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/client/WebSocketClientTransport;
331+
public static final fun clientOptionsFor (ZZZZZ)Lio/modelcontextprotocol/kotlin/sdk/client/ClientOptions;
332+
public static synthetic fun clientOptionsFor$default (ZZZZZILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/client/ClientOptions;
333+
public static final fun normalizeWebSocketUrlString (Lokhttp3/HttpUrl;)Ljava/lang/String;
274334
}
275335

0 commit comments

Comments
 (0)