modelcontextprotocol / modelcontextprotocol/kotlin-sdk
Add Declarative KSP for MCP Server
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 1.5k
- Forks
- 248
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 23
Description
We can make a declarative tool for MCP server developing.
The expected function is like following:
We write code:
@McpServer
public class MyServerComponent {
@McpTool(description = "Response as a list")
public fun response(
@Description("The first value in the list") message1: String,
@Description("The second value in the list") message2: String,
): List<String> {
return listOf(message1, message2)
}
}
And we can use it like:
val server = Server(...)
val component = MyServerComponent() // maybe injected from DI framework
server.addTools(component.tools())
This can be implemented by KSP codegen.
Expected behaviour:
Following code is generated:
// extension fun tools() for annotated class
public fun MyServerComponent.tools(adapter: ServerAdapter = ServerAdapter()): List<RegisteredTool> = listOf(
adapter.makeTool(
"response",
"Response as a list",
this::`response$boxed`
),
)
// schema and input type for annotated method
@Serializable
internal data class `MyServerComponent$response$Box`(
@property:Description(`value` = "The first value in the list")
public val message1: String,
@property:Description(`value` = "The second value in the list")
public val message2: String,
)
// Proper boxing logic for method parameters
internal suspend fun MyServerComponent.`response$boxed`(box: `MyServerComponent$response$Box`): List<String> = response(
message1 = box.message1,
message2 = box.message2,
)
When the annotated function returns String, the tool should return TextContent that exactly contains the string.
When the annotated function returns Serializable types, the tool should return TextContent that contains the serialized result.
When the annotated function throws an exception, the tool should return a error with TextContent that contains error message.
When the annotated function requires multiple parameters, the tool should box these parameters with their descriptions together as a Serializable class.
When the annotated function have parameters with @Description or other annotations about the schema, these annotations on parameters should be copied to the schema accordingly.
As the kotlin-sdk only supports object type input schema, when the parameter is: a primitive type, a sealed type, a nullable type, the schema cannot be "type": "object". Then we need to box the parameter with a object type:
@Serializable
data class Box<T>(
val value: T,
)
So its schema can be expressed with "type": "object"
Otherwise, as there is a single parameter and no need to box, we should generate the schema directly according its type, allowing developers to customize the input schema.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the existing Server, ServerAdapter, RegisteredTool, and annotation entry points in the Kotlin SDK, then trace how tool schemas and results are currently represented. The work is complete when KSP-generated tools cover the annotated class and method cases described here, including parameter boxing, copied schema annotations, serialized results, and error text.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100