* add wasm and ios targets * add yarn.lock file to gitignore * clean up code * fix typo in method name * add wasm server example * update jrelease publishing for klibs * update gradle-publish workflow to use macos runner * update README to reflect multiplatform support and clarify server setup for JVM and WASM * remove the old main file from the kotlin-mcp-server example * update api dump * Refactor `build.gradle.kts` * clean up imports and remove unnecessary charset specification in tests * add JS target configuration and update API dump
151 lines
No EOL
5.2 KiB
Kotlin
151 lines
No EOL
5.2 KiB
Kotlin
package shared
|
|
|
|
import io.ktor.http.HttpStatusCode
|
|
import io.ktor.server.application.install
|
|
import io.ktor.server.cio.CIO
|
|
import io.ktor.server.engine.embeddedServer
|
|
import io.ktor.server.response.respond
|
|
import io.ktor.server.routing.post
|
|
import io.ktor.server.routing.routing
|
|
import io.ktor.server.sse.SSE
|
|
import io.ktor.server.sse.sse
|
|
import io.ktor.util.collections.ConcurrentMap
|
|
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
|
|
import io.modelcontextprotocol.kotlin.sdk.GetPromptResult
|
|
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
|
import io.modelcontextprotocol.kotlin.sdk.PromptArgument
|
|
import io.modelcontextprotocol.kotlin.sdk.PromptMessage
|
|
import io.modelcontextprotocol.kotlin.sdk.ReadResourceResult
|
|
import io.modelcontextprotocol.kotlin.sdk.Role
|
|
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
|
|
import io.modelcontextprotocol.kotlin.sdk.TextContent
|
|
import io.modelcontextprotocol.kotlin.sdk.TextResourceContents
|
|
import io.modelcontextprotocol.kotlin.sdk.Tool
|
|
import io.modelcontextprotocol.kotlin.sdk.server.Server
|
|
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
|
|
import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
|
|
import io.modelcontextprotocol.kotlin.sdk.server.mcp
|
|
import kotlin.collections.set
|
|
|
|
fun configureServer(): Server {
|
|
val server = Server(
|
|
Implementation(
|
|
name = "mcp-kotlin test server",
|
|
version = "0.1.0"
|
|
),
|
|
ServerOptions(
|
|
capabilities = ServerCapabilities(
|
|
prompts = ServerCapabilities.Prompts(listChanged = true),
|
|
resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
|
|
tools = ServerCapabilities.Tools(listChanged = true),
|
|
)
|
|
)
|
|
)
|
|
|
|
server.addPrompt(
|
|
name = "Kotlin Developer",
|
|
description = "Develop small kotlin applications",
|
|
arguments = listOf(
|
|
PromptArgument(
|
|
name = "Project Name",
|
|
description = "Project name for the new project",
|
|
required = true
|
|
)
|
|
)
|
|
) { request ->
|
|
GetPromptResult(
|
|
"Description for ${request.name}",
|
|
messages = listOf(
|
|
PromptMessage(
|
|
role = Role.user,
|
|
content = TextContent("Develop a kotlin project named <name>${request.arguments?.get("Project Name")}</name>")
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
// Add a tool
|
|
server.addTool(
|
|
name = "kotlin-sdk-tool",
|
|
description = "A test tool",
|
|
inputSchema = Tool.Input()
|
|
) { request ->
|
|
CallToolResult(
|
|
content = listOf(TextContent("Hello, world!"))
|
|
)
|
|
}
|
|
|
|
// Add a resource
|
|
server.addResource(
|
|
uri = "https://search.com/",
|
|
name = "Web Search",
|
|
description = "Web search engine",
|
|
mimeType = "text/html"
|
|
) { request ->
|
|
ReadResourceResult(
|
|
contents = listOf(
|
|
TextResourceContents("Placeholder content for ${request.uri}", request.uri, "text/html")
|
|
)
|
|
)
|
|
}
|
|
|
|
return server
|
|
}
|
|
|
|
suspend fun runSseMcpServerWithPlainConfiguration(port: Int): Unit {
|
|
val servers = ConcurrentMap<String, Server>()
|
|
println("Starting sse server on port $port. ")
|
|
println("Use inspector to connect to the http://localhost:$port/sse")
|
|
|
|
embeddedServer(CIO, host = "0.0.0.0", port = port) {
|
|
install(SSE)
|
|
routing {
|
|
sse("/sse") {
|
|
val transport = SseServerTransport("/message", this)
|
|
val server = configureServer()
|
|
|
|
// For SSE, you can also add prompts/tools/resources if needed:
|
|
// server.addTool(...), server.addPrompt(...), server.addResource(...)
|
|
|
|
servers[transport.sessionId] = server
|
|
|
|
server.onClose {
|
|
println("Server closed")
|
|
servers.remove(transport.sessionId)
|
|
}
|
|
|
|
server.connect(transport)
|
|
}
|
|
post("/message") {
|
|
println("Received Message")
|
|
val sessionId: String = call.request.queryParameters["sessionId"]!!
|
|
val transport = servers[sessionId]?.transport as? SseServerTransport
|
|
if (transport == null) {
|
|
call.respond(HttpStatusCode.NotFound, "Session not found")
|
|
return@post
|
|
}
|
|
|
|
transport.handlePostMessage(call)
|
|
}
|
|
}
|
|
}.startSuspend(wait = true)
|
|
}
|
|
|
|
/**
|
|
* Starts an SSE (Server Sent Events) MCP server using the Ktor framework and the specified port.
|
|
*
|
|
* The url can be accessed in the MCP inspector at [http://localhost:$port]
|
|
*
|
|
* @param port The port number on which the SSE MCP server will listen for client connections.
|
|
* @return Unit This method does not return a value.
|
|
*/
|
|
suspend fun runSseMcpServerUsingKtorPlugin(port: Int): Unit {
|
|
println("Starting sse server on port $port")
|
|
println("Use inspector to connect to the http://localhost:$port/sse")
|
|
|
|
embeddedServer(CIO, host = "0.0.0.0", port = port) {
|
|
mcp {
|
|
return@mcp configureServer()
|
|
}
|
|
}.startSuspend(wait = true)
|
|
} |