-
Notifications
You must be signed in to change notification settings - Fork 88
Support for MCP definations using kotlin annotation #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Support for MCP definations using kotlin annotation #80
Conversation
@devcrocod @e5l it's ready for review. |
Sorry, I don’t fully understand the motivation. |
It basically provides better and more kotlin idiomatic way to define MCP tool.
Now, with the proposed changes, defining a MCP tool is simpler with annotation ( uses kotlin annotations https://kotlinlang.org/docs/annotations.html) similar to how it's there in python sdk which uses decorators (similar concept to kotlin annotations). check out this for example which we built using jar from this changes:
so in short, it's less of a schema generators and more around simplifying MCP tool definitions for kotlin-sdk users. |
That’s understandable, but it doesn’t explain why not support one of the libraries I sent earlier. Besides, the solution using annotations seems excessive to me at this point. Also, adding such a solution complicates support for multiplatform #70 , since reflection is platform-dependent |
because they're MCP agnostic and have a generic purpose (schema generation)
required is only one of the usecase, larger purpose is to reduce verbosity defining MCP tool. i.e
currently, it's too verbose to define a tool and can be simplified.
fair point, hence this PR adds support for doing it with annotations as an another way instead of replacing current one. |
I'm working on a solution based on KSP. With that, we can do this:
Generate code from below code (@McpServerCompnent @mcptool annotation) with KSP as follow:
And we can use it like:
I think this plan is friendly for dependency injection and Kotlin Multiplatform, with less runtime cost. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces support for MCP tools using Kotlin annotations, adding new annotations and registration mechanisms while updating documentation and samples to demonstrate the new usage.
- Added new annotations McpTool and McpParam in the SDK.
- Implemented helper functions to register annotated tools in ServerAnnotations.kt.
- Updated the Server class, sample applications, and documentation to support the new annotated approach.
Reviewed Changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/annotations.kt | Introduces MCP tool and parameter annotations. |
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerAnnotations.kt | Adds functions to register annotated tools with reflection. |
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt | Adjusts access levels and fixes a typo in the initialization function name. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/main.kt | Updates main to support an annotation-based server mode via command-line arguments. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/AnnotatedToolsExample.kt | Provides a sample implementation of annotated MCP tools. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/AnnotatedMcpWeatherServer.kt | Implements an annotated MCP server example. |
samples/weather-stdio-server/README.md | Updates documentation to include both traditional and annotation-based approaches. |
gradle/libs.versions.toml | Adds the kotlin-reflect dependency required for reflection support. |
Files not reviewed (2)
- .idea/artifacts/kotlin_sdk_jvm_0_4_0.xml: Language not supported
- api/kotlin-sdk.api: Language not supported
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerAnnotations.kt
Outdated
Show resolved
Hide resolved
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerAnnotations.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @alpeshvas, thank you for the PR.
I'm fine with a new concept. It looks like it will be better to keep it separate from the core module: the core will have raw implementation without kotlin-reflect dependencies, and annotations can be in a separate module.
Could you please create a new module and extract the annotation and reflection logic?
Co-authored-by: Leonid Stashevsky <e5l@users.noreply.github.com>
7477932
to
7c7afcf
Compare
7c7afcf
to
7d9a27a
Compare
@@ -539,12 +539,12 @@ public open class Server( | |||
) | |||
} | |||
|
|||
private suspend fun handleListTools(): ListToolsResult { | |||
public suspend fun handleListTools(): ListToolsResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
visibility change is needed to be accessible by the annotation module.
val toolList = tools.values.map { it.tool } | ||
return ListToolsResult(tools = toolList, nextCursor = null) | ||
} | ||
|
||
private suspend fun handleCallTool(request: CallToolRequest): CallToolResult { | ||
public suspend fun handleCallTool(request: CallToolRequest): CallToolResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above.
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for MCP definitions using Kotlin annotations by introducing annotation-based tool registration and updating the server API accordingly. Key changes include fixing a typo in the server method name, changing the visibility of tool handler functions to public, and adding new sample implementations for annotated MCP tools.
Reviewed Changes
Copilot reviewed 10 out of 13 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt | Corrected typo in method name and updated handler visibility for tool calls. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/main.kt | Added conditional logic to start the server in annotated or traditional mode based on command-line arguments. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/AnnotatedToolsExample.kt | Introduced annotated tool implementations including a weather summary tool. |
samples/weather-stdio-server/src/main/kotlin/io/modelcontextprotocol/sample/server/AnnotatedMcpWeatherServer.kt | Provided a complete annotated server implementation leveraging the new tool registration mechanism. |
samples/weather-stdio-server/README.md | Updated documentation to describe both traditional and annotation-based tool registration approaches. |
gradle/libs.versions.toml | Added kotlin-reflect dependency required for reflective tool registration. |
feature.annotation/src/main/kotlin/io/modelcontextprotocol/annotation/ServerAnnotations.kt | Implemented annotation-based tool registration for the MCP server using reflection. |
feature.annotation/src/main/kotlin/io/modelcontextprotocol/annotation/Annotations.kt | Defined annotations for MCP tool and parameter metadata. |
Files not reviewed (3)
- api/kotlin-sdk.api: Language not supported
- feature.annotation/build.gradle.kts: Language not supported
- settings.gradle.kts: Language not supported
Comments suppressed due to low confidence (3)
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt:108
- The method name has been corrected from 'onInitalized' to 'onInitialized'. Please ensure that any related documentation or comments are updated to reflect this change.
public fun onInitialized(block: () -> Unit) {
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt:542
- Changing 'handleListTools' visibility from private to public exposes the API. Verify that this aligns with the intended design and usage of the server’s public interface.
public suspend fun handleListTools(): ListToolsResult {
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt:547
- Changing 'handleCallTool' visibility from private to public exposes this API endpoint. Confirm that this change is intentional and that no internal implementation details are inadvertently exposed.
public suspend fun handleCallTool(request: CallToolRequest): CallToolResult {
src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt
Show resolved
Hide resolved
@e5l to run test - |
@alpeshvas I see that the solution is reflection based, which would make it KMP incompatible. Please take a look how I approached it in this fully KMP-compatible It's For the reference. Here is how it works in my KMP @SerialName("get_weather")
@Description("Get the weather for a specific location")
data class GetWeather(val location: String)
fun main() = runBlocking {
val tool = Tool<GetWeather> { "The weather is 73f" }
val myTools = listOf(tool)
val anthropic = Anthropic()
val conversation = mutableListOf<Message>()
conversation += "What is the weather in SF?"
val initialResponse = client.messages.create {
messages = conversation
tools = myTools
}
println("Initial response: ${initialResponse.text}")
conversation += initialResponse
conversation += initialResponse.useTools()
val finalResponse = client.messages.create {
messages = conversation
tools = myTools
}
println("Final response: ${finalResponse.text}")
} https://github.com/xemantic/anthropic-sdk-kotlin#using-tools This is the friendliness/compatibility level I wish to have in |
Fair points,that's the reason relfect based annotation has been moved to a different module, and can be iterated with KSP support or anything else in future iterations with separate PRs. |
Motivation and Context
Add support for #76
How Has This Been Tested?
Unit tested and built jar was locally tested with MCP server built with annotations.
Breaking Changes
No
Types of changes
Checklist
Additional context