Add ktlint (#213)
* Add ktlint * Simplify `initClient` function and clean imports in SseIntegrationTest.
This commit is contained in:
parent
b0f075900a
commit
91cf1205af
7 changed files with 800 additions and 758 deletions
|
|
@ -25,4 +25,4 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,9 +94,7 @@ internal fun ServerSSESession.mcpSseTransport(
|
|||
return transport
|
||||
}
|
||||
|
||||
internal suspend fun RoutingContext.mcpPostEndpoint(
|
||||
transports: ConcurrentMap<String, SseServerTransport>,
|
||||
) {
|
||||
internal suspend fun RoutingContext.mcpPostEndpoint(transports: ConcurrentMap<String, SseServerTransport>) {
|
||||
val sessionId: String = call.request.queryParameters["sessionId"]
|
||||
?: run {
|
||||
call.respond(HttpStatusCode.BadRequest, "sessionId query parameter is not provided")
|
||||
|
|
|
|||
|
|
@ -28,10 +28,8 @@ public typealias SSEServerTransport = SseServerTransport
|
|||
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
|
||||
*/
|
||||
@OptIn(ExperimentalAtomicApi::class)
|
||||
public class SseServerTransport(
|
||||
private val endpoint: String,
|
||||
private val session: ServerSSESession,
|
||||
) : AbstractTransport() {
|
||||
public class SseServerTransport(private val endpoint: String, private val session: ServerSSESession) :
|
||||
AbstractTransport() {
|
||||
private val initialized: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
|
|
@ -44,13 +42,15 @@ public class SseServerTransport(
|
|||
*/
|
||||
override suspend fun start() {
|
||||
if (!initialized.compareAndSet(expectedValue = false, newValue = true)) {
|
||||
error("SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.")
|
||||
error(
|
||||
"SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.",
|
||||
)
|
||||
}
|
||||
|
||||
// Send the endpoint event
|
||||
session.send(
|
||||
event = "endpoint",
|
||||
data = "${endpoint.encodeURLPath()}?$SESSION_ID_PARAM=${sessionId}",
|
||||
data = "${endpoint.encodeURLPath()}?$SESSION_ID_PARAM=$sessionId",
|
||||
)
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -64,10 +64,8 @@ private val logger = KotlinLogging.logger {}
|
|||
* @property capabilities The capabilities this server supports.
|
||||
* @property enforceStrictCapabilities Whether to strictly enforce capabilities when interacting with clients.
|
||||
*/
|
||||
public class ServerOptions(
|
||||
public val capabilities: ServerCapabilities,
|
||||
enforceStrictCapabilities: Boolean = true,
|
||||
) : ProtocolOptions(enforceStrictCapabilities = enforceStrictCapabilities)
|
||||
public class ServerOptions(public val capabilities: ServerCapabilities, enforceStrictCapabilities: Boolean = true) :
|
||||
ProtocolOptions(enforceStrictCapabilities = enforceStrictCapabilities)
|
||||
|
||||
/**
|
||||
* An MCP server on top of a pluggable transport.
|
||||
|
|
@ -79,11 +77,11 @@ public class ServerOptions(
|
|||
* @param serverInfo Information about this server implementation (name, version).
|
||||
* @param options Configuration options for the server.
|
||||
*/
|
||||
public open class Server(
|
||||
private val serverInfo: Implementation,
|
||||
options: ServerOptions,
|
||||
) : Protocol(options) {
|
||||
public open class Server(private val serverInfo: Implementation, options: ServerOptions) : Protocol(options) {
|
||||
@Suppress("ktlint:standard:backing-property-naming")
|
||||
private var _onInitialized: (() -> Unit) = {}
|
||||
|
||||
@Suppress("ktlint:standard:backing-property-naming")
|
||||
private var _onClose: () -> Unit = {}
|
||||
|
||||
/**
|
||||
|
|
@ -221,7 +219,7 @@ public open class Server(
|
|||
title: String? = null,
|
||||
outputSchema: Tool.Output? = null,
|
||||
toolAnnotations: ToolAnnotations? = null,
|
||||
handler: suspend (CallToolRequest) -> CallToolResult
|
||||
handler: suspend (CallToolRequest) -> CallToolResult,
|
||||
) {
|
||||
val tool = Tool(name, title, description, inputSchema, outputSchema, toolAnnotations)
|
||||
addTool(tool, handler)
|
||||
|
|
@ -325,7 +323,7 @@ public open class Server(
|
|||
name: String,
|
||||
description: String? = null,
|
||||
arguments: List<PromptArgument>? = null,
|
||||
promptProvider: suspend (GetPromptRequest) -> GetPromptResult
|
||||
promptProvider: suspend (GetPromptRequest) -> GetPromptResult,
|
||||
) {
|
||||
val prompt = Prompt(name = name, description = description, arguments = arguments)
|
||||
addPrompt(prompt, promptProvider)
|
||||
|
|
@ -416,7 +414,7 @@ public open class Server(
|
|||
name: String,
|
||||
description: String,
|
||||
mimeType: String = "text/html",
|
||||
readHandler: suspend (ReadResourceRequest) -> ReadResourceResult
|
||||
readHandler: suspend (ReadResourceRequest) -> ReadResourceResult,
|
||||
) {
|
||||
if (capabilities.resources == null) {
|
||||
logger.error { "Failed to add resource '$name': Server does not support resources capability" }
|
||||
|
|
@ -426,7 +424,7 @@ public open class Server(
|
|||
_resources.update { current ->
|
||||
current.put(
|
||||
uri,
|
||||
RegisteredResource(Resource(uri, name, description, mimeType), readHandler)
|
||||
RegisteredResource(Resource(uri, name, description, mimeType), readHandler),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -507,9 +505,7 @@ public open class Server(
|
|||
* @return The result of the ping request.
|
||||
* @throws IllegalStateException If for some reason the method is not supported or the connection is closed.
|
||||
*/
|
||||
public suspend fun ping(): EmptyRequestResult {
|
||||
return request<EmptyRequestResult>(PingRequest())
|
||||
}
|
||||
public suspend fun ping(): EmptyRequestResult = request<EmptyRequestResult>(PingRequest())
|
||||
|
||||
/**
|
||||
* Creates a message using the server's sampling capability.
|
||||
|
|
@ -521,7 +517,7 @@ public open class Server(
|
|||
*/
|
||||
public suspend fun createMessage(
|
||||
params: CreateMessageRequest,
|
||||
options: RequestOptions? = null
|
||||
options: RequestOptions? = null,
|
||||
): CreateMessageResult {
|
||||
logger.debug { "Creating message with params: $params" }
|
||||
return request<CreateMessageResult>(params, options)
|
||||
|
|
@ -537,7 +533,7 @@ public open class Server(
|
|||
*/
|
||||
public suspend fun listRoots(
|
||||
params: JsonObject = EmptyJsonObject,
|
||||
options: RequestOptions? = null
|
||||
options: RequestOptions? = null,
|
||||
): ListRootsResult {
|
||||
logger.debug { "Listing roots with params: $params" }
|
||||
return request<ListRootsResult>(ListRootsRequest(params), options)
|
||||
|
|
@ -546,7 +542,7 @@ public open class Server(
|
|||
public suspend fun createElicitation(
|
||||
message: String,
|
||||
requestedSchema: RequestedSchema,
|
||||
options: RequestOptions? = null
|
||||
options: RequestOptions? = null,
|
||||
): CreateElicitationResult {
|
||||
logger.debug { "Creating elicitation with message: $message" }
|
||||
return request(CreateElicitationRequest(message, requestedSchema), options)
|
||||
|
|
@ -607,14 +603,16 @@ public open class Server(
|
|||
val protocolVersion = if (SUPPORTED_PROTOCOL_VERSIONS.contains(requestedVersion)) {
|
||||
requestedVersion
|
||||
} else {
|
||||
logger.warn { "Client requested unsupported protocol version $requestedVersion, falling back to $LATEST_PROTOCOL_VERSION" }
|
||||
logger.warn {
|
||||
"Client requested unsupported protocol version $requestedVersion, falling back to $LATEST_PROTOCOL_VERSION"
|
||||
}
|
||||
LATEST_PROTOCOL_VERSION
|
||||
}
|
||||
|
||||
return InitializeResult(
|
||||
protocolVersion = protocolVersion,
|
||||
capabilities = capabilities,
|
||||
serverInfo = serverInfo
|
||||
serverInfo = serverInfo,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -723,26 +721,34 @@ public open class Server(
|
|||
}
|
||||
|
||||
"notifications/resources/updated",
|
||||
"notifications/resources/list_changed" -> {
|
||||
"notifications/resources/list_changed",
|
||||
-> {
|
||||
if (capabilities.resources == null) {
|
||||
throw IllegalStateException("Server does not support notifying about resources (required for ${method.value})")
|
||||
throw IllegalStateException(
|
||||
"Server does not support notifying about resources (required for ${method.value})",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"notifications/tools/list_changed" -> {
|
||||
if (capabilities.tools == null) {
|
||||
throw IllegalStateException("Server does not support notifying of tool list changes (required for ${method.value})")
|
||||
throw IllegalStateException(
|
||||
"Server does not support notifying of tool list changes (required for ${method.value})",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"notifications/prompts/list_changed" -> {
|
||||
if (capabilities.prompts == null) {
|
||||
throw IllegalStateException("Server does not support notifying of prompt list changes (required for ${method.value})")
|
||||
throw IllegalStateException(
|
||||
"Server does not support notifying of prompt list changes (required for ${method.value})",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"notifications/cancelled",
|
||||
"notifications/progress" -> {
|
||||
"notifications/progress",
|
||||
-> {
|
||||
// Always allowed
|
||||
}
|
||||
}
|
||||
|
|
@ -772,7 +778,8 @@ public open class Server(
|
|||
}
|
||||
|
||||
"prompts/get",
|
||||
"prompts/list" -> {
|
||||
"prompts/list",
|
||||
-> {
|
||||
if (capabilities.prompts == null) {
|
||||
throw IllegalStateException("Server does not support prompts (required for $method)")
|
||||
}
|
||||
|
|
@ -780,14 +787,16 @@ public open class Server(
|
|||
|
||||
"resources/list",
|
||||
"resources/templates/list",
|
||||
"resources/read" -> {
|
||||
"resources/read",
|
||||
-> {
|
||||
if (capabilities.resources == null) {
|
||||
throw IllegalStateException("Server does not support resources (required for $method)")
|
||||
}
|
||||
}
|
||||
|
||||
"tools/call",
|
||||
"tools/list" -> {
|
||||
"tools/list",
|
||||
-> {
|
||||
if (capabilities.tools == null) {
|
||||
throw IllegalStateException("Server does not support tools (required for $method)")
|
||||
}
|
||||
|
|
@ -806,10 +815,7 @@ public open class Server(
|
|||
* @property tool The tool definition.
|
||||
* @property handler A suspend function to handle the tool call requests.
|
||||
*/
|
||||
public data class RegisteredTool(
|
||||
val tool: Tool,
|
||||
val handler: suspend (CallToolRequest) -> CallToolResult
|
||||
)
|
||||
public data class RegisteredTool(val tool: Tool, val handler: suspend (CallToolRequest) -> CallToolResult)
|
||||
|
||||
/**
|
||||
* A wrapper class representing a registered prompt on the server.
|
||||
|
|
@ -819,7 +825,7 @@ public data class RegisteredTool(
|
|||
*/
|
||||
public data class RegisteredPrompt(
|
||||
val prompt: Prompt,
|
||||
val messageProvider: suspend (GetPromptRequest) -> GetPromptResult
|
||||
val messageProvider: suspend (GetPromptRequest) -> GetPromptResult,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -830,5 +836,5 @@ public data class RegisteredPrompt(
|
|||
*/
|
||||
public data class RegisteredResource(
|
||||
val resource: Resource,
|
||||
val readHandler: suspend (ReadResourceRequest) -> ReadResourceResult
|
||||
val readHandler: suspend (ReadResourceRequest) -> ReadResourceResult,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,10 +31,7 @@ import kotlin.coroutines.CoroutineContext
|
|||
* Reads from System.in and writes to System.out.
|
||||
*/
|
||||
@OptIn(ExperimentalAtomicApi::class)
|
||||
public class StdioServerTransport(
|
||||
private val inputStream: Source,
|
||||
outputStream: Sink
|
||||
) : AbstractTransport() {
|
||||
public class StdioServerTransport(private val inputStream: Source, outputStream: Sink) : AbstractTransport() {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
private val readBuffer = ReadBuffer()
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ import io.modelcontextprotocol.kotlin.sdk.shared.IMPLEMENTATION_NAME
|
|||
* @param options Optional server configuration settings for the MCP server.
|
||||
* @param handler A suspend function that defines the server's behavior.
|
||||
*/
|
||||
public fun Route.mcpWebSocket(
|
||||
options: ServerOptions? = null,
|
||||
handler: suspend Server.() -> Unit = {},
|
||||
) {
|
||||
public fun Route.mcpWebSocket(options: ServerOptions? = null, handler: suspend Server.() -> Unit = {}) {
|
||||
webSocket {
|
||||
createMcpServer(this, options, handler)
|
||||
}
|
||||
|
|
@ -30,11 +27,7 @@ public fun Route.mcpWebSocket(
|
|||
* @param options Optional server configuration settings for the MCP server.
|
||||
* @param handler A suspend function that defines the server's behavior.
|
||||
*/
|
||||
public fun Route.mcpWebSocket(
|
||||
path: String,
|
||||
options: ServerOptions? = null,
|
||||
handler: suspend Server.() -> Unit = {},
|
||||
) {
|
||||
public fun Route.mcpWebSocket(path: String, options: ServerOptions? = null, handler: suspend Server.() -> Unit = {}) {
|
||||
webSocket(path) {
|
||||
createMcpServer(this, options, handler)
|
||||
}
|
||||
|
|
@ -45,9 +38,7 @@ public fun Route.mcpWebSocket(
|
|||
*
|
||||
* @param handler A suspend function that defines the behavior of the transport layer.
|
||||
*/
|
||||
public fun Route.mcpWebSocketTransport(
|
||||
handler: suspend WebSocketMcpServerTransport.() -> Unit = {},
|
||||
) {
|
||||
public fun Route.mcpWebSocketTransport(handler: suspend WebSocketMcpServerTransport.() -> Unit = {}) {
|
||||
webSocket {
|
||||
val transport = createMcpTransport(this)
|
||||
transport.start()
|
||||
|
|
@ -62,10 +53,7 @@ public fun Route.mcpWebSocketTransport(
|
|||
* @param path The URL path at which to register the WebSocket route.
|
||||
* @param handler A suspend function that defines the behavior of the transport layer.
|
||||
*/
|
||||
public fun Route.mcpWebSocketTransport(
|
||||
path: String,
|
||||
handler: suspend WebSocketMcpServerTransport.() -> Unit = {},
|
||||
) {
|
||||
public fun Route.mcpWebSocketTransport(path: String, handler: suspend WebSocketMcpServerTransport.() -> Unit = {}) {
|
||||
webSocket(path) {
|
||||
val transport = createMcpTransport(this)
|
||||
transport.start()
|
||||
|
|
@ -74,7 +62,6 @@ public fun Route.mcpWebSocketTransport(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private suspend fun Route.createMcpServer(
|
||||
session: WebSocketServerSession,
|
||||
options: ServerOptions?,
|
||||
|
|
@ -85,14 +72,14 @@ private suspend fun Route.createMcpServer(
|
|||
val server = Server(
|
||||
serverInfo = Implementation(
|
||||
name = IMPLEMENTATION_NAME,
|
||||
version = LIB_VERSION
|
||||
version = LIB_VERSION,
|
||||
),
|
||||
options = options ?: ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
prompts = ServerCapabilities.Prompts(listChanged = null),
|
||||
resources = ServerCapabilities.Resources(subscribe = null, listChanged = null),
|
||||
tools = ServerCapabilities.Tools(listChanged = null),
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -101,8 +88,5 @@ private suspend fun Route.createMcpServer(
|
|||
server.close()
|
||||
}
|
||||
|
||||
private fun createMcpTransport(
|
||||
session: WebSocketServerSession,
|
||||
): WebSocketMcpServerTransport {
|
||||
return WebSocketMcpServerTransport(session)
|
||||
}
|
||||
private fun createMcpTransport(session: WebSocketServerSession): WebSocketMcpServerTransport =
|
||||
WebSocketMcpServerTransport(session)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ import io.modelcontextprotocol.kotlin.sdk.shared.WebSocketMcpTransport
|
|||
*
|
||||
* @property session The WebSocket server session used for communication.
|
||||
*/
|
||||
public class WebSocketMcpServerTransport(
|
||||
override val session: WebSocketServerSession,
|
||||
) : WebSocketMcpTransport() {
|
||||
public class WebSocketMcpServerTransport(override val session: WebSocketServerSession) : WebSocketMcpTransport() {
|
||||
override suspend fun initializeSession() {
|
||||
val subprotocol = session.call.request.headers[HttpHeaders.SecWebSocketProtocol]
|
||||
if (subprotocol != MCP_SUBPROTOCOL) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue