mcp4k
Categories
Language:
Kotlin
Stars:
50
Forks:
3
README
mcp4k is a compiler-driven framework that handles all the Model Context Protocol details behind the scenes.
You just annotate your functions and mcp4k takes care of JSON-RPC messages, schema generation and protocol lifecycle:
/**
* Reverses an input string
*
* @param input The string to be reversed
*/
@McpTool
fun reverseString(input: String) =
"Reversed: ${input.reversed()}".toTextContent()
fun main() = runBlocking {
val server = Server.Builder()
.withTool(::reverseString)
.withTransport(StdioTransport())
.build()
server.start()
// Keep server running
while (true) {
delay(1000)
}
}
That’s it! To use the above tool in Claude Desktop (or any other MCP-compatible client), add the compiled binary to your configuration file.
mcp4k will do the following for you:
- Generate the required JSON schemas (including tool and parameter descriptions)
- Handle incoming tool requests
- Convert thrown Kotlin exceptions to MCP error codes
For instance, if this tool received an invalid parameter (like passing a number when a string is expected), it would respond with a -32602 (INVALID_PARAMS) code. The same is true in case an IllegalArgumentException (or any other exception) is thrown from inside a tool function — mcp4k will catch it and map exceptions according to the protocol.
Installation
Add the mcp4k plugin to your multiplatform (or jvm) project:
plugins {
kotlin("multiplatform") version "2.1.0" // or kotlin("jvm")
kotlin("plugin.serialization") version "2.1.0"
id("sh.ondr.mcp4k") version "0.3.5" //
// Prompt the user for confirmation here
true
}
.withSamplingProvider(samplingProvider) // Register the provider
.build()
runBlocking {
client.start()
client.initialize()
// Now, if a server sends a "sampling/createMessage" request,
// the samplingProvider will be invoked to generate a response.
}
Request Cancellations
mcp4k uses Kotlin coroutines for cooperative cancellation. For example, suppose you have a long-running tool operation on the server:
@McpTool
suspend fun slowToolOperation(iterations: Int = 10): ToolContent {
for (i in 1..iterations) {
delay(1000)
}
return "Operation completed successfully after $iterations iterations".toTextContent()
}
From the client side, after you invoked the tool, you can simply cancel the coroutine job:
val requestJob = launch {
client.sendRequest { id ->
CallToolRequest(
id = id,
params = CallToolRequest.CallToolParams(
name = "slowToolOperation",
arguments = mapOf("iterations" to 20),
),
)
}
}
// Let the server do partial work
delay(600)
// Now cancel
requestJob.cancel("User doesn't want to wait anymore")
Under the hood, mcp4k automatically sends a JSON-RPC notifications/cancelled message to the server, and your suspended tool operation will be aborted:
{
"method": "notifications/cancelled",
"jsonrpc": "2.0",
"params": {
"requestId": "2",
"reason": "Client doesn't want to wait anymore"
}
}
This gives you straightforward cancellations across the entire client-server flow.
TODO
✅ Add resource capability
✅ Suspendable logger, @McpTool and @McpPrompt functions
✅ Request cancellations
✅ Pagination
✅ Sampling (client-side)
✅ Roots
⬜ Completions
⬜ Support logging levels
⬜ Proper version negotiation
⬜ Emit progress notifications from @McpTool functions
⬜ Proper MIME detection
⬜ Add FileWatcher to automate resources/updated nofications
⬜ HTTP-SSE transport
⬜ Add references, property descriptions and validation keywords to the JSON schemas
How mcp4k Works
- Annotated
@McpTooland@McpPromptfunctions are processed at compile time. - mcp4k generates schemas, handlers, and registrations automatically.
- Generated code is injected during the IR phase.
- If you mess something up, you (hopefully) get a compile-time error.
Contributing
Issues and pull requests are welcome.
License
Licensed under the Apache License 2.0.
Publisher info
More MCP servers built with Kotlin
The MCP Strava Server facilitates seamless integration between Strava APIs and Claude for Desktop.